Import Cobalt 19.master.0.203780
Includes the following patches:
https://cobalt-review.googlesource.com/c/cobalt/+/5210
by errong.leng@samsung.com
https://cobalt-review.googlesource.com/c/cobalt/+/5270
by linus.wang@samsung.com
diff --git a/src/third_party/llvm-project/clang-tools-extra/.arcconfig b/src/third_party/llvm-project/clang-tools-extra/.arcconfig
new file mode 100644
index 0000000..d4a0016
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/.arcconfig
@@ -0,0 +1,4 @@
+{
+ "repository.callsign" : "CTE",
+ "conduit_uri" : "https://reviews.llvm.org/"
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/CMakeLists.txt
new file mode 100644
index 0000000..c434682
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/CMakeLists.txt
@@ -0,0 +1,29 @@
+add_subdirectory(clang-apply-replacements)
+add_subdirectory(clang-reorder-fields)
+add_subdirectory(modularize)
+if(CLANG_ENABLE_STATIC_ANALYZER)
+add_subdirectory(clang-tidy)
+add_subdirectory(clang-tidy-vs)
+endif()
+
+add_subdirectory(change-namespace)
+add_subdirectory(clang-doc)
+add_subdirectory(clang-query)
+add_subdirectory(clang-move)
+add_subdirectory(clangd)
+add_subdirectory(include-fixer)
+add_subdirectory(pp-trace)
+add_subdirectory(tool-template)
+
+# Add the common testsuite after all the tools.
+if(CLANG_INCLUDE_TESTS)
+add_subdirectory(test)
+add_subdirectory(unittests)
+endif()
+
+option(CLANG_TOOLS_EXTRA_INCLUDE_DOCS "Generate build targets for the Clang Extra Tools docs."
+ ${LLVM_INCLUDE_DOCS})
+if( CLANG_TOOLS_EXTRA_INCLUDE_DOCS )
+ add_subdirectory(docs)
+endif()
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/CODE_OWNERS.TXT b/src/third_party/llvm-project/clang-tools-extra/CODE_OWNERS.TXT
new file mode 100644
index 0000000..af8beb4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/CODE_OWNERS.TXT
@@ -0,0 +1,21 @@
+This file is a list of the people responsible for ensuring that patches for a
+particular tool are reviewed, either by themself or by someone else. They are
+also the gatekeepers for their part of Clang, with the final word on what goes
+in or not.
+
+The list is sorted by surname and formatted to allow easy grepping and
+beautification by scripts. The fields are: name (N), email (E), web-address
+(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
+(S).
+
+N: Peter Collingbourne
+E: peter@pcc.me.uk
+D: clang-query
+
+N: Manuel Klimek
+E: klimek@google.com
+D: clang-rename, all parts of clang-tools-extra not covered by someone else
+
+N: Alexander Kornienko
+E: alexfh@google.com
+D: clang-tidy
diff --git a/src/third_party/llvm-project/clang-tools-extra/LICENSE.TXT b/src/third_party/llvm-project/clang-tools-extra/LICENSE.TXT
new file mode 100644
index 0000000..b886535
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/LICENSE.TXT
@@ -0,0 +1,63 @@
+==============================================================================
+LLVM Release License
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2007-2018 University of Illinois at Urbana-Champaign.
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at
+ Urbana-Champaign, nor the names of its contributors may be used to
+ endorse or promote products derived from this Software without specific
+ prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+The LLVM software contains code written by third parties. Such software will
+have its own individual LICENSE.TXT file in the directory in which it appears.
+This file will describe the copyrights, license, and restrictions which apply
+to that code.
+
+The disclaimer of warranty in the University of Illinois Open Source License
+applies to all code in the LLVM Distribution, and nothing in any of the
+other licenses gives permission to use the names of the LLVM Team or the
+University of Illinois to endorse or promote products derived from this
+Software.
+
+The following pieces of software have additional or alternate copyrights,
+licenses, and/or restrictions:
+
+Program Directory
+------- ---------
+clang-tidy clang-tidy/cert
+clang-tidy clang-tidy/hicpp
diff --git a/src/third_party/llvm-project/clang-tools-extra/README.txt b/src/third_party/llvm-project/clang-tools-extra/README.txt
new file mode 100644
index 0000000..9809cc3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/README.txt
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+// Clang Tools repository
+//===----------------------------------------------------------------------===//
+
+Welcome to the repository of extra Clang Tools. This repository holds tools
+that are developed as part of the LLVM compiler infrastructure project and the
+Clang frontend. These tools are kept in a separate "extra" repository to
+allow lighter weight checkouts of the core Clang codebase.
+
+This repository is only intended to be checked out inside of a full LLVM+Clang
+tree, and in the 'tools/extra' subdirectory of the Clang checkout.
+
+All discussion regarding Clang, Clang-based tools, and code in this repository
+should be held using the standard Clang mailing lists:
+ http://lists.llvm.org/mailman/listinfo/cfe-dev
+
+Code review for this tree should take place on the standard Clang patch and
+commit lists:
+ http://lists.llvm.org/mailman/listinfo/cfe-commits
+
+If you find a bug in these tools, please file it in the LLVM bug tracker:
+ http://llvm.org/bugs/
diff --git a/src/third_party/llvm-project/clang-tools-extra/change-namespace/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/change-namespace/CMakeLists.txt
new file mode 100644
index 0000000..1c8aba9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/change-namespace/CMakeLists.txt
@@ -0,0 +1,19 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+add_clang_library(clangChangeNamespace
+ ChangeNamespace.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFormat
+ clangFrontend
+ clangLex
+ clangTooling
+ clangToolingCore
+ )
+
+add_subdirectory(tool)
diff --git a/src/third_party/llvm-project/clang-tools-extra/change-namespace/ChangeNamespace.cpp b/src/third_party/llvm-project/clang-tools-extra/change-namespace/ChangeNamespace.cpp
new file mode 100644
index 0000000..35c321a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/change-namespace/ChangeNamespace.cpp
@@ -0,0 +1,1015 @@
+//===-- ChangeNamespace.cpp - Change namespace implementation -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "ChangeNamespace.h"
+#include "clang/Format/Format.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace change_namespace {
+
+namespace {
+
+inline std::string
+joinNamespaces(const llvm::SmallVectorImpl<StringRef> &Namespaces) {
+ if (Namespaces.empty())
+ return "";
+ std::string Result = Namespaces.front();
+ for (auto I = Namespaces.begin() + 1, E = Namespaces.end(); I != E; ++I)
+ Result += ("::" + *I).str();
+ return Result;
+}
+
+// Given "a::b::c", returns {"a", "b", "c"}.
+llvm::SmallVector<llvm::StringRef, 4> splitSymbolName(llvm::StringRef Name) {
+ llvm::SmallVector<llvm::StringRef, 4> Splitted;
+ Name.split(Splitted, "::", /*MaxSplit=*/-1,
+ /*KeepEmpty=*/false);
+ return Splitted;
+}
+
+SourceLocation startLocationForType(TypeLoc TLoc) {
+ // For elaborated types (e.g. `struct a::A`) we want the portion after the
+ // `struct` but including the namespace qualifier, `a::`.
+ if (TLoc.getTypeLocClass() == TypeLoc::Elaborated) {
+ NestedNameSpecifierLoc NestedNameSpecifier =
+ TLoc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
+ if (NestedNameSpecifier.getNestedNameSpecifier())
+ return NestedNameSpecifier.getBeginLoc();
+ TLoc = TLoc.getNextTypeLoc();
+ }
+ return TLoc.getLocStart();
+}
+
+SourceLocation endLocationForType(TypeLoc TLoc) {
+ // Dig past any namespace or keyword qualifications.
+ while (TLoc.getTypeLocClass() == TypeLoc::Elaborated ||
+ TLoc.getTypeLocClass() == TypeLoc::Qualified)
+ TLoc = TLoc.getNextTypeLoc();
+
+ // The location for template specializations (e.g. Foo<int>) includes the
+ // templated types in its location range. We want to restrict this to just
+ // before the `<` character.
+ if (TLoc.getTypeLocClass() == TypeLoc::TemplateSpecialization)
+ return TLoc.castAs<TemplateSpecializationTypeLoc>()
+ .getLAngleLoc()
+ .getLocWithOffset(-1);
+ return TLoc.getEndLoc();
+}
+
+// Returns the containing namespace of `InnerNs` by skipping `PartialNsName`.
+// If the `InnerNs` does not have `PartialNsName` as suffix, or `PartialNsName`
+// is empty, nullptr is returned.
+// For example, if `InnerNs` is "a::b::c" and `PartialNsName` is "b::c", then
+// the NamespaceDecl of namespace "a" will be returned.
+const NamespaceDecl *getOuterNamespace(const NamespaceDecl *InnerNs,
+ llvm::StringRef PartialNsName) {
+ if (!InnerNs || PartialNsName.empty())
+ return nullptr;
+ const auto *CurrentContext = llvm::cast<DeclContext>(InnerNs);
+ const auto *CurrentNs = InnerNs;
+ auto PartialNsNameSplitted = splitSymbolName(PartialNsName);
+ while (!PartialNsNameSplitted.empty()) {
+ // Get the inner-most namespace in CurrentContext.
+ while (CurrentContext && !llvm::isa<NamespaceDecl>(CurrentContext))
+ CurrentContext = CurrentContext->getParent();
+ if (!CurrentContext)
+ return nullptr;
+ CurrentNs = llvm::cast<NamespaceDecl>(CurrentContext);
+ if (PartialNsNameSplitted.back() != CurrentNs->getNameAsString())
+ return nullptr;
+ PartialNsNameSplitted.pop_back();
+ CurrentContext = CurrentContext->getParent();
+ }
+ return CurrentNs;
+}
+
+static std::unique_ptr<Lexer>
+getLexerStartingFromLoc(SourceLocation Loc, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ if (Loc.isMacroID() &&
+ !Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
+ return nullptr;
+ // Break down the source location.
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ // Try to load the file buffer.
+ bool InvalidTemp = false;
+ llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
+ if (InvalidTemp)
+ return nullptr;
+
+ const char *TokBegin = File.data() + LocInfo.second;
+ // Lex from the start of the given location.
+ return llvm::make_unique<Lexer>(SM.getLocForStartOfFile(LocInfo.first),
+ LangOpts, File.begin(), TokBegin, File.end());
+}
+
+// FIXME: get rid of this helper function if this is supported in clang-refactor
+// library.
+static SourceLocation getStartOfNextLine(SourceLocation Loc,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ std::unique_ptr<Lexer> Lex = getLexerStartingFromLoc(Loc, SM, LangOpts);
+ if (!Lex.get())
+ return SourceLocation();
+ llvm::SmallVector<char, 16> Line;
+ // FIXME: this is a bit hacky to get ReadToEndOfLine work.
+ Lex->setParsingPreprocessorDirective(true);
+ Lex->ReadToEndOfLine(&Line);
+ auto End = Loc.getLocWithOffset(Line.size());
+ return SM.getLocForEndOfFile(SM.getDecomposedLoc(Loc).first) == End
+ ? End
+ : End.getLocWithOffset(1);
+}
+
+// Returns `R` with new range that refers to code after `Replaces` being
+// applied.
+tooling::Replacement
+getReplacementInChangedCode(const tooling::Replacements &Replaces,
+ const tooling::Replacement &R) {
+ unsigned NewStart = Replaces.getShiftedCodePosition(R.getOffset());
+ unsigned NewEnd =
+ Replaces.getShiftedCodePosition(R.getOffset() + R.getLength());
+ return tooling::Replacement(R.getFilePath(), NewStart, NewEnd - NewStart,
+ R.getReplacementText());
+}
+
+// Adds a replacement `R` into `Replaces` or merges it into `Replaces` by
+// applying all existing Replaces first if there is conflict.
+void addOrMergeReplacement(const tooling::Replacement &R,
+ tooling::Replacements *Replaces) {
+ auto Err = Replaces->add(R);
+ if (Err) {
+ llvm::consumeError(std::move(Err));
+ auto Replace = getReplacementInChangedCode(*Replaces, R);
+ *Replaces = Replaces->merge(tooling::Replacements(Replace));
+ }
+}
+
+tooling::Replacement createReplacement(SourceLocation Start, SourceLocation End,
+ llvm::StringRef ReplacementText,
+ const SourceManager &SM) {
+ if (!Start.isValid() || !End.isValid()) {
+ llvm::errs() << "start or end location were invalid\n";
+ return tooling::Replacement();
+ }
+ if (SM.getDecomposedLoc(Start).first != SM.getDecomposedLoc(End).first) {
+ llvm::errs()
+ << "start or end location were in different macro expansions\n";
+ return tooling::Replacement();
+ }
+ Start = SM.getSpellingLoc(Start);
+ End = SM.getSpellingLoc(End);
+ if (SM.getFileID(Start) != SM.getFileID(End)) {
+ llvm::errs() << "start or end location were in different files\n";
+ return tooling::Replacement();
+ }
+ return tooling::Replacement(
+ SM, CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
+ SM.getSpellingLoc(End)),
+ ReplacementText);
+}
+
+void addReplacementOrDie(
+ SourceLocation Start, SourceLocation End, llvm::StringRef ReplacementText,
+ const SourceManager &SM,
+ std::map<std::string, tooling::Replacements> *FileToReplacements) {
+ const auto R = createReplacement(Start, End, ReplacementText, SM);
+ auto Err = (*FileToReplacements)[R.getFilePath()].add(R);
+ if (Err)
+ llvm_unreachable(llvm::toString(std::move(Err)).c_str());
+}
+
+tooling::Replacement createInsertion(SourceLocation Loc,
+ llvm::StringRef InsertText,
+ const SourceManager &SM) {
+ if (Loc.isInvalid()) {
+ llvm::errs() << "insert Location is invalid.\n";
+ return tooling::Replacement();
+ }
+ Loc = SM.getSpellingLoc(Loc);
+ return tooling::Replacement(SM, Loc, 0, InsertText);
+}
+
+// Returns the shortest qualified name for declaration `DeclName` in the
+// namespace `NsName`. For example, if `DeclName` is "a::b::X" and `NsName`
+// is "a::c::d", then "b::X" will be returned.
+// Note that if `DeclName` is `::b::X` and `NsName` is `::a::b`, this returns
+// "::b::X" instead of "b::X" since there will be a name conflict otherwise.
+// \param DeclName A fully qualified name, "::a::b::X" or "a::b::X".
+// \param NsName A fully qualified name, "::a::b" or "a::b". Global namespace
+// will have empty name.
+std::string getShortestQualifiedNameInNamespace(llvm::StringRef DeclName,
+ llvm::StringRef NsName) {
+ DeclName = DeclName.ltrim(':');
+ NsName = NsName.ltrim(':');
+ if (DeclName.find(':') == llvm::StringRef::npos)
+ return DeclName;
+
+ auto NsNameSplitted = splitSymbolName(NsName);
+ auto DeclNsSplitted = splitSymbolName(DeclName);
+ llvm::StringRef UnqualifiedDeclName = DeclNsSplitted.pop_back_val();
+ // If the Decl is in global namespace, there is no need to shorten it.
+ if (DeclNsSplitted.empty())
+ return UnqualifiedDeclName;
+ // If NsName is the global namespace, we can simply use the DeclName sans
+ // leading "::".
+ if (NsNameSplitted.empty())
+ return DeclName;
+
+ if (NsNameSplitted.front() != DeclNsSplitted.front()) {
+ // The DeclName must be fully-qualified, but we still need to decide if a
+ // leading "::" is necessary. For example, if `NsName` is "a::b::c" and the
+ // `DeclName` is "b::X", then the reference must be qualified as "::b::X"
+ // to avoid conflict.
+ if (llvm::is_contained(NsNameSplitted, DeclNsSplitted.front()))
+ return ("::" + DeclName).str();
+ return DeclName;
+ }
+ // Since there is already an overlap namespace, we know that `DeclName` can be
+ // shortened, so we reduce the longest common prefix.
+ auto DeclI = DeclNsSplitted.begin();
+ auto DeclE = DeclNsSplitted.end();
+ auto NsI = NsNameSplitted.begin();
+ auto NsE = NsNameSplitted.end();
+ for (; DeclI != DeclE && NsI != NsE && *DeclI == *NsI; ++DeclI, ++NsI) {
+ }
+ return (DeclI == DeclE)
+ ? UnqualifiedDeclName.str()
+ : (llvm::join(DeclI, DeclE, "::") + "::" + UnqualifiedDeclName)
+ .str();
+}
+
+std::string wrapCodeInNamespace(StringRef NestedNs, std::string Code) {
+ if (Code.back() != '\n')
+ Code += "\n";
+ auto NsSplitted = splitSymbolName(NestedNs);
+ while (!NsSplitted.empty()) {
+ // FIXME: consider code style for comments.
+ Code = ("namespace " + NsSplitted.back() + " {\n" + Code +
+ "} // namespace " + NsSplitted.back() + "\n")
+ .str();
+ NsSplitted.pop_back();
+ }
+ return Code;
+}
+
+// Returns true if \p D is a nested DeclContext in \p Context
+bool isNestedDeclContext(const DeclContext *D, const DeclContext *Context) {
+ while (D) {
+ if (D == Context)
+ return true;
+ D = D->getParent();
+ }
+ return false;
+}
+
+// Returns true if \p D is visible at \p Loc with DeclContext \p DeclCtx.
+bool isDeclVisibleAtLocation(const SourceManager &SM, const Decl *D,
+ const DeclContext *DeclCtx, SourceLocation Loc) {
+ SourceLocation DeclLoc = SM.getSpellingLoc(D->getLocStart());
+ Loc = SM.getSpellingLoc(Loc);
+ return SM.isBeforeInTranslationUnit(DeclLoc, Loc) &&
+ (SM.getFileID(DeclLoc) == SM.getFileID(Loc) &&
+ isNestedDeclContext(DeclCtx, D->getDeclContext()));
+}
+
+// Given a qualified symbol name, returns true if the symbol will be
+// incorrectly qualified without leading "::".
+bool conflictInNamespace(llvm::StringRef QualifiedSymbol,
+ llvm::StringRef Namespace) {
+ auto SymbolSplitted = splitSymbolName(QualifiedSymbol.trim(":"));
+ assert(!SymbolSplitted.empty());
+ SymbolSplitted.pop_back(); // We are only interested in namespaces.
+
+ if (SymbolSplitted.size() > 1 && !Namespace.empty()) {
+ auto NsSplitted = splitSymbolName(Namespace.trim(":"));
+ assert(!NsSplitted.empty());
+ // We do not check the outermost namespace since it would not be a conflict
+ // if it equals to the symbol's outermost namespace and the symbol name
+ // would have been shortened.
+ for (auto I = NsSplitted.begin() + 1, E = NsSplitted.end(); I != E; ++I) {
+ if (*I == SymbolSplitted.front())
+ return true;
+ }
+ }
+ return false;
+}
+
+AST_MATCHER(EnumDecl, isScoped) {
+ return Node.isScoped();
+}
+
+bool isTemplateParameter(TypeLoc Type) {
+ while (!Type.isNull()) {
+ if (Type.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
+ return true;
+ Type = Type.getNextTypeLoc();
+ }
+ return false;
+}
+
+} // anonymous namespace
+
+ChangeNamespaceTool::ChangeNamespaceTool(
+ llvm::StringRef OldNs, llvm::StringRef NewNs, llvm::StringRef FilePattern,
+ llvm::ArrayRef<std::string> WhiteListedSymbolPatterns,
+ std::map<std::string, tooling::Replacements> *FileToReplacements,
+ llvm::StringRef FallbackStyle)
+ : FallbackStyle(FallbackStyle), FileToReplacements(*FileToReplacements),
+ OldNamespace(OldNs.ltrim(':')), NewNamespace(NewNs.ltrim(':')),
+ FilePattern(FilePattern), FilePatternRE(FilePattern) {
+ FileToReplacements->clear();
+ auto OldNsSplitted = splitSymbolName(OldNamespace);
+ auto NewNsSplitted = splitSymbolName(NewNamespace);
+ // Calculates `DiffOldNamespace` and `DiffNewNamespace`.
+ while (!OldNsSplitted.empty() && !NewNsSplitted.empty() &&
+ OldNsSplitted.front() == NewNsSplitted.front()) {
+ OldNsSplitted.erase(OldNsSplitted.begin());
+ NewNsSplitted.erase(NewNsSplitted.begin());
+ }
+ DiffOldNamespace = joinNamespaces(OldNsSplitted);
+ DiffNewNamespace = joinNamespaces(NewNsSplitted);
+
+ for (const auto &Pattern : WhiteListedSymbolPatterns)
+ WhiteListedSymbolRegexes.emplace_back(Pattern);
+}
+
+void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
+ std::string FullOldNs = "::" + OldNamespace;
+ // Prefix is the outer-most namespace in DiffOldNamespace. For example, if the
+ // OldNamespace is "a::b::c" and DiffOldNamespace is "b::c", then Prefix will
+ // be "a::b". Declarations in this namespace will not be visible in the new
+ // namespace. If DiffOldNamespace is empty, Prefix will be a invalid name "-".
+ llvm::SmallVector<llvm::StringRef, 4> DiffOldNsSplitted;
+ llvm::StringRef(DiffOldNamespace)
+ .split(DiffOldNsSplitted, "::", /*MaxSplit=*/-1,
+ /*KeepEmpty=*/false);
+ std::string Prefix = "-";
+ if (!DiffOldNsSplitted.empty())
+ Prefix = (StringRef(FullOldNs).drop_back(DiffOldNamespace.size()) +
+ DiffOldNsSplitted.front())
+ .str();
+ auto IsInMovedNs =
+ allOf(hasAncestor(namespaceDecl(hasName(FullOldNs)).bind("ns_decl")),
+ isExpansionInFileMatching(FilePattern));
+ auto IsVisibleInNewNs = anyOf(
+ IsInMovedNs, unless(hasAncestor(namespaceDecl(hasName(Prefix)))));
+ // Match using declarations.
+ Finder->addMatcher(
+ usingDecl(isExpansionInFileMatching(FilePattern), IsVisibleInNewNs)
+ .bind("using"),
+ this);
+ // Match using namespace declarations.
+ Finder->addMatcher(usingDirectiveDecl(isExpansionInFileMatching(FilePattern),
+ IsVisibleInNewNs)
+ .bind("using_namespace"),
+ this);
+ // Match namespace alias declarations.
+ Finder->addMatcher(namespaceAliasDecl(isExpansionInFileMatching(FilePattern),
+ IsVisibleInNewNs)
+ .bind("namespace_alias"),
+ this);
+
+ // Match old namespace blocks.
+ Finder->addMatcher(
+ namespaceDecl(hasName(FullOldNs), isExpansionInFileMatching(FilePattern))
+ .bind("old_ns"),
+ this);
+
+ // Match class forward-declarations in the old namespace.
+ // Note that forward-declarations in classes are not matched.
+ Finder->addMatcher(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())),
+ IsInMovedNs, hasParent(namespaceDecl()))
+ .bind("class_fwd_decl"),
+ this);
+
+ // Match template class forward-declarations in the old namespace.
+ Finder->addMatcher(
+ classTemplateDecl(unless(hasDescendant(cxxRecordDecl(isDefinition()))),
+ IsInMovedNs, hasParent(namespaceDecl()))
+ .bind("template_class_fwd_decl"),
+ this);
+
+ // Match references to types that are not defined in the old namespace.
+ // Forward-declarations in the old namespace are also matched since they will
+ // be moved back to the old namespace.
+ auto DeclMatcher = namedDecl(
+ hasAncestor(namespaceDecl()),
+ unless(anyOf(
+ isImplicit(), hasAncestor(namespaceDecl(isAnonymous())),
+ hasAncestor(cxxRecordDecl()),
+ allOf(IsInMovedNs, unless(cxxRecordDecl(unless(isDefinition())))))));
+
+ // Using shadow declarations in classes always refers to base class, which
+ // does not need to be qualified since it can be inferred from inheritance.
+ // Note that this does not match using alias declarations.
+ auto UsingShadowDeclInClass =
+ usingDecl(hasAnyUsingShadowDecl(decl()), hasParent(cxxRecordDecl()));
+
+ // Match TypeLocs on the declaration. Carefully match only the outermost
+ // TypeLoc and template specialization arguments (which are not outermost)
+ // that are directly linked to types matching `DeclMatcher`. Nested name
+ // specifier locs are handled separately below.
+ Finder->addMatcher(
+ typeLoc(IsInMovedNs,
+ loc(qualType(hasDeclaration(DeclMatcher.bind("from_decl")))),
+ unless(anyOf(hasParent(typeLoc(loc(qualType(
+ allOf(hasDeclaration(DeclMatcher),
+ unless(templateSpecializationType())))))),
+ hasParent(nestedNameSpecifierLoc()),
+ hasAncestor(isImplicit()),
+ hasAncestor(UsingShadowDeclInClass),
+ hasAncestor(functionDecl(isDefaulted())))),
+ hasAncestor(decl().bind("dc")))
+ .bind("type"),
+ this);
+
+ // Types in `UsingShadowDecl` is not matched by `typeLoc` above, so we need to
+ // special case it.
+ // Since using declarations inside classes must have the base class in the
+ // nested name specifier, we leave it to the nested name specifier matcher.
+ Finder->addMatcher(usingDecl(IsInMovedNs, hasAnyUsingShadowDecl(decl()),
+ unless(UsingShadowDeclInClass))
+ .bind("using_with_shadow"),
+ this);
+
+ // Handle types in nested name specifier. Specifiers that are in a TypeLoc
+ // matched above are not matched, e.g. "A::" in "A::A" is not matched since
+ // "A::A" would have already been fixed.
+ Finder->addMatcher(
+ nestedNameSpecifierLoc(
+ hasAncestor(decl(IsInMovedNs).bind("dc")),
+ loc(nestedNameSpecifier(
+ specifiesType(hasDeclaration(DeclMatcher.bind("from_decl"))))),
+ unless(anyOf(hasAncestor(isImplicit()),
+ hasAncestor(UsingShadowDeclInClass),
+ hasAncestor(functionDecl(isDefaulted())),
+ hasAncestor(typeLoc(loc(qualType(hasDeclaration(
+ decl(equalsBoundNode("from_decl"))))))))))
+ .bind("nested_specifier_loc"),
+ this);
+
+ // Matches base class initializers in constructors. TypeLocs of base class
+ // initializers do not need to be fixed. For example,
+ // class X : public a::b::Y {
+ // public:
+ // X() : Y::Y() {} // Y::Y do not need namespace specifier.
+ // };
+ Finder->addMatcher(
+ cxxCtorInitializer(isBaseInitializer()).bind("base_initializer"), this);
+
+ // Handle function.
+ // Only handle functions that are defined in a namespace excluding member
+ // function, static methods (qualified by nested specifier), and functions
+ // defined in the global namespace.
+ // Note that the matcher does not exclude calls to out-of-line static method
+ // definitions, so we need to exclude them in the callback handler.
+ auto FuncMatcher =
+ functionDecl(unless(anyOf(cxxMethodDecl(), IsInMovedNs,
+ hasAncestor(namespaceDecl(isAnonymous())),
+ hasAncestor(cxxRecordDecl()))),
+ hasParent(namespaceDecl()));
+ Finder->addMatcher(
+ expr(allOf(hasAncestor(decl().bind("dc")), IsInMovedNs,
+ unless(hasAncestor(isImplicit())),
+ anyOf(callExpr(callee(FuncMatcher)).bind("call"),
+ declRefExpr(to(FuncMatcher.bind("func_decl")))
+ .bind("func_ref")))),
+ this);
+
+ auto GlobalVarMatcher = varDecl(
+ hasGlobalStorage(), hasParent(namespaceDecl()),
+ unless(anyOf(IsInMovedNs, hasAncestor(namespaceDecl(isAnonymous())))));
+ Finder->addMatcher(declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
+ to(GlobalVarMatcher.bind("var_decl")))
+ .bind("var_ref"),
+ this);
+
+ // Handle unscoped enum constant.
+ auto UnscopedEnumMatcher = enumConstantDecl(hasParent(enumDecl(
+ hasParent(namespaceDecl()),
+ unless(anyOf(isScoped(), IsInMovedNs, hasAncestor(cxxRecordDecl()),
+ hasAncestor(namespaceDecl(isAnonymous())))))));
+ Finder->addMatcher(
+ declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
+ to(UnscopedEnumMatcher.bind("enum_const_decl")))
+ .bind("enum_const_ref"),
+ this);
+}
+
+void ChangeNamespaceTool::run(
+ const ast_matchers::MatchFinder::MatchResult &Result) {
+ if (const auto *Using = Result.Nodes.getNodeAs<UsingDecl>("using")) {
+ UsingDecls.insert(Using);
+ } else if (const auto *UsingNamespace =
+ Result.Nodes.getNodeAs<UsingDirectiveDecl>(
+ "using_namespace")) {
+ UsingNamespaceDecls.insert(UsingNamespace);
+ } else if (const auto *NamespaceAlias =
+ Result.Nodes.getNodeAs<NamespaceAliasDecl>(
+ "namespace_alias")) {
+ NamespaceAliasDecls.insert(NamespaceAlias);
+ } else if (const auto *NsDecl =
+ Result.Nodes.getNodeAs<NamespaceDecl>("old_ns")) {
+ moveOldNamespace(Result, NsDecl);
+ } else if (const auto *FwdDecl =
+ Result.Nodes.getNodeAs<CXXRecordDecl>("class_fwd_decl")) {
+ moveClassForwardDeclaration(Result, cast<NamedDecl>(FwdDecl));
+ } else if (const auto *TemplateFwdDecl =
+ Result.Nodes.getNodeAs<ClassTemplateDecl>(
+ "template_class_fwd_decl")) {
+ moveClassForwardDeclaration(Result, cast<NamedDecl>(TemplateFwdDecl));
+ } else if (const auto *UsingWithShadow =
+ Result.Nodes.getNodeAs<UsingDecl>("using_with_shadow")) {
+ fixUsingShadowDecl(Result, UsingWithShadow);
+ } else if (const auto *Specifier =
+ Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
+ "nested_specifier_loc")) {
+ SourceLocation Start = Specifier->getBeginLoc();
+ SourceLocation End = endLocationForType(Specifier->getTypeLoc());
+ fixTypeLoc(Result, Start, End, Specifier->getTypeLoc());
+ } else if (const auto *BaseInitializer =
+ Result.Nodes.getNodeAs<CXXCtorInitializer>(
+ "base_initializer")) {
+ BaseCtorInitializerTypeLocs.push_back(
+ BaseInitializer->getTypeSourceInfo()->getTypeLoc());
+ } else if (const auto *TLoc = Result.Nodes.getNodeAs<TypeLoc>("type")) {
+ // This avoids fixing types with record types as qualifier, which is not
+ // filtered by matchers in some cases, e.g. the type is templated. We should
+ // handle the record type qualifier instead.
+ TypeLoc Loc = *TLoc;
+ while (Loc.getTypeLocClass() == TypeLoc::Qualified)
+ Loc = Loc.getNextTypeLoc();
+ if (Loc.getTypeLocClass() == TypeLoc::Elaborated) {
+ NestedNameSpecifierLoc NestedNameSpecifier =
+ Loc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
+ // This happens for friend declaration of a base class with injected class
+ // name.
+ if (!NestedNameSpecifier.getNestedNameSpecifier())
+ return;
+ const Type *SpecifierType =
+ NestedNameSpecifier.getNestedNameSpecifier()->getAsType();
+ if (SpecifierType && SpecifierType->isRecordType())
+ return;
+ }
+ fixTypeLoc(Result, startLocationForType(Loc), endLocationForType(Loc), Loc);
+ } else if (const auto *VarRef =
+ Result.Nodes.getNodeAs<DeclRefExpr>("var_ref")) {
+ const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var_decl");
+ assert(Var);
+ if (Var->getCanonicalDecl()->isStaticDataMember())
+ return;
+ const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
+ assert(Context && "Empty decl context.");
+ fixDeclRefExpr(Result, Context->getDeclContext(),
+ llvm::cast<NamedDecl>(Var), VarRef);
+ } else if (const auto *EnumConstRef =
+ Result.Nodes.getNodeAs<DeclRefExpr>("enum_const_ref")) {
+ // Do not rename the reference if it is already scoped by the EnumDecl name.
+ if (EnumConstRef->hasQualifier() &&
+ EnumConstRef->getQualifier()->getKind() ==
+ NestedNameSpecifier::SpecifierKind::TypeSpec &&
+ EnumConstRef->getQualifier()->getAsType()->isEnumeralType())
+ return;
+ const auto *EnumConstDecl =
+ Result.Nodes.getNodeAs<EnumConstantDecl>("enum_const_decl");
+ assert(EnumConstDecl);
+ const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
+ assert(Context && "Empty decl context.");
+ // FIXME: this would qualify "ns::VALUE" as "ns::EnumValue::VALUE". Fix it
+ // if it turns out to be an issue.
+ fixDeclRefExpr(Result, Context->getDeclContext(),
+ llvm::cast<NamedDecl>(EnumConstDecl), EnumConstRef);
+ } else if (const auto *FuncRef =
+ Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
+ // If this reference has been processed as a function call, we do not
+ // process it again.
+ if (ProcessedFuncRefs.count(FuncRef))
+ return;
+ ProcessedFuncRefs.insert(FuncRef);
+ const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func_decl");
+ assert(Func);
+ const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
+ assert(Context && "Empty decl context.");
+ fixDeclRefExpr(Result, Context->getDeclContext(),
+ llvm::cast<NamedDecl>(Func), FuncRef);
+ } else {
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+ assert(Call != nullptr && "Expecting callback for CallExpr.");
+ const auto *CalleeFuncRef =
+ llvm::cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit());
+ ProcessedFuncRefs.insert(CalleeFuncRef);
+ const FunctionDecl *Func = Call->getDirectCallee();
+ assert(Func != nullptr);
+ // FIXME: ignore overloaded operators. This would miss cases where operators
+ // are called by qualified names (i.e. "ns::operator <"). Ignore such
+ // cases for now.
+ if (Func->isOverloadedOperator())
+ return;
+ // Ignore out-of-line static methods since they will be handled by nested
+ // name specifiers.
+ if (Func->getCanonicalDecl()->getStorageClass() ==
+ StorageClass::SC_Static &&
+ Func->isOutOfLine())
+ return;
+ const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
+ assert(Context && "Empty decl context.");
+ SourceRange CalleeRange = Call->getCallee()->getSourceRange();
+ replaceQualifiedSymbolInDeclContext(
+ Result, Context->getDeclContext(), CalleeRange.getBegin(),
+ CalleeRange.getEnd(), llvm::cast<NamedDecl>(Func));
+ }
+}
+
+static SourceLocation getLocAfterNamespaceLBrace(const NamespaceDecl *NsDecl,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ std::unique_ptr<Lexer> Lex =
+ getLexerStartingFromLoc(NsDecl->getLocStart(), SM, LangOpts);
+ assert(Lex.get() &&
+ "Failed to create lexer from the beginning of namespace.");
+ if (!Lex.get())
+ return SourceLocation();
+ Token Tok;
+ while (!Lex->LexFromRawLexer(Tok) && Tok.isNot(tok::TokenKind::l_brace)) {
+ }
+ return Tok.isNot(tok::TokenKind::l_brace)
+ ? SourceLocation()
+ : Tok.getEndLoc().getLocWithOffset(1);
+}
+
+// Stores information about a moved namespace in `MoveNamespaces` and leaves
+// the actual movement to `onEndOfTranslationUnit()`.
+void ChangeNamespaceTool::moveOldNamespace(
+ const ast_matchers::MatchFinder::MatchResult &Result,
+ const NamespaceDecl *NsDecl) {
+ // If the namespace is empty, do nothing.
+ if (Decl::castToDeclContext(NsDecl)->decls_empty())
+ return;
+
+ const SourceManager &SM = *Result.SourceManager;
+ // Get the range of the code in the old namespace.
+ SourceLocation Start =
+ getLocAfterNamespaceLBrace(NsDecl, SM, Result.Context->getLangOpts());
+ assert(Start.isValid() && "Can't find l_brace for namespace.");
+ MoveNamespace MoveNs;
+ MoveNs.Offset = SM.getFileOffset(Start);
+ // The range of the moved namespace is from the location just past the left
+ // brace to the location right before the right brace.
+ MoveNs.Length = SM.getFileOffset(NsDecl->getRBraceLoc()) - MoveNs.Offset;
+
+ // Insert the new namespace after `DiffOldNamespace`. For example, if
+ // `OldNamespace` is "a::b::c" and `NewNamespace` is `a::x::y`, then
+ // "x::y" will be inserted inside the existing namespace "a" and after "a::b".
+ // `OuterNs` is the first namespace in `DiffOldNamespace`, e.g. "namespace b"
+ // in the above example.
+ // If there is no outer namespace (i.e. DiffOldNamespace is empty), the new
+ // namespace will be a nested namespace in the old namespace.
+ const NamespaceDecl *OuterNs = getOuterNamespace(NsDecl, DiffOldNamespace);
+ SourceLocation InsertionLoc = Start;
+ if (OuterNs) {
+ SourceLocation LocAfterNs = getStartOfNextLine(
+ OuterNs->getRBraceLoc(), SM, Result.Context->getLangOpts());
+ assert(LocAfterNs.isValid() &&
+ "Failed to get location after DiffOldNamespace");
+ InsertionLoc = LocAfterNs;
+ }
+ MoveNs.InsertionOffset = SM.getFileOffset(SM.getSpellingLoc(InsertionLoc));
+ MoveNs.FID = SM.getFileID(Start);
+ MoveNs.SourceMgr = Result.SourceManager;
+ MoveNamespaces[SM.getFilename(Start)].push_back(MoveNs);
+}
+
+// Removes a class forward declaration from the code in the moved namespace and
+// creates an `InsertForwardDeclaration` to insert the forward declaration back
+// into the old namespace after moving code from the old namespace to the new
+// namespace.
+// For example, changing "a" to "x":
+// Old code:
+// namespace a {
+// class FWD;
+// class A { FWD *fwd; }
+// } // a
+// New code:
+// namespace a {
+// class FWD;
+// } // a
+// namespace x {
+// class A { a::FWD *fwd; }
+// } // x
+void ChangeNamespaceTool::moveClassForwardDeclaration(
+ const ast_matchers::MatchFinder::MatchResult &Result,
+ const NamedDecl *FwdDecl) {
+ SourceLocation Start = FwdDecl->getLocStart();
+ SourceLocation End = FwdDecl->getLocEnd();
+ const SourceManager &SM = *Result.SourceManager;
+ SourceLocation AfterSemi = Lexer::findLocationAfterToken(
+ End, tok::semi, SM, Result.Context->getLangOpts(),
+ /*SkipTrailingWhitespaceAndNewLine=*/true);
+ if (AfterSemi.isValid())
+ End = AfterSemi.getLocWithOffset(-1);
+ // Delete the forward declaration from the code to be moved.
+ addReplacementOrDie(Start, End, "", SM, &FileToReplacements);
+ llvm::StringRef Code = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
+ SM.getSpellingLoc(End)),
+ SM, Result.Context->getLangOpts());
+ // Insert the forward declaration back into the old namespace after moving the
+ // code from old namespace to new namespace.
+ // Insertion information is stored in `InsertFwdDecls` and actual
+ // insertion will be performed in `onEndOfTranslationUnit`.
+ // Get the (old) namespace that contains the forward declaration.
+ const auto *NsDecl = Result.Nodes.getNodeAs<NamespaceDecl>("ns_decl");
+ // The namespace contains the forward declaration, so it must not be empty.
+ assert(!NsDecl->decls_empty());
+ const auto Insertion = createInsertion(
+ getLocAfterNamespaceLBrace(NsDecl, SM, Result.Context->getLangOpts()),
+ Code, SM);
+ InsertForwardDeclaration InsertFwd;
+ InsertFwd.InsertionOffset = Insertion.getOffset();
+ InsertFwd.ForwardDeclText = Insertion.getReplacementText().str();
+ InsertFwdDecls[Insertion.getFilePath()].push_back(InsertFwd);
+}
+
+// Replaces a qualified symbol (in \p DeclCtx) that refers to a declaration \p
+// FromDecl with the shortest qualified name possible when the reference is in
+// `NewNamespace`.
+void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext(
+ const ast_matchers::MatchFinder::MatchResult &Result,
+ const DeclContext *DeclCtx, SourceLocation Start, SourceLocation End,
+ const NamedDecl *FromDecl) {
+ const auto *NsDeclContext = DeclCtx->getEnclosingNamespaceContext();
+ if (llvm::isa<TranslationUnitDecl>(NsDeclContext)) {
+ // This should not happen in usual unless the TypeLoc is in function type
+ // parameters, e.g `std::function<void(T)>`. In this case, DeclContext of
+ // `T` will be the translation unit. We simply use fully-qualified name
+ // here.
+ // Note that `FromDecl` must not be defined in the old namespace (according
+ // to `DeclMatcher`), so its fully-qualified name will not change after
+ // changing the namespace.
+ addReplacementOrDie(Start, End, FromDecl->getQualifiedNameAsString(),
+ *Result.SourceManager, &FileToReplacements);
+ return;
+ }
+ const auto *NsDecl = llvm::cast<NamespaceDecl>(NsDeclContext);
+ // Calculate the name of the `NsDecl` after it is moved to new namespace.
+ std::string OldNs = NsDecl->getQualifiedNameAsString();
+ llvm::StringRef Postfix = OldNs;
+ bool Consumed = Postfix.consume_front(OldNamespace);
+ assert(Consumed && "Expect OldNS to start with OldNamespace.");
+ (void)Consumed;
+ const std::string NewNs = (NewNamespace + Postfix).str();
+
+ llvm::StringRef NestedName = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(
+ Result.SourceManager->getSpellingLoc(Start),
+ Result.SourceManager->getSpellingLoc(End)),
+ *Result.SourceManager, Result.Context->getLangOpts());
+ std::string FromDeclName = FromDecl->getQualifiedNameAsString();
+ for (llvm::Regex &RE : WhiteListedSymbolRegexes)
+ if (RE.match(FromDeclName))
+ return;
+ std::string ReplaceName =
+ getShortestQualifiedNameInNamespace(FromDeclName, NewNs);
+ // Checks if there is any using namespace declarations that can shorten the
+ // qualified name.
+ for (const auto *UsingNamespace : UsingNamespaceDecls) {
+ if (!isDeclVisibleAtLocation(*Result.SourceManager, UsingNamespace, DeclCtx,
+ Start))
+ continue;
+ StringRef FromDeclNameRef = FromDeclName;
+ if (FromDeclNameRef.consume_front(UsingNamespace->getNominatedNamespace()
+ ->getQualifiedNameAsString())) {
+ FromDeclNameRef = FromDeclNameRef.drop_front(2);
+ if (FromDeclNameRef.size() < ReplaceName.size())
+ ReplaceName = FromDeclNameRef;
+ }
+ }
+ // Checks if there is any namespace alias declarations that can shorten the
+ // qualified name.
+ for (const auto *NamespaceAlias : NamespaceAliasDecls) {
+ if (!isDeclVisibleAtLocation(*Result.SourceManager, NamespaceAlias, DeclCtx,
+ Start))
+ continue;
+ StringRef FromDeclNameRef = FromDeclName;
+ if (FromDeclNameRef.consume_front(
+ NamespaceAlias->getNamespace()->getQualifiedNameAsString() +
+ "::")) {
+ std::string AliasName = NamespaceAlias->getNameAsString();
+ std::string AliasQualifiedName =
+ NamespaceAlias->getQualifiedNameAsString();
+ // We only consider namespace aliases define in the global namepspace or
+ // in namespaces that are directly visible from the reference, i.e.
+ // ancestor of the `OldNs`. Note that declarations in ancestor namespaces
+ // but not visible in the new namespace is filtered out by
+ // "IsVisibleInNewNs" matcher.
+ if (AliasQualifiedName != AliasName) {
+ // The alias is defined in some namespace.
+ assert(StringRef(AliasQualifiedName).endswith("::" + AliasName));
+ llvm::StringRef AliasNs =
+ StringRef(AliasQualifiedName).drop_back(AliasName.size() + 2);
+ if (!llvm::StringRef(OldNs).startswith(AliasNs))
+ continue;
+ }
+ std::string NameWithAliasNamespace =
+ (AliasName + "::" + FromDeclNameRef).str();
+ if (NameWithAliasNamespace.size() < ReplaceName.size())
+ ReplaceName = NameWithAliasNamespace;
+ }
+ }
+ // Checks if there is any using shadow declarations that can shorten the
+ // qualified name.
+ bool Matched = false;
+ for (const UsingDecl *Using : UsingDecls) {
+ if (Matched)
+ break;
+ if (isDeclVisibleAtLocation(*Result.SourceManager, Using, DeclCtx, Start)) {
+ for (const auto *UsingShadow : Using->shadows()) {
+ const auto *TargetDecl = UsingShadow->getTargetDecl();
+ if (TargetDecl->getQualifiedNameAsString() ==
+ FromDecl->getQualifiedNameAsString()) {
+ ReplaceName = FromDecl->getNameAsString();
+ Matched = true;
+ break;
+ }
+ }
+ }
+ }
+ // If the new nested name in the new namespace is the same as it was in the
+ // old namespace, we don't create replacement.
+ if (NestedName == ReplaceName ||
+ (NestedName.startswith("::") && NestedName.drop_front(2) == ReplaceName))
+ return;
+ // If the reference need to be fully-qualified, add a leading "::" unless
+ // NewNamespace is the global namespace.
+ if (ReplaceName == FromDeclName && !NewNamespace.empty() &&
+ conflictInNamespace(ReplaceName, NewNamespace))
+ ReplaceName = "::" + ReplaceName;
+ addReplacementOrDie(Start, End, ReplaceName, *Result.SourceManager,
+ &FileToReplacements);
+}
+
+// Replace the [Start, End] of `Type` with the shortest qualified name when the
+// `Type` is in `NewNamespace`.
+void ChangeNamespaceTool::fixTypeLoc(
+ const ast_matchers::MatchFinder::MatchResult &Result, SourceLocation Start,
+ SourceLocation End, TypeLoc Type) {
+ // FIXME: do not rename template parameter.
+ if (Start.isInvalid() || End.isInvalid())
+ return;
+ // Types of CXXCtorInitializers do not need to be fixed.
+ if (llvm::is_contained(BaseCtorInitializerTypeLocs, Type))
+ return;
+ if (isTemplateParameter(Type))
+ return;
+ // The declaration which this TypeLoc refers to.
+ const auto *FromDecl = Result.Nodes.getNodeAs<NamedDecl>("from_decl");
+ // `hasDeclaration` gives underlying declaration, but if the type is
+ // a typedef type, we need to use the typedef type instead.
+ auto IsInMovedNs = [&](const NamedDecl *D) {
+ if (!llvm::StringRef(D->getQualifiedNameAsString())
+ .startswith(OldNamespace + "::"))
+ return false;
+ auto ExpansionLoc = Result.SourceManager->getExpansionLoc(D->getLocStart());
+ if (ExpansionLoc.isInvalid())
+ return false;
+ llvm::StringRef Filename = Result.SourceManager->getFilename(ExpansionLoc);
+ return FilePatternRE.match(Filename);
+ };
+ // Make `FromDecl` the immediate declaration that `Type` refers to, i.e. if
+ // `Type` is an alias type, we make `FromDecl` the type alias declaration.
+ // Also, don't fix the \p Type if it refers to a type alias decl in the moved
+ // namespace since the alias decl will be moved along with the type reference.
+ if (auto *Typedef = Type.getType()->getAs<TypedefType>()) {
+ FromDecl = Typedef->getDecl();
+ if (IsInMovedNs(FromDecl))
+ return;
+ } else if (auto *TemplateType =
+ Type.getType()->getAs<TemplateSpecializationType>()) {
+ if (TemplateType->isTypeAlias()) {
+ FromDecl = TemplateType->getTemplateName().getAsTemplateDecl();
+ if (IsInMovedNs(FromDecl))
+ return;
+ }
+ }
+ const auto *DeclCtx = Result.Nodes.getNodeAs<Decl>("dc");
+ assert(DeclCtx && "Empty decl context.");
+ replaceQualifiedSymbolInDeclContext(Result, DeclCtx->getDeclContext(), Start,
+ End, FromDecl);
+}
+
+void ChangeNamespaceTool::fixUsingShadowDecl(
+ const ast_matchers::MatchFinder::MatchResult &Result,
+ const UsingDecl *UsingDeclaration) {
+ SourceLocation Start = UsingDeclaration->getLocStart();
+ SourceLocation End = UsingDeclaration->getLocEnd();
+ if (Start.isInvalid() || End.isInvalid())
+ return;
+
+ assert(UsingDeclaration->shadow_size() > 0);
+ // FIXME: it might not be always accurate to use the first using-decl.
+ const NamedDecl *TargetDecl =
+ UsingDeclaration->shadow_begin()->getTargetDecl();
+ std::string TargetDeclName = TargetDecl->getQualifiedNameAsString();
+ // FIXME: check if target_decl_name is in moved ns, which doesn't make much
+ // sense. If this happens, we need to use name with the new namespace.
+ // Use fully qualified name in UsingDecl for now.
+ addReplacementOrDie(Start, End, "using ::" + TargetDeclName,
+ *Result.SourceManager, &FileToReplacements);
+}
+
+void ChangeNamespaceTool::fixDeclRefExpr(
+ const ast_matchers::MatchFinder::MatchResult &Result,
+ const DeclContext *UseContext, const NamedDecl *From,
+ const DeclRefExpr *Ref) {
+ SourceRange RefRange = Ref->getSourceRange();
+ replaceQualifiedSymbolInDeclContext(Result, UseContext, RefRange.getBegin(),
+ RefRange.getEnd(), From);
+}
+
+void ChangeNamespaceTool::onEndOfTranslationUnit() {
+ // Move namespace blocks and insert forward declaration to old namespace.
+ for (const auto &FileAndNsMoves : MoveNamespaces) {
+ auto &NsMoves = FileAndNsMoves.second;
+ if (NsMoves.empty())
+ continue;
+ const std::string &FilePath = FileAndNsMoves.first;
+ auto &Replaces = FileToReplacements[FilePath];
+ auto &SM = *NsMoves.begin()->SourceMgr;
+ llvm::StringRef Code = SM.getBufferData(NsMoves.begin()->FID);
+ auto ChangedCode = tooling::applyAllReplacements(Code, Replaces);
+ if (!ChangedCode) {
+ llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
+ continue;
+ }
+ // Replacements on the changed code for moving namespaces and inserting
+ // forward declarations to old namespaces.
+ tooling::Replacements NewReplacements;
+ // Cut the changed code from the old namespace and paste the code in the new
+ // namespace.
+ for (const auto &NsMove : NsMoves) {
+ // Calculate the range of the old namespace block in the changed
+ // code.
+ const unsigned NewOffset = Replaces.getShiftedCodePosition(NsMove.Offset);
+ const unsigned NewLength =
+ Replaces.getShiftedCodePosition(NsMove.Offset + NsMove.Length) -
+ NewOffset;
+ tooling::Replacement Deletion(FilePath, NewOffset, NewLength, "");
+ std::string MovedCode = ChangedCode->substr(NewOffset, NewLength);
+ std::string MovedCodeWrappedInNewNs =
+ wrapCodeInNamespace(DiffNewNamespace, MovedCode);
+ // Calculate the new offset at which the code will be inserted in the
+ // changed code.
+ unsigned NewInsertionOffset =
+ Replaces.getShiftedCodePosition(NsMove.InsertionOffset);
+ tooling::Replacement Insertion(FilePath, NewInsertionOffset, 0,
+ MovedCodeWrappedInNewNs);
+ addOrMergeReplacement(Deletion, &NewReplacements);
+ addOrMergeReplacement(Insertion, &NewReplacements);
+ }
+ // After moving namespaces, insert forward declarations back to old
+ // namespaces.
+ const auto &FwdDeclInsertions = InsertFwdDecls[FilePath];
+ for (const auto &FwdDeclInsertion : FwdDeclInsertions) {
+ unsigned NewInsertionOffset =
+ Replaces.getShiftedCodePosition(FwdDeclInsertion.InsertionOffset);
+ tooling::Replacement Insertion(FilePath, NewInsertionOffset, 0,
+ FwdDeclInsertion.ForwardDeclText);
+ addOrMergeReplacement(Insertion, &NewReplacements);
+ }
+ // Add replacements referring to the changed code to existing replacements,
+ // which refers to the original code.
+ Replaces = Replaces.merge(NewReplacements);
+ auto Style = format::getStyle("file", FilePath, FallbackStyle);
+ if (!Style) {
+ llvm::errs() << llvm::toString(Style.takeError()) << "\n";
+ continue;
+ }
+ // Clean up old namespaces if there is nothing in it after moving.
+ auto CleanReplacements =
+ format::cleanupAroundReplacements(Code, Replaces, *Style);
+ if (!CleanReplacements) {
+ llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
+ continue;
+ }
+ FileToReplacements[FilePath] = *CleanReplacements;
+ }
+
+ // Make sure we don't generate replacements for files that do not match
+ // FilePattern.
+ for (auto &Entry : FileToReplacements)
+ if (!FilePatternRE.match(Entry.first))
+ Entry.second.clear();
+}
+
+} // namespace change_namespace
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/change-namespace/ChangeNamespace.h b/src/third_party/llvm-project/clang-tools-extra/change-namespace/ChangeNamespace.h
new file mode 100644
index 0000000..cfe3cbc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/change-namespace/ChangeNamespace.h
@@ -0,0 +1,176 @@
+//===-- ChangeNamespace.h -- Change namespace ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CHANGE_NAMESPACE_CHANGENAMESPACE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CHANGE_NAMESPACE_CHANGENAMESPACE_H
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Format/Format.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/Support/Regex.h"
+#include <string>
+
+namespace clang {
+namespace change_namespace {
+
+// This tool can be used to change the surrounding namespaces of class/function
+// definitions. Classes/functions in the moved namespace will have new
+// namespaces while references to symbols (e.g. types, functions) which are not
+// defined in the changed namespace will be correctly qualified by prepending
+// namespace specifiers before them.
+// This will try to add shortest namespace specifiers possible. When a symbol
+// reference needs to be fully-qualified, this adds a "::" prefix to the
+// namespace specifiers unless the new namespace is the global namespace.
+// For classes, only classes that are declared/defined in the given namespace in
+// speficifed files will be moved: forward declarations will remain in the old
+// namespace.
+// For example, changing "a" to "x":
+// Old code:
+// namespace a {
+// class FWD;
+// class A { FWD *fwd; }
+// } // a
+// New code:
+// namespace a {
+// class FWD;
+// } // a
+// namespace x {
+// class A { ::a::FWD *fwd; }
+// } // x
+// FIXME: support moving typedef, enums across namespaces.
+class ChangeNamespaceTool : public ast_matchers::MatchFinder::MatchCallback {
+public:
+ // Moves code in the old namespace `OldNs` to the new namespace `NewNs` in
+ // files matching `FilePattern`.
+ ChangeNamespaceTool(
+ llvm::StringRef OldNs, llvm::StringRef NewNs, llvm::StringRef FilePattern,
+ llvm::ArrayRef<std::string> WhiteListedSymbolPatterns,
+ std::map<std::string, tooling::Replacements> *FileToReplacements,
+ llvm::StringRef FallbackStyle = "LLVM");
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder);
+
+ void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+ // Moves the changed code in old namespaces but leaves class forward
+ // declarations behind.
+ void onEndOfTranslationUnit() override;
+
+private:
+ void moveOldNamespace(const ast_matchers::MatchFinder::MatchResult &Result,
+ const NamespaceDecl *NsDecl);
+
+ void moveClassForwardDeclaration(
+ const ast_matchers::MatchFinder::MatchResult &Result,
+ const NamedDecl *FwdDecl);
+
+ void replaceQualifiedSymbolInDeclContext(
+ const ast_matchers::MatchFinder::MatchResult &Result,
+ const DeclContext *DeclContext, SourceLocation Start, SourceLocation End,
+ const NamedDecl *FromDecl);
+
+ void fixTypeLoc(const ast_matchers::MatchFinder::MatchResult &Result,
+ SourceLocation Start, SourceLocation End, TypeLoc Type);
+
+ void fixUsingShadowDecl(const ast_matchers::MatchFinder::MatchResult &Result,
+ const UsingDecl *UsingDeclaration);
+
+ void fixDeclRefExpr(const ast_matchers::MatchFinder::MatchResult &Result,
+ const DeclContext *UseContext, const NamedDecl *From,
+ const DeclRefExpr *Ref);
+
+ // Information about moving an old namespace.
+ struct MoveNamespace {
+ // The start offset of the namespace block being moved in the original
+ // code.
+ unsigned Offset;
+ // The length of the namespace block in the original code.
+ unsigned Length;
+ // The offset at which the new namespace block will be inserted in the
+ // original code.
+ unsigned InsertionOffset;
+ // The file in which the namespace is declared.
+ FileID FID;
+ SourceManager *SourceMgr;
+ };
+
+ // Information about inserting a class forward declaration.
+ struct InsertForwardDeclaration {
+ // The offset at while the forward declaration will be inserted in the
+ // original code.
+ unsigned InsertionOffset;
+ // The code to be inserted.
+ std::string ForwardDeclText;
+ };
+
+ std::string FallbackStyle;
+ // In match callbacks, this contains replacements for replacing `typeLoc`s in
+ // and deleting forward declarations in the moved namespace blocks.
+ // In `onEndOfTranslationUnit` callback, the previous added replacements are
+ // applied (on the moved namespace blocks), and then changed code in old
+ // namespaces re moved to new namespaces, and previously deleted forward
+ // declarations are inserted back to old namespaces, from which they are
+ // deleted.
+ std::map<std::string, tooling::Replacements> &FileToReplacements;
+ // A fully qualified name of the old namespace without "::" prefix, e.g.
+ // "a::b::c".
+ std::string OldNamespace;
+ // A fully qualified name of the new namespace without "::" prefix, e.g.
+ // "x::y::z".
+ std::string NewNamespace;
+ // The longest suffix in the old namespace that does not overlap the new
+ // namespace.
+ // For example, if `OldNamespace` is "a::b::c" and `NewNamespace` is
+ // "a::x::y", then `DiffOldNamespace` will be "b::c".
+ std::string DiffOldNamespace;
+ // The longest suffix in the new namespace that does not overlap the old
+ // namespace.
+ // For example, if `OldNamespace` is "a::b::c" and `NewNamespace` is
+ // "a::x::y", then `DiffNewNamespace` will be "x::y".
+ std::string DiffNewNamespace;
+ // A regex pattern that matches files to be processed.
+ std::string FilePattern;
+ llvm::Regex FilePatternRE;
+ // Information about moved namespaces grouped by file.
+ // Since we are modifying code in old namespaces (e.g. add namespace
+ // spedifiers) as well as moving them, we store information about namespaces
+ // to be moved and only move them after all modifications are finished (i.e.
+ // in `onEndOfTranslationUnit`).
+ std::map<std::string, std::vector<MoveNamespace>> MoveNamespaces;
+ // Information about forward declaration insertions grouped by files.
+ // A class forward declaration is not moved, so it will be deleted from the
+ // moved code block and inserted back into the old namespace. The insertion
+ // will be done after removing the code from the old namespace and before
+ // inserting it to the new namespace.
+ std::map<std::string, std::vector<InsertForwardDeclaration>> InsertFwdDecls;
+ // Records all using declarations, which can be used to shorten namespace
+ // specifiers.
+ llvm::SmallPtrSet<const UsingDecl *, 8> UsingDecls;
+ // Records all using namespace declarations, which can be used to shorten
+ // namespace specifiers.
+ llvm::SmallPtrSet<const UsingDirectiveDecl *, 8> UsingNamespaceDecls;
+ // Records all namespace alias declarations, which can be used to shorten
+ // namespace specifiers.
+ llvm::SmallPtrSet<const NamespaceAliasDecl *, 8> NamespaceAliasDecls;
+ // TypeLocs of CXXCtorInitializer. Types of CXXCtorInitializers do not need to
+ // be fixed.
+ llvm::SmallVector<TypeLoc, 8> BaseCtorInitializerTypeLocs;
+ // Since a DeclRefExpr for a function call can be matched twice (one as
+ // CallExpr and one as DeclRefExpr), we record all DeclRefExpr's that have
+ // been processed so that we don't handle them twice.
+ llvm::SmallPtrSet<const clang::DeclRefExpr*, 16> ProcessedFuncRefs;
+ // Patterns of symbol names whose references are not expected to be updated
+ // when changing namespaces around them.
+ std::vector<llvm::Regex> WhiteListedSymbolRegexes;
+};
+
+} // namespace change_namespace
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CHANGE_NAMESPACE_CHANGENAMESPACE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/change-namespace/tool/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/change-namespace/tool/CMakeLists.txt
new file mode 100644
index 0000000..f1d8ddb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/change-namespace/tool/CMakeLists.txt
@@ -0,0 +1,24 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_executable(clang-change-namespace
+ ClangChangeNamespace.cpp
+ )
+target_link_libraries(clang-change-namespace
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangChangeNamespace
+ clangFormat
+ clangFrontend
+ clangRewrite
+ clangTooling
+ clangToolingCore
+ )
+
+install(TARGETS clang-change-namespace
+ RUNTIME DESTINATION bin)
diff --git a/src/third_party/llvm-project/clang-tools-extra/change-namespace/tool/ClangChangeNamespace.cpp b/src/third_party/llvm-project/clang-tools-extra/change-namespace/tool/ClangChangeNamespace.cpp
new file mode 100644
index 0000000..180e8c3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/change-namespace/tool/ClangChangeNamespace.cpp
@@ -0,0 +1,178 @@
+//===-- ClangIncludeFixer.cpp - Standalone change namespace ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This tool can be used to change the surrounding namespaces of class/function
+// definitions.
+//
+// Example: test.cc
+// namespace na {
+// class X {};
+// namespace nb {
+// class Y { X x; };
+// } // namespace nb
+// } // namespace na
+// To move the definition of class Y from namespace "na::nb" to "x::y", run:
+// clang-change-namespace --old_namespace "na::nb" \
+// --new_namespace "x::y" --file_pattern "test.cc" test.cc --
+// Output:
+// namespace na {
+// class X {};
+// } // namespace na
+// namespace x {
+// namespace y {
+// class Y { na::X x; };
+// } // namespace y
+// } // namespace x
+
+#include "ChangeNamespace.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+
+cl::OptionCategory ChangeNamespaceCategory("Change namespace.");
+
+cl::opt<std::string> OldNamespace("old_namespace", cl::Required,
+ cl::desc("Old namespace."),
+ cl::cat(ChangeNamespaceCategory));
+
+cl::opt<std::string> NewNamespace("new_namespace", cl::Required,
+ cl::desc("New namespace."),
+ cl::cat(ChangeNamespaceCategory));
+
+cl::opt<std::string> FilePattern(
+ "file_pattern", cl::Required,
+ cl::desc("Only rename namespaces in files that match the given pattern."),
+ cl::cat(ChangeNamespaceCategory));
+
+cl::opt<bool> Inplace("i", cl::desc("Inplace edit <file>s, if specified."),
+ cl::cat(ChangeNamespaceCategory));
+
+cl::opt<bool>
+ DumpYAML("dump_result",
+ cl::desc("Dump new file contents in YAML, if specified."),
+ cl::cat(ChangeNamespaceCategory));
+
+cl::opt<std::string> Style("style",
+ cl::desc("The style name used for reformatting."),
+ cl::init("LLVM"), cl::cat(ChangeNamespaceCategory));
+
+cl::opt<std::string> WhiteListFile(
+ "whitelist_file",
+ cl::desc("A file containing regexes of symbol names that are not expected "
+ "to be updated when changing namespaces around them."),
+ cl::init(""), cl::cat(ChangeNamespaceCategory));
+
+llvm::ErrorOr<std::vector<std::string>> GetWhiteListedSymbolPatterns() {
+ std::vector<std::string> Patterns;
+ if (WhiteListFile.empty())
+ return Patterns;
+
+ llvm::SmallVector<StringRef, 8> Lines;
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
+ llvm::MemoryBuffer::getFile(WhiteListFile);
+ if (!File)
+ return File.getError();
+ llvm::StringRef Content = File.get()->getBuffer();
+ Content.split(Lines, '\n', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ for (auto Line : Lines)
+ Patterns.push_back(Line.trim());
+ return Patterns;
+}
+
+} // anonymous namespace
+
+int main(int argc, const char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+ tooling::CommonOptionsParser OptionsParser(argc, argv,
+ ChangeNamespaceCategory);
+ const auto &Files = OptionsParser.getSourcePathList();
+ tooling::RefactoringTool Tool(OptionsParser.getCompilations(), Files);
+ llvm::ErrorOr<std::vector<std::string>> WhiteListPatterns =
+ GetWhiteListedSymbolPatterns();
+ if (!WhiteListPatterns) {
+ llvm::errs() << "Failed to open whitelist file " << WhiteListFile << ". "
+ << WhiteListPatterns.getError().message() << "\n";
+ return 1;
+ }
+ change_namespace::ChangeNamespaceTool NamespaceTool(
+ OldNamespace, NewNamespace, FilePattern, *WhiteListPatterns,
+ &Tool.getReplacements(), Style);
+ ast_matchers::MatchFinder Finder;
+ NamespaceTool.registerMatchers(&Finder);
+ std::unique_ptr<tooling::FrontendActionFactory> Factory =
+ tooling::newFrontendActionFactory(&Finder);
+
+ if (int Result = Tool.run(Factory.get()))
+ return Result;
+ LangOptions DefaultLangOptions;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+ &DiagnosticPrinter, false);
+ auto &FileMgr = Tool.getFiles();
+ SourceManager Sources(Diagnostics, FileMgr);
+ Rewriter Rewrite(Sources, DefaultLangOptions);
+
+ if (!formatAndApplyAllReplacements(Tool.getReplacements(), Rewrite, Style)) {
+ llvm::errs() << "Failed applying all replacements.\n";
+ return 1;
+ }
+ if (Inplace)
+ return Rewrite.overwriteChangedFiles();
+
+ std::set<llvm::StringRef> ChangedFiles;
+ for (const auto &it : Tool.getReplacements())
+ ChangedFiles.insert(it.first);
+
+ if (DumpYAML) {
+ auto WriteToYAML = [&](llvm::raw_ostream &OS) {
+ OS << "[\n";
+ for (auto I = ChangedFiles.begin(), E = ChangedFiles.end(); I != E; ++I) {
+ OS << " {\n";
+ OS << " \"FilePath\": \"" << *I << "\",\n";
+ const auto *Entry = FileMgr.getFile(*I);
+ auto ID = Sources.getOrCreateFileID(Entry, SrcMgr::C_User);
+ std::string Content;
+ llvm::raw_string_ostream ContentStream(Content);
+ Rewrite.getEditBuffer(ID).write(ContentStream);
+ OS << " \"SourceText\": \""
+ << llvm::yaml::escape(ContentStream.str()) << "\"\n";
+ OS << " }";
+ if (I != std::prev(E))
+ OS << ",\n";
+ }
+ OS << "\n]\n";
+ };
+ WriteToYAML(llvm::outs());
+ return 0;
+ }
+
+ for (const auto &File : ChangedFiles) {
+ const auto *Entry = FileMgr.getFile(File);
+
+ auto ID = Sources.getOrCreateFileID(Entry, SrcMgr::C_User);
+ outs() << "============== " << File << " ==============\n";
+ Rewrite.getEditBuffer(ID).write(llvm::outs());
+ outs() << "\n============================================\n";
+ }
+
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/CMakeLists.txt
new file mode 100644
index 0000000..02da085
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/CMakeLists.txt
@@ -0,0 +1,20 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_library(clangApplyReplacements
+ lib/Tooling/ApplyReplacements.cpp
+
+ LINK_LIBS
+ clangAST
+ clangBasic
+ clangRewrite
+ clangToolingCore
+ clangToolingRefactor
+ )
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ include
+ )
+add_subdirectory(tool)
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/include/clang-apply-replacements/Tooling/ApplyReplacements.h b/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/include/clang-apply-replacements/Tooling/ApplyReplacements.h
new file mode 100644
index 0000000..da9ae0c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/include/clang-apply-replacements/Tooling/ApplyReplacements.h
@@ -0,0 +1,123 @@
+//===-- ApplyReplacements.h - Deduplicate and apply replacements -- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides the interface for deduplicating, detecting
+/// conflicts in, and applying collections of Replacements.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_APPLYREPLACEMENTS_H
+#define LLVM_CLANG_APPLYREPLACEMENTS_H
+
+#include "clang/Tooling/Core/Diagnostic.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+#include <system_error>
+#include <vector>
+
+namespace clang {
+
+class DiagnosticsEngine;
+class Rewriter;
+
+namespace replace {
+
+/// \brief Collection of TranslationUnitReplacements.
+typedef std::vector<clang::tooling::TranslationUnitReplacements> TUReplacements;
+
+/// \brief Collection of TranslationUnitReplacement files.
+typedef std::vector<std::string> TUReplacementFiles;
+
+/// \brief Collection of TranslationUniDiagnostics.
+typedef std::vector<clang::tooling::TranslationUnitDiagnostics> TUDiagnostics;
+
+/// \brief Map mapping file name to a set of AtomicChange targeting that file.
+typedef llvm::DenseMap<const clang::FileEntry *,
+ std::vector<tooling::AtomicChange>>
+ FileToChangesMap;
+
+/// \brief Recursively descends through a directory structure rooted at \p
+/// Directory and attempts to deserialize *.yaml files as
+/// TranslationUnitReplacements. All docs that successfully deserialize are
+/// added to \p TUs.
+///
+/// Directories starting with '.' are ignored during traversal.
+///
+/// \param[in] Directory Directory to begin search for serialized
+/// TranslationUnitReplacements.
+/// \param[out] TUs Collection of all found and deserialized
+/// TranslationUnitReplacements or TranslationUnitDiagnostics.
+/// \param[out] TUFiles Collection of all TranslationUnitReplacement files
+/// found in \c Directory.
+/// \param[in] Diagnostics DiagnosticsEngine used for error output.
+///
+/// \returns An error_code indicating success or failure in navigating the
+/// directory structure.
+std::error_code collectReplacementsFromDirectory(
+ const llvm::StringRef Directory, TUReplacements &TUs,
+ TUReplacementFiles &TUFiles, clang::DiagnosticsEngine &Diagnostics);
+
+std::error_code collectReplacementsFromDirectory(
+ const llvm::StringRef Directory, TUDiagnostics &TUs,
+ TUReplacementFiles &TUFiles, clang::DiagnosticsEngine &Diagnostics);
+
+/// \brief Deduplicate, check for conflicts, and extract all Replacements stored
+/// in \c TUs. Conflicting replacements are skipped.
+///
+/// \post For all (key,value) in FileChanges, value[i].getOffset() <=
+/// value[i+1].getOffset().
+///
+/// \param[in] TUs Collection of TranslationUnitReplacements or
+/// TranslationUnitDiagnostics to merge, deduplicate, and test for conflicts.
+/// \param[out] FileChanges Container grouping all changes by the
+/// file they target. Only non conflicting replacements are kept into
+/// FileChanges.
+/// \param[in] SM SourceManager required for conflict reporting.
+///
+/// \returns \parblock
+/// \li true If all changes were converted successfully.
+/// \li false If there were conflicts.
+bool mergeAndDeduplicate(const TUReplacements &TUs, const TUDiagnostics &TUDs,
+ FileToChangesMap &FileChanges,
+ clang::SourceManager &SM);
+
+/// \brief Apply \c AtomicChange on File and rewrite it.
+///
+/// \param[in] File Path of the file where to apply AtomicChange.
+/// \param[in] Changes to apply.
+/// \param[in] Spec For code cleanup and formatting.
+/// \param[in] Diagnostics DiagnosticsEngine used for error output.
+///
+/// \returns The changed code if all changes are applied successfully;
+/// otherwise, an llvm::Error carrying llvm::StringError or an error_code.
+llvm::Expected<std::string>
+applyChanges(StringRef File, const std::vector<tooling::AtomicChange> &Changes,
+ const tooling::ApplyChangesSpec &Spec,
+ DiagnosticsEngine &Diagnostics);
+
+/// \brief Delete the replacement files.
+///
+/// \param[in] Files Replacement files to delete.
+/// \param[in] Diagnostics DiagnosticsEngine used for error output.
+///
+/// \returns \parblock
+/// \li true If all files have been deleted successfully.
+/// \li false If at least one or more failures occur when deleting
+/// files.
+bool deleteReplacementFiles(const TUReplacementFiles &Files,
+ clang::DiagnosticsEngine &Diagnostics);
+
+} // end namespace replace
+} // end namespace clang
+
+#endif // LLVM_CLANG_APPLYREPLACEMENTS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp
new file mode 100644
index 0000000..1970d05
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp
@@ -0,0 +1,249 @@
+//===-- ApplyReplacements.cpp - Apply and deduplicate replacements --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides the implementation for deduplicating, detecting
+/// conflicts in, and applying collections of Replacements.
+///
+/// FIXME: Use Diagnostics for output instead of llvm::errs().
+///
+//===----------------------------------------------------------------------===//
+#include "clang-apply-replacements/Tooling/ApplyReplacements.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Format/Format.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/DiagnosticsYaml.h"
+#include "clang/Tooling/ReplacementsYaml.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace clang;
+
+static void eatDiagnostics(const SMDiagnostic &, void *) {}
+
+namespace clang {
+namespace replace {
+
+std::error_code collectReplacementsFromDirectory(
+ const llvm::StringRef Directory, TUReplacements &TUs,
+ TUReplacementFiles &TUFiles, clang::DiagnosticsEngine &Diagnostics) {
+ using namespace llvm::sys::fs;
+ using namespace llvm::sys::path;
+
+ std::error_code ErrorCode;
+
+ for (recursive_directory_iterator I(Directory, ErrorCode), E;
+ I != E && !ErrorCode; I.increment(ErrorCode)) {
+ if (filename(I->path())[0] == '.') {
+ // Indicate not to descend into directories beginning with '.'
+ I.no_push();
+ continue;
+ }
+
+ if (extension(I->path()) != ".yaml")
+ continue;
+
+ TUFiles.push_back(I->path());
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> Out =
+ MemoryBuffer::getFile(I->path());
+ if (std::error_code BufferError = Out.getError()) {
+ errs() << "Error reading " << I->path() << ": " << BufferError.message()
+ << "\n";
+ continue;
+ }
+
+ yaml::Input YIn(Out.get()->getBuffer(), nullptr, &eatDiagnostics);
+ tooling::TranslationUnitReplacements TU;
+ YIn >> TU;
+ if (YIn.error()) {
+ // File doesn't appear to be a header change description. Ignore it.
+ continue;
+ }
+
+ // Only keep files that properly parse.
+ TUs.push_back(TU);
+ }
+
+ return ErrorCode;
+}
+
+std::error_code collectReplacementsFromDirectory(
+ const llvm::StringRef Directory, TUDiagnostics &TUs,
+ TUReplacementFiles &TUFiles, clang::DiagnosticsEngine &Diagnostics) {
+ using namespace llvm::sys::fs;
+ using namespace llvm::sys::path;
+
+ std::error_code ErrorCode;
+
+ for (recursive_directory_iterator I(Directory, ErrorCode), E;
+ I != E && !ErrorCode; I.increment(ErrorCode)) {
+ if (filename(I->path())[0] == '.') {
+ // Indicate not to descend into directories beginning with '.'
+ I.no_push();
+ continue;
+ }
+
+ if (extension(I->path()) != ".yaml")
+ continue;
+
+ TUFiles.push_back(I->path());
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> Out =
+ MemoryBuffer::getFile(I->path());
+ if (std::error_code BufferError = Out.getError()) {
+ errs() << "Error reading " << I->path() << ": " << BufferError.message()
+ << "\n";
+ continue;
+ }
+
+ yaml::Input YIn(Out.get()->getBuffer(), nullptr, &eatDiagnostics);
+ tooling::TranslationUnitDiagnostics TU;
+ YIn >> TU;
+ if (YIn.error()) {
+ // File doesn't appear to be a header change description. Ignore it.
+ continue;
+ }
+
+ // Only keep files that properly parse.
+ TUs.push_back(TU);
+ }
+
+ return ErrorCode;
+}
+
+/// \brief Extract replacements from collected TranslationUnitReplacements and
+/// TranslationUnitDiagnostics and group them per file.
+///
+/// \param[in] TUs Collection of all found and deserialized
+/// TranslationUnitReplacements.
+/// \param[in] TUDs Collection of all found and deserialized
+/// TranslationUnitDiagnostics.
+/// \param[in] SM Used to deduplicate paths.
+///
+/// \returns A map mapping FileEntry to a set of Replacement targeting that
+/// file.
+static llvm::DenseMap<const FileEntry *, std::vector<tooling::Replacement>>
+groupReplacements(const TUReplacements &TUs, const TUDiagnostics &TUDs,
+ const clang::SourceManager &SM) {
+ std::set<StringRef> Warned;
+ llvm::DenseMap<const FileEntry *, std::vector<tooling::Replacement>>
+ GroupedReplacements;
+
+ auto AddToGroup = [&](const tooling::Replacement &R) {
+ // Use the file manager to deduplicate paths. FileEntries are
+ // automatically canonicalized.
+ if (const FileEntry *Entry = SM.getFileManager().getFile(R.getFilePath())) {
+ GroupedReplacements[Entry].push_back(R);
+ } else if (Warned.insert(R.getFilePath()).second) {
+ errs() << "Described file '" << R.getFilePath()
+ << "' doesn't exist. Ignoring...\n";
+ }
+ };
+
+ for (const auto &TU : TUs)
+ for (const tooling::Replacement &R : TU.Replacements)
+ AddToGroup(R);
+
+ for (const auto &TU : TUDs)
+ for (const auto &D : TU.Diagnostics)
+ for (const auto &Fix : D.Fix)
+ for (const tooling::Replacement &R : Fix.second)
+ AddToGroup(R);
+
+ // Sort replacements per file to keep consistent behavior when
+ // clang-apply-replacements run on differents machine.
+ for (auto &FileAndReplacements : GroupedReplacements) {
+ llvm::sort(FileAndReplacements.second.begin(),
+ FileAndReplacements.second.end());
+ }
+
+ return GroupedReplacements;
+}
+
+bool mergeAndDeduplicate(const TUReplacements &TUs, const TUDiagnostics &TUDs,
+ FileToChangesMap &FileChanges,
+ clang::SourceManager &SM) {
+ auto GroupedReplacements = groupReplacements(TUs, TUDs, SM);
+ bool ConflictDetected = false;
+
+ // To report conflicting replacements on corresponding file, all replacements
+ // are stored into 1 big AtomicChange.
+ for (const auto &FileAndReplacements : GroupedReplacements) {
+ const FileEntry *Entry = FileAndReplacements.first;
+ const SourceLocation BeginLoc =
+ SM.getLocForStartOfFile(SM.getOrCreateFileID(Entry, SrcMgr::C_User));
+ tooling::AtomicChange FileChange(Entry->getName(), Entry->getName());
+ for (const auto &R : FileAndReplacements.second) {
+ llvm::Error Err =
+ FileChange.replace(SM, BeginLoc.getLocWithOffset(R.getOffset()),
+ R.getLength(), R.getReplacementText());
+ if (Err) {
+ // FIXME: This will report conflicts by pair using a file+offset format
+ // which is not so much human readable.
+ // A first improvement could be to translate offset to line+col. For
+ // this and without loosing error message some modifications arround
+ // `tooling::ReplacementError` are need (access to
+ // `getReplacementErrString`).
+ // A better strategy could be to add a pretty printer methods for
+ // conflict reporting. Methods that could be parameterized to report a
+ // conflict in different format, file+offset, file+line+col, or even
+ // more human readable using VCS conflict markers.
+ // For now, printing directly the error reported by `AtomicChange` is
+ // the easiest solution.
+ errs() << llvm::toString(std::move(Err)) << "\n";
+ ConflictDetected = true;
+ }
+ }
+ FileChanges.try_emplace(Entry,
+ std::vector<tooling::AtomicChange>{FileChange});
+ }
+
+ return !ConflictDetected;
+}
+
+llvm::Expected<std::string>
+applyChanges(StringRef File, const std::vector<tooling::AtomicChange> &Changes,
+ const tooling::ApplyChangesSpec &Spec,
+ DiagnosticsEngine &Diagnostics) {
+ FileManager Files((FileSystemOptions()));
+ SourceManager SM(Diagnostics, Files);
+
+ llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
+ SM.getFileManager().getBufferForFile(File);
+ if (!Buffer)
+ return errorCodeToError(Buffer.getError());
+ return tooling::applyAtomicChanges(File, Buffer.get()->getBuffer(), Changes,
+ Spec);
+}
+
+bool deleteReplacementFiles(const TUReplacementFiles &Files,
+ clang::DiagnosticsEngine &Diagnostics) {
+ bool Success = true;
+ for (const auto &Filename : Files) {
+ std::error_code Error = llvm::sys::fs::remove(Filename);
+ if (Error) {
+ Success = false;
+ // FIXME: Use Diagnostics for outputting errors.
+ errs() << "Error deleting file: " << Filename << "\n";
+ errs() << Error.message() << "\n";
+ errs() << "Please delete the file manually\n";
+ }
+ }
+ return Success;
+}
+
+} // end namespace replace
+} // end namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/tool/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/tool/CMakeLists.txt
new file mode 100644
index 0000000..945b486
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/tool/CMakeLists.txt
@@ -0,0 +1,19 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_tool(clang-apply-replacements
+ ClangApplyReplacementsMain.cpp
+ )
+target_link_libraries(clang-apply-replacements
+ PRIVATE
+ clangApplyReplacements
+ clangBasic
+ clangFormat
+ clangRewrite
+ clangToolingCore
+ clangToolingRefactor
+ )
+
+install(TARGETS clang-apply-replacements
+ RUNTIME DESTINATION bin)
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
new file mode 100644
index 0000000..24a430f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
@@ -0,0 +1,165 @@
+//===-- ClangApplyReplacementsMain.cpp - Main file for the tool -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides the main function for the
+/// clang-apply-replacements tool.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang-apply-replacements/Tooling/ApplyReplacements.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Version.h"
+#include "clang/Format/Format.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/CommandLine.h"
+
+using namespace llvm;
+using namespace clang;
+using namespace clang::replace;
+
+static cl::opt<std::string> Directory(cl::Positional, cl::Required,
+ cl::desc("<Search Root Directory>"));
+
+static cl::OptionCategory ReplacementCategory("Replacement Options");
+static cl::OptionCategory FormattingCategory("Formatting Options");
+
+const cl::OptionCategory *VisibleCategories[] = {&ReplacementCategory,
+ &FormattingCategory};
+
+static cl::opt<bool> RemoveTUReplacementFiles(
+ "remove-change-desc-files",
+ cl::desc("Remove the change description files regardless of successful\n"
+ "merging/replacing."),
+ cl::init(false), cl::cat(ReplacementCategory));
+
+static cl::opt<bool> DoFormat(
+ "format",
+ cl::desc("Enable formatting of code changed by applying replacements.\n"
+ "Use -style to choose formatting style.\n"),
+ cl::cat(FormattingCategory));
+
+// FIXME: Consider making the default behaviour for finding a style
+// configuration file to start the search anew for every file being changed to
+// handle situations where the style is different for different parts of a
+// project.
+
+static cl::opt<std::string> FormatStyleConfig(
+ "style-config",
+ cl::desc("Path to a directory containing a .clang-format file\n"
+ "describing a formatting style to use for formatting\n"
+ "code when -style=file.\n"),
+ cl::init(""), cl::cat(FormattingCategory));
+
+static cl::opt<std::string>
+ FormatStyleOpt("style", cl::desc(format::StyleOptionHelpDescription),
+ cl::init("LLVM"), cl::cat(FormattingCategory));
+
+namespace {
+// Helper object to remove the TUReplacement and TUDiagnostic (triggered by
+// "remove-change-desc-files" command line option) when exiting current scope.
+class ScopedFileRemover {
+public:
+ ScopedFileRemover(const TUReplacementFiles &Files,
+ clang::DiagnosticsEngine &Diagnostics)
+ : TURFiles(Files), Diag(Diagnostics) {}
+
+ ~ScopedFileRemover() { deleteReplacementFiles(TURFiles, Diag); }
+
+private:
+ const TUReplacementFiles &TURFiles;
+ clang::DiagnosticsEngine &Diag;
+};
+} // namespace
+
+static void printVersion(raw_ostream &OS) {
+ OS << "clang-apply-replacements version " CLANG_VERSION_STRING << "\n";
+}
+
+int main(int argc, char **argv) {
+ cl::HideUnrelatedOptions(makeArrayRef(VisibleCategories));
+
+ cl::SetVersionPrinter(printVersion);
+ cl::ParseCommandLineOptions(argc, argv);
+
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts.get());
+
+ // Determine a formatting style from options.
+ auto FormatStyleOrError =
+ format::getStyle(FormatStyleOpt, FormatStyleConfig, "LLVM");
+ if (!FormatStyleOrError) {
+ llvm::errs() << llvm::toString(FormatStyleOrError.takeError()) << "\n";
+ return 1;
+ }
+ format::FormatStyle FormatStyle = std::move(*FormatStyleOrError);
+
+ TUReplacements TURs;
+ TUReplacementFiles TUFiles;
+
+ std::error_code ErrorCode =
+ collectReplacementsFromDirectory(Directory, TURs, TUFiles, Diagnostics);
+
+ TUDiagnostics TUDs;
+ TUFiles.clear();
+ ErrorCode =
+ collectReplacementsFromDirectory(Directory, TUDs, TUFiles, Diagnostics);
+
+ if (ErrorCode) {
+ errs() << "Trouble iterating over directory '" << Directory
+ << "': " << ErrorCode.message() << "\n";
+ return 1;
+ }
+
+ // Remove the TUReplacementFiles (triggered by "remove-change-desc-files"
+ // command line option) when exiting main().
+ std::unique_ptr<ScopedFileRemover> Remover;
+ if (RemoveTUReplacementFiles)
+ Remover.reset(new ScopedFileRemover(TUFiles, Diagnostics));
+
+ FileManager Files((FileSystemOptions()));
+ SourceManager SM(Diagnostics, Files);
+
+ FileToChangesMap Changes;
+ if (!mergeAndDeduplicate(TURs, TUDs, Changes, SM))
+ return 1;
+
+ tooling::ApplyChangesSpec Spec;
+ Spec.Cleanup = true;
+ Spec.Style = FormatStyle;
+ Spec.Format = DoFormat ? tooling::ApplyChangesSpec::kAll
+ : tooling::ApplyChangesSpec::kNone;
+
+ for (const auto &FileChange : Changes) {
+ const FileEntry *Entry = FileChange.first;
+ StringRef FileName = Entry->getName();
+ llvm::Expected<std::string> NewFileData =
+ applyChanges(FileName, FileChange.second, Spec, Diagnostics);
+ if (!NewFileData) {
+ errs() << llvm::toString(NewFileData.takeError()) << "\n";
+ continue;
+ }
+
+ // Write new file to disk
+ std::error_code EC;
+ llvm::raw_fd_ostream FileStream(FileName, EC, llvm::sys::fs::F_None);
+ if (EC) {
+ llvm::errs() << "Could not open " << FileName << " for writing\n";
+ continue;
+ }
+ FileStream << *NewFileData;
+ }
+
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/BitcodeReader.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-doc/BitcodeReader.cpp
new file mode 100644
index 0000000..fa51d01
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -0,0 +1,622 @@
+//===-- BitcodeReader.cpp - ClangDoc Bitcode Reader ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BitcodeReader.h"
+#include "llvm/ADT/IndexedMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace doc {
+
+using Record = llvm::SmallVector<uint64_t, 1024>;
+
+bool decodeRecord(Record R, llvm::SmallVectorImpl<char> &Field,
+ llvm::StringRef Blob) {
+ Field.assign(Blob.begin(), Blob.end());
+ return true;
+}
+
+bool decodeRecord(Record R, SymbolID &Field, llvm::StringRef Blob) {
+ if (R[0] != BitCodeConstants::USRHashSize)
+ return false;
+
+ // First position in the record is the length of the following array, so we
+ // copy the following elements to the field.
+ for (int I = 0, E = R[0]; I < E; ++I)
+ Field[I] = R[I + 1];
+ return true;
+}
+
+bool decodeRecord(Record R, bool &Field, llvm::StringRef Blob) {
+ Field = R[0] != 0;
+ return true;
+}
+
+bool decodeRecord(Record R, int &Field, llvm::StringRef Blob) {
+ if (R[0] > INT_MAX)
+ return false;
+ Field = (int)R[0];
+ return true;
+}
+
+bool decodeRecord(Record R, AccessSpecifier &Field, llvm::StringRef Blob) {
+ switch (R[0]) {
+ case AS_public:
+ case AS_private:
+ case AS_protected:
+ case AS_none:
+ Field = (AccessSpecifier)R[0];
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool decodeRecord(Record R, TagTypeKind &Field, llvm::StringRef Blob) {
+ switch (R[0]) {
+ case TTK_Struct:
+ case TTK_Interface:
+ case TTK_Union:
+ case TTK_Class:
+ case TTK_Enum:
+ Field = (TagTypeKind)R[0];
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool decodeRecord(Record R, llvm::Optional<Location> &Field,
+ llvm::StringRef Blob) {
+ if (R[0] > INT_MAX)
+ return false;
+ Field.emplace((int)R[0], Blob);
+ return true;
+}
+
+bool decodeRecord(Record R, InfoType &Field, llvm::StringRef Blob) {
+ switch (auto IT = static_cast<InfoType>(R[0])) {
+ case InfoType::IT_namespace:
+ case InfoType::IT_record:
+ case InfoType::IT_function:
+ case InfoType::IT_default:
+ case InfoType::IT_enum:
+ Field = IT;
+ return true;
+ }
+ return false;
+}
+
+bool decodeRecord(Record R, FieldId &Field, llvm::StringRef Blob) {
+ switch (auto F = static_cast<FieldId>(R[0])) {
+ case FieldId::F_namespace:
+ case FieldId::F_parent:
+ case FieldId::F_vparent:
+ case FieldId::F_type:
+ case FieldId::F_default:
+ Field = F;
+ return true;
+ }
+ return false;
+}
+
+bool decodeRecord(Record R, llvm::SmallVectorImpl<llvm::SmallString<16>> &Field,
+ llvm::StringRef Blob) {
+ Field.push_back(Blob);
+ return true;
+}
+
+bool decodeRecord(Record R, llvm::SmallVectorImpl<Location> &Field,
+ llvm::StringRef Blob) {
+ if (R[0] > INT_MAX)
+ return false;
+ Field.emplace_back((int)R[0], Blob);
+ return true;
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
+ const unsigned VersionNo) {
+ if (ID == VERSION && R[0] == VersionNo)
+ return true;
+ return false;
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
+ NamespaceInfo *I) {
+ switch (ID) {
+ case NAMESPACE_USR:
+ return decodeRecord(R, I->USR, Blob);
+ case NAMESPACE_NAME:
+ return decodeRecord(R, I->Name, Blob);
+ default:
+ return false;
+ }
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, RecordInfo *I) {
+ switch (ID) {
+ case RECORD_USR:
+ return decodeRecord(R, I->USR, Blob);
+ case RECORD_NAME:
+ return decodeRecord(R, I->Name, Blob);
+ case RECORD_DEFLOCATION:
+ return decodeRecord(R, I->DefLoc, Blob);
+ case RECORD_LOCATION:
+ return decodeRecord(R, I->Loc, Blob);
+ case RECORD_TAG_TYPE:
+ return decodeRecord(R, I->TagType, Blob);
+ default:
+ return false;
+ }
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, EnumInfo *I) {
+ switch (ID) {
+ case ENUM_USR:
+ return decodeRecord(R, I->USR, Blob);
+ case ENUM_NAME:
+ return decodeRecord(R, I->Name, Blob);
+ case ENUM_DEFLOCATION:
+ return decodeRecord(R, I->DefLoc, Blob);
+ case ENUM_LOCATION:
+ return decodeRecord(R, I->Loc, Blob);
+ case ENUM_MEMBER:
+ return decodeRecord(R, I->Members, Blob);
+ case ENUM_SCOPED:
+ return decodeRecord(R, I->Scoped, Blob);
+ default:
+ return false;
+ }
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, FunctionInfo *I) {
+ switch (ID) {
+ case FUNCTION_USR:
+ return decodeRecord(R, I->USR, Blob);
+ case FUNCTION_NAME:
+ return decodeRecord(R, I->Name, Blob);
+ case FUNCTION_DEFLOCATION:
+ return decodeRecord(R, I->DefLoc, Blob);
+ case FUNCTION_LOCATION:
+ return decodeRecord(R, I->Loc, Blob);
+ case FUNCTION_ACCESS:
+ return decodeRecord(R, I->Access, Blob);
+ case FUNCTION_IS_METHOD:
+ return decodeRecord(R, I->IsMethod, Blob);
+ default:
+ return false;
+ }
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, TypeInfo *I) {
+ return true;
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
+ FieldTypeInfo *I) {
+ switch (ID) {
+ case FIELD_TYPE_NAME:
+ return decodeRecord(R, I->Name, Blob);
+ default:
+ return false;
+ }
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
+ MemberTypeInfo *I) {
+ switch (ID) {
+ case MEMBER_TYPE_NAME:
+ return decodeRecord(R, I->Name, Blob);
+ case MEMBER_TYPE_ACCESS:
+ return decodeRecord(R, I->Access, Blob);
+ default:
+ return false;
+ }
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, CommentInfo *I) {
+ switch (ID) {
+ case COMMENT_KIND:
+ return decodeRecord(R, I->Kind, Blob);
+ case COMMENT_TEXT:
+ return decodeRecord(R, I->Text, Blob);
+ case COMMENT_NAME:
+ return decodeRecord(R, I->Name, Blob);
+ case COMMENT_DIRECTION:
+ return decodeRecord(R, I->Direction, Blob);
+ case COMMENT_PARAMNAME:
+ return decodeRecord(R, I->ParamName, Blob);
+ case COMMENT_CLOSENAME:
+ return decodeRecord(R, I->CloseName, Blob);
+ case COMMENT_ATTRKEY:
+ return decodeRecord(R, I->AttrKeys, Blob);
+ case COMMENT_ATTRVAL:
+ return decodeRecord(R, I->AttrValues, Blob);
+ case COMMENT_ARG:
+ return decodeRecord(R, I->Args, Blob);
+ case COMMENT_SELFCLOSING:
+ return decodeRecord(R, I->SelfClosing, Blob);
+ case COMMENT_EXPLICIT:
+ return decodeRecord(R, I->Explicit, Blob);
+ default:
+ return false;
+ }
+}
+
+bool parseRecord(Record R, unsigned ID, llvm::StringRef Blob, Reference *I,
+ FieldId &F) {
+ switch (ID) {
+ case REFERENCE_USR:
+ return decodeRecord(R, I->USR, Blob);
+ case REFERENCE_NAME:
+ return decodeRecord(R, I->Name, Blob);
+ case REFERENCE_TYPE:
+ return decodeRecord(R, I->RefType, Blob);
+ case REFERENCE_FIELD:
+ return decodeRecord(R, F, Blob);
+ default:
+ return false;
+ }
+}
+
+template <typename T> CommentInfo *getCommentInfo(T I) {
+ llvm::errs() << "Cannot have comment subblock.\n";
+ exit(1);
+}
+
+template <> CommentInfo *getCommentInfo(FunctionInfo *I) {
+ I->Description.emplace_back();
+ return &I->Description.back();
+}
+
+template <> CommentInfo *getCommentInfo(NamespaceInfo *I) {
+ I->Description.emplace_back();
+ return &I->Description.back();
+}
+
+template <> CommentInfo *getCommentInfo(RecordInfo *I) {
+ I->Description.emplace_back();
+ return &I->Description.back();
+}
+
+template <> CommentInfo *getCommentInfo(EnumInfo *I) {
+ I->Description.emplace_back();
+ return &I->Description.back();
+}
+
+template <> CommentInfo *getCommentInfo(CommentInfo *I) {
+ I->Children.emplace_back(llvm::make_unique<CommentInfo>());
+ return I->Children.back().get();
+}
+
+template <> CommentInfo *getCommentInfo(std::unique_ptr<CommentInfo> &I) {
+ return getCommentInfo(I.get());
+}
+
+template <typename T, typename TTypeInfo>
+void addTypeInfo(T I, TTypeInfo &&TI) {
+ llvm::errs() << "Invalid type for info.\n";
+ exit(1);
+}
+
+template <> void addTypeInfo(RecordInfo *I, MemberTypeInfo &&T) {
+ I->Members.emplace_back(std::move(T));
+}
+
+template <> void addTypeInfo(FunctionInfo *I, TypeInfo &&T) {
+ I->ReturnType = std::move(T);
+}
+
+template <> void addTypeInfo(FunctionInfo *I, FieldTypeInfo &&T) {
+ I->Params.emplace_back(std::move(T));
+}
+
+template <typename T> void addReference(T I, Reference &&R, FieldId F) {
+ llvm::errs() << "Invalid field type for info.\n";
+ exit(1);
+}
+
+template <> void addReference(TypeInfo *I, Reference &&R, FieldId F) {
+ switch (F) {
+ case FieldId::F_type:
+ I->Type = std::move(R);
+ break;
+ default:
+ llvm::errs() << "Invalid field type for info.\n";
+ exit(1);
+ }
+}
+
+template <> void addReference(FieldTypeInfo *I, Reference &&R, FieldId F) {
+ switch (F) {
+ case FieldId::F_type:
+ I->Type = std::move(R);
+ break;
+ default:
+ llvm::errs() << "Invalid field type for info.\n";
+ exit(1);
+ }
+}
+
+template <> void addReference(MemberTypeInfo *I, Reference &&R, FieldId F) {
+ switch (F) {
+ case FieldId::F_type:
+ I->Type = std::move(R);
+ break;
+ default:
+ llvm::errs() << "Invalid field type for info.\n";
+ exit(1);
+ }
+}
+
+template <> void addReference(EnumInfo *I, Reference &&R, FieldId F) {
+ switch (F) {
+ case FieldId::F_namespace:
+ I->Namespace.emplace_back(std::move(R));
+ break;
+ default:
+ llvm::errs() << "Invalid field type for info.\n";
+ exit(1);
+ }
+}
+
+template <> void addReference(NamespaceInfo *I, Reference &&R, FieldId F) {
+ switch (F) {
+ case FieldId::F_namespace:
+ I->Namespace.emplace_back(std::move(R));
+ break;
+ default:
+ llvm::errs() << "Invalid field type for info.\n";
+ exit(1);
+ }
+}
+
+template <> void addReference(FunctionInfo *I, Reference &&R, FieldId F) {
+ switch (F) {
+ case FieldId::F_namespace:
+ I->Namespace.emplace_back(std::move(R));
+ break;
+ case FieldId::F_parent:
+ I->Parent = std::move(R);
+ break;
+ default:
+ llvm::errs() << "Invalid field type for info.\n";
+ exit(1);
+ }
+}
+
+template <> void addReference(RecordInfo *I, Reference &&R, FieldId F) {
+ switch (F) {
+ case FieldId::F_namespace:
+ I->Namespace.emplace_back(std::move(R));
+ break;
+ case FieldId::F_parent:
+ I->Parents.emplace_back(std::move(R));
+ break;
+ case FieldId::F_vparent:
+ I->VirtualParents.emplace_back(std::move(R));
+ break;
+ default:
+ llvm::errs() << "Invalid field type for info.\n";
+ exit(1);
+ }
+}
+
+// Read records from bitcode into a given info.
+template <typename T> bool ClangDocBitcodeReader::readRecord(unsigned ID, T I) {
+ Record R;
+ llvm::StringRef Blob;
+ unsigned RecID = Stream.readRecord(ID, R, &Blob);
+ return parseRecord(R, RecID, Blob, I);
+}
+
+template <> bool ClangDocBitcodeReader::readRecord(unsigned ID, Reference *I) {
+ Record R;
+ llvm::StringRef Blob;
+ unsigned RecID = Stream.readRecord(ID, R, &Blob);
+ return parseRecord(R, RecID, Blob, I, CurrentReferenceField);
+}
+
+// Read a block of records into a single info.
+template <typename T> bool ClangDocBitcodeReader::readBlock(unsigned ID, T I) {
+ if (Stream.EnterSubBlock(ID))
+ return false;
+
+ while (true) {
+ unsigned BlockOrCode = 0;
+ Cursor Res = skipUntilRecordOrBlock(BlockOrCode);
+
+ switch (Res) {
+ case Cursor::BadBlock:
+ return false;
+ case Cursor::BlockEnd:
+ return true;
+ case Cursor::BlockBegin:
+ if (readSubBlock(BlockOrCode, I))
+ continue;
+ if (!Stream.SkipBlock())
+ return false;
+ continue;
+ case Cursor::Record:
+ break;
+ }
+ if (!readRecord(BlockOrCode, I))
+ return false;
+ }
+}
+
+template <typename T>
+bool ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) {
+ switch (ID) {
+ // Blocks can only have Comment, Reference, or TypeInfo subblocks
+ case BI_COMMENT_BLOCK_ID:
+ if (readBlock(ID, getCommentInfo(I)))
+ return true;
+ return false;
+ case BI_TYPE_BLOCK_ID: {
+ TypeInfo TI;
+ if (readBlock(ID, &TI)) {
+ addTypeInfo(I, std::move(TI));
+ return true;
+ }
+ return false;
+ }
+ case BI_FIELD_TYPE_BLOCK_ID: {
+ FieldTypeInfo TI;
+ if (readBlock(ID, &TI)) {
+ addTypeInfo(I, std::move(TI));
+ return true;
+ }
+ return false;
+ }
+ case BI_MEMBER_TYPE_BLOCK_ID: {
+ MemberTypeInfo TI;
+ if (readBlock(ID, &TI)) {
+ addTypeInfo(I, std::move(TI));
+ return true;
+ }
+ return false;
+ }
+ case BI_REFERENCE_BLOCK_ID: {
+ Reference R;
+ if (readBlock(ID, &R)) {
+ addReference(I, std::move(R), CurrentReferenceField);
+ return true;
+ }
+ return false;
+ }
+ default:
+ llvm::errs() << "Invalid subblock type.\n";
+ return false;
+ }
+}
+
+ClangDocBitcodeReader::Cursor
+ClangDocBitcodeReader::skipUntilRecordOrBlock(unsigned &BlockOrRecordID) {
+ BlockOrRecordID = 0;
+
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ switch ((llvm::bitc::FixedAbbrevIDs)Code) {
+ case llvm::bitc::ENTER_SUBBLOCK:
+ BlockOrRecordID = Stream.ReadSubBlockID();
+ return Cursor::BlockBegin;
+ case llvm::bitc::END_BLOCK:
+ if (Stream.ReadBlockEnd())
+ return Cursor::BadBlock;
+ return Cursor::BlockEnd;
+ case llvm::bitc::DEFINE_ABBREV:
+ Stream.ReadAbbrevRecord();
+ continue;
+ case llvm::bitc::UNABBREV_RECORD:
+ return Cursor::BadBlock;
+ default:
+ BlockOrRecordID = Code;
+ return Cursor::Record;
+ }
+ }
+ llvm_unreachable("Premature stream end.");
+}
+
+bool ClangDocBitcodeReader::validateStream() {
+ if (Stream.AtEndOfStream())
+ return false;
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != BitCodeConstants::Signature[0] ||
+ Stream.Read(8) != BitCodeConstants::Signature[1] ||
+ Stream.Read(8) != BitCodeConstants::Signature[2] ||
+ Stream.Read(8) != BitCodeConstants::Signature[3])
+ return false;
+ return true;
+}
+
+bool ClangDocBitcodeReader::readBlockInfoBlock() {
+ BlockInfo = Stream.ReadBlockInfoBlock();
+ if (!BlockInfo)
+ return false;
+ Stream.setBlockInfo(&*BlockInfo);
+ return true;
+}
+
+template <typename T>
+std::unique_ptr<Info> ClangDocBitcodeReader::createInfo(unsigned ID) {
+ std::unique_ptr<Info> I = llvm::make_unique<T>();
+ if (readBlock(ID, static_cast<T *>(I.get())))
+ return I;
+ llvm::errs() << "Error reading from block.\n";
+ return nullptr;
+}
+
+std::unique_ptr<Info> ClangDocBitcodeReader::readBlockToInfo(unsigned ID) {
+ switch (ID) {
+ case BI_NAMESPACE_BLOCK_ID:
+ return createInfo<NamespaceInfo>(ID);
+ case BI_RECORD_BLOCK_ID:
+ return createInfo<RecordInfo>(ID);
+ case BI_ENUM_BLOCK_ID:
+ return createInfo<EnumInfo>(ID);
+ case BI_FUNCTION_BLOCK_ID:
+ return createInfo<FunctionInfo>(ID);
+ default:
+ llvm::errs() << "Error reading from block.\n";
+ return nullptr;
+ }
+}
+
+// Entry point
+std::vector<std::unique_ptr<Info>> ClangDocBitcodeReader::readBitcode() {
+ std::vector<std::unique_ptr<Info>> Infos;
+ if (!validateStream())
+ return Infos;
+
+ // Read the top level blocks.
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+ if (Code != llvm::bitc::ENTER_SUBBLOCK)
+ return Infos;
+
+ unsigned ID = Stream.ReadSubBlockID();
+ switch (ID) {
+ // NamedType and Comment blocks should not appear at the top level
+ case BI_TYPE_BLOCK_ID:
+ case BI_FIELD_TYPE_BLOCK_ID:
+ case BI_MEMBER_TYPE_BLOCK_ID:
+ case BI_COMMENT_BLOCK_ID:
+ case BI_REFERENCE_BLOCK_ID:
+ llvm::errs() << "Invalid top level block.\n";
+ return Infos;
+ case BI_NAMESPACE_BLOCK_ID:
+ case BI_RECORD_BLOCK_ID:
+ case BI_ENUM_BLOCK_ID:
+ case BI_FUNCTION_BLOCK_ID:
+ if (std::unique_ptr<Info> I = readBlockToInfo(ID)) {
+ Infos.emplace_back(std::move(I));
+ }
+ return Infos;
+ case BI_VERSION_BLOCK_ID:
+ if (readBlock(ID, VersionNumber))
+ continue;
+ return Infos;
+ case llvm::bitc::BLOCKINFO_BLOCK_ID:
+ if (readBlockInfoBlock())
+ continue;
+ return Infos;
+ default:
+ if (!Stream.SkipBlock())
+ continue;
+ }
+ }
+ return Infos;
+}
+
+} // namespace doc
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/BitcodeReader.h b/src/third_party/llvm-project/clang-tools-extra/clang-doc/BitcodeReader.h
new file mode 100644
index 0000000..c0cf24a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/BitcodeReader.h
@@ -0,0 +1,73 @@
+//===-- BitcodeReader.h - ClangDoc Bitcode Reader --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a reader for parsing the clang-doc internal
+// representation from LLVM bitcode. The reader takes in a stream of bits and
+// generates the set of infos that it represents.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEREADER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEREADER_H
+
+#include "BitcodeWriter.h"
+#include "Representation.h"
+#include "clang/AST/AST.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+
+namespace clang {
+namespace doc {
+
+// Class to read bitstream into an InfoSet collection
+class ClangDocBitcodeReader {
+public:
+ ClangDocBitcodeReader(llvm::BitstreamCursor &Stream) : Stream(Stream) {}
+
+ // Main entry point, calls readBlock to read each block in the given stream.
+ std::vector<std::unique_ptr<Info>> readBitcode();
+
+private:
+ enum class Cursor { BadBlock = 1, Record, BlockEnd, BlockBegin };
+
+ // Top level parsing
+ bool validateStream();
+ bool readVersion();
+ bool readBlockInfoBlock();
+
+ // Read a block of records into a single Info struct, calls readRecord on each
+ // record found.
+ template <typename T> bool readBlock(unsigned ID, T I);
+
+ // Step through a block of records to find the next data field.
+ template <typename T> bool readSubBlock(unsigned ID, T I);
+
+ // Read record data into the given Info data field, calling the appropriate
+ // parseRecord functions to parse and store the data.
+ template <typename T> bool readRecord(unsigned ID, T I);
+
+ // Allocate the relevant type of info and add read data to the object.
+ template <typename T> std::unique_ptr<Info> createInfo(unsigned ID);
+
+ // Helper function to step through blocks to find and dispatch the next record
+ // or block to be read.
+ Cursor skipUntilRecordOrBlock(unsigned &BlockOrRecordID);
+
+ // Helper function to set up the approriate type of Info.
+ std::unique_ptr<Info> readBlockToInfo(unsigned ID);
+
+ llvm::BitstreamCursor &Stream;
+ Optional<llvm::BitstreamBlockInfo> BlockInfo;
+ FieldId CurrentReferenceField;
+};
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEREADER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-doc/BitcodeWriter.cpp
new file mode 100644
index 0000000..623ed1a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -0,0 +1,518 @@
+//===-- BitcodeWriter.cpp - ClangDoc Bitcode Writer ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BitcodeWriter.h"
+#include "llvm/ADT/IndexedMap.h"
+#include <initializer_list>
+
+namespace clang {
+namespace doc {
+
+// Empty SymbolID for comparison, so we don't have to construct one every time.
+static const SymbolID EmptySID = SymbolID();
+
+// Since id enums are not zero-indexed, we need to transform the given id into
+// its associated index.
+struct BlockIdToIndexFunctor {
+ using argument_type = unsigned;
+ unsigned operator()(unsigned ID) const { return ID - BI_FIRST; }
+};
+
+struct RecordIdToIndexFunctor {
+ using argument_type = unsigned;
+ unsigned operator()(unsigned ID) const { return ID - RI_FIRST; }
+};
+
+using AbbrevDsc = void (*)(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev);
+
+static void AbbrevGen(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev,
+ const std::initializer_list<llvm::BitCodeAbbrevOp> Ops) {
+ for (const auto &Op : Ops)
+ Abbrev->Add(Op);
+}
+
+static void BoolAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
+ AbbrevGen(Abbrev,
+ {// 0. Boolean
+ llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+ BitCodeConstants::BoolSize)});
+}
+
+static void IntAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
+ AbbrevGen(Abbrev,
+ {// 0. Fixed-size integer
+ llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+ BitCodeConstants::IntSize)});
+}
+
+static void SymbolIDAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
+ AbbrevGen(Abbrev,
+ {// 0. Fixed-size integer (length of the sha1'd USR)
+ llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+ BitCodeConstants::USRLengthSize),
+ // 1. Fixed-size array of Char6 (USR)
+ llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Array),
+ llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+ BitCodeConstants::USRBitLengthSize)});
+}
+
+static void StringAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
+ AbbrevGen(Abbrev,
+ {// 0. Fixed-size integer (length of the following string)
+ llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+ BitCodeConstants::StringLengthSize),
+ // 1. The string blob
+ llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
+}
+
+// Assumes that the file will not have more than 65535 lines.
+static void LocationAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
+ AbbrevGen(
+ Abbrev,
+ {// 0. Fixed-size integer (line number)
+ llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+ BitCodeConstants::LineNumberSize),
+ // 1. Fixed-size integer (length of the following string (filename))
+ llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+ BitCodeConstants::StringLengthSize),
+ // 2. The string blob
+ llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
+}
+
+struct RecordIdDsc {
+ llvm::StringRef Name;
+ AbbrevDsc Abbrev = nullptr;
+
+ RecordIdDsc() = default;
+ RecordIdDsc(llvm::StringRef Name, AbbrevDsc Abbrev)
+ : Name(Name), Abbrev(Abbrev) {}
+
+ // Is this 'description' valid?
+ operator bool() const {
+ return Abbrev != nullptr && Name.data() != nullptr && !Name.empty();
+ }
+};
+
+static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor>
+ BlockIdNameMap = []() {
+ llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor> BlockIdNameMap;
+ BlockIdNameMap.resize(BlockIdCount);
+
+ // There is no init-list constructor for the IndexedMap, so have to
+ // improvise
+ static const std::vector<std::pair<BlockId, const char *const>> Inits = {
+ {BI_VERSION_BLOCK_ID, "VersionBlock"},
+ {BI_NAMESPACE_BLOCK_ID, "NamespaceBlock"},
+ {BI_ENUM_BLOCK_ID, "EnumBlock"},
+ {BI_TYPE_BLOCK_ID, "TypeBlock"},
+ {BI_FIELD_TYPE_BLOCK_ID, "FieldTypeBlock"},
+ {BI_MEMBER_TYPE_BLOCK_ID, "MemberTypeBlock"},
+ {BI_RECORD_BLOCK_ID, "RecordBlock"},
+ {BI_FUNCTION_BLOCK_ID, "FunctionBlock"},
+ {BI_COMMENT_BLOCK_ID, "CommentBlock"},
+ {BI_REFERENCE_BLOCK_ID, "ReferenceBlock"}};
+ assert(Inits.size() == BlockIdCount);
+ for (const auto &Init : Inits)
+ BlockIdNameMap[Init.first] = Init.second;
+ assert(BlockIdNameMap.size() == BlockIdCount);
+ return BlockIdNameMap;
+ }();
+
+static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
+ RecordIdNameMap = []() {
+ llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> RecordIdNameMap;
+ RecordIdNameMap.resize(RecordIdCount);
+
+ // There is no init-list constructor for the IndexedMap, so have to
+ // improvise
+ static const std::vector<std::pair<RecordId, RecordIdDsc>> Inits = {
+ {VERSION, {"Version", &IntAbbrev}},
+ {COMMENT_KIND, {"Kind", &StringAbbrev}},
+ {COMMENT_TEXT, {"Text", &StringAbbrev}},
+ {COMMENT_NAME, {"Name", &StringAbbrev}},
+ {COMMENT_DIRECTION, {"Direction", &StringAbbrev}},
+ {COMMENT_PARAMNAME, {"ParamName", &StringAbbrev}},
+ {COMMENT_CLOSENAME, {"CloseName", &StringAbbrev}},
+ {COMMENT_SELFCLOSING, {"SelfClosing", &BoolAbbrev}},
+ {COMMENT_EXPLICIT, {"Explicit", &BoolAbbrev}},
+ {COMMENT_ATTRKEY, {"AttrKey", &StringAbbrev}},
+ {COMMENT_ATTRVAL, {"AttrVal", &StringAbbrev}},
+ {COMMENT_ARG, {"Arg", &StringAbbrev}},
+ {FIELD_TYPE_NAME, {"Name", &StringAbbrev}},
+ {MEMBER_TYPE_NAME, {"Name", &StringAbbrev}},
+ {MEMBER_TYPE_ACCESS, {"Access", &IntAbbrev}},
+ {NAMESPACE_USR, {"USR", &SymbolIDAbbrev}},
+ {NAMESPACE_NAME, {"Name", &StringAbbrev}},
+ {ENUM_USR, {"USR", &SymbolIDAbbrev}},
+ {ENUM_NAME, {"Name", &StringAbbrev}},
+ {ENUM_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
+ {ENUM_LOCATION, {"Location", &LocationAbbrev}},
+ {ENUM_MEMBER, {"Member", &StringAbbrev}},
+ {ENUM_SCOPED, {"Scoped", &BoolAbbrev}},
+ {RECORD_USR, {"USR", &SymbolIDAbbrev}},
+ {RECORD_NAME, {"Name", &StringAbbrev}},
+ {RECORD_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
+ {RECORD_LOCATION, {"Location", &LocationAbbrev}},
+ {RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},
+ {FUNCTION_USR, {"USR", &SymbolIDAbbrev}},
+ {FUNCTION_NAME, {"Name", &StringAbbrev}},
+ {FUNCTION_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
+ {FUNCTION_LOCATION, {"Location", &LocationAbbrev}},
+ {FUNCTION_ACCESS, {"Access", &IntAbbrev}},
+ {FUNCTION_IS_METHOD, {"IsMethod", &BoolAbbrev}},
+ {REFERENCE_USR, {"USR", &SymbolIDAbbrev}},
+ {REFERENCE_NAME, {"Name", &StringAbbrev}},
+ {REFERENCE_TYPE, {"RefType", &IntAbbrev}},
+ {REFERENCE_FIELD, {"Field", &IntAbbrev}}};
+ assert(Inits.size() == RecordIdCount);
+ for (const auto &Init : Inits) {
+ RecordIdNameMap[Init.first] = Init.second;
+ assert((Init.second.Name.size() + 1) <= BitCodeConstants::RecordSize);
+ }
+ assert(RecordIdNameMap.size() == RecordIdCount);
+ return RecordIdNameMap;
+ }();
+
+static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
+ RecordsByBlock{
+ // Version Block
+ {BI_VERSION_BLOCK_ID, {VERSION}},
+ // Comment Block
+ {BI_COMMENT_BLOCK_ID,
+ {COMMENT_KIND, COMMENT_TEXT, COMMENT_NAME, COMMENT_DIRECTION,
+ COMMENT_PARAMNAME, COMMENT_CLOSENAME, COMMENT_SELFCLOSING,
+ COMMENT_EXPLICIT, COMMENT_ATTRKEY, COMMENT_ATTRVAL, COMMENT_ARG}},
+ // Type Block
+ {BI_TYPE_BLOCK_ID, {}},
+ // FieldType Block
+ {BI_FIELD_TYPE_BLOCK_ID, {FIELD_TYPE_NAME}},
+ // MemberType Block
+ {BI_MEMBER_TYPE_BLOCK_ID, {MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS}},
+ // Enum Block
+ {BI_ENUM_BLOCK_ID,
+ {ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_MEMBER,
+ ENUM_SCOPED}},
+ // Namespace Block
+ {BI_NAMESPACE_BLOCK_ID, {NAMESPACE_USR, NAMESPACE_NAME}},
+ // Record Block
+ {BI_RECORD_BLOCK_ID,
+ {RECORD_USR, RECORD_NAME, RECORD_DEFLOCATION, RECORD_LOCATION,
+ RECORD_TAG_TYPE}},
+ // Function Block
+ {BI_FUNCTION_BLOCK_ID,
+ {FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION,
+ FUNCTION_ACCESS, FUNCTION_IS_METHOD}},
+ // Reference Block
+ {BI_REFERENCE_BLOCK_ID,
+ {REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_FIELD}}};
+
+// AbbreviationMap
+
+constexpr char BitCodeConstants::Signature[];
+
+void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID,
+ unsigned AbbrevID) {
+ assert(RecordIdNameMap[RID] && "Unknown RecordId.");
+ assert(Abbrevs.find(RID) == Abbrevs.end() && "Abbreviation already added.");
+ Abbrevs[RID] = AbbrevID;
+}
+
+unsigned ClangDocBitcodeWriter::AbbreviationMap::get(RecordId RID) const {
+ assert(RecordIdNameMap[RID] && "Unknown RecordId.");
+ assert(Abbrevs.find(RID) != Abbrevs.end() && "Unknown abbreviation.");
+ return Abbrevs.lookup(RID);
+}
+
+// Validation and Overview Blocks
+
+/// \brief Emits the magic number header to check that its the right format,
+/// in this case, 'DOCS'.
+void ClangDocBitcodeWriter::emitHeader() {
+ for (char C : BitCodeConstants::Signature)
+ Stream.Emit((unsigned)C, BitCodeConstants::SignatureBitSize);
+}
+
+void ClangDocBitcodeWriter::emitVersionBlock() {
+ StreamSubBlockGuard Block(Stream, BI_VERSION_BLOCK_ID);
+ emitRecord(VersionNumber, VERSION);
+}
+
+/// \brief Emits a block ID and the block name to the BLOCKINFO block.
+void ClangDocBitcodeWriter::emitBlockID(BlockId BID) {
+ const auto &BlockIdName = BlockIdNameMap[BID];
+ assert(BlockIdName.data() && BlockIdName.size() && "Unknown BlockId.");
+
+ Record.clear();
+ Record.push_back(BID);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
+ ArrayRef<unsigned char>(BlockIdName.bytes_begin(),
+ BlockIdName.bytes_end()));
+}
+
+/// \brief Emits a record name to the BLOCKINFO block.
+void ClangDocBitcodeWriter::emitRecordID(RecordId ID) {
+ assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+ prepRecordData(ID);
+ Record.append(RecordIdNameMap[ID].Name.begin(),
+ RecordIdNameMap[ID].Name.end());
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
+}
+
+// Abbreviations
+
+void ClangDocBitcodeWriter::emitAbbrev(RecordId ID, BlockId Block) {
+ assert(RecordIdNameMap[ID] && "Unknown abbreviation.");
+ auto Abbrev = std::make_shared<llvm::BitCodeAbbrev>();
+ Abbrev->Add(llvm::BitCodeAbbrevOp(ID));
+ RecordIdNameMap[ID].Abbrev(Abbrev);
+ Abbrevs.add(ID, Stream.EmitBlockInfoAbbrev(Block, std::move(Abbrev)));
+}
+
+// Records
+
+void ClangDocBitcodeWriter::emitRecord(const SymbolID &Sym, RecordId ID) {
+ assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+ assert(RecordIdNameMap[ID].Abbrev == &SymbolIDAbbrev &&
+ "Abbrev type mismatch.");
+ if (!prepRecordData(ID, Sym != EmptySID))
+ return;
+ assert(Sym.size() == 20);
+ Record.push_back(Sym.size());
+ Record.append(Sym.begin(), Sym.end());
+ Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
+}
+
+void ClangDocBitcodeWriter::emitRecord(llvm::StringRef Str, RecordId ID) {
+ assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+ assert(RecordIdNameMap[ID].Abbrev == &StringAbbrev &&
+ "Abbrev type mismatch.");
+ if (!prepRecordData(ID, !Str.empty()))
+ return;
+ assert(Str.size() < (1U << BitCodeConstants::StringLengthSize));
+ Record.push_back(Str.size());
+ Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Str);
+}
+
+void ClangDocBitcodeWriter::emitRecord(const Location &Loc, RecordId ID) {
+ assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+ assert(RecordIdNameMap[ID].Abbrev == &LocationAbbrev &&
+ "Abbrev type mismatch.");
+ if (!prepRecordData(ID, true))
+ return;
+ // FIXME: Assert that the line number is of the appropriate size.
+ Record.push_back(Loc.LineNumber);
+ assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize));
+ // Record.push_back(Loc.Filename.size());
+ // Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Loc.Filename);
+ Record.push_back(4);
+ Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, "test");
+}
+
+void ClangDocBitcodeWriter::emitRecord(bool Val, RecordId ID) {
+ assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+ assert(RecordIdNameMap[ID].Abbrev == &BoolAbbrev && "Abbrev type mismatch.");
+ if (!prepRecordData(ID, Val))
+ return;
+ Record.push_back(Val);
+ Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
+}
+
+void ClangDocBitcodeWriter::emitRecord(int Val, RecordId ID) {
+ assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+ assert(RecordIdNameMap[ID].Abbrev == &IntAbbrev && "Abbrev type mismatch.");
+ if (!prepRecordData(ID, Val))
+ return;
+ // FIXME: Assert that the integer is of the appropriate size.
+ Record.push_back(Val);
+ Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
+}
+
+void ClangDocBitcodeWriter::emitRecord(unsigned Val, RecordId ID) {
+ assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+ assert(RecordIdNameMap[ID].Abbrev == &IntAbbrev && "Abbrev type mismatch.");
+ if (!prepRecordData(ID, Val))
+ return;
+ assert(Val < (1U << BitCodeConstants::IntSize));
+ Record.push_back(Val);
+ Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
+}
+
+bool ClangDocBitcodeWriter::prepRecordData(RecordId ID, bool ShouldEmit) {
+ assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+ if (!ShouldEmit)
+ return false;
+ Record.clear();
+ Record.push_back(ID);
+ return true;
+}
+
+// BlockInfo Block
+
+void ClangDocBitcodeWriter::emitBlockInfoBlock() {
+ Stream.EnterBlockInfoBlock();
+ for (const auto &Block : RecordsByBlock) {
+ assert(Block.second.size() < (1U << BitCodeConstants::SubblockIDSize));
+ emitBlockInfo(Block.first, Block.second);
+ }
+ Stream.ExitBlock();
+}
+
+void ClangDocBitcodeWriter::emitBlockInfo(BlockId BID,
+ const std::vector<RecordId> &RIDs) {
+ assert(RIDs.size() < (1U << BitCodeConstants::SubblockIDSize));
+ emitBlockID(BID);
+ for (RecordId RID : RIDs) {
+ emitRecordID(RID);
+ emitAbbrev(RID, BID);
+ }
+}
+
+// Block emission
+
+void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) {
+ if (R.USR == EmptySID && R.Name.empty())
+ return;
+ StreamSubBlockGuard Block(Stream, BI_REFERENCE_BLOCK_ID);
+ emitRecord(R.USR, REFERENCE_USR);
+ emitRecord(R.Name, REFERENCE_NAME);
+ emitRecord((unsigned)R.RefType, REFERENCE_TYPE);
+ emitRecord((unsigned)Field, REFERENCE_FIELD);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) {
+ StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID);
+ emitBlock(T.Type, FieldId::F_type);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const FieldTypeInfo &T) {
+ StreamSubBlockGuard Block(Stream, BI_FIELD_TYPE_BLOCK_ID);
+ emitBlock(T.Type, FieldId::F_type);
+ emitRecord(T.Name, FIELD_TYPE_NAME);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {
+ StreamSubBlockGuard Block(Stream, BI_MEMBER_TYPE_BLOCK_ID);
+ emitBlock(T.Type, FieldId::F_type);
+ emitRecord(T.Name, MEMBER_TYPE_NAME);
+ emitRecord(T.Access, MEMBER_TYPE_ACCESS);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) {
+ StreamSubBlockGuard Block(Stream, BI_COMMENT_BLOCK_ID);
+ for (const auto &L : std::vector<std::pair<llvm::StringRef, RecordId>>{
+ {I.Kind, COMMENT_KIND},
+ {I.Text, COMMENT_TEXT},
+ {I.Name, COMMENT_NAME},
+ {I.Direction, COMMENT_DIRECTION},
+ {I.ParamName, COMMENT_PARAMNAME},
+ {I.CloseName, COMMENT_CLOSENAME}})
+ emitRecord(L.first, L.second);
+ emitRecord(I.SelfClosing, COMMENT_SELFCLOSING);
+ emitRecord(I.Explicit, COMMENT_EXPLICIT);
+ for (const auto &A : I.AttrKeys)
+ emitRecord(A, COMMENT_ATTRKEY);
+ for (const auto &A : I.AttrValues)
+ emitRecord(A, COMMENT_ATTRVAL);
+ for (const auto &A : I.Args)
+ emitRecord(A, COMMENT_ARG);
+ for (const auto &C : I.Children)
+ emitBlock(*C);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
+ StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);
+ emitRecord(I.USR, NAMESPACE_USR);
+ emitRecord(I.Name, NAMESPACE_NAME);
+ for (const auto &N : I.Namespace)
+ emitBlock(N, FieldId::F_namespace);
+ for (const auto &CI : I.Description)
+ emitBlock(CI);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
+ StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID);
+ emitRecord(I.USR, ENUM_USR);
+ emitRecord(I.Name, ENUM_NAME);
+ for (const auto &N : I.Namespace)
+ emitBlock(N, FieldId::F_namespace);
+ for (const auto &CI : I.Description)
+ emitBlock(CI);
+ if (I.DefLoc)
+ emitRecord(I.DefLoc.getValue(), ENUM_DEFLOCATION);
+ for (const auto &L : I.Loc)
+ emitRecord(L, ENUM_LOCATION);
+ emitRecord(I.Scoped, ENUM_SCOPED);
+ for (const auto &N : I.Members)
+ emitRecord(N, ENUM_MEMBER);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
+ StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);
+ emitRecord(I.USR, RECORD_USR);
+ emitRecord(I.Name, RECORD_NAME);
+ for (const auto &N : I.Namespace)
+ emitBlock(N, FieldId::F_namespace);
+ for (const auto &CI : I.Description)
+ emitBlock(CI);
+ if (I.DefLoc)
+ emitRecord(I.DefLoc.getValue(), RECORD_DEFLOCATION);
+ for (const auto &L : I.Loc)
+ emitRecord(L, RECORD_LOCATION);
+ emitRecord(I.TagType, RECORD_TAG_TYPE);
+ for (const auto &N : I.Members)
+ emitBlock(N);
+ for (const auto &P : I.Parents)
+ emitBlock(P, FieldId::F_parent);
+ for (const auto &P : I.VirtualParents)
+ emitBlock(P, FieldId::F_vparent);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
+ StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID);
+ emitRecord(I.USR, FUNCTION_USR);
+ emitRecord(I.Name, FUNCTION_NAME);
+ for (const auto &N : I.Namespace)
+ emitBlock(N, FieldId::F_namespace);
+ for (const auto &CI : I.Description)
+ emitBlock(CI);
+ emitRecord(I.IsMethod, FUNCTION_IS_METHOD);
+ if (I.DefLoc)
+ emitRecord(I.DefLoc.getValue(), FUNCTION_DEFLOCATION);
+ for (const auto &L : I.Loc)
+ emitRecord(L, FUNCTION_LOCATION);
+ emitBlock(I.Parent, FieldId::F_parent);
+ emitBlock(I.ReturnType);
+ for (const auto &N : I.Params)
+ emitBlock(N);
+}
+
+bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
+ switch (I->IT) {
+ case InfoType::IT_namespace:
+ emitBlock(*static_cast<clang::doc::NamespaceInfo *>(I));
+ break;
+ case InfoType::IT_record:
+ emitBlock(*static_cast<clang::doc::RecordInfo *>(I));
+ break;
+ case InfoType::IT_enum:
+ emitBlock(*static_cast<clang::doc::EnumInfo *>(I));
+ break;
+ case InfoType::IT_function:
+ emitBlock(*static_cast<clang::doc::FunctionInfo *>(I));
+ break;
+ default:
+ llvm::errs() << "Unexpected info, unable to write.\n";
+ return true;
+ }
+ return false;
+}
+
+} // namespace doc
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/BitcodeWriter.h b/src/third_party/llvm-project/clang-tools-extra/clang-doc/BitcodeWriter.h
new file mode 100644
index 0000000..3d8a68f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/BitcodeWriter.h
@@ -0,0 +1,201 @@
+//===-- BitcodeWriter.h - ClangDoc Bitcode Writer --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a writer for serializing the clang-doc internal
+// representation to LLVM bitcode. The writer takes in a stream and emits the
+// generated bitcode to that stream.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H
+
+#include "Representation.h"
+#include "clang/AST/AST.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include <initializer_list>
+#include <vector>
+
+namespace clang {
+namespace doc {
+
+// Current version number of clang-doc bitcode.
+// Should be bumped when removing or changing BlockIds, RecordIds, or
+// BitCodeConstants, though they can be added without breaking it.
+static const unsigned VersionNumber = 2;
+
+struct BitCodeConstants {
+ static constexpr unsigned RecordSize = 32U;
+ static constexpr unsigned SignatureBitSize = 8U;
+ static constexpr unsigned SubblockIDSize = 4U;
+ static constexpr unsigned BoolSize = 1U;
+ static constexpr unsigned IntSize = 16U;
+ static constexpr unsigned StringLengthSize = 16U;
+ static constexpr unsigned FilenameLengthSize = 16U;
+ static constexpr unsigned LineNumberSize = 16U;
+ static constexpr unsigned ReferenceTypeSize = 8U;
+ static constexpr unsigned USRLengthSize = 6U;
+ static constexpr unsigned USRBitLengthSize = 8U;
+ static constexpr char Signature[4] = {'D', 'O', 'C', 'S'};
+ static constexpr int USRHashSize = 20;
+};
+
+// New Ids need to be added to both the enum here and the relevant IdNameMap in
+// the implementation file.
+enum BlockId {
+ BI_VERSION_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID,
+ BI_NAMESPACE_BLOCK_ID,
+ BI_ENUM_BLOCK_ID,
+ BI_TYPE_BLOCK_ID,
+ BI_FIELD_TYPE_BLOCK_ID,
+ BI_MEMBER_TYPE_BLOCK_ID,
+ BI_RECORD_BLOCK_ID,
+ BI_FUNCTION_BLOCK_ID,
+ BI_COMMENT_BLOCK_ID,
+ BI_REFERENCE_BLOCK_ID,
+ BI_LAST,
+ BI_FIRST = BI_VERSION_BLOCK_ID
+};
+
+// New Ids need to be added to the enum here, and to the relevant IdNameMap and
+// initialization list in the implementation file.
+#define INFORECORDS(X) X##_USR, X##_NAME
+
+enum RecordId {
+ VERSION = 1,
+ INFORECORDS(FUNCTION),
+ FUNCTION_DEFLOCATION,
+ FUNCTION_LOCATION,
+ FUNCTION_ACCESS,
+ FUNCTION_IS_METHOD,
+ COMMENT_KIND,
+ COMMENT_TEXT,
+ COMMENT_NAME,
+ COMMENT_DIRECTION,
+ COMMENT_PARAMNAME,
+ COMMENT_CLOSENAME,
+ COMMENT_SELFCLOSING,
+ COMMENT_EXPLICIT,
+ COMMENT_ATTRKEY,
+ COMMENT_ATTRVAL,
+ COMMENT_ARG,
+ FIELD_TYPE_NAME,
+ MEMBER_TYPE_NAME,
+ MEMBER_TYPE_ACCESS,
+ INFORECORDS(NAMESPACE),
+ INFORECORDS(ENUM),
+ ENUM_DEFLOCATION,
+ ENUM_LOCATION,
+ ENUM_MEMBER,
+ ENUM_SCOPED,
+ INFORECORDS(RECORD),
+ RECORD_DEFLOCATION,
+ RECORD_LOCATION,
+ RECORD_TAG_TYPE,
+ REFERENCE_USR,
+ REFERENCE_NAME,
+ REFERENCE_TYPE,
+ REFERENCE_FIELD,
+ RI_LAST,
+ RI_FIRST = VERSION
+};
+
+static constexpr unsigned BlockIdCount = BI_LAST - BI_FIRST;
+static constexpr unsigned RecordIdCount = RI_LAST - RI_FIRST;
+
+#undef INFORECORDS
+
+// Identifiers for differentiating between subblocks
+enum class FieldId { F_default, F_namespace, F_parent, F_vparent, F_type };
+
+class ClangDocBitcodeWriter {
+public:
+ ClangDocBitcodeWriter(llvm::BitstreamWriter &Stream) : Stream(Stream) {
+ emitHeader();
+ emitBlockInfoBlock();
+ emitVersionBlock();
+ }
+
+ // Write a specific info to a bitcode stream.
+ bool dispatchInfoForWrite(Info *I);
+
+ // Block emission of different info types.
+ void emitBlock(const NamespaceInfo &I);
+ void emitBlock(const RecordInfo &I);
+ void emitBlock(const FunctionInfo &I);
+ void emitBlock(const EnumInfo &I);
+ void emitBlock(const TypeInfo &B);
+ void emitBlock(const FieldTypeInfo &B);
+ void emitBlock(const MemberTypeInfo &B);
+ void emitBlock(const CommentInfo &B);
+ void emitBlock(const Reference &B, FieldId F);
+
+private:
+ class AbbreviationMap {
+ llvm::DenseMap<unsigned, unsigned> Abbrevs;
+
+ public:
+ AbbreviationMap() : Abbrevs(RecordIdCount) {}
+
+ void add(RecordId RID, unsigned AbbrevID);
+ unsigned get(RecordId RID) const;
+ };
+
+ class StreamSubBlockGuard {
+ llvm::BitstreamWriter &Stream;
+
+ public:
+ StreamSubBlockGuard(llvm::BitstreamWriter &Stream_, BlockId ID)
+ : Stream(Stream_) {
+ // NOTE: SubBlockIDSize could theoretically be calculated on the fly,
+ // based on the initialization list of records in each block.
+ Stream.EnterSubblock(ID, BitCodeConstants::SubblockIDSize);
+ }
+
+ StreamSubBlockGuard(const StreamSubBlockGuard &) = delete;
+ StreamSubBlockGuard &operator=(const StreamSubBlockGuard &) = delete;
+
+ ~StreamSubBlockGuard() { Stream.ExitBlock(); }
+ };
+
+ // Emission of validation and overview blocks.
+ void emitHeader();
+ void emitVersionBlock();
+ void emitRecordID(RecordId ID);
+ void emitBlockID(BlockId ID);
+ void emitBlockInfoBlock();
+ void emitBlockInfo(BlockId BID, const std::vector<RecordId> &RIDs);
+
+ // Emission of individual record types.
+ void emitRecord(StringRef Str, RecordId ID);
+ void emitRecord(const SymbolID &Str, RecordId ID);
+ void emitRecord(const Location &Loc, RecordId ID);
+ void emitRecord(const Reference &Ref, RecordId ID);
+ void emitRecord(bool Value, RecordId ID);
+ void emitRecord(int Value, RecordId ID);
+ void emitRecord(unsigned Value, RecordId ID);
+ bool prepRecordData(RecordId ID, bool ShouldEmit = true);
+
+ // Emission of appropriate abbreviation type.
+ void emitAbbrev(RecordId ID, BlockId Block);
+
+ // Static size is the maximum length of the block/record names we're pushing
+ // to this + 1. Longest is currently `MemberTypeBlock` at 15 chars.
+ SmallVector<uint32_t, BitCodeConstants::RecordSize> Record;
+ llvm::BitstreamWriter &Stream;
+ AbbreviationMap Abbrevs;
+};
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-doc/CMakeLists.txt
new file mode 100644
index 0000000..eaebf61
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/CMakeLists.txt
@@ -0,0 +1,29 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ BitReader
+ BitWriter
+ )
+
+add_clang_library(clangDoc
+ BitcodeReader.cpp
+ BitcodeWriter.cpp
+ ClangDoc.cpp
+ Generators.cpp
+ Mapper.cpp
+ Representation.cpp
+ Serialize.cpp
+ YAMLGenerator.cpp
+
+ LINK_LIBS
+ clangAnalysis
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFrontend
+ clangIndex
+ clangLex
+ clangTooling
+ clangToolingCore
+ )
+
+add_subdirectory(tool)
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/ClangDoc.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-doc/ClangDoc.cpp
new file mode 100644
index 0000000..a11c584
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/ClangDoc.cpp
@@ -0,0 +1,62 @@
+//===-- ClangDoc.cpp - ClangDoc ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the main entry point for the clang-doc tool. It runs
+// the clang-doc mapper on a given set of source code files using a
+// FrontendActionFactory.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangDoc.h"
+#include "Mapper.h"
+#include "Representation.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+
+namespace clang {
+namespace doc {
+
+class MapperActionFactory : public tooling::FrontendActionFactory {
+public:
+ MapperActionFactory(ClangDocContext CDCtx) : CDCtx(CDCtx) {}
+ clang::FrontendAction *create() override;
+
+private:
+ ClangDocContext CDCtx;
+};
+
+clang::FrontendAction *MapperActionFactory::create() {
+ class ClangDocAction : public clang::ASTFrontendAction {
+ public:
+ ClangDocAction(ClangDocContext CDCtx) : CDCtx(CDCtx) {}
+
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &Compiler,
+ llvm::StringRef InFile) override {
+ return llvm::make_unique<MapASTVisitor>(&Compiler.getASTContext(), CDCtx);
+ }
+
+ private:
+ ClangDocContext CDCtx;
+ };
+ return new ClangDocAction(CDCtx);
+}
+
+std::unique_ptr<tooling::FrontendActionFactory>
+newMapperActionFactory(ClangDocContext CDCtx) {
+ return llvm::make_unique<MapperActionFactory>(CDCtx);
+}
+
+} // namespace doc
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/ClangDoc.h b/src/third_party/llvm-project/clang-tools-extra/clang-doc/ClangDoc.h
new file mode 100644
index 0000000..59e9a92
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/ClangDoc.h
@@ -0,0 +1,34 @@
+//===-- ClangDoc.h - ClangDoc -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file exposes a method to craete the FrontendActionFactory for the
+// clang-doc tool. The factory runs the clang-doc mapper on a given set of
+// source code files, storing the results key-value pairs in its
+// ExecutionContext.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
+
+#include "Representation.h"
+#include "clang/Tooling/Execution.h"
+#include "clang/Tooling/StandaloneExecution.h"
+#include "clang/Tooling/Tooling.h"
+
+namespace clang {
+namespace doc {
+
+std::unique_ptr<tooling::FrontendActionFactory>
+newMapperActionFactory(ClangDocContext CDCtx);
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/Generators.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Generators.cpp
new file mode 100644
index 0000000..fe01d61
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Generators.cpp
@@ -0,0 +1,36 @@
+//===---- Generator.cpp - Generator Registry ---------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Generators.h"
+
+LLVM_INSTANTIATE_REGISTRY(clang::doc::GeneratorRegistry)
+
+namespace clang {
+namespace doc {
+
+llvm::Expected<std::unique_ptr<Generator>>
+findGeneratorByName(llvm::StringRef Format) {
+ for (auto I = GeneratorRegistry::begin(), E = GeneratorRegistry::end();
+ I != E; ++I) {
+ if (I->getName() != Format)
+ continue;
+ return I->instantiate();
+ }
+ return llvm::make_error<llvm::StringError>("Can't find generator: " + Format,
+ llvm::inconvertibleErrorCode());
+}
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the generators.
+extern volatile int YAMLGeneratorAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED YAMLGeneratorAnchorDest =
+ YAMLGeneratorAnchorSource;
+
+} // namespace doc
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/Generators.h b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Generators.h
new file mode 100644
index 0000000..9106d2c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Generators.h
@@ -0,0 +1,41 @@
+//===-- Generators.h - ClangDoc Generator ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Generator classes for converting declaration information into documentation
+// in a specified format.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_GENERATOR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_GENERATOR_H
+
+#include "Representation.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Registry.h"
+
+namespace clang {
+namespace doc {
+
+// Abstract base class for generators.
+// This is expected to be implemented and exposed via the GeneratorRegistry.
+class Generator {
+public:
+ virtual ~Generator() = default;
+
+ // Write out the decl info in the specified format.
+ virtual bool generateDocForInfo(Info *I, llvm::raw_ostream &OS) = 0;
+};
+
+typedef llvm::Registry<Generator> GeneratorRegistry;
+
+llvm::Expected<std::unique_ptr<Generator>>
+findGeneratorByName(llvm::StringRef Format);
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_GENERATOR_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/Mapper.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Mapper.cpp
new file mode 100644
index 0000000..fb0b42a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Mapper.cpp
@@ -0,0 +1,90 @@
+//===-- Mapper.cpp - ClangDoc Mapper ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Mapper.h"
+#include "BitcodeWriter.h"
+#include "Serialize.h"
+#include "clang/AST/Comment.h"
+#include "clang/Index/USRGeneration.h"
+#include "llvm/ADT/StringExtras.h"
+
+using clang::comments::FullComment;
+
+namespace clang {
+namespace doc {
+
+void MapASTVisitor::HandleTranslationUnit(ASTContext &Context) {
+ TraverseDecl(Context.getTranslationUnitDecl());
+}
+
+template <typename T> bool MapASTVisitor::mapDecl(const T *D) {
+ // If we're looking a decl not in user files, skip this decl.
+ if (D->getASTContext().getSourceManager().isInSystemHeader(D->getLocation()))
+ return true;
+
+ llvm::SmallString<128> USR;
+ // If there is an error generating a USR for the decl, skip this decl.
+ if (index::generateUSRForDecl(D, USR))
+ return true;
+
+ std::string info = serialize::emitInfo(
+ D, getComment(D, D->getASTContext()), getLine(D, D->getASTContext()),
+ getFile(D, D->getASTContext()), CDCtx.PublicOnly);
+
+ if (info != "")
+ CDCtx.ECtx->reportResult(
+ llvm::toHex(llvm::toStringRef(serialize::hashUSR(USR))), info);
+
+ return true;
+}
+
+bool MapASTVisitor::VisitNamespaceDecl(const NamespaceDecl *D) {
+ return mapDecl(D);
+}
+
+bool MapASTVisitor::VisitRecordDecl(const RecordDecl *D) { return mapDecl(D); }
+
+bool MapASTVisitor::VisitEnumDecl(const EnumDecl *D) { return mapDecl(D); }
+
+bool MapASTVisitor::VisitCXXMethodDecl(const CXXMethodDecl *D) {
+ return mapDecl(D);
+}
+
+bool MapASTVisitor::VisitFunctionDecl(const FunctionDecl *D) {
+ // Don't visit CXXMethodDecls twice
+ if (dyn_cast<CXXMethodDecl>(D))
+ return true;
+ return mapDecl(D);
+}
+
+comments::FullComment *
+MapASTVisitor::getComment(const NamedDecl *D, const ASTContext &Context) const {
+ RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
+ // FIXME: Move setAttached to the initial comment parsing.
+ if (Comment) {
+ Comment->setAttached();
+ return Comment->parse(Context, nullptr, D);
+ }
+ return nullptr;
+}
+
+int MapASTVisitor::getLine(const NamedDecl *D,
+ const ASTContext &Context) const {
+ return Context.getSourceManager().getPresumedLoc(D->getLocStart()).getLine();
+}
+
+llvm::StringRef MapASTVisitor::getFile(const NamedDecl *D,
+ const ASTContext &Context) const {
+ return Context.getSourceManager()
+ .getPresumedLoc(D->getLocStart())
+ .getFilename();
+}
+
+} // namespace doc
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/Mapper.h b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Mapper.h
new file mode 100644
index 0000000..a0b1ac2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Mapper.h
@@ -0,0 +1,58 @@
+//===-- Mapper.h - ClangDoc Mapper ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Mapper piece of the clang-doc tool. It implements
+// a RecursiveASTVisitor to look at each declaration and populate the info
+// into the internal representation. Each seen declaration is serialized to
+// to bitcode and written out to the ExecutionContext as a KV pair where the
+// key is the declaration's USR and the value is the serialized bitcode.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_MAPPER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_MAPPER_H
+
+#include "Representation.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Tooling/Execution.h"
+
+using namespace clang::comments;
+using namespace clang::tooling;
+
+namespace clang {
+namespace doc {
+
+class MapASTVisitor : public clang::RecursiveASTVisitor<MapASTVisitor>,
+ public ASTConsumer {
+public:
+ explicit MapASTVisitor(ASTContext *Ctx, ClangDocContext CDCtx)
+ : CDCtx(CDCtx) {}
+
+ void HandleTranslationUnit(ASTContext &Context) override;
+ bool VisitNamespaceDecl(const NamespaceDecl *D);
+ bool VisitRecordDecl(const RecordDecl *D);
+ bool VisitEnumDecl(const EnumDecl *D);
+ bool VisitCXXMethodDecl(const CXXMethodDecl *D);
+ bool VisitFunctionDecl(const FunctionDecl *D);
+
+private:
+ template <typename T> bool mapDecl(const T *D);
+
+ int getLine(const NamedDecl *D, const ASTContext &Context) const;
+ StringRef getFile(const NamedDecl *D, const ASTContext &Context) const;
+ comments::FullComment *getComment(const NamedDecl *D,
+ const ASTContext &Context) const;
+
+ ClangDocContext CDCtx;
+};
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_MAPPER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/Representation.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Representation.cpp
new file mode 100644
index 0000000..6107b98
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Representation.cpp
@@ -0,0 +1,131 @@
+///===-- Representation.cpp - ClangDoc Representation -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the merging of different types of infos. The data in the
+// calling Info is preserved during a merge unless that field is empty or
+// default. In that case, the data from the parameter Info is used to replace
+// the empty or default data.
+//
+// For most fields, the first decl seen provides the data. Exceptions to this
+// include the location and description fields, which are collections of data on
+// all decls related to a given definition. All other fields are ignored in new
+// decls unless the first seen decl didn't, for whatever reason, incorporate
+// data on that field (e.g. a forward declared class wouldn't have information
+// on members on the forward declaration, but would have the class name).
+//
+//===----------------------------------------------------------------------===//
+#include "Representation.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace doc {
+
+static const SymbolID EmptySID = SymbolID();
+
+template <typename T>
+std::unique_ptr<Info> reduce(std::vector<std::unique_ptr<Info>> &Values) {
+ std::unique_ptr<Info> Merged = llvm::make_unique<T>();
+ T *Tmp = static_cast<T *>(Merged.get());
+ for (auto &I : Values)
+ Tmp->merge(std::move(*static_cast<T *>(I.get())));
+ return Merged;
+}
+
+// Dispatch function.
+llvm::Expected<std::unique_ptr<Info>>
+mergeInfos(std::vector<std::unique_ptr<Info>> &Values) {
+ if (Values.empty())
+ return llvm::make_error<llvm::StringError>("No info values to merge.\n",
+ llvm::inconvertibleErrorCode());
+
+ switch (Values[0]->IT) {
+ case InfoType::IT_namespace:
+ return reduce<NamespaceInfo>(Values);
+ case InfoType::IT_record:
+ return reduce<RecordInfo>(Values);
+ case InfoType::IT_enum:
+ return reduce<EnumInfo>(Values);
+ case InfoType::IT_function:
+ return reduce<FunctionInfo>(Values);
+ default:
+ return llvm::make_error<llvm::StringError>("Unexpected info type.\n",
+ llvm::inconvertibleErrorCode());
+ }
+}
+
+void Info::mergeBase(Info &&Other) {
+ assert(mergeable(Other));
+ if (USR == EmptySID)
+ USR = Other.USR;
+ if (Name == "")
+ Name = Other.Name;
+ if (Namespace.empty())
+ Namespace = std::move(Other.Namespace);
+ // Unconditionally extend the description, since each decl may have a comment.
+ std::move(Other.Description.begin(), Other.Description.end(),
+ std::back_inserter(Description));
+}
+
+bool Info::mergeable(const Info &Other) {
+ return IT == Other.IT && (USR == EmptySID || USR == Other.USR);
+}
+
+void SymbolInfo::merge(SymbolInfo &&Other) {
+ assert(mergeable(Other));
+ if (!DefLoc)
+ DefLoc = std::move(Other.DefLoc);
+ // Unconditionally extend the list of locations, since we want all of them.
+ std::move(Other.Loc.begin(), Other.Loc.end(), std::back_inserter(Loc));
+ mergeBase(std::move(Other));
+}
+
+void NamespaceInfo::merge(NamespaceInfo &&Other) {
+ assert(mergeable(Other));
+ mergeBase(std::move(Other));
+}
+
+void RecordInfo::merge(RecordInfo &&Other) {
+ assert(mergeable(Other));
+ if (!TagType)
+ TagType = Other.TagType;
+ if (Members.empty())
+ Members = std::move(Other.Members);
+ if (Parents.empty())
+ Parents = std::move(Other.Parents);
+ if (VirtualParents.empty())
+ VirtualParents = std::move(Other.VirtualParents);
+ SymbolInfo::merge(std::move(Other));
+}
+
+void EnumInfo::merge(EnumInfo &&Other) {
+ assert(mergeable(Other));
+ if (!Scoped)
+ Scoped = Other.Scoped;
+ if (Members.empty())
+ Members = std::move(Other.Members);
+ SymbolInfo::merge(std::move(Other));
+}
+
+void FunctionInfo::merge(FunctionInfo &&Other) {
+ assert(mergeable(Other));
+ if (!IsMethod)
+ IsMethod = Other.IsMethod;
+ if (!Access)
+ Access = Other.Access;
+ if (ReturnType.Type.USR == EmptySID && ReturnType.Type.Name == "")
+ ReturnType = std::move(Other.ReturnType);
+ if (Parent.USR == EmptySID && Parent.Name == "")
+ Parent = std::move(Other.Parent);
+ if (Params.empty())
+ Params = std::move(Other.Params);
+ SymbolInfo::merge(std::move(Other));
+}
+
+} // namespace doc
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/Representation.h b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Representation.h
new file mode 100644
index 0000000..f952954
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Representation.h
@@ -0,0 +1,251 @@
+///===-- Representation.h - ClangDoc Representation -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the internal representations of different declaration
+// types for the clang-doc tool.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H
+
+#include "clang/AST/Type.h"
+#include "clang/Basic/Specifiers.h"
+#include "clang/Tooling/StandaloneExecution.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include <array>
+#include <string>
+
+namespace clang {
+namespace doc {
+
+// SHA1'd hash of a USR.
+using SymbolID = std::array<uint8_t, 20>;
+
+struct Info;
+enum class InfoType {
+ IT_default,
+ IT_namespace,
+ IT_record,
+ IT_function,
+ IT_enum
+};
+
+// A representation of a parsed comment.
+struct CommentInfo {
+ CommentInfo() = default;
+ CommentInfo(CommentInfo &Other) = delete;
+ CommentInfo(CommentInfo &&Other) = default;
+
+ SmallString<16> Kind; // Kind of comment (TextComment, InlineCommandComment,
+ // HTMLStartTagComment, HTMLEndTagComment,
+ // BlockCommandComment, ParamCommandComment,
+ // TParamCommandComment, VerbatimBlockComment,
+ // VerbatimBlockLineComment, VerbatimLineComment).
+ SmallString<64> Text; // Text of the comment.
+ SmallString<16> Name; // Name of the comment (for Verbatim and HTML).
+ SmallString<8> Direction; // Parameter direction (for (T)ParamCommand).
+ SmallString<16> ParamName; // Parameter name (for (T)ParamCommand).
+ SmallString<16> CloseName; // Closing tag name (for VerbatimBlock).
+ bool SelfClosing = false; // Indicates if tag is self-closing (for HTML).
+ bool Explicit = false; // Indicates if the direction of a param is explicit
+ // (for (T)ParamCommand).
+ llvm::SmallVector<SmallString<16>, 4>
+ AttrKeys; // List of attribute keys (for HTML).
+ llvm::SmallVector<SmallString<16>, 4>
+ AttrValues; // List of attribute values for each key (for HTML).
+ llvm::SmallVector<SmallString<16>, 4>
+ Args; // List of arguments to commands (for InlineCommand).
+ std::vector<std::unique_ptr<CommentInfo>>
+ Children; // List of child comments for this CommentInfo.
+};
+
+struct Reference {
+ Reference() = default;
+ Reference(llvm::StringRef Name) : Name(Name) {}
+ Reference(SymbolID USR, StringRef Name, InfoType IT)
+ : USR(USR), Name(Name), RefType(IT) {}
+
+ bool operator==(const Reference &Other) const {
+ return std::tie(USR, Name, RefType) ==
+ std::tie(Other.USR, Other.Name, Other.RefType);
+ }
+
+ SymbolID USR = SymbolID(); // Unique identifer for referenced decl
+ SmallString<16> Name; // Name of type (possibly unresolved).
+ InfoType RefType = InfoType::IT_default; // Indicates the type of this
+ // Reference (namespace, record,
+ // function, enum, default).
+};
+
+// A base struct for TypeInfos
+struct TypeInfo {
+ TypeInfo() = default;
+ TypeInfo(SymbolID Type, StringRef Field, InfoType IT)
+ : Type(Type, Field, IT) {}
+ TypeInfo(llvm::StringRef RefName) : Type(RefName) {}
+
+ bool operator==(const TypeInfo &Other) const { return Type == Other.Type; }
+
+ Reference Type; // Referenced type in this info.
+};
+
+// Info for field types.
+struct FieldTypeInfo : public TypeInfo {
+ FieldTypeInfo() = default;
+ FieldTypeInfo(SymbolID Type, StringRef Field, InfoType IT,
+ llvm::StringRef Name)
+ : TypeInfo(Type, Field, IT), Name(Name) {}
+ FieldTypeInfo(llvm::StringRef RefName, llvm::StringRef Name)
+ : TypeInfo(RefName), Name(Name) {}
+
+ bool operator==(const FieldTypeInfo &Other) const {
+ return std::tie(Type, Name) == std::tie(Other.Type, Other.Name);
+ }
+
+ SmallString<16> Name; // Name associated with this info.
+};
+
+// Info for member types.
+struct MemberTypeInfo : public FieldTypeInfo {
+ MemberTypeInfo() = default;
+ MemberTypeInfo(SymbolID Type, StringRef Field, InfoType IT,
+ llvm::StringRef Name, AccessSpecifier Access)
+ : FieldTypeInfo(Type, Field, IT, Name), Access(Access) {}
+ MemberTypeInfo(llvm::StringRef RefName, llvm::StringRef Name,
+ AccessSpecifier Access)
+ : FieldTypeInfo(RefName, Name), Access(Access) {}
+
+ bool operator==(const MemberTypeInfo &Other) const {
+ return std::tie(Type, Name, Access) ==
+ std::tie(Other.Type, Other.Name, Other.Access);
+ }
+
+ AccessSpecifier Access = AccessSpecifier::AS_none; // Access level associated
+ // with this info (public,
+ // protected, private,
+ // none).
+};
+
+struct Location {
+ Location() = default;
+ Location(int LineNumber, SmallString<16> Filename)
+ : LineNumber(LineNumber), Filename(std::move(Filename)) {}
+
+ bool operator==(const Location &Other) const {
+ return std::tie(LineNumber, Filename) ==
+ std::tie(Other.LineNumber, Other.Filename);
+ }
+
+ int LineNumber; // Line number of this Location.
+ SmallString<32> Filename; // File for this Location.
+};
+
+/// A base struct for Infos.
+struct Info {
+ Info() = default;
+ Info(InfoType IT) : IT(IT) {}
+ Info(const Info &Other) = delete;
+ Info(Info &&Other) = default;
+
+ SymbolID USR =
+ SymbolID(); // Unique identifier for the decl described by this Info.
+ const InfoType IT = InfoType::IT_default; // InfoType of this particular Info.
+ SmallString<16> Name; // Unqualified name of the decl.
+ llvm::SmallVector<Reference, 4>
+ Namespace; // List of parent namespaces for this decl.
+ std::vector<CommentInfo> Description; // Comment description of this decl.
+
+ void mergeBase(Info &&I);
+ bool mergeable(const Info &Other);
+};
+
+// Info for namespaces.
+struct NamespaceInfo : public Info {
+ NamespaceInfo() : Info(InfoType::IT_namespace) {}
+
+ void merge(NamespaceInfo &&I);
+};
+
+// Info for symbols.
+struct SymbolInfo : public Info {
+ SymbolInfo(InfoType IT) : Info(IT) {}
+
+ void merge(SymbolInfo &&I);
+
+ llvm::Optional<Location> DefLoc; // Location where this decl is defined.
+ llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared.
+};
+
+// TODO: Expand to allow for documenting templating and default args.
+// Info for functions.
+struct FunctionInfo : public SymbolInfo {
+ FunctionInfo() : SymbolInfo(InfoType::IT_function) {}
+
+ void merge(FunctionInfo &&I);
+
+ bool IsMethod = false; // Indicates whether this function is a class method.
+ Reference Parent; // Reference to the parent class decl for this method.
+ TypeInfo ReturnType; // Info about the return type of this function.
+ llvm::SmallVector<FieldTypeInfo, 4> Params; // List of parameters.
+ // Access level for this method (public, private, protected, none).
+ AccessSpecifier Access = AccessSpecifier::AS_none;
+};
+
+// TODO: Expand to allow for documenting templating, inheritance access,
+// friend classes
+// Info for types.
+struct RecordInfo : public SymbolInfo {
+ RecordInfo() : SymbolInfo(InfoType::IT_record) {}
+
+ void merge(RecordInfo &&I);
+
+ TagTypeKind TagType = TagTypeKind::TTK_Struct; // Type of this record
+ // (struct, class, union,
+ // interface).
+ llvm::SmallVector<MemberTypeInfo, 4>
+ Members; // List of info about record members.
+ llvm::SmallVector<Reference, 4> Parents; // List of base/parent records
+ // (does not include virtual
+ // parents).
+ llvm::SmallVector<Reference, 4>
+ VirtualParents; // List of virtual base/parent records.
+};
+
+// TODO: Expand to allow for documenting templating.
+// Info for types.
+struct EnumInfo : public SymbolInfo {
+ EnumInfo() : SymbolInfo(InfoType::IT_enum) {}
+
+ void merge(EnumInfo &&I);
+
+ bool Scoped =
+ false; // Indicates whether this enum is scoped (e.g. enum class).
+ llvm::SmallVector<SmallString<16>, 4> Members; // List of enum members.
+};
+
+// TODO: Add functionality to include separate markdown pages.
+
+// A standalone function to call to merge a vector of infos into one.
+// This assumes that all infos in the vector are of the same type, and will fail
+// if they are different.
+llvm::Expected<std::unique_ptr<Info>>
+mergeInfos(std::vector<std::unique_ptr<Info>> &Values);
+
+struct ClangDocContext {
+ tooling::ExecutionContext *ECtx;
+ bool PublicOnly;
+};
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/Serialize.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Serialize.cpp
new file mode 100644
index 0000000..c1e6d31
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Serialize.cpp
@@ -0,0 +1,368 @@
+//===-- Serializer.cpp - ClangDoc Serializer --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Serialize.h"
+#include "BitcodeWriter.h"
+#include "clang/AST/Comment.h"
+#include "clang/Index/USRGeneration.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/SHA1.h"
+
+using clang::comments::FullComment;
+
+namespace clang {
+namespace doc {
+namespace serialize {
+
+SymbolID hashUSR(llvm::StringRef USR) {
+ return llvm::SHA1::hash(arrayRefFromStringRef(USR));
+}
+
+class ClangDocCommentVisitor
+ : public ConstCommentVisitor<ClangDocCommentVisitor> {
+public:
+ ClangDocCommentVisitor(CommentInfo &CI) : CurrentCI(CI) {}
+
+ void parseComment(const comments::Comment *C);
+
+ void visitTextComment(const TextComment *C);
+ void visitInlineCommandComment(const InlineCommandComment *C);
+ void visitHTMLStartTagComment(const HTMLStartTagComment *C);
+ void visitHTMLEndTagComment(const HTMLEndTagComment *C);
+ void visitBlockCommandComment(const BlockCommandComment *C);
+ void visitParamCommandComment(const ParamCommandComment *C);
+ void visitTParamCommandComment(const TParamCommandComment *C);
+ void visitVerbatimBlockComment(const VerbatimBlockComment *C);
+ void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
+ void visitVerbatimLineComment(const VerbatimLineComment *C);
+
+private:
+ std::string getCommandName(unsigned CommandID) const;
+ bool isWhitespaceOnly(StringRef S) const;
+
+ CommentInfo &CurrentCI;
+};
+
+void ClangDocCommentVisitor::parseComment(const comments::Comment *C) {
+ CurrentCI.Kind = C->getCommentKindName();
+ ConstCommentVisitor<ClangDocCommentVisitor>::visit(C);
+ for (comments::Comment *Child :
+ llvm::make_range(C->child_begin(), C->child_end())) {
+ CurrentCI.Children.emplace_back(llvm::make_unique<CommentInfo>());
+ ClangDocCommentVisitor Visitor(*CurrentCI.Children.back());
+ Visitor.parseComment(Child);
+ }
+}
+
+void ClangDocCommentVisitor::visitTextComment(const TextComment *C) {
+ if (!isWhitespaceOnly(C->getText()))
+ CurrentCI.Text = C->getText();
+}
+
+void ClangDocCommentVisitor::visitInlineCommandComment(
+ const InlineCommandComment *C) {
+ CurrentCI.Name = getCommandName(C->getCommandID());
+ for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I)
+ CurrentCI.Args.push_back(C->getArgText(I));
+}
+
+void ClangDocCommentVisitor::visitHTMLStartTagComment(
+ const HTMLStartTagComment *C) {
+ CurrentCI.Name = C->getTagName();
+ CurrentCI.SelfClosing = C->isSelfClosing();
+ for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) {
+ const HTMLStartTagComment::Attribute &Attr = C->getAttr(I);
+ CurrentCI.AttrKeys.push_back(Attr.Name);
+ CurrentCI.AttrValues.push_back(Attr.Value);
+ }
+}
+
+void ClangDocCommentVisitor::visitHTMLEndTagComment(
+ const HTMLEndTagComment *C) {
+ CurrentCI.Name = C->getTagName();
+ CurrentCI.SelfClosing = true;
+}
+
+void ClangDocCommentVisitor::visitBlockCommandComment(
+ const BlockCommandComment *C) {
+ CurrentCI.Name = getCommandName(C->getCommandID());
+ for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
+ CurrentCI.Args.push_back(C->getArgText(I));
+}
+
+void ClangDocCommentVisitor::visitParamCommandComment(
+ const ParamCommandComment *C) {
+ CurrentCI.Direction =
+ ParamCommandComment::getDirectionAsString(C->getDirection());
+ CurrentCI.Explicit = C->isDirectionExplicit();
+ if (C->hasParamName())
+ CurrentCI.ParamName = C->getParamNameAsWritten();
+}
+
+void ClangDocCommentVisitor::visitTParamCommandComment(
+ const TParamCommandComment *C) {
+ if (C->hasParamName())
+ CurrentCI.ParamName = C->getParamNameAsWritten();
+}
+
+void ClangDocCommentVisitor::visitVerbatimBlockComment(
+ const VerbatimBlockComment *C) {
+ CurrentCI.Name = getCommandName(C->getCommandID());
+ CurrentCI.CloseName = C->getCloseName();
+}
+
+void ClangDocCommentVisitor::visitVerbatimBlockLineComment(
+ const VerbatimBlockLineComment *C) {
+ if (!isWhitespaceOnly(C->getText()))
+ CurrentCI.Text = C->getText();
+}
+
+void ClangDocCommentVisitor::visitVerbatimLineComment(
+ const VerbatimLineComment *C) {
+ if (!isWhitespaceOnly(C->getText()))
+ CurrentCI.Text = C->getText();
+}
+
+bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S) const {
+ return std::all_of(S.begin(), S.end(), isspace);
+}
+
+std::string ClangDocCommentVisitor::getCommandName(unsigned CommandID) const {
+ const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
+ if (Info)
+ return Info->Name;
+ // TODO: Add parsing for \file command.
+ return "<not a builtin command>";
+}
+
+// Serializing functions.
+
+template <typename T> static std::string serialize(T &I) {
+ SmallString<2048> Buffer;
+ llvm::BitstreamWriter Stream(Buffer);
+ ClangDocBitcodeWriter Writer(Stream);
+ Writer.emitBlock(I);
+ return Buffer.str().str();
+}
+
+static void parseFullComment(const FullComment *C, CommentInfo &CI) {
+ ClangDocCommentVisitor Visitor(CI);
+ Visitor.parseComment(C);
+}
+
+static SymbolID getUSRForDecl(const Decl *D) {
+ llvm::SmallString<128> USR;
+ if (index::generateUSRForDecl(D, USR))
+ return SymbolID();
+ return hashUSR(USR);
+}
+
+static RecordDecl *getDeclForType(const QualType &T) {
+ auto *Ty = T->getAs<RecordType>();
+ if (!Ty)
+ return nullptr;
+ return Ty->getDecl()->getDefinition();
+}
+
+static bool isPublic(const clang::AccessSpecifier AS,
+ const clang::Linkage Link) {
+ if (AS == clang::AccessSpecifier::AS_private)
+ return false;
+ else if ((Link == clang::Linkage::ModuleLinkage) ||
+ (Link == clang::Linkage::ExternalLinkage))
+ return true;
+ return false; // otherwise, linkage is some form of internal linkage
+}
+
+static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly) {
+ for (const FieldDecl *F : D->fields()) {
+ if (PublicOnly && !isPublic(F->getAccessUnsafe(), F->getLinkageInternal()))
+ continue;
+ if (const auto *T = getDeclForType(F->getTypeSourceInfo()->getType())) {
+ // Use getAccessUnsafe so that we just get the default AS_none if it's not
+ // valid, as opposed to an assert.
+ if (const auto *N = dyn_cast<EnumDecl>(T)) {
+ I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
+ InfoType::IT_enum, F->getNameAsString(),
+ N->getAccessUnsafe());
+ continue;
+ } else if (const auto *N = dyn_cast<RecordDecl>(T)) {
+ I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
+ InfoType::IT_record, F->getNameAsString(),
+ N->getAccessUnsafe());
+ continue;
+ }
+ }
+ I.Members.emplace_back(F->getTypeSourceInfo()->getType().getAsString(),
+ F->getNameAsString(), F->getAccessUnsafe());
+ }
+}
+
+static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
+ for (const EnumConstantDecl *E : D->enumerators())
+ I.Members.emplace_back(E->getNameAsString());
+}
+
+static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
+ for (const ParmVarDecl *P : D->parameters()) {
+ if (const auto *T = getDeclForType(P->getOriginalType())) {
+ if (const auto *N = dyn_cast<EnumDecl>(T)) {
+ I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
+ InfoType::IT_enum, P->getNameAsString());
+ continue;
+ } else if (const auto *N = dyn_cast<RecordDecl>(T)) {
+ I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
+ InfoType::IT_record, P->getNameAsString());
+ continue;
+ }
+ }
+ I.Params.emplace_back(P->getOriginalType().getAsString(),
+ P->getNameAsString());
+ }
+}
+
+static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
+ for (const CXXBaseSpecifier &B : D->bases()) {
+ if (B.isVirtual())
+ continue;
+ if (const auto *P = getDeclForType(B.getType()))
+ I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
+ InfoType::IT_record);
+ else
+ I.Parents.emplace_back(B.getType().getAsString());
+ }
+ for (const CXXBaseSpecifier &B : D->vbases()) {
+ if (const auto *P = getDeclForType(B.getType()))
+ I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
+ InfoType::IT_record);
+ else
+ I.VirtualParents.emplace_back(B.getType().getAsString());
+ }
+}
+
+template <typename T>
+static void
+populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
+ const T *D) {
+ const auto *DC = dyn_cast<DeclContext>(D);
+ while ((DC = DC->getParent())) {
+ if (const auto *N = dyn_cast<NamespaceDecl>(DC))
+ Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
+ InfoType::IT_namespace);
+ else if (const auto *N = dyn_cast<RecordDecl>(DC))
+ Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
+ InfoType::IT_record);
+ else if (const auto *N = dyn_cast<FunctionDecl>(DC))
+ Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
+ InfoType::IT_function);
+ else if (const auto *N = dyn_cast<EnumDecl>(DC))
+ Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
+ InfoType::IT_enum);
+ }
+}
+
+template <typename T>
+static void populateInfo(Info &I, const T *D, const FullComment *C) {
+ I.USR = getUSRForDecl(D);
+ I.Name = D->getNameAsString();
+ populateParentNamespaces(I.Namespace, D);
+ if (C) {
+ I.Description.emplace_back();
+ parseFullComment(C, I.Description.back());
+ }
+}
+
+template <typename T>
+static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
+ int LineNumber, StringRef Filename) {
+ populateInfo(I, D, C);
+ if (D->isThisDeclarationADefinition())
+ I.DefLoc.emplace(LineNumber, Filename);
+ else
+ I.Loc.emplace_back(LineNumber, Filename);
+}
+
+static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
+ const FullComment *FC, int LineNumber,
+ StringRef Filename) {
+ populateSymbolInfo(I, D, FC, LineNumber, Filename);
+ if (const auto *T = getDeclForType(D->getReturnType())) {
+ if (dyn_cast<EnumDecl>(T))
+ I.ReturnType =
+ TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_enum);
+ else if (dyn_cast<RecordDecl>(T))
+ I.ReturnType =
+ TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_record);
+ } else {
+ I.ReturnType = TypeInfo(D->getReturnType().getAsString());
+ }
+ parseParameters(I, D);
+}
+
+std::string emitInfo(const NamespaceDecl *D, const FullComment *FC,
+ int LineNumber, llvm::StringRef File, bool PublicOnly) {
+ if (PublicOnly && ((D->isAnonymousNamespace()) ||
+ !isPublic(D->getAccess(), D->getLinkageInternal())))
+ return "";
+ NamespaceInfo I;
+ populateInfo(I, D, FC);
+ return serialize(I);
+}
+
+std::string emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
+ llvm::StringRef File, bool PublicOnly) {
+ if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
+ return "";
+ RecordInfo I;
+ populateSymbolInfo(I, D, FC, LineNumber, File);
+ I.TagType = D->getTagKind();
+ parseFields(I, D, PublicOnly);
+ if (const auto *C = dyn_cast<CXXRecordDecl>(D))
+ parseBases(I, C);
+ return serialize(I);
+}
+
+std::string emitInfo(const FunctionDecl *D, const FullComment *FC,
+ int LineNumber, llvm::StringRef File, bool PublicOnly) {
+ if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
+ return "";
+ FunctionInfo I;
+ populateFunctionInfo(I, D, FC, LineNumber, File);
+ I.Access = clang::AccessSpecifier::AS_none;
+ return serialize(I);
+}
+
+std::string emitInfo(const CXXMethodDecl *D, const FullComment *FC,
+ int LineNumber, llvm::StringRef File, bool PublicOnly) {
+ if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
+ return "";
+ FunctionInfo I;
+ populateFunctionInfo(I, D, FC, LineNumber, File);
+ I.IsMethod = true;
+ I.Parent = Reference{getUSRForDecl(D->getParent()),
+ D->getParent()->getNameAsString(), InfoType::IT_record};
+ I.Access = D->getAccess();
+ return serialize(I);
+}
+
+std::string emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
+ llvm::StringRef File, bool PublicOnly) {
+ if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
+ return "";
+ EnumInfo I;
+ populateSymbolInfo(I, D, FC, LineNumber, File);
+ I.Scoped = D->isScoped();
+ parseEnumerators(I, D);
+ return serialize(I);
+}
+
+} // namespace serialize
+} // namespace doc
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/Serialize.h b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Serialize.h
new file mode 100644
index 0000000..5181cf6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/Serialize.h
@@ -0,0 +1,53 @@
+//===-- Serializer.h - ClangDoc Serializer ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the serializing functions fro the clang-doc tool. Given
+// a particular declaration, it collects the appropriate information and returns
+// a serialized bitcode string for the declaration.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_SERIALIZE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_SERIALIZE_H
+
+#include "Representation.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/CommentVisitor.h"
+#include <string>
+#include <vector>
+
+using namespace clang::comments;
+
+namespace clang {
+namespace doc {
+namespace serialize {
+
+std::string emitInfo(const NamespaceDecl *D, const FullComment *FC,
+ int LineNumber, StringRef File, bool PublicOnly);
+std::string emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
+ StringRef File, bool PublicOnly);
+std::string emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
+ StringRef File, bool PublicOnly);
+std::string emitInfo(const FunctionDecl *D, const FullComment *FC,
+ int LineNumber, StringRef File, bool PublicOnly);
+std::string emitInfo(const CXXMethodDecl *D, const FullComment *FC,
+ int LineNumber, StringRef File, bool PublicOnly);
+
+// Function to hash a given USR value for storage.
+// As USRs (Unified Symbol Resolution) could be large, especially for functions
+// with long type arguments, we use 160-bits SHA1(USR) values to
+// guarantee the uniqueness of symbols while using a relatively small amount of
+// memory (vs storing USRs directly).
+SymbolID hashUSR(llvm::StringRef USR);
+
+} // namespace serialize
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_SERIALIZE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/YAMLGenerator.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-doc/YAMLGenerator.cpp
new file mode 100644
index 0000000..f29b478
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/YAMLGenerator.cpp
@@ -0,0 +1,268 @@
+//===-- ClangDocYAML.cpp - ClangDoc YAML -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Implementation of the YAML generator, converting decl info into YAML output.
+//===----------------------------------------------------------------------===//
+
+#include "Generators.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang::doc;
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(FieldTypeInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(MemberTypeInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Reference)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Location)
+LLVM_YAML_IS_SEQUENCE_VECTOR(CommentInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<CommentInfo>)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::SmallString<16>)
+
+namespace llvm {
+namespace yaml {
+
+// Enumerations to YAML output.
+
+template <> struct ScalarEnumerationTraits<clang::AccessSpecifier> {
+ static void enumeration(IO &IO, clang::AccessSpecifier &Value) {
+ IO.enumCase(Value, "Public", clang::AccessSpecifier::AS_public);
+ IO.enumCase(Value, "Protected", clang::AccessSpecifier::AS_protected);
+ IO.enumCase(Value, "Private", clang::AccessSpecifier::AS_private);
+ IO.enumCase(Value, "None", clang::AccessSpecifier::AS_none);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<clang::TagTypeKind> {
+ static void enumeration(IO &IO, clang::TagTypeKind &Value) {
+ IO.enumCase(Value, "Struct", clang::TagTypeKind::TTK_Struct);
+ IO.enumCase(Value, "Interface", clang::TagTypeKind::TTK_Interface);
+ IO.enumCase(Value, "Union", clang::TagTypeKind::TTK_Union);
+ IO.enumCase(Value, "Class", clang::TagTypeKind::TTK_Class);
+ IO.enumCase(Value, "Enum", clang::TagTypeKind::TTK_Enum);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<InfoType> {
+ static void enumeration(IO &IO, InfoType &Value) {
+ IO.enumCase(Value, "Namespace", InfoType::IT_namespace);
+ IO.enumCase(Value, "Record", InfoType::IT_record);
+ IO.enumCase(Value, "Function", InfoType::IT_function);
+ IO.enumCase(Value, "Enum", InfoType::IT_enum);
+ IO.enumCase(Value, "Default", InfoType::IT_default);
+ }
+};
+
+// Scalars to YAML output.
+template <unsigned U> struct ScalarTraits<SmallString<U>> {
+
+ static void output(const SmallString<U> &S, void *, llvm::raw_ostream &OS) {
+ for (const auto &C : S)
+ OS << C;
+ }
+
+ static StringRef input(StringRef Scalar, void *, SmallString<U> &Value) {
+ Value.assign(Scalar.begin(), Scalar.end());
+ return StringRef();
+ }
+
+ static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
+};
+
+template <> struct ScalarTraits<std::array<unsigned char, 20>> {
+
+ static void output(const std::array<unsigned char, 20> &S, void *,
+ llvm::raw_ostream &OS) {
+ OS << toHex(toStringRef(S));
+ }
+
+ static StringRef input(StringRef Scalar, void *,
+ std::array<unsigned char, 20> &Value) {
+ if (Scalar.size() != 40)
+ return "Error: Incorrect scalar size for USR.";
+ Value = StringToSymbol(Scalar);
+ return StringRef();
+ }
+
+ static SymbolID StringToSymbol(llvm::StringRef Value) {
+ SymbolID USR;
+ std::string HexString = fromHex(Value);
+ std::copy(HexString.begin(), HexString.end(), USR.begin());
+ return SymbolID(USR);
+ }
+
+ static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
+};
+
+// Helper functions to map infos to YAML.
+
+static void TypeInfoMapping(IO &IO, TypeInfo &I) {
+ IO.mapOptional("Type", I.Type, Reference());
+}
+
+static void FieldTypeInfoMapping(IO &IO, FieldTypeInfo &I) {
+ TypeInfoMapping(IO, I);
+ IO.mapOptional("Name", I.Name, SmallString<16>());
+}
+
+static void InfoMapping(IO &IO, Info &I) {
+ IO.mapRequired("USR", I.USR);
+ IO.mapOptional("Name", I.Name, SmallString<16>());
+ IO.mapOptional("Namespace", I.Namespace, llvm::SmallVector<Reference, 4>());
+ IO.mapOptional("Description", I.Description);
+}
+
+static void SymbolInfoMapping(IO &IO, SymbolInfo &I) {
+ InfoMapping(IO, I);
+ IO.mapOptional("DefLocation", I.DefLoc, Optional<Location>());
+ IO.mapOptional("Location", I.Loc, llvm::SmallVector<Location, 2>());
+}
+
+static void CommentInfoMapping(IO &IO, CommentInfo &I) {
+ IO.mapOptional("Kind", I.Kind, SmallString<16>());
+ IO.mapOptional("Text", I.Text, SmallString<64>());
+ IO.mapOptional("Name", I.Name, SmallString<16>());
+ IO.mapOptional("Direction", I.Direction, SmallString<8>());
+ IO.mapOptional("ParamName", I.ParamName, SmallString<16>());
+ IO.mapOptional("CloseName", I.CloseName, SmallString<16>());
+ IO.mapOptional("SelfClosing", I.SelfClosing, false);
+ IO.mapOptional("Explicit", I.Explicit, false);
+ IO.mapOptional("Args", I.Args, llvm::SmallVector<SmallString<16>, 4>());
+ IO.mapOptional("AttrKeys", I.AttrKeys,
+ llvm::SmallVector<SmallString<16>, 4>());
+ IO.mapOptional("AttrValues", I.AttrValues,
+ llvm::SmallVector<SmallString<16>, 4>());
+ IO.mapOptional("Children", I.Children);
+}
+
+// Template specialization to YAML traits for Infos.
+
+template <> struct MappingTraits<Location> {
+ static void mapping(IO &IO, Location &Loc) {
+ IO.mapOptional("LineNumber", Loc.LineNumber, 0);
+ IO.mapOptional("Filename", Loc.Filename, SmallString<32>());
+ }
+};
+
+template <> struct MappingTraits<Reference> {
+ static void mapping(IO &IO, Reference &Ref) {
+ IO.mapOptional("Type", Ref.RefType, InfoType::IT_default);
+ IO.mapOptional("Name", Ref.Name, SmallString<16>());
+ IO.mapOptional("USR", Ref.USR, SymbolID());
+ }
+};
+
+template <> struct MappingTraits<TypeInfo> {
+ static void mapping(IO &IO, TypeInfo &I) { TypeInfoMapping(IO, I); }
+};
+
+template <> struct MappingTraits<FieldTypeInfo> {
+ static void mapping(IO &IO, FieldTypeInfo &I) {
+ TypeInfoMapping(IO, I);
+ IO.mapOptional("Name", I.Name, SmallString<16>());
+ }
+};
+
+template <> struct MappingTraits<MemberTypeInfo> {
+ static void mapping(IO &IO, MemberTypeInfo &I) {
+ FieldTypeInfoMapping(IO, I);
+ IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);
+ }
+};
+
+template <> struct MappingTraits<NamespaceInfo> {
+ static void mapping(IO &IO, NamespaceInfo &I) { InfoMapping(IO, I); }
+};
+
+template <> struct MappingTraits<RecordInfo> {
+ static void mapping(IO &IO, RecordInfo &I) {
+ SymbolInfoMapping(IO, I);
+ IO.mapOptional("TagType", I.TagType, clang::TagTypeKind::TTK_Struct);
+ IO.mapOptional("Members", I.Members);
+ IO.mapOptional("Parents", I.Parents, llvm::SmallVector<Reference, 4>());
+ IO.mapOptional("VirtualParents", I.VirtualParents,
+ llvm::SmallVector<Reference, 4>());
+ }
+};
+
+template <> struct MappingTraits<EnumInfo> {
+ static void mapping(IO &IO, EnumInfo &I) {
+ SymbolInfoMapping(IO, I);
+ IO.mapOptional("Scoped", I.Scoped, false);
+ IO.mapOptional("Members", I.Members);
+ }
+};
+
+template <> struct MappingTraits<FunctionInfo> {
+ static void mapping(IO &IO, FunctionInfo &I) {
+ SymbolInfoMapping(IO, I);
+ IO.mapOptional("IsMethod", I.IsMethod, false);
+ IO.mapOptional("Parent", I.Parent, Reference());
+ IO.mapOptional("Params", I.Params);
+ IO.mapOptional("ReturnType", I.ReturnType);
+ IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);
+ }
+};
+
+template <> struct MappingTraits<CommentInfo> {
+ static void mapping(IO &IO, CommentInfo &I) { CommentInfoMapping(IO, I); }
+};
+
+template <> struct MappingTraits<std::unique_ptr<CommentInfo>> {
+ static void mapping(IO &IO, std::unique_ptr<CommentInfo> &I) {
+ if (I)
+ CommentInfoMapping(IO, *I);
+ }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+namespace clang {
+namespace doc {
+
+/// Generator for YAML documentation.
+class YAMLGenerator : public Generator {
+public:
+ static const char *Format;
+
+ bool generateDocForInfo(Info *I, llvm::raw_ostream &OS) override;
+};
+
+const char *YAMLGenerator::Format = "yaml";
+
+bool YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
+ llvm::yaml::Output InfoYAML(OS);
+ switch (I->IT) {
+ case InfoType::IT_namespace:
+ InfoYAML << *static_cast<clang::doc::NamespaceInfo *>(I);
+ break;
+ case InfoType::IT_record:
+ InfoYAML << *static_cast<clang::doc::RecordInfo *>(I);
+ break;
+ case InfoType::IT_enum:
+ InfoYAML << *static_cast<clang::doc::EnumInfo *>(I);
+ break;
+ case InfoType::IT_function:
+ InfoYAML << *static_cast<clang::doc::FunctionInfo *>(I);
+ break;
+ case InfoType::IT_default:
+ llvm::errs() << "Unexpected info type in index.\n";
+ return true;
+ }
+ return false;
+}
+
+static GeneratorRegistry::Add<YAMLGenerator> YAML(YAMLGenerator::Format,
+ "Generator for YAML output.");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the generator.
+volatile int YAMLGeneratorAnchorSource = 0;
+
+} // namespace doc
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/gen_tests.py b/src/third_party/llvm-project/clang-tools-extra/clang-doc/gen_tests.py
new file mode 100644
index 0000000..5004892
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/gen_tests.py
@@ -0,0 +1,200 @@
+#!/usr/bin/env python3
+#
+#===- gen_tests.py - clang-doc test generator ----------------*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+"""
+clang-doc test generator
+==========================
+
+Generates tests for clang-doc given a certain set of flags, a prefix for the
+test file, and a given clang-doc binary. Please check emitted tests for
+accuracy before using.
+
+To generate all current tests:
+- Generate mapper tests:
+ gen_tests.py -flag='--dump-mapper' -flag='--doxygen' -prefix mapper
+
+- Generate reducer tests:
+ gen_tests.py -flag='--dump-intermediate' -flag='--doxygen' -prefix bc
+
+- Generate yaml tests:
+ gen_tests.py -flag='--format=yaml' -flag='--doxygen' -prefix yaml
+
+This script was written on/for Linux, and has not been tested on any other
+platform and so it may not work.
+
+"""
+
+import argparse
+import glob
+import os
+import shutil
+import subprocess
+
+RUN_CLANG_DOC = """
+// RUN: clang-doc {0} -p %t %t/test.cpp -output=%t/docs
+"""
+RUN = """
+// RUN: {0} %t/{1} | FileCheck %s --check-prefix CHECK-{2}
+"""
+
+CHECK = '// CHECK-{0}: '
+
+CHECK_NEXT = '// CHECK-{0}-NEXT: '
+
+
+def clear_test_prefix_files(prefix, tests_path):
+ if os.path.isdir(tests_path):
+ for root, dirs, files in os.walk(tests_path):
+ for filename in files:
+ if filename.startswith(prefix):
+ os.remove(os.path.join(root, filename))
+
+
+def copy_to_test_file(test_case_path, test_cases_path):
+ # Copy file to 'test.cpp' to preserve file-dependent USRs
+ test_file = os.path.join(test_cases_path, 'test.cpp')
+ shutil.copyfile(test_case_path, test_file)
+ return test_file
+
+
+def run_clang_doc(args, out_dir, test_file):
+ # Run clang-doc.
+ current_cmd = [args.clangdoc]
+ current_cmd.extend(args.flags)
+ current_cmd.append('--output=' + out_dir)
+ current_cmd.append(test_file)
+ print('Running ' + ' '.join(current_cmd))
+ return_code = subprocess.call(current_cmd)
+ if return_code:
+ return 1
+ return 0
+
+
+def get_test_case_code(test_case_path, flags):
+ # Get the test case code
+ code = ''
+ with open(test_case_path, 'r') as code_file:
+ code = code_file.read()
+
+ code += RUN_CLANG_DOC.format(flags)
+ return code
+
+
+def get_output(root, out_file, case_out_path, flags, checkname, bcanalyzer):
+ output = ''
+ run_cmd = ''
+ if '--dump-mapper' in flags or '--dump-intermediate' in flags:
+ # Run llvm-bcanalyzer
+ output = subprocess.check_output(
+ [bcanalyzer, '--dump',
+ os.path.join(root, out_file)])
+ output = output[:output.find('Summary of ')].rstrip()
+ run_cmd = RUN.format('llvm-bcanalyzer --dump',
+ os.path.join('docs', 'bc', out_file), checkname)
+ else:
+ # Run cat
+ output = subprocess.check_output(['cat', os.path.join(root, out_file)])
+ run_cmd = RUN.format(
+ 'cat',
+ os.path.join('docs', os.path.relpath(root, case_out_path),
+ out_file), checkname)
+
+ # Format output.
+ output = output.replace('blob data = \'test\'', 'blob data = \'{{.*}}\'')
+ output = CHECK.format(checkname) + output.rstrip()
+ output = run_cmd + output.replace('\n',
+ '\n' + CHECK_NEXT.format(checkname))
+
+ return output + '\n'
+
+
+def main():
+ parser = argparse.ArgumentParser(description='Generate clang-doc tests.')
+ parser.add_argument(
+ '-flag',
+ action='append',
+ default=[],
+ dest='flags',
+ help='Flags to pass to clang-doc.')
+ parser.add_argument(
+ '-prefix',
+ type=str,
+ default='',
+ dest='prefix',
+ help='Prefix for this test group.')
+ parser.add_argument(
+ '-clang-doc-binary',
+ dest='clangdoc',
+ metavar="PATH",
+ default='clang-doc',
+ help='path to clang-doc binary')
+ parser.add_argument(
+ '-llvm-bcanalyzer-binary',
+ dest='bcanalyzer',
+ metavar="PATH",
+ default='llvm-bcanalyzer',
+ help='path to llvm-bcanalyzer binary')
+ args = parser.parse_args()
+
+ flags = ' '.join(args.flags)
+
+ clang_doc_path = os.path.dirname(__file__)
+ tests_path = os.path.join(clang_doc_path, '..', 'test', 'clang-doc')
+ test_cases_path = os.path.join(tests_path, 'test_cases')
+
+ clear_test_prefix_files(args.prefix, tests_path)
+
+ for test_case_path in glob.glob(os.path.join(test_cases_path, '*')):
+ if test_case_path.endswith(
+ 'compile_flags.txt') or test_case_path.endswith(
+ 'compile_commands.json'):
+ continue
+
+ # Name of this test case
+ case_name = os.path.basename(test_case_path).split('.')[0]
+
+ test_file = copy_to_test_file(test_case_path, test_cases_path)
+ out_dir = os.path.join(test_cases_path, case_name)
+
+ if run_clang_doc(args, out_dir, test_file):
+ return 1
+
+ # Retrieve output and format as FileCheck tests
+ all_output = ''
+ num_outputs = 0
+ for root, dirs, files in os.walk(out_dir):
+ for out_file in files:
+ # Make the file check the first 3 letters (there's a very small chance
+ # that this will collide, but the fix is to simply change the decl name)
+ usr = os.path.basename(out_file).split('.')
+ # If the usr is less than 2, this isn't one of the test files.
+ if len(usr) < 2:
+ continue
+ all_output += get_output(root, out_file, out_dir, args.flags,
+ num_outputs, args.bcanalyzer)
+ num_outputs += 1
+
+ # Add test case code to test
+ all_output = get_test_case_code(test_case_path,
+ flags) + '\n' + all_output
+
+ # Write to test case file in /test.
+ test_out_path = os.path.join(
+ tests_path, args.prefix + '-' + os.path.basename(test_case_path))
+ with open(test_out_path, 'w+') as o:
+ o.write(all_output)
+
+ # Clean up
+ shutil.rmtree(out_dir)
+ os.remove(test_file)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/tool/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-doc/tool/CMakeLists.txt
new file mode 100644
index 0000000..d7f28cf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/tool/CMakeLists.txt
@@ -0,0 +1,17 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+add_clang_executable(clang-doc
+ ClangDocMain.cpp
+ )
+
+target_link_libraries(clang-doc
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFrontend
+ clangDoc
+ clangTooling
+ clangToolingCore
+ )
+
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
new file mode 100644
index 0000000..9e89e85
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -0,0 +1,253 @@
+//===-- ClangDocMain.cpp - ClangDoc -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tool for generating C and C++ documenation from source code
+// and comments. Generally, it runs a LibTooling FrontendAction on source files,
+// mapping each declaration in those files to its USR and serializing relevant
+// information into LLVM bitcode. It then runs a pass over the collected
+// declaration information, reducing by USR. There is an option to dump this
+// intermediate result to bitcode. Finally, it hands the reduced information
+// off to a generator, which does the final parsing from the intermediate
+// representation to the desired output format.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BitcodeReader.h"
+#include "BitcodeWriter.h"
+#include "ClangDoc.h"
+#include "Generators.h"
+#include "Representation.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/Decl.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "clang/Driver/Options.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Execution.h"
+#include "clang/Tooling/StandaloneExecution.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+using namespace clang::ast_matchers;
+using namespace clang::tooling;
+using namespace clang;
+
+static llvm::cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+static llvm::cl::OptionCategory ClangDocCategory("clang-doc options");
+
+static llvm::cl::opt<std::string>
+ OutDirectory("output",
+ llvm::cl::desc("Directory for outputting generated files."),
+ llvm::cl::init("docs"), llvm::cl::cat(ClangDocCategory));
+
+static llvm::cl::opt<bool>
+ DumpMapperResult("dump-mapper",
+ llvm::cl::desc("Dump mapper results to bitcode file."),
+ llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
+
+static llvm::cl::opt<bool> DumpIntermediateResult(
+ "dump-intermediate",
+ llvm::cl::desc("Dump intermediate results to bitcode file."),
+ llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
+
+static llvm::cl::opt<bool>
+ PublicOnly("public", llvm::cl::desc("Document only public declarations."),
+ llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
+
+enum OutputFormatTy {
+ yaml,
+};
+
+static llvm::cl::opt<OutputFormatTy> FormatEnum(
+ "format", llvm::cl::desc("Format for outputted docs."),
+ llvm::cl::values(clEnumVal(yaml, "Documentation in YAML format.")),
+ llvm::cl::init(yaml), llvm::cl::cat(ClangDocCategory));
+
+static llvm::cl::opt<bool> DoxygenOnly(
+ "doxygen",
+ llvm::cl::desc("Use only doxygen-style comments to generate docs."),
+ llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
+
+bool CreateDirectory(const Twine &DirName, bool ClearDirectory = false) {
+ std::error_code OK;
+ llvm::SmallString<128> DocsRootPath;
+ if (ClearDirectory) {
+ std::error_code RemoveStatus = llvm::sys::fs::remove_directories(DirName);
+ if (RemoveStatus != OK) {
+ llvm::errs() << "Unable to remove existing documentation directory for "
+ << DirName << ".\n";
+ return true;
+ }
+ }
+ std::error_code DirectoryStatus = llvm::sys::fs::create_directories(DirName);
+ if (DirectoryStatus != OK) {
+ llvm::errs() << "Unable to create documentation directories.\n";
+ return true;
+ }
+ return false;
+}
+
+bool DumpResultToFile(const Twine &DirName, const Twine &FileName,
+ StringRef Buffer, bool ClearDirectory = false) {
+ std::error_code OK;
+ llvm::SmallString<128> IRRootPath;
+ llvm::sys::path::native(OutDirectory, IRRootPath);
+ llvm::sys::path::append(IRRootPath, DirName);
+ if (CreateDirectory(IRRootPath, ClearDirectory))
+ return true;
+ llvm::sys::path::append(IRRootPath, FileName);
+ std::error_code OutErrorInfo;
+ llvm::raw_fd_ostream OS(IRRootPath, OutErrorInfo, llvm::sys::fs::F_None);
+ if (OutErrorInfo != OK) {
+ llvm::errs() << "Error opening documentation file.\n";
+ return true;
+ }
+ OS << Buffer;
+ OS.close();
+ return false;
+}
+
+llvm::Expected<llvm::SmallString<128>>
+getPath(StringRef Root, StringRef Ext, StringRef Name,
+ llvm::SmallVectorImpl<doc::Reference> &Namespaces) {
+ std::error_code OK;
+ llvm::SmallString<128> Path;
+ llvm::sys::path::native(Root, Path);
+ for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
+ llvm::sys::path::append(Path, R->Name);
+
+ if (CreateDirectory(Path))
+ return llvm::make_error<llvm::StringError>("Unable to create directory.\n",
+ llvm::inconvertibleErrorCode());
+
+ llvm::sys::path::append(Path, Name + Ext);
+ return Path;
+}
+
+std::string getFormatString(OutputFormatTy Ty) {
+ switch (Ty) {
+ case yaml:
+ return "yaml";
+ }
+ llvm_unreachable("Unknown OutputFormatTy");
+}
+
+int main(int argc, const char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+ std::error_code OK;
+
+ // Fail early if an invalid format was provided.
+ std::string Format = getFormatString(FormatEnum);
+ auto G = doc::findGeneratorByName(Format);
+ if (!G) {
+ llvm::errs() << toString(G.takeError()) << "\n";
+ return 1;
+ }
+
+ auto Exec = clang::tooling::createExecutorFromCommandLineArgs(
+ argc, argv, ClangDocCategory);
+
+ if (!Exec) {
+ llvm::errs() << toString(Exec.takeError()) << "\n";
+ return 1;
+ }
+
+ ArgumentsAdjuster ArgAdjuster;
+ if (!DoxygenOnly)
+ ArgAdjuster = combineAdjusters(
+ getInsertArgumentAdjuster("-fparse-all-comments",
+ tooling::ArgumentInsertPosition::END),
+ ArgAdjuster);
+
+ // Mapping phase
+ llvm::outs() << "Mapping decls...\n";
+ clang::doc::ClangDocContext CDCtx = {Exec->get()->getExecutionContext(),
+ PublicOnly};
+ auto Err =
+ Exec->get()->execute(doc::newMapperActionFactory(CDCtx), ArgAdjuster);
+ if (Err) {
+ llvm::errs() << toString(std::move(Err)) << "\n";
+ return 1;
+ }
+
+ if (DumpMapperResult) {
+ bool Err = false;
+ Exec->get()->getToolResults()->forEachResult(
+ [&](StringRef Key, StringRef Value) {
+ Err = DumpResultToFile("bc", Key + ".bc", Value);
+ });
+ if (Err)
+ llvm::errs() << "Error dumping map results.\n";
+ return Err;
+ }
+
+ // Collect values into output by key.
+ llvm::outs() << "Collecting infos...\n";
+ llvm::StringMap<std::vector<std::unique_ptr<doc::Info>>> MapOutput;
+
+ // In ToolResults, the Key is the hashed USR and the value is the
+ // bitcode-encoded representation of the Info object.
+ Exec->get()->getToolResults()->forEachResult([&](StringRef Key,
+ StringRef Value) {
+ llvm::BitstreamCursor Stream(Value);
+ doc::ClangDocBitcodeReader Reader(Stream);
+ auto Infos = Reader.readBitcode();
+ for (auto &I : Infos) {
+ auto R =
+ MapOutput.try_emplace(Key, std::vector<std::unique_ptr<doc::Info>>());
+ R.first->second.emplace_back(std::move(I));
+ }
+ });
+
+ // Reducing and generation phases
+ llvm::outs() << "Reducing " << MapOutput.size() << " infos...\n";
+ llvm::StringMap<std::unique_ptr<doc::Info>> ReduceOutput;
+ for (auto &Group : MapOutput) {
+ auto Reduced = doc::mergeInfos(Group.getValue());
+ if (!Reduced)
+ llvm::errs() << llvm::toString(Reduced.takeError());
+
+ if (DumpIntermediateResult) {
+ SmallString<4096> Buffer;
+ llvm::BitstreamWriter Stream(Buffer);
+ doc::ClangDocBitcodeWriter Writer(Stream);
+ Writer.dispatchInfoForWrite(Reduced.get().get());
+ if (DumpResultToFile("bc", Group.getKey() + ".bc", Buffer))
+ llvm::errs() << "Error dumping to bitcode.\n";
+ continue;
+ }
+
+ // Create the relevant ostream and emit the documentation for this decl.
+ doc::Info *I = Reduced.get().get();
+ auto InfoPath = getPath(OutDirectory, "." + Format, I->Name, I->Namespace);
+ if (!InfoPath) {
+ llvm::errs() << toString(InfoPath.takeError()) << "\n";
+ continue;
+ }
+ std::error_code FileErr;
+ llvm::raw_fd_ostream InfoOS(InfoPath.get(), FileErr, llvm::sys::fs::F_None);
+ if (FileErr != OK) {
+ llvm::errs() << "Error opening index file: " << FileErr.message() << "\n";
+ continue;
+ }
+
+ if (G->get()->generateDocForInfo(I, InfoOS))
+ llvm::errs() << "Unable to generate docs for info.\n";
+ }
+
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-move/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-move/CMakeLists.txt
new file mode 100644
index 0000000..84175fd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-move/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+add_clang_library(clangMove
+ ClangMove.cpp
+ HelperDeclRefGraph.cpp
+
+ LINK_LIBS
+ clangAnalysis
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFormat
+ clangFrontend
+ clangLex
+ clangTooling
+ clangToolingCore
+ )
+
+add_subdirectory(tool)
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-move/ClangMove.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-move/ClangMove.cpp
new file mode 100644
index 0000000..e126852
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-move/ClangMove.cpp
@@ -0,0 +1,954 @@
+//===-- ClangMove.cpp - Implement ClangMove functationalities ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangMove.h"
+#include "HelperDeclRefGraph.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Path.h"
+
+#define DEBUG_TYPE "clang-move"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace move {
+namespace {
+
+// FIXME: Move to ASTMatchers.
+AST_MATCHER(VarDecl, isStaticDataMember) { return Node.isStaticDataMember(); }
+
+AST_MATCHER(NamedDecl, notInMacro) { return !Node.getLocation().isMacroID(); }
+
+AST_MATCHER_P(Decl, hasOutermostEnclosingClass,
+ ast_matchers::internal::Matcher<Decl>, InnerMatcher) {
+ const auto *Context = Node.getDeclContext();
+ if (!Context)
+ return false;
+ while (const auto *NextContext = Context->getParent()) {
+ if (isa<NamespaceDecl>(NextContext) ||
+ isa<TranslationUnitDecl>(NextContext))
+ break;
+ Context = NextContext;
+ }
+ return InnerMatcher.matches(*Decl::castFromDeclContext(Context), Finder,
+ Builder);
+}
+
+AST_MATCHER_P(CXXMethodDecl, ofOutermostEnclosingClass,
+ ast_matchers::internal::Matcher<CXXRecordDecl>, InnerMatcher) {
+ const CXXRecordDecl *Parent = Node.getParent();
+ if (!Parent)
+ return false;
+ while (const auto *NextParent =
+ dyn_cast<CXXRecordDecl>(Parent->getParent())) {
+ Parent = NextParent;
+ }
+
+ return InnerMatcher.matches(*Parent, Finder, Builder);
+}
+
+std::string CleanPath(StringRef PathRef) {
+ llvm::SmallString<128> Path(PathRef);
+ llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
+ // FIXME: figure out why this is necessary.
+ llvm::sys::path::native(Path);
+ return Path.str();
+}
+
+// Make the Path absolute using the CurrentDir if the Path is not an absolute
+// path. An empty Path will result in an empty string.
+std::string MakeAbsolutePath(StringRef CurrentDir, StringRef Path) {
+ if (Path.empty())
+ return "";
+ llvm::SmallString<128> InitialDirectory(CurrentDir);
+ llvm::SmallString<128> AbsolutePath(Path);
+ if (std::error_code EC =
+ llvm::sys::fs::make_absolute(InitialDirectory, AbsolutePath))
+ llvm::errs() << "Warning: could not make absolute file: '" << EC.message()
+ << '\n';
+ return CleanPath(std::move(AbsolutePath));
+}
+
+// Make the Path absolute using the current working directory of the given
+// SourceManager if the Path is not an absolute path.
+//
+// The Path can be a path relative to the build directory, or retrieved from
+// the SourceManager.
+std::string MakeAbsolutePath(const SourceManager &SM, StringRef Path) {
+ llvm::SmallString<128> AbsolutePath(Path);
+ if (std::error_code EC =
+ SM.getFileManager().getVirtualFileSystem()->makeAbsolute(
+ AbsolutePath))
+ llvm::errs() << "Warning: could not make absolute file: '" << EC.message()
+ << '\n';
+ // Handle symbolic link path cases.
+ // We are trying to get the real file path of the symlink.
+ const DirectoryEntry *Dir = SM.getFileManager().getDirectory(
+ llvm::sys::path::parent_path(AbsolutePath.str()));
+ if (Dir) {
+ StringRef DirName = SM.getFileManager().getCanonicalName(Dir);
+ // FIXME: getCanonicalName might fail to get real path on VFS.
+ if (llvm::sys::path::is_absolute(DirName)) {
+ SmallString<128> AbsoluteFilename;
+ llvm::sys::path::append(AbsoluteFilename, DirName,
+ llvm::sys::path::filename(AbsolutePath.str()));
+ return CleanPath(AbsoluteFilename);
+ }
+ }
+ return CleanPath(AbsolutePath);
+}
+
+// Matches AST nodes that are expanded within the given AbsoluteFilePath.
+AST_POLYMORPHIC_MATCHER_P(isExpansionInFile,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc),
+ std::string, AbsoluteFilePath) {
+ auto &SourceManager = Finder->getASTContext().getSourceManager();
+ auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart());
+ if (ExpansionLoc.isInvalid())
+ return false;
+ auto FileEntry =
+ SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc));
+ if (!FileEntry)
+ return false;
+ return MakeAbsolutePath(SourceManager, FileEntry->getName()) ==
+ AbsoluteFilePath;
+}
+
+class FindAllIncludes : public clang::PPCallbacks {
+public:
+ explicit FindAllIncludes(SourceManager *SM, ClangMoveTool *const MoveTool)
+ : SM(*SM), MoveTool(MoveTool) {}
+
+ void InclusionDirective(clang::SourceLocation HashLoc,
+ const clang::Token & /*IncludeTok*/,
+ StringRef FileName, bool IsAngled,
+ clang::CharSourceRange FilenameRange,
+ const clang::FileEntry * /*File*/,
+ StringRef SearchPath, StringRef /*RelativePath*/,
+ const clang::Module * /*Imported*/,
+ SrcMgr::CharacteristicKind /*FileType*/) override {
+ if (const auto *FileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc)))
+ MoveTool->addIncludes(FileName, IsAngled, SearchPath,
+ FileEntry->getName(), FilenameRange, SM);
+ }
+
+private:
+ const SourceManager &SM;
+ ClangMoveTool *const MoveTool;
+};
+
+/// Add a declatration being moved to new.h/cc. Note that the declaration will
+/// also be deleted in old.h/cc.
+void MoveDeclFromOldFileToNewFile(ClangMoveTool *MoveTool, const NamedDecl *D) {
+ MoveTool->getMovedDecls().push_back(D);
+ MoveTool->addRemovedDecl(D);
+ MoveTool->getUnremovedDeclsInOldHeader().erase(D);
+}
+
+class FunctionDeclarationMatch : public MatchFinder::MatchCallback {
+public:
+ explicit FunctionDeclarationMatch(ClangMoveTool *MoveTool)
+ : MoveTool(MoveTool) {}
+
+ void run(const MatchFinder::MatchResult &Result) override {
+ const auto *FD = Result.Nodes.getNodeAs<clang::FunctionDecl>("function");
+ assert(FD);
+ const clang::NamedDecl *D = FD;
+ if (const auto *FTD = FD->getDescribedFunctionTemplate())
+ D = FTD;
+ MoveDeclFromOldFileToNewFile(MoveTool, D);
+ }
+
+private:
+ ClangMoveTool *MoveTool;
+};
+
+class VarDeclarationMatch : public MatchFinder::MatchCallback {
+public:
+ explicit VarDeclarationMatch(ClangMoveTool *MoveTool)
+ : MoveTool(MoveTool) {}
+
+ void run(const MatchFinder::MatchResult &Result) override {
+ const auto *VD = Result.Nodes.getNodeAs<clang::VarDecl>("var");
+ assert(VD);
+ MoveDeclFromOldFileToNewFile(MoveTool, VD);
+ }
+
+private:
+ ClangMoveTool *MoveTool;
+};
+
+class TypeAliasMatch : public MatchFinder::MatchCallback {
+public:
+ explicit TypeAliasMatch(ClangMoveTool *MoveTool)
+ : MoveTool(MoveTool) {}
+
+ void run(const MatchFinder::MatchResult &Result) override {
+ if (const auto *TD = Result.Nodes.getNodeAs<clang::TypedefDecl>("typedef"))
+ MoveDeclFromOldFileToNewFile(MoveTool, TD);
+ else if (const auto *TAD =
+ Result.Nodes.getNodeAs<clang::TypeAliasDecl>("type_alias")) {
+ const NamedDecl * D = TAD;
+ if (const auto * TD = TAD->getDescribedAliasTemplate())
+ D = TD;
+ MoveDeclFromOldFileToNewFile(MoveTool, D);
+ }
+ }
+
+private:
+ ClangMoveTool *MoveTool;
+};
+
+class EnumDeclarationMatch : public MatchFinder::MatchCallback {
+public:
+ explicit EnumDeclarationMatch(ClangMoveTool *MoveTool)
+ : MoveTool(MoveTool) {}
+
+ void run(const MatchFinder::MatchResult &Result) override {
+ const auto *ED = Result.Nodes.getNodeAs<clang::EnumDecl>("enum");
+ assert(ED);
+ MoveDeclFromOldFileToNewFile(MoveTool, ED);
+ }
+
+private:
+ ClangMoveTool *MoveTool;
+};
+
+class ClassDeclarationMatch : public MatchFinder::MatchCallback {
+public:
+ explicit ClassDeclarationMatch(ClangMoveTool *MoveTool)
+ : MoveTool(MoveTool) {}
+ void run(const MatchFinder::MatchResult &Result) override {
+ clang::SourceManager* SM = &Result.Context->getSourceManager();
+ if (const auto *CMD =
+ Result.Nodes.getNodeAs<clang::CXXMethodDecl>("class_method"))
+ MatchClassMethod(CMD, SM);
+ else if (const auto *VD = Result.Nodes.getNodeAs<clang::VarDecl>(
+ "class_static_var_decl"))
+ MatchClassStaticVariable(VD, SM);
+ else if (const auto *CD = Result.Nodes.getNodeAs<clang::CXXRecordDecl>(
+ "moved_class"))
+ MatchClassDeclaration(CD, SM);
+ }
+
+private:
+ void MatchClassMethod(const clang::CXXMethodDecl* CMD,
+ clang::SourceManager* SM) {
+ // Skip inline class methods. isInline() ast matcher doesn't ignore this
+ // case.
+ if (!CMD->isInlined()) {
+ MoveTool->getMovedDecls().push_back(CMD);
+ MoveTool->addRemovedDecl(CMD);
+ // Get template class method from its method declaration as
+ // UnremovedDecls stores template class method.
+ if (const auto *FTD = CMD->getDescribedFunctionTemplate())
+ MoveTool->getUnremovedDeclsInOldHeader().erase(FTD);
+ else
+ MoveTool->getUnremovedDeclsInOldHeader().erase(CMD);
+ }
+ }
+
+ void MatchClassStaticVariable(const clang::NamedDecl *VD,
+ clang::SourceManager* SM) {
+ MoveDeclFromOldFileToNewFile(MoveTool, VD);
+ }
+
+ void MatchClassDeclaration(const clang::CXXRecordDecl *CD,
+ clang::SourceManager* SM) {
+ // Get class template from its class declaration as UnremovedDecls stores
+ // class template.
+ if (const auto *TC = CD->getDescribedClassTemplate())
+ MoveTool->getMovedDecls().push_back(TC);
+ else
+ MoveTool->getMovedDecls().push_back(CD);
+ MoveTool->addRemovedDecl(MoveTool->getMovedDecls().back());
+ MoveTool->getUnremovedDeclsInOldHeader().erase(
+ MoveTool->getMovedDecls().back());
+ }
+
+ ClangMoveTool *MoveTool;
+};
+
+// Expand to get the end location of the line where the EndLoc of the given
+// Decl.
+SourceLocation
+getLocForEndOfDecl(const clang::Decl *D,
+ const LangOptions &LangOpts = clang::LangOptions()) {
+ const auto &SM = D->getASTContext().getSourceManager();
+ // If the expansion range is a character range, this is the location of
+ // the first character past the end. Otherwise it's the location of the
+ // first character in the final token in the range.
+ auto EndExpansionLoc = SM.getExpansionRange(D->getLocEnd()).getEnd();
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(EndExpansionLoc);
+ // Try to load the file buffer.
+ bool InvalidTemp = false;
+ llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
+ if (InvalidTemp)
+ return SourceLocation();
+
+ const char *TokBegin = File.data() + LocInfo.second;
+ // Lex from the start of the given location.
+ Lexer Lex(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
+ TokBegin, File.end());
+
+ llvm::SmallVector<char, 16> Line;
+ // FIXME: this is a bit hacky to get ReadToEndOfLine work.
+ Lex.setParsingPreprocessorDirective(true);
+ Lex.ReadToEndOfLine(&Line);
+ SourceLocation EndLoc = EndExpansionLoc.getLocWithOffset(Line.size());
+ // If we already reach EOF, just return the EOF SourceLocation;
+ // otherwise, move 1 offset ahead to include the trailing newline character
+ // '\n'.
+ return SM.getLocForEndOfFile(LocInfo.first) == EndLoc
+ ? EndLoc
+ : EndLoc.getLocWithOffset(1);
+}
+
+// Get full range of a Decl including the comments associated with it.
+clang::CharSourceRange
+getFullRange(const clang::Decl *D,
+ const clang::LangOptions &options = clang::LangOptions()) {
+ const auto &SM = D->getASTContext().getSourceManager();
+ clang::SourceRange Full(SM.getExpansionLoc(D->getLocStart()),
+ getLocForEndOfDecl(D));
+ // Expand to comments that are associated with the Decl.
+ if (const auto *Comment = D->getASTContext().getRawCommentForDeclNoCache(D)) {
+ if (SM.isBeforeInTranslationUnit(Full.getEnd(), Comment->getLocEnd()))
+ Full.setEnd(Comment->getLocEnd());
+ // FIXME: Don't delete a preceding comment, if there are no other entities
+ // it could refer to.
+ if (SM.isBeforeInTranslationUnit(Comment->getLocStart(), Full.getBegin()))
+ Full.setBegin(Comment->getLocStart());
+ }
+
+ return clang::CharSourceRange::getCharRange(Full);
+}
+
+std::string getDeclarationSourceText(const clang::Decl *D) {
+ const auto &SM = D->getASTContext().getSourceManager();
+ llvm::StringRef SourceText =
+ clang::Lexer::getSourceText(getFullRange(D), SM, clang::LangOptions());
+ return SourceText.str();
+}
+
+bool isInHeaderFile(const clang::Decl *D,
+ llvm::StringRef OriginalRunningDirectory,
+ llvm::StringRef OldHeader) {
+ const auto &SM = D->getASTContext().getSourceManager();
+ if (OldHeader.empty())
+ return false;
+ auto ExpansionLoc = SM.getExpansionLoc(D->getLocStart());
+ if (ExpansionLoc.isInvalid())
+ return false;
+
+ if (const auto *FE = SM.getFileEntryForID(SM.getFileID(ExpansionLoc))) {
+ return MakeAbsolutePath(SM, FE->getName()) ==
+ MakeAbsolutePath(OriginalRunningDirectory, OldHeader);
+ }
+
+ return false;
+}
+
+std::vector<std::string> getNamespaces(const clang::Decl *D) {
+ std::vector<std::string> Namespaces;
+ for (const auto *Context = D->getDeclContext(); Context;
+ Context = Context->getParent()) {
+ if (llvm::isa<clang::TranslationUnitDecl>(Context) ||
+ llvm::isa<clang::LinkageSpecDecl>(Context))
+ break;
+
+ if (const auto *ND = llvm::dyn_cast<clang::NamespaceDecl>(Context))
+ Namespaces.push_back(ND->getName().str());
+ }
+ std::reverse(Namespaces.begin(), Namespaces.end());
+ return Namespaces;
+}
+
+clang::tooling::Replacements
+createInsertedReplacements(const std::vector<std::string> &Includes,
+ const std::vector<const NamedDecl *> &Decls,
+ llvm::StringRef FileName, bool IsHeader = false,
+ StringRef OldHeaderInclude = "") {
+ std::string NewCode;
+ std::string GuardName(FileName);
+ if (IsHeader) {
+ for (size_t i = 0; i < GuardName.size(); ++i) {
+ if (!isAlphanumeric(GuardName[i]))
+ GuardName[i] = '_';
+ }
+ GuardName = StringRef(GuardName).upper();
+ NewCode += "#ifndef " + GuardName + "\n";
+ NewCode += "#define " + GuardName + "\n\n";
+ }
+
+ NewCode += OldHeaderInclude;
+ // Add #Includes.
+ for (const auto &Include : Includes)
+ NewCode += Include;
+
+ if (!Includes.empty())
+ NewCode += "\n";
+
+ // Add moved class definition and its related declarations. All declarations
+ // in same namespace are grouped together.
+ //
+ // Record namespaces where the current position is in.
+ std::vector<std::string> CurrentNamespaces;
+ for (const auto *MovedDecl : Decls) {
+ // The namespaces of the declaration being moved.
+ std::vector<std::string> DeclNamespaces = getNamespaces(MovedDecl);
+ auto CurrentIt = CurrentNamespaces.begin();
+ auto DeclIt = DeclNamespaces.begin();
+ // Skip the common prefix.
+ while (CurrentIt != CurrentNamespaces.end() &&
+ DeclIt != DeclNamespaces.end()) {
+ if (*CurrentIt != *DeclIt)
+ break;
+ ++CurrentIt;
+ ++DeclIt;
+ }
+ // Calculate the new namespaces after adding MovedDecl in CurrentNamespace,
+ // which is used for next iteration of this loop.
+ std::vector<std::string> NextNamespaces(CurrentNamespaces.begin(),
+ CurrentIt);
+ NextNamespaces.insert(NextNamespaces.end(), DeclIt, DeclNamespaces.end());
+
+
+ // End with CurrentNamespace.
+ bool HasEndCurrentNamespace = false;
+ auto RemainingSize = CurrentNamespaces.end() - CurrentIt;
+ for (auto It = CurrentNamespaces.rbegin(); RemainingSize > 0;
+ --RemainingSize, ++It) {
+ assert(It < CurrentNamespaces.rend());
+ NewCode += "} // namespace " + *It + "\n";
+ HasEndCurrentNamespace = true;
+ }
+ // Add trailing '\n' after the nested namespace definition.
+ if (HasEndCurrentNamespace)
+ NewCode += "\n";
+
+ // If the moved declaration is not in CurrentNamespace, add extra namespace
+ // definitions.
+ bool IsInNewNamespace = false;
+ while (DeclIt != DeclNamespaces.end()) {
+ NewCode += "namespace " + *DeclIt + " {\n";
+ IsInNewNamespace = true;
+ ++DeclIt;
+ }
+ // If the moved declaration is in same namespace CurrentNamespace, add
+ // a preceeding `\n' before the moved declaration.
+ // FIXME: Don't add empty lines between using declarations.
+ if (!IsInNewNamespace)
+ NewCode += "\n";
+ NewCode += getDeclarationSourceText(MovedDecl);
+ CurrentNamespaces = std::move(NextNamespaces);
+ }
+ std::reverse(CurrentNamespaces.begin(), CurrentNamespaces.end());
+ for (const auto &NS : CurrentNamespaces)
+ NewCode += "} // namespace " + NS + "\n";
+
+ if (IsHeader)
+ NewCode += "\n#endif // " + GuardName + "\n";
+ return clang::tooling::Replacements(
+ clang::tooling::Replacement(FileName, 0, 0, NewCode));
+}
+
+// Return a set of all decls which are used/referenced by the given Decls.
+// Specically, given a class member declaration, this method will return all
+// decls which are used by the whole class.
+llvm::DenseSet<const Decl *>
+getUsedDecls(const HelperDeclRefGraph *RG,
+ const std::vector<const NamedDecl *> &Decls) {
+ assert(RG);
+ llvm::DenseSet<const CallGraphNode *> Nodes;
+ for (const auto *D : Decls) {
+ auto Result = RG->getReachableNodes(
+ HelperDeclRGBuilder::getOutmostClassOrFunDecl(D));
+ Nodes.insert(Result.begin(), Result.end());
+ }
+ llvm::DenseSet<const Decl *> Results;
+ for (const auto *Node : Nodes)
+ Results.insert(Node->getDecl());
+ return Results;
+}
+
+} // namespace
+
+std::unique_ptr<clang::ASTConsumer>
+ClangMoveAction::CreateASTConsumer(clang::CompilerInstance &Compiler,
+ StringRef /*InFile*/) {
+ Compiler.getPreprocessor().addPPCallbacks(llvm::make_unique<FindAllIncludes>(
+ &Compiler.getSourceManager(), &MoveTool));
+ return MatchFinder.newASTConsumer();
+}
+
+ClangMoveTool::ClangMoveTool(ClangMoveContext *const Context,
+ DeclarationReporter *const Reporter)
+ : Context(Context), Reporter(Reporter) {
+ if (!Context->Spec.NewHeader.empty())
+ CCIncludes.push_back("#include \"" + Context->Spec.NewHeader + "\"\n");
+}
+
+void ClangMoveTool::addRemovedDecl(const NamedDecl *Decl) {
+ const auto &SM = Decl->getASTContext().getSourceManager();
+ auto Loc = Decl->getLocation();
+ StringRef FilePath = SM.getFilename(Loc);
+ FilePathToFileID[FilePath] = SM.getFileID(Loc);
+ RemovedDecls.push_back(Decl);
+}
+
+void ClangMoveTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
+ auto InOldHeader =
+ isExpansionInFile(makeAbsolutePath(Context->Spec.OldHeader));
+ auto InOldCC = isExpansionInFile(makeAbsolutePath(Context->Spec.OldCC));
+ auto InOldFiles = anyOf(InOldHeader, InOldCC);
+ auto classTemplateForwardDecls =
+ classTemplateDecl(unless(has(cxxRecordDecl(isDefinition()))));
+ auto ForwardClassDecls = namedDecl(
+ anyOf(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition()))),
+ classTemplateForwardDecls));
+ auto TopLevelDecl =
+ hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()));
+
+ //============================================================================
+ // Matchers for old header
+ //============================================================================
+ // Match all top-level named declarations (e.g. function, variable, enum) in
+ // old header, exclude forward class declarations and namespace declarations.
+ //
+ // We consider declarations inside a class belongs to the class. So these
+ // declarations will be ignored.
+ auto AllDeclsInHeader = namedDecl(
+ unless(ForwardClassDecls), unless(namespaceDecl()),
+ unless(usingDirectiveDecl()), // using namespace decl.
+ notInMacro(),
+ InOldHeader,
+ hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))),
+ hasDeclContext(decl(anyOf(namespaceDecl(), translationUnitDecl()))));
+ Finder->addMatcher(AllDeclsInHeader.bind("decls_in_header"), this);
+
+ // Don't register other matchers when dumping all declarations in header.
+ if (Context->DumpDeclarations)
+ return;
+
+ // Match forward declarations in old header.
+ Finder->addMatcher(namedDecl(ForwardClassDecls, InOldHeader).bind("fwd_decl"),
+ this);
+
+ //============================================================================
+ // Matchers for old cc
+ //============================================================================
+ auto IsOldCCTopLevelDecl = allOf(
+ hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))), InOldCC);
+ // Matching using decls/type alias decls which are in named/anonymous/global
+ // namespace, these decls are always copied to new.h/cc. Those in classes,
+ // functions are covered in other matchers.
+ Finder->addMatcher(namedDecl(anyOf(usingDecl(IsOldCCTopLevelDecl),
+ usingDirectiveDecl(IsOldCCTopLevelDecl),
+ typeAliasDecl(IsOldCCTopLevelDecl)),
+ notInMacro())
+ .bind("using_decl"),
+ this);
+
+ // Match static functions/variable definitions which are defined in named
+ // namespaces.
+ Optional<ast_matchers::internal::Matcher<NamedDecl>> HasAnySymbolNames;
+ for (StringRef SymbolName : Context->Spec.Names) {
+ llvm::StringRef GlobalSymbolName = SymbolName.trim().ltrim(':');
+ const auto HasName = hasName(("::" + GlobalSymbolName).str());
+ HasAnySymbolNames =
+ HasAnySymbolNames ? anyOf(*HasAnySymbolNames, HasName) : HasName;
+ }
+
+ if (!HasAnySymbolNames) {
+ llvm::errs() << "No symbols being moved.\n";
+ return;
+ }
+ auto InMovedClass =
+ hasOutermostEnclosingClass(cxxRecordDecl(*HasAnySymbolNames));
+
+ // Matchers for helper declarations in old.cc.
+ auto InAnonymousNS = hasParent(namespaceDecl(isAnonymous()));
+ auto NotInMovedClass= allOf(unless(InMovedClass), InOldCC);
+ auto IsOldCCHelper =
+ allOf(NotInMovedClass, anyOf(isStaticStorageClass(), InAnonymousNS));
+ // Match helper classes separately with helper functions/variables since we
+ // want to reuse these matchers in finding helpers usage below.
+ //
+ // There could be forward declarations usage for helpers, especially for
+ // classes and functions. We need include these forward declarations.
+ //
+ // Forward declarations for variable helpers will be excluded as these
+ // declarations (with "extern") are not supposed in cpp file.
+ auto HelperFuncOrVar =
+ namedDecl(notInMacro(), anyOf(functionDecl(IsOldCCHelper),
+ varDecl(isDefinition(), IsOldCCHelper)));
+ auto HelperClasses =
+ cxxRecordDecl(notInMacro(), NotInMovedClass, InAnonymousNS);
+ // Save all helper declarations in old.cc.
+ Finder->addMatcher(
+ namedDecl(anyOf(HelperFuncOrVar, HelperClasses)).bind("helper_decls"),
+ this);
+
+ // Construct an AST-based call graph of helper declarations in old.cc.
+ // In the following matcheres, "dc" is a caller while "helper_decls" and
+ // "used_class" is a callee, so a new edge starting from caller to callee will
+ // be add in the graph.
+ //
+ // Find helper function/variable usages.
+ Finder->addMatcher(
+ declRefExpr(to(HelperFuncOrVar), hasAncestor(decl().bind("dc")))
+ .bind("func_ref"),
+ &RGBuilder);
+ // Find helper class usages.
+ Finder->addMatcher(
+ typeLoc(loc(recordType(hasDeclaration(HelperClasses.bind("used_class")))),
+ hasAncestor(decl().bind("dc"))),
+ &RGBuilder);
+
+ //============================================================================
+ // Matchers for old files, including old.h/old.cc
+ //============================================================================
+ // Create a MatchCallback for class declarations.
+ MatchCallbacks.push_back(llvm::make_unique<ClassDeclarationMatch>(this));
+ // Match moved class declarations.
+ auto MovedClass = cxxRecordDecl(InOldFiles, *HasAnySymbolNames,
+ isDefinition(), TopLevelDecl)
+ .bind("moved_class");
+ Finder->addMatcher(MovedClass, MatchCallbacks.back().get());
+ // Match moved class methods (static methods included) which are defined
+ // outside moved class declaration.
+ Finder->addMatcher(
+ cxxMethodDecl(InOldFiles, ofOutermostEnclosingClass(*HasAnySymbolNames),
+ isDefinition())
+ .bind("class_method"),
+ MatchCallbacks.back().get());
+ // Match static member variable definition of the moved class.
+ Finder->addMatcher(
+ varDecl(InMovedClass, InOldFiles, isDefinition(), isStaticDataMember())
+ .bind("class_static_var_decl"),
+ MatchCallbacks.back().get());
+
+ MatchCallbacks.push_back(llvm::make_unique<FunctionDeclarationMatch>(this));
+ Finder->addMatcher(functionDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl)
+ .bind("function"),
+ MatchCallbacks.back().get());
+
+ MatchCallbacks.push_back(llvm::make_unique<VarDeclarationMatch>(this));
+ Finder->addMatcher(
+ varDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl).bind("var"),
+ MatchCallbacks.back().get());
+
+ // Match enum definition in old.h. Enum helpers (which are defined in old.cc)
+ // will not be moved for now no matter whether they are used or not.
+ MatchCallbacks.push_back(llvm::make_unique<EnumDeclarationMatch>(this));
+ Finder->addMatcher(
+ enumDecl(InOldHeader, *HasAnySymbolNames, isDefinition(), TopLevelDecl)
+ .bind("enum"),
+ MatchCallbacks.back().get());
+
+ // Match type alias in old.h, this includes "typedef" and "using" type alias
+ // declarations. Type alias helpers (which are defined in old.cc) will not be
+ // moved for now no matter whether they are used or not.
+ MatchCallbacks.push_back(llvm::make_unique<TypeAliasMatch>(this));
+ Finder->addMatcher(namedDecl(anyOf(typedefDecl().bind("typedef"),
+ typeAliasDecl().bind("type_alias")),
+ InOldHeader, *HasAnySymbolNames, TopLevelDecl),
+ MatchCallbacks.back().get());
+}
+
+void ClangMoveTool::run(const ast_matchers::MatchFinder::MatchResult &Result) {
+ if (const auto *D =
+ Result.Nodes.getNodeAs<clang::NamedDecl>("decls_in_header")) {
+ UnremovedDeclsInOldHeader.insert(D);
+ } else if (const auto *FWD =
+ Result.Nodes.getNodeAs<clang::CXXRecordDecl>("fwd_decl")) {
+ // Skip all forward declarations which appear after moved class declaration.
+ if (RemovedDecls.empty()) {
+ if (const auto *DCT = FWD->getDescribedClassTemplate())
+ MovedDecls.push_back(DCT);
+ else
+ MovedDecls.push_back(FWD);
+ }
+ } else if (const auto *ND =
+ Result.Nodes.getNodeAs<clang::NamedDecl>("helper_decls")) {
+ MovedDecls.push_back(ND);
+ HelperDeclarations.push_back(ND);
+ LLVM_DEBUG(llvm::dbgs() << "Add helper : " << ND->getNameAsString() << " ("
+ << ND << ")\n");
+ } else if (const auto *UD =
+ Result.Nodes.getNodeAs<clang::NamedDecl>("using_decl")) {
+ MovedDecls.push_back(UD);
+ }
+}
+
+std::string ClangMoveTool::makeAbsolutePath(StringRef Path) {
+ return MakeAbsolutePath(Context->OriginalRunningDirectory, Path);
+}
+
+void ClangMoveTool::addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
+ llvm::StringRef SearchPath,
+ llvm::StringRef FileName,
+ clang::CharSourceRange IncludeFilenameRange,
+ const SourceManager &SM) {
+ SmallVector<char, 128> HeaderWithSearchPath;
+ llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
+ std::string AbsoluteIncludeHeader =
+ MakeAbsolutePath(SM, llvm::StringRef(HeaderWithSearchPath.data(),
+ HeaderWithSearchPath.size()));
+ std::string IncludeLine =
+ IsAngled ? ("#include <" + IncludeHeader + ">\n").str()
+ : ("#include \"" + IncludeHeader + "\"\n").str();
+
+ std::string AbsoluteOldHeader = makeAbsolutePath(Context->Spec.OldHeader);
+ std::string AbsoluteCurrentFile = MakeAbsolutePath(SM, FileName);
+ if (AbsoluteOldHeader == AbsoluteCurrentFile) {
+ // Find old.h includes "old.h".
+ if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
+ OldHeaderIncludeRangeInHeader = IncludeFilenameRange;
+ return;
+ }
+ HeaderIncludes.push_back(IncludeLine);
+ } else if (makeAbsolutePath(Context->Spec.OldCC) == AbsoluteCurrentFile) {
+ // Find old.cc includes "old.h".
+ if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
+ OldHeaderIncludeRangeInCC = IncludeFilenameRange;
+ return;
+ }
+ CCIncludes.push_back(IncludeLine);
+ }
+}
+
+void ClangMoveTool::removeDeclsInOldFiles() {
+ if (RemovedDecls.empty()) return;
+
+ // If old_header is not specified (only move declarations from old.cc), remain
+ // all the helper function declarations in old.cc as UnremovedDeclsInOldHeader
+ // is empty in this case, there is no way to verify unused/used helpers.
+ if (!Context->Spec.OldHeader.empty()) {
+ std::vector<const NamedDecl *> UnremovedDecls;
+ for (const auto *D : UnremovedDeclsInOldHeader)
+ UnremovedDecls.push_back(D);
+
+ auto UsedDecls = getUsedDecls(RGBuilder.getGraph(), UnremovedDecls);
+
+ // We remove the helper declarations which are not used in the old.cc after
+ // moving the given declarations.
+ for (const auto *D : HelperDeclarations) {
+ LLVM_DEBUG(llvm::dbgs() << "Check helper is used: "
+ << D->getNameAsString() << " (" << D << ")\n");
+ if (!UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(
+ D->getCanonicalDecl()))) {
+ LLVM_DEBUG(llvm::dbgs() << "Helper removed in old.cc: "
+ << D->getNameAsString() << " (" << D << ")\n");
+ RemovedDecls.push_back(D);
+ }
+ }
+ }
+
+ for (const auto *RemovedDecl : RemovedDecls) {
+ const auto &SM = RemovedDecl->getASTContext().getSourceManager();
+ auto Range = getFullRange(RemovedDecl);
+ clang::tooling::Replacement RemoveReplacement(
+ SM,
+ clang::CharSourceRange::getCharRange(Range.getBegin(), Range.getEnd()),
+ "");
+ std::string FilePath = RemoveReplacement.getFilePath().str();
+ auto Err = Context->FileToReplacements[FilePath].add(RemoveReplacement);
+ if (Err)
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ }
+ const auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
+
+ // Post process of cleanup around all the replacements.
+ for (auto &FileAndReplacements : Context->FileToReplacements) {
+ StringRef FilePath = FileAndReplacements.first;
+ // Add #include of new header to old header.
+ if (Context->Spec.OldDependOnNew &&
+ MakeAbsolutePath(SM, FilePath) ==
+ makeAbsolutePath(Context->Spec.OldHeader)) {
+ // FIXME: Minimize the include path like include-fixer.
+ std::string IncludeNewH =
+ "#include \"" + Context->Spec.NewHeader + "\"\n";
+ // This replacment for inserting header will be cleaned up at the end.
+ auto Err = FileAndReplacements.second.add(
+ tooling::Replacement(FilePath, UINT_MAX, 0, IncludeNewH));
+ if (Err)
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ }
+
+ auto SI = FilePathToFileID.find(FilePath);
+ // Ignore replacements for new.h/cc.
+ if (SI == FilePathToFileID.end()) continue;
+ llvm::StringRef Code = SM.getBufferData(SI->second);
+ auto Style = format::getStyle("file", FilePath, Context->FallbackStyle);
+ if (!Style) {
+ llvm::errs() << llvm::toString(Style.takeError()) << "\n";
+ continue;
+ }
+ auto CleanReplacements = format::cleanupAroundReplacements(
+ Code, Context->FileToReplacements[FilePath], *Style);
+
+ if (!CleanReplacements) {
+ llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
+ continue;
+ }
+ Context->FileToReplacements[FilePath] = *CleanReplacements;
+ }
+}
+
+void ClangMoveTool::moveDeclsToNewFiles() {
+ std::vector<const NamedDecl *> NewHeaderDecls;
+ std::vector<const NamedDecl *> NewCCDecls;
+ for (const auto *MovedDecl : MovedDecls) {
+ if (isInHeaderFile(MovedDecl, Context->OriginalRunningDirectory,
+ Context->Spec.OldHeader))
+ NewHeaderDecls.push_back(MovedDecl);
+ else
+ NewCCDecls.push_back(MovedDecl);
+ }
+
+ auto UsedDecls = getUsedDecls(RGBuilder.getGraph(), RemovedDecls);
+ std::vector<const NamedDecl *> ActualNewCCDecls;
+
+ // Filter out all unused helpers in NewCCDecls.
+ // We only move the used helpers (including transively used helpers) and the
+ // given symbols being moved.
+ for (const auto *D : NewCCDecls) {
+ if (llvm::is_contained(HelperDeclarations, D) &&
+ !UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(
+ D->getCanonicalDecl())))
+ continue;
+
+ LLVM_DEBUG(llvm::dbgs() << "Helper used in new.cc: " << D->getNameAsString()
+ << " " << D << "\n");
+ ActualNewCCDecls.push_back(D);
+ }
+
+ if (!Context->Spec.NewHeader.empty()) {
+ std::string OldHeaderInclude =
+ Context->Spec.NewDependOnOld
+ ? "#include \"" + Context->Spec.OldHeader + "\"\n"
+ : "";
+ Context->FileToReplacements[Context->Spec.NewHeader] =
+ createInsertedReplacements(HeaderIncludes, NewHeaderDecls,
+ Context->Spec.NewHeader, /*IsHeader=*/true,
+ OldHeaderInclude);
+ }
+ if (!Context->Spec.NewCC.empty())
+ Context->FileToReplacements[Context->Spec.NewCC] =
+ createInsertedReplacements(CCIncludes, ActualNewCCDecls,
+ Context->Spec.NewCC);
+}
+
+// Move all contents from OldFile to NewFile.
+void ClangMoveTool::moveAll(SourceManager &SM, StringRef OldFile,
+ StringRef NewFile) {
+ const FileEntry *FE = SM.getFileManager().getFile(makeAbsolutePath(OldFile));
+ if (!FE) {
+ llvm::errs() << "Failed to get file: " << OldFile << "\n";
+ return;
+ }
+ FileID ID = SM.getOrCreateFileID(FE, SrcMgr::C_User);
+ auto Begin = SM.getLocForStartOfFile(ID);
+ auto End = SM.getLocForEndOfFile(ID);
+ clang::tooling::Replacement RemoveAll (
+ SM, clang::CharSourceRange::getCharRange(Begin, End), "");
+ std::string FilePath = RemoveAll.getFilePath().str();
+ Context->FileToReplacements[FilePath] =
+ clang::tooling::Replacements(RemoveAll);
+
+ StringRef Code = SM.getBufferData(ID);
+ if (!NewFile.empty()) {
+ auto AllCode = clang::tooling::Replacements(
+ clang::tooling::Replacement(NewFile, 0, 0, Code));
+ auto ReplaceOldInclude = [&](clang::CharSourceRange OldHeaderIncludeRange) {
+ AllCode = AllCode.merge(clang::tooling::Replacements(
+ clang::tooling::Replacement(SM, OldHeaderIncludeRange,
+ '"' + Context->Spec.NewHeader + '"')));
+ };
+ // Fix the case where old.h/old.cc includes "old.h", we replace the
+ // `#include "old.h"` with `#include "new.h"`.
+ if (Context->Spec.NewCC == NewFile && OldHeaderIncludeRangeInCC.isValid())
+ ReplaceOldInclude(OldHeaderIncludeRangeInCC);
+ else if (Context->Spec.NewHeader == NewFile &&
+ OldHeaderIncludeRangeInHeader.isValid())
+ ReplaceOldInclude(OldHeaderIncludeRangeInHeader);
+ Context->FileToReplacements[NewFile] = std::move(AllCode);
+ }
+}
+
+void ClangMoveTool::onEndOfTranslationUnit() {
+ if (Context->DumpDeclarations) {
+ assert(Reporter);
+ for (const auto *Decl : UnremovedDeclsInOldHeader) {
+ auto Kind = Decl->getKind();
+ const std::string QualifiedName = Decl->getQualifiedNameAsString();
+ if (Kind == Decl::Kind::Var)
+ Reporter->reportDeclaration(QualifiedName, "Variable");
+ else if (Kind == Decl::Kind::Function ||
+ Kind == Decl::Kind::FunctionTemplate)
+ Reporter->reportDeclaration(QualifiedName, "Function");
+ else if (Kind == Decl::Kind::ClassTemplate ||
+ Kind == Decl::Kind::CXXRecord)
+ Reporter->reportDeclaration(QualifiedName, "Class");
+ else if (Kind == Decl::Kind::Enum)
+ Reporter->reportDeclaration(QualifiedName, "Enum");
+ else if (Kind == Decl::Kind::Typedef ||
+ Kind == Decl::Kind::TypeAlias ||
+ Kind == Decl::Kind::TypeAliasTemplate)
+ Reporter->reportDeclaration(QualifiedName, "TypeAlias");
+ }
+ return;
+ }
+
+ if (RemovedDecls.empty())
+ return;
+ // Ignore symbols that are not supported when checking if there is unremoved
+ // symbol in old header. This makes sure that we always move old files to new
+ // files when all symbols produced from dump_decls are moved.
+ auto IsSupportedKind = [](const clang::NamedDecl *Decl) {
+ switch (Decl->getKind()) {
+ case Decl::Kind::Function:
+ case Decl::Kind::FunctionTemplate:
+ case Decl::Kind::ClassTemplate:
+ case Decl::Kind::CXXRecord:
+ case Decl::Kind::Enum:
+ case Decl::Kind::Typedef:
+ case Decl::Kind::TypeAlias:
+ case Decl::Kind::TypeAliasTemplate:
+ case Decl::Kind::Var:
+ return true;
+ default:
+ return false;
+ }
+ };
+ if (std::none_of(UnremovedDeclsInOldHeader.begin(),
+ UnremovedDeclsInOldHeader.end(), IsSupportedKind) &&
+ !Context->Spec.OldHeader.empty()) {
+ auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
+ moveAll(SM, Context->Spec.OldHeader, Context->Spec.NewHeader);
+ moveAll(SM, Context->Spec.OldCC, Context->Spec.NewCC);
+ return;
+ }
+ LLVM_DEBUG(RGBuilder.getGraph()->dump());
+ moveDeclsToNewFiles();
+ removeDeclsInOldFiles();
+}
+
+} // namespace move
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-move/ClangMove.h b/src/third_party/llvm-project/clang-tools-extra/clang-move/ClangMove.h
new file mode 100644
index 0000000..945c6db
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-move/ClangMove.h
@@ -0,0 +1,233 @@
+//===-- ClangMove.h - Clang move -----------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
+
+#include "HelperDeclRefGraph.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringMap.h"
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace move {
+
+// A reporter which collects and reports declarations in old header.
+class DeclarationReporter {
+public:
+ DeclarationReporter() = default;
+ ~DeclarationReporter() = default;
+
+ void reportDeclaration(llvm::StringRef DeclarationName,
+ llvm::StringRef Type) {
+ DeclarationList.emplace_back(DeclarationName, Type);
+ };
+
+ // A <DeclarationName, DeclarationKind> pair.
+ // The DeclarationName is a fully qualified name for the declaration, like
+ // A::B::Foo. The DeclarationKind is a string represents the kind of the
+ // declaration, currently only "Function" and "Class" are supported.
+ typedef std::pair<std::string, std::string> DeclarationPair;
+
+ const std::vector<DeclarationPair> getDeclarationList() const {
+ return DeclarationList;
+ }
+
+private:
+ std::vector<DeclarationPair> DeclarationList;
+};
+
+// Specify declarations being moved. It contains all information of the moved
+// declarations.
+struct MoveDefinitionSpec {
+ // The list of fully qualified names, e.g. Foo, a::Foo, b::Foo.
+ SmallVector<std::string, 4> Names;
+ // The file path of old header, can be relative path and absolute path.
+ std::string OldHeader;
+ // The file path of old cc, can be relative path and absolute path.
+ std::string OldCC;
+ // The file path of new header, can be relative path and absolute path.
+ std::string NewHeader;
+ // The file path of new cc, can be relative path and absolute path.
+ std::string NewCC;
+ // Whether old.h depends on new.h. If true, #include "new.h" will be added
+ // in old.h.
+ bool OldDependOnNew = false;
+ // Whether new.h depends on old.h. If true, #include "old.h" will be added
+ // in new.h.
+ bool NewDependOnOld = false;
+};
+
+// A Context which contains extra options which are used in ClangMoveTool.
+struct ClangMoveContext {
+ MoveDefinitionSpec Spec;
+ // The Key is file path, value is the replacements being applied to the file.
+ std::map<std::string, tooling::Replacements> &FileToReplacements;
+ // The original working directory where the local clang-move binary runs.
+ //
+ // clang-move will change its current working directory to the build
+ // directory when analyzing the source file. We save the original working
+ // directory in order to get the absolute file path for the fields in Spec.
+ std::string OriginalRunningDirectory;
+ // The name of a predefined code style.
+ std::string FallbackStyle;
+ // Whether dump all declarations in old header.
+ bool DumpDeclarations;
+};
+
+// This tool is used to move class/function definitions from the given source
+// files (old.h/cc) to new files (new.h/cc).
+// The goal of this tool is to make the new/old files as compilable as possible.
+//
+// When moving a symbol,all used helper declarations (e.g. static
+// functions/variables definitions in global/named namespace,
+// functions/variables/classes definitions in anonymous namespace) used by the
+// moved symbol in old.cc are moved to the new.cc. In addition, all
+// using-declarations in old.cc are also moved to new.cc; forward class
+// declarations in old.h are also moved to new.h.
+//
+// The remaining helper declarations which are unused by non-moved symbols in
+// old.cc will be removed.
+//
+// Note: When all declarations in old header are being moved, all code in
+// old.h/cc will be moved, which means old.h/cc are empty. This ignores symbols
+// that are not supported (e.g. typedef and enum) so that we always move old
+// files to new files when all symbols produced from dump_decls are moved.
+class ClangMoveTool : public ast_matchers::MatchFinder::MatchCallback {
+public:
+ ClangMoveTool(ClangMoveContext *const Context,
+ DeclarationReporter *const Reporter);
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder);
+
+ void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+ void onEndOfTranslationUnit() override;
+
+ /// Add #includes from old.h/cc files.
+ ///
+ /// \param IncludeHeader The name of the file being included, as written in
+ /// the source code.
+ /// \param IsAngled Whether the file name was enclosed in angle brackets.
+ /// \param SearchPath The search path which was used to find the IncludeHeader
+ /// in the file system. It can be a relative path or an absolute path.
+ /// \param FileName The name of file where the IncludeHeader comes from.
+ /// \param IncludeFilenameRange The source range for the written file name in
+ /// #include (i.e. "old.h" for #include "old.h") in old.cc.
+ /// \param SM The SourceManager.
+ void addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
+ llvm::StringRef SearchPath, llvm::StringRef FileName,
+ clang::CharSourceRange IncludeFilenameRange,
+ const SourceManager &SM);
+
+ std::vector<const NamedDecl *> &getMovedDecls() { return MovedDecls; }
+
+ /// Add declarations being removed from old.h/cc. For each declarations, the
+ /// method also records the mapping relationship between the corresponding
+ /// FilePath and its FileID.
+ void addRemovedDecl(const NamedDecl *Decl);
+
+ llvm::SmallPtrSet<const NamedDecl *, 8> &getUnremovedDeclsInOldHeader() {
+ return UnremovedDeclsInOldHeader;
+ }
+
+private:
+ // Make the Path absolute using the OrignalRunningDirectory if the Path is not
+ // an absolute path. An empty Path will result in an empty string.
+ std::string makeAbsolutePath(StringRef Path);
+
+ void removeDeclsInOldFiles();
+ void moveDeclsToNewFiles();
+ void moveAll(SourceManager& SM, StringRef OldFile, StringRef NewFile);
+
+ // Stores all MatchCallbacks created by this tool.
+ std::vector<std::unique_ptr<ast_matchers::MatchFinder::MatchCallback>>
+ MatchCallbacks;
+ // Store all potential declarations (decls being moved, forward decls) that
+ // might need to move to new.h/cc. It includes all helper declarations
+ // (include unused ones) by default. The unused ones will be filtered out in
+ // the last stage. Saving in an AST-visited order.
+ std::vector<const NamedDecl *> MovedDecls;
+ // The declarations that needs to be removed in old.cc/h.
+ std::vector<const NamedDecl *> RemovedDecls;
+ // The #includes in old_header.h.
+ std::vector<std::string> HeaderIncludes;
+ // The #includes in old_cc.cc.
+ std::vector<std::string> CCIncludes;
+ // Records all helper declarations (function/variable/class definitions in
+ // anonymous namespaces, static function/variable definitions in global/named
+ // namespaces) in old.cc. saving in an AST-visited order.
+ std::vector<const NamedDecl *> HelperDeclarations;
+ // The unmoved named declarations in old header.
+ llvm::SmallPtrSet<const NamedDecl*, 8> UnremovedDeclsInOldHeader;
+ /// The source range for the written file name in #include (i.e. "old.h" for
+ /// #include "old.h") in old.cc, including the enclosing quotes or angle
+ /// brackets.
+ clang::CharSourceRange OldHeaderIncludeRangeInCC;
+ /// The source range for the written file name in #include (i.e. "old.h" for
+ /// #include "old.h") in old.h, including the enclosing quotes or angle
+ /// brackets.
+ clang::CharSourceRange OldHeaderIncludeRangeInHeader;
+ /// Mapping from FilePath to FileID, which can be used in post processes like
+ /// cleanup around replacements.
+ llvm::StringMap<FileID> FilePathToFileID;
+ /// A context contains all running options. It is not owned.
+ ClangMoveContext *const Context;
+ /// A reporter to report all declarations from old header. It is not owned.
+ DeclarationReporter *const Reporter;
+ /// Builder for helper declarations reference graph.
+ HelperDeclRGBuilder RGBuilder;
+};
+
+class ClangMoveAction : public clang::ASTFrontendAction {
+public:
+ ClangMoveAction(ClangMoveContext *const Context,
+ DeclarationReporter *const Reporter)
+ : MoveTool(Context, Reporter) {
+ MoveTool.registerMatchers(&MatchFinder);
+ }
+
+ ~ClangMoveAction() override = default;
+
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &Compiler,
+ llvm::StringRef InFile) override;
+
+private:
+ ast_matchers::MatchFinder MatchFinder;
+ ClangMoveTool MoveTool;
+};
+
+class ClangMoveActionFactory : public tooling::FrontendActionFactory {
+public:
+ ClangMoveActionFactory(ClangMoveContext *const Context,
+ DeclarationReporter *const Reporter = nullptr)
+ : Context(Context), Reporter(Reporter) {}
+
+ clang::FrontendAction *create() override {
+ return new ClangMoveAction(Context, Reporter);
+ }
+
+private:
+ // Not owned.
+ ClangMoveContext *const Context;
+ DeclarationReporter *const Reporter;
+};
+
+} // namespace move
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp
new file mode 100644
index 0000000..28200e0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp
@@ -0,0 +1,137 @@
+//===-- UsedHelperDeclFinder.cpp - AST-based call graph for helper decls --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HelperDeclRefGraph.h"
+#include "ClangMove.h"
+#include "clang/AST/Decl.h"
+#include "llvm/Support/Debug.h"
+#include <vector>
+
+#define DEBUG_TYPE "clang-move"
+
+namespace clang {
+namespace move {
+
+void HelperDeclRefGraph::print(raw_ostream &OS) const {
+ OS << " --- Call graph Dump --- \n";
+ for (auto I = DeclMap.begin(); I != DeclMap.end(); ++I) {
+ const CallGraphNode *N = (I->second).get();
+
+ OS << " Declarations: ";
+ N->print(OS);
+ OS << " (" << N << ") ";
+ OS << " calls: ";
+ for (auto CI = N->begin(), CE = N->end(); CI != CE; ++CI) {
+ (*CI)->print(OS);
+ OS << " (" << CI << ") ";
+ }
+ OS << '\n';
+ }
+ OS.flush();
+}
+
+void HelperDeclRefGraph::addEdge(const Decl *Caller, const Decl *Callee) {
+ assert(Caller);
+ assert(Callee);
+
+ // Ignore the case where Caller equals Callee. This happens in the static
+ // class member definitions in global namespace like "int CLASS::static_var =
+ // 1;", its DC is a VarDel whose outmost enclosing declaration is the "CLASS"
+ // CXXRecordDecl.
+ if (Caller == Callee) return;
+
+ // Allocate a new node, mark it as root, and process it's calls.
+ CallGraphNode *CallerNode = getOrInsertNode(const_cast<Decl *>(Caller));
+ CallGraphNode *CalleeNode = getOrInsertNode(const_cast<Decl *>(Callee));
+ CallerNode->addCallee(CalleeNode);
+}
+
+void HelperDeclRefGraph::dump() const { print(llvm::errs()); }
+
+CallGraphNode *HelperDeclRefGraph::getOrInsertNode(Decl *F) {
+ F = F->getCanonicalDecl();
+ std::unique_ptr<CallGraphNode> &Node = DeclMap[F];
+ if (Node)
+ return Node.get();
+
+ Node = llvm::make_unique<CallGraphNode>(F);
+ return Node.get();
+}
+
+CallGraphNode *HelperDeclRefGraph::getNode(const Decl *D) const {
+ auto I = DeclMap.find(D->getCanonicalDecl());
+ return I == DeclMap.end() ? nullptr : I->second.get();
+}
+
+llvm::DenseSet<const CallGraphNode *>
+HelperDeclRefGraph::getReachableNodes(const Decl *Root) const {
+ const auto *RootNode = getNode(Root);
+ if (!RootNode)
+ return {};
+ llvm::DenseSet<const CallGraphNode *> ConnectedNodes;
+ std::function<void(const CallGraphNode *)> VisitNode =
+ [&](const CallGraphNode *Node) {
+ if (ConnectedNodes.count(Node))
+ return;
+ ConnectedNodes.insert(Node);
+ for (auto It = Node->begin(), End = Node->end(); It != End; ++It)
+ VisitNode(*It);
+ };
+
+ VisitNode(RootNode);
+ return ConnectedNodes;
+}
+
+const Decl *HelperDeclRGBuilder::getOutmostClassOrFunDecl(const Decl *D) {
+ const auto *DC = D->getDeclContext();
+ const auto *Result = D;
+ while (DC) {
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))
+ Result = RD;
+ else if (const auto *FD = dyn_cast<FunctionDecl>(DC))
+ Result = FD;
+ DC = DC->getParent();
+ }
+ return Result;
+}
+
+void HelperDeclRGBuilder::run(
+ const ast_matchers::MatchFinder::MatchResult &Result) {
+ // Construct the graph by adding a directed edge from caller to callee.
+ //
+ // "dc" is the closest ancestor declaration of "func_ref" or "used_class", it
+ // might be not the targetted Caller Decl, we always use the outmost enclosing
+ // FunctionDecl/CXXRecordDecl of "dc". For example,
+ //
+ // int MoveClass::F() { int a = helper(); return a; }
+ //
+ // The matched "dc" of "helper" DeclRefExpr is a VarDecl, we traverse up AST
+ // to find the outmost "MoveClass" CXXRecordDecl and use it as Caller.
+ if (const auto *FuncRef = Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
+ const auto *DC = Result.Nodes.getNodeAs<Decl>("dc");
+ assert(DC);
+ LLVM_DEBUG(llvm::dbgs() << "Find helper function usage: "
+ << FuncRef->getDecl()->getNameAsString() << " ("
+ << FuncRef->getDecl() << ")\n");
+ RG->addEdge(
+ getOutmostClassOrFunDecl(DC->getCanonicalDecl()),
+ getOutmostClassOrFunDecl(FuncRef->getDecl()->getCanonicalDecl()));
+ } else if (const auto *UsedClass =
+ Result.Nodes.getNodeAs<CXXRecordDecl>("used_class")) {
+ const auto *DC = Result.Nodes.getNodeAs<Decl>("dc");
+ assert(DC);
+ LLVM_DEBUG(llvm::dbgs()
+ << "Find helper class usage: " << UsedClass->getNameAsString()
+ << " (" << UsedClass << ")\n");
+ RG->addEdge(getOutmostClassOrFunDecl(DC->getCanonicalDecl()), UsedClass);
+ }
+}
+
+} // namespace move
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-move/HelperDeclRefGraph.h b/src/third_party/llvm-project/clang-tools-extra/clang-move/HelperDeclRefGraph.h
new file mode 100644
index 0000000..11b3c9c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-move/HelperDeclRefGraph.h
@@ -0,0 +1,99 @@
+//===-- UsedHelperDeclFinder.h - AST-based call graph for helper decls ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_USED_HELPER_DECL_FINDER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_USED_HELPER_DECL_FINDER_H
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Analysis/CallGraph.h"
+#include "llvm/ADT/DenseSet.h"
+#include <memory>
+#include <vector>
+
+namespace clang {
+namespace move {
+
+// A reference graph for finding used/unused helper declarations in a single
+// translation unit (e.g. old.cc). We don't reuse CallGraph in clang/Analysis
+// because that CallGraph only supports function declarations.
+//
+// Helper declarations include following types:
+// * function/variable/class definitions in an anonymous namespace.
+// * static function/variable definitions in a global/named namespace.
+//
+// The reference graph is a directed graph. Each node in the graph represents a
+// helper declaration in old.cc or a non-moved/moved declaration (e.g. class,
+// function) in old.h, which means each node is associated with a Decl.
+//
+// To construct the graph, we use AST matcher to find interesting Decls (usually
+// a pair of Caller and Callee), and add an edge from the Caller node to the
+// Callee node.
+//
+// Specially, for a class, it might have multiple declarations such methods
+// and member variables. We only use a single node to present this class, and
+// this node is associated with the class declaration (CXXRecordDecl).
+//
+// The graph has 3 types of edges:
+// 1. moved_decl => helper_decl
+// 2. non_moved_decl => helper_decl
+// 3. helper_decl => helper_decl
+class HelperDeclRefGraph {
+public:
+ HelperDeclRefGraph() = default;
+ ~HelperDeclRefGraph() = default;
+
+ // Add a directed edge from the caller node to the callee node.
+ // A new node will be created if the node for Caller/Callee doesn't exist.
+ //
+ // Note that, all class member declarations are represented by a single node
+ // in the graph. The corresponding Decl of this node is the class declaration.
+ void addEdge(const Decl *Caller, const Decl *Callee);
+ CallGraphNode *getNode(const Decl *D) const;
+
+ // Get all reachable nodes in the graph from the given declaration D's node,
+ // including D.
+ llvm::DenseSet<const CallGraphNode *> getReachableNodes(const Decl *D) const;
+
+ // Dump the call graph for debug purpose.
+ void dump() const;
+
+private:
+ void print(raw_ostream &OS) const;
+ // Lookup a node for the given declaration D. If not found, insert a new
+ // node into the graph.
+ CallGraphNode *getOrInsertNode(Decl *D);
+
+ typedef llvm::DenseMap<const Decl *, std::unique_ptr<CallGraphNode>>
+ DeclMapTy;
+
+ // DeclMap owns all CallGraphNodes.
+ DeclMapTy DeclMap;
+};
+
+// A builder helps to construct a call graph of helper declarations.
+class HelperDeclRGBuilder : public ast_matchers::MatchFinder::MatchCallback {
+public:
+ HelperDeclRGBuilder() : RG(new HelperDeclRefGraph) {}
+ void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ const HelperDeclRefGraph *getGraph() const { return RG.get(); }
+
+ // Find out the outmost enclosing class/function declaration of a given D.
+ // For a CXXMethodDecl, get its CXXRecordDecl; For a VarDecl/FunctionDecl, get
+ // its outmost enclosing FunctionDecl or CXXRecordDecl.
+ // Return D if not found.
+ static const Decl *getOutmostClassOrFunDecl(const Decl *D);
+
+private:
+ std::unique_ptr<HelperDeclRefGraph> RG;
+};
+
+} // namespace move
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_USED_HELPER_DECL_FINDER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-move/tool/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-move/tool/CMakeLists.txt
new file mode 100644
index 0000000..9f678bb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-move/tool/CMakeLists.txt
@@ -0,0 +1,18 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+add_clang_executable(clang-move
+ ClangMoveMain.cpp
+ )
+
+target_link_libraries(clang-move
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFormat
+ clangFrontend
+ clangMove
+ clangRewrite
+ clangTooling
+ clangToolingCore
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-move/tool/ClangMoveMain.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-move/tool/ClangMoveMain.cpp
new file mode 100644
index 0000000..e5fee26
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-move/tool/ClangMoveMain.cpp
@@ -0,0 +1,210 @@
+//===-- ClangMoveMain.cpp - move defintion to new file ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangMove.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/ArgumentsAdjusters.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <set>
+#include <string>
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+
+std::error_code CreateNewFile(const llvm::Twine &path) {
+ int fd = 0;
+ if (std::error_code ec = llvm::sys::fs::openFileForWrite(
+ path, fd, llvm::sys::fs::CD_CreateAlways, llvm::sys::fs::F_Text))
+ return ec;
+
+ return llvm::sys::Process::SafelyCloseFileDescriptor(fd);
+}
+
+cl::OptionCategory ClangMoveCategory("clang-move options");
+
+cl::list<std::string> Names("names", cl::CommaSeparated,
+ cl::desc("The list of the names of classes being "
+ "moved, e.g. \"Foo,a::Foo,b::Foo\"."),
+ cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+ OldHeader("old_header",
+ cl::desc("The relative/absolute file path of old header."),
+ cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+ OldCC("old_cc", cl::desc("The relative/absolute file path of old cc."),
+ cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+ NewHeader("new_header",
+ cl::desc("The relative/absolute file path of new header."),
+ cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+ NewCC("new_cc", cl::desc("The relative/absolute file path of new cc."),
+ cl::cat(ClangMoveCategory));
+
+cl::opt<bool>
+ OldDependOnNew("old_depend_on_new",
+ cl::desc("Whether old header will depend on new header. If "
+ "true, clang-move will "
+ "add #include of new header to old header."),
+ cl::init(false), cl::cat(ClangMoveCategory));
+
+cl::opt<bool>
+ NewDependOnOld("new_depend_on_old",
+ cl::desc("Whether new header will depend on old header. If "
+ "true, clang-move will "
+ "add #include of old header to new header."),
+ cl::init(false), cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+ Style("style",
+ cl::desc("The style name used for reformatting. Default is \"llvm\""),
+ cl::init("llvm"), cl::cat(ClangMoveCategory));
+
+cl::opt<bool> Dump("dump_result",
+ cl::desc("Dump results in JSON format to stdout."),
+ cl::cat(ClangMoveCategory));
+
+cl::opt<bool> DumpDecls(
+ "dump_decls",
+ cl::desc("Dump all declarations in old header (JSON format) to stdout. If "
+ "the option is specified, other command options will be ignored. "
+ "An empty JSON will be returned if old header isn't specified."),
+ cl::cat(ClangMoveCategory));
+
+} // namespace
+
+int main(int argc, const char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+ tooling::CommonOptionsParser OptionsParser(argc, argv, ClangMoveCategory);
+
+ if (OldDependOnNew && NewDependOnOld) {
+ llvm::errs() << "Provide either --old_depend_on_new or "
+ "--new_depend_on_old. clang-move doesn't support these two "
+ "options at same time (It will introduce include cycle).\n";
+ return 1;
+ }
+
+ tooling::RefactoringTool Tool(OptionsParser.getCompilations(),
+ OptionsParser.getSourcePathList());
+ // Add "-fparse-all-comments" compile option to make clang parse all comments.
+ Tool.appendArgumentsAdjuster(tooling::getInsertArgumentAdjuster(
+ "-fparse-all-comments", tooling::ArgumentInsertPosition::BEGIN));
+ move::MoveDefinitionSpec Spec;
+ Spec.Names = {Names.begin(), Names.end()};
+ Spec.OldHeader = OldHeader;
+ Spec.NewHeader = NewHeader;
+ Spec.OldCC = OldCC;
+ Spec.NewCC = NewCC;
+ Spec.OldDependOnNew = OldDependOnNew;
+ Spec.NewDependOnOld = NewDependOnOld;
+
+ llvm::SmallString<128> InitialDirectory;
+ if (std::error_code EC = llvm::sys::fs::current_path(InitialDirectory))
+ llvm::report_fatal_error("Cannot detect current path: " +
+ Twine(EC.message()));
+
+ move::ClangMoveContext Context{Spec, Tool.getReplacements(),
+ InitialDirectory.str(), Style, DumpDecls};
+ move::DeclarationReporter Reporter;
+ move::ClangMoveActionFactory Factory(&Context, &Reporter);
+
+ int CodeStatus = Tool.run(&Factory);
+ if (CodeStatus)
+ return CodeStatus;
+
+ if (DumpDecls) {
+ llvm::outs() << "[\n";
+ const auto &Declarations = Reporter.getDeclarationList();
+ for (auto I = Declarations.begin(), E = Declarations.end(); I != E; ++I) {
+ llvm::outs() << " {\n";
+ llvm::outs() << " \"DeclarationName\": \"" << I->first << "\",\n";
+ llvm::outs() << " \"DeclarationType\": \"" << I->second << "\"\n";
+ llvm::outs() << " }";
+ // Don't print trailing "," at the end of last element.
+ if (I != std::prev(E))
+ llvm::outs() << ",\n";
+ }
+ llvm::outs() << "\n]\n";
+ return 0;
+ }
+
+ if (!NewCC.empty()) {
+ std::error_code EC = CreateNewFile(NewCC);
+ if (EC) {
+ llvm::errs() << "Failed to create " << NewCC << ": " << EC.message()
+ << "\n";
+ return EC.value();
+ }
+ }
+ if (!NewHeader.empty()) {
+ std::error_code EC = CreateNewFile(NewHeader);
+ if (EC) {
+ llvm::errs() << "Failed to create " << NewHeader << ": " << EC.message()
+ << "\n";
+ return EC.value();
+ }
+ }
+
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+ clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+ &DiagnosticPrinter, false);
+ auto &FileMgr = Tool.getFiles();
+ SourceManager SM(Diagnostics, FileMgr);
+ Rewriter Rewrite(SM, LangOptions());
+
+ if (!formatAndApplyAllReplacements(Tool.getReplacements(), Rewrite, Style)) {
+ llvm::errs() << "Failed applying all replacements.\n";
+ return 1;
+ }
+
+ if (Dump) {
+ std::set<llvm::StringRef> Files;
+ for (const auto &it : Tool.getReplacements())
+ Files.insert(it.first);
+ auto WriteToJson = [&](llvm::raw_ostream &OS) {
+ OS << "[\n";
+ for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
+ OS << " {\n";
+ OS << " \"FilePath\": \"" << *I << "\",\n";
+ const auto *Entry = FileMgr.getFile(*I);
+ auto ID = SM.translateFile(Entry);
+ std::string Content;
+ llvm::raw_string_ostream ContentStream(Content);
+ Rewrite.getEditBuffer(ID).write(ContentStream);
+ OS << " \"SourceText\": \""
+ << llvm::yaml::escape(ContentStream.str()) << "\"\n";
+ OS << " }";
+ if (I != std::prev(E))
+ OS << ",\n";
+ }
+ OS << "\n]\n";
+ };
+ WriteToJson(llvm::outs());
+ return 0;
+ }
+
+ return Rewrite.overwriteChangedFiles();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-query/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-query/CMakeLists.txt
new file mode 100644
index 0000000..46febd6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-query/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(LLVM_LINK_COMPONENTS
+ lineeditor
+ support
+ )
+
+add_clang_library(clangQuery
+ Query.cpp
+ QueryParser.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangDynamicASTMatchers
+ clangFrontend
+ )
+
+add_subdirectory(tool)
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-query/Query.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-query/Query.cpp
new file mode 100644
index 0000000..072ee6b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-query/Query.cpp
@@ -0,0 +1,146 @@
+//===---- Query.cpp - clang-query query -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Query.h"
+#include "QuerySession.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/TextDiagnostic.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::ast_matchers::dynamic;
+
+namespace clang {
+namespace query {
+
+Query::~Query() {}
+
+bool InvalidQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
+ OS << ErrStr << "\n";
+ return false;
+}
+
+bool NoOpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
+ return true;
+}
+
+bool HelpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
+ OS << "Available commands:\n\n"
+ " match MATCHER, m MATCHER "
+ "Match the loaded ASTs against the given matcher.\n"
+ " let NAME MATCHER, l NAME MATCHER "
+ "Give a matcher expression a name, to be used later\n"
+ " "
+ "as part of other expressions.\n"
+ " set bind-root (true|false) "
+ "Set whether to bind the root matcher to \"root\".\n"
+ " set output (diag|print|dump) "
+ "Set whether to print bindings as diagnostics,\n"
+ " "
+ "AST pretty prints or AST dumps.\n"
+ " quit "
+ "Terminates the query session.\n\n";
+ return true;
+}
+
+bool QuitQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
+ QS.Terminate = true;
+ return true;
+}
+
+namespace {
+
+struct CollectBoundNodes : MatchFinder::MatchCallback {
+ std::vector<BoundNodes> &Bindings;
+ CollectBoundNodes(std::vector<BoundNodes> &Bindings) : Bindings(Bindings) {}
+ void run(const MatchFinder::MatchResult &Result) override {
+ Bindings.push_back(Result.Nodes);
+ }
+};
+
+} // namespace
+
+bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
+ unsigned MatchCount = 0;
+
+ for (auto &AST : QS.ASTs) {
+ MatchFinder Finder;
+ std::vector<BoundNodes> Matches;
+ DynTypedMatcher MaybeBoundMatcher = Matcher;
+ if (QS.BindRoot) {
+ llvm::Optional<DynTypedMatcher> M = Matcher.tryBind("root");
+ if (M)
+ MaybeBoundMatcher = *M;
+ }
+ CollectBoundNodes Collect(Matches);
+ if (!Finder.addDynamicMatcher(MaybeBoundMatcher, &Collect)) {
+ OS << "Not a valid top-level matcher.\n";
+ return false;
+ }
+ Finder.matchAST(AST->getASTContext());
+
+ for (auto MI = Matches.begin(), ME = Matches.end(); MI != ME; ++MI) {
+ OS << "\nMatch #" << ++MatchCount << ":\n\n";
+
+ for (auto BI = MI->getMap().begin(), BE = MI->getMap().end(); BI != BE;
+ ++BI) {
+ switch (QS.OutKind) {
+ case OK_Diag: {
+ clang::SourceRange R = BI->second.getSourceRange();
+ if (R.isValid()) {
+ TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
+ &AST->getDiagnostics().getDiagnosticOptions());
+ TD.emitDiagnostic(
+ FullSourceLoc(R.getBegin(), AST->getSourceManager()),
+ DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here",
+ CharSourceRange::getTokenRange(R), None);
+ }
+ break;
+ }
+ case OK_Print: {
+ OS << "Binding for \"" << BI->first << "\":\n";
+ BI->second.print(OS, AST->getASTContext().getPrintingPolicy());
+ OS << "\n";
+ break;
+ }
+ case OK_Dump: {
+ OS << "Binding for \"" << BI->first << "\":\n";
+ BI->second.dump(OS, AST->getSourceManager());
+ OS << "\n";
+ break;
+ }
+ }
+ }
+
+ if (MI->getMap().empty())
+ OS << "No bindings.\n";
+ }
+ }
+
+ OS << MatchCount << (MatchCount == 1 ? " match.\n" : " matches.\n");
+ return true;
+}
+
+bool LetQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
+ if (Value) {
+ QS.NamedValues[Name] = Value;
+ } else {
+ QS.NamedValues.erase(Name);
+ }
+ return true;
+}
+
+#ifndef _MSC_VER
+const QueryKind SetQueryKind<bool>::value;
+const QueryKind SetQueryKind<OutputKind>::value;
+#endif
+
+} // namespace query
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-query/Query.h b/src/third_party/llvm-project/clang-tools-extra/clang-query/Query.h
new file mode 100644
index 0000000..b8c59cb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-query/Query.h
@@ -0,0 +1,136 @@
+//===--- Query.h - clang-query ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_H
+
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/Optional.h"
+#include <string>
+
+namespace clang {
+namespace query {
+
+enum OutputKind { OK_Diag, OK_Print, OK_Dump };
+
+enum QueryKind {
+ QK_Invalid,
+ QK_NoOp,
+ QK_Help,
+ QK_Let,
+ QK_Match,
+ QK_SetBool,
+ QK_SetOutputKind,
+ QK_Quit
+};
+
+class QuerySession;
+
+struct Query : llvm::RefCountedBase<Query> {
+ Query(QueryKind Kind) : Kind(Kind) {}
+ virtual ~Query();
+
+ /// Perform the query on \p QS and print output to \p OS.
+ ///
+ /// \return false if an error occurs, otherwise return true.
+ virtual bool run(llvm::raw_ostream &OS, QuerySession &QS) const = 0;
+
+ const QueryKind Kind;
+};
+
+typedef llvm::IntrusiveRefCntPtr<Query> QueryRef;
+
+/// Any query which resulted in a parse error. The error message is in ErrStr.
+struct InvalidQuery : Query {
+ InvalidQuery(const Twine &ErrStr) : Query(QK_Invalid), ErrStr(ErrStr.str()) {}
+ bool run(llvm::raw_ostream &OS, QuerySession &QS) const override;
+
+ std::string ErrStr;
+
+ static bool classof(const Query *Q) { return Q->Kind == QK_Invalid; }
+};
+
+/// No-op query (i.e. a blank line).
+struct NoOpQuery : Query {
+ NoOpQuery() : Query(QK_NoOp) {}
+ bool run(llvm::raw_ostream &OS, QuerySession &QS) const override;
+
+ static bool classof(const Query *Q) { return Q->Kind == QK_NoOp; }
+};
+
+/// Query for "help".
+struct HelpQuery : Query {
+ HelpQuery() : Query(QK_Help) {}
+ bool run(llvm::raw_ostream &OS, QuerySession &QS) const override;
+
+ static bool classof(const Query *Q) { return Q->Kind == QK_Help; }
+};
+
+/// Query for "quit".
+struct QuitQuery : Query {
+ QuitQuery() : Query(QK_Quit) {}
+ bool run(llvm::raw_ostream &OS, QuerySession &QS) const override;
+
+ static bool classof(const Query *Q) { return Q->Kind == QK_Quit; }
+};
+
+/// Query for "match MATCHER".
+struct MatchQuery : Query {
+ MatchQuery(const ast_matchers::dynamic::DynTypedMatcher &Matcher)
+ : Query(QK_Match), Matcher(Matcher) {}
+ bool run(llvm::raw_ostream &OS, QuerySession &QS) const override;
+
+ ast_matchers::dynamic::DynTypedMatcher Matcher;
+
+ static bool classof(const Query *Q) { return Q->Kind == QK_Match; }
+};
+
+struct LetQuery : Query {
+ LetQuery(StringRef Name, const ast_matchers::dynamic::VariantValue &Value)
+ : Query(QK_Let), Name(Name), Value(Value) {}
+ bool run(llvm::raw_ostream &OS, QuerySession &QS) const override;
+
+ std::string Name;
+ ast_matchers::dynamic::VariantValue Value;
+
+ static bool classof(const Query *Q) { return Q->Kind == QK_Let; }
+};
+
+template <typename T> struct SetQueryKind {};
+
+template <> struct SetQueryKind<bool> {
+ static const QueryKind value = QK_SetBool;
+};
+
+template <> struct SetQueryKind<OutputKind> {
+ static const QueryKind value = QK_SetOutputKind;
+};
+
+/// Query for "set VAR VALUE".
+template <typename T> struct SetQuery : Query {
+ SetQuery(T QuerySession::*Var, T Value)
+ : Query(SetQueryKind<T>::value), Var(Var), Value(Value) {}
+ bool run(llvm::raw_ostream &OS, QuerySession &QS) const override {
+ QS.*Var = Value;
+ return true;
+ }
+
+ static bool classof(const Query *Q) {
+ return Q->Kind == SetQueryKind<T>::value;
+ }
+
+ T QuerySession::*Var;
+ T Value;
+};
+
+} // namespace query
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-query/QueryParser.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-query/QueryParser.cpp
new file mode 100644
index 0000000..bb3d1b3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-query/QueryParser.cpp
@@ -0,0 +1,272 @@
+//===---- QueryParser.cpp - clang-query command parser --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "QueryParser.h"
+#include "Query.h"
+#include "QuerySession.h"
+#include "clang/ASTMatchers/Dynamic/Parser.h"
+#include "clang/Basic/CharInfo.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include <set>
+
+using namespace llvm;
+using namespace clang::ast_matchers::dynamic;
+
+namespace clang {
+namespace query {
+
+// Lex any amount of whitespace followed by a "word" (any sequence of
+// non-whitespace characters) from the start of region [Begin,End). If no word
+// is found before End, return StringRef(). Begin is adjusted to exclude the
+// lexed region.
+StringRef QueryParser::lexWord() {
+ while (true) {
+ if (Begin == End)
+ return StringRef(Begin, 0);
+
+ if (!isWhitespace(*Begin))
+ break;
+
+ ++Begin;
+ }
+
+ const char *WordBegin = Begin;
+
+ while (true) {
+ ++Begin;
+
+ if (Begin == End || isWhitespace(*Begin))
+ return StringRef(WordBegin, Begin - WordBegin);
+ }
+}
+
+// This is the StringSwitch-alike used by lexOrCompleteWord below. See that
+// function for details.
+template <typename T> struct QueryParser::LexOrCompleteWord {
+ StringRef Word;
+ StringSwitch<T> Switch;
+
+ QueryParser *P;
+ // Set to the completion point offset in Word, or StringRef::npos if
+ // completion point not in Word.
+ size_t WordCompletionPos;
+
+ // Lexes a word and stores it in Word. Returns a LexOrCompleteWord<T> object
+ // that can be used like a llvm::StringSwitch<T>, but adds cases as possible
+ // completions if the lexed word contains the completion point.
+ LexOrCompleteWord(QueryParser *P, StringRef &OutWord)
+ : Word(P->lexWord()), Switch(Word), P(P),
+ WordCompletionPos(StringRef::npos) {
+ OutWord = Word;
+ if (P->CompletionPos && P->CompletionPos <= Word.data() + Word.size()) {
+ if (P->CompletionPos < Word.data())
+ WordCompletionPos = 0;
+ else
+ WordCompletionPos = P->CompletionPos - Word.data();
+ }
+ }
+
+ LexOrCompleteWord &Case(llvm::StringLiteral CaseStr, const T &Value,
+ bool IsCompletion = true) {
+
+ if (WordCompletionPos == StringRef::npos)
+ Switch.Case(CaseStr, Value);
+ else if (CaseStr.size() != 0 && IsCompletion && WordCompletionPos <= CaseStr.size() &&
+ CaseStr.substr(0, WordCompletionPos) ==
+ Word.substr(0, WordCompletionPos))
+ P->Completions.push_back(LineEditor::Completion(
+ (CaseStr.substr(WordCompletionPos) + " ").str(), CaseStr));
+ return *this;
+ }
+
+ T Default(T Value) { return Switch.Default(Value); }
+};
+
+QueryRef QueryParser::parseSetBool(bool QuerySession::*Var) {
+ StringRef ValStr;
+ unsigned Value = LexOrCompleteWord<unsigned>(this, ValStr)
+ .Case("false", 0)
+ .Case("true", 1)
+ .Default(~0u);
+ if (Value == ~0u) {
+ return new InvalidQuery("expected 'true' or 'false', got '" + ValStr + "'");
+ }
+ return new SetQuery<bool>(Var, Value);
+}
+
+QueryRef QueryParser::parseSetOutputKind() {
+ StringRef ValStr;
+ unsigned OutKind = LexOrCompleteWord<unsigned>(this, ValStr)
+ .Case("diag", OK_Diag)
+ .Case("print", OK_Print)
+ .Case("dump", OK_Dump)
+ .Default(~0u);
+ if (OutKind == ~0u) {
+ return new InvalidQuery("expected 'diag', 'print' or 'dump', got '" +
+ ValStr + "'");
+ }
+ return new SetQuery<OutputKind>(&QuerySession::OutKind, OutputKind(OutKind));
+}
+
+QueryRef QueryParser::endQuery(QueryRef Q) {
+ const char *Extra = Begin;
+ if (!lexWord().empty())
+ return new InvalidQuery("unexpected extra input: '" +
+ StringRef(Extra, End - Extra) + "'");
+ return Q;
+}
+
+namespace {
+
+enum ParsedQueryKind {
+ PQK_Invalid,
+ PQK_NoOp,
+ PQK_Help,
+ PQK_Let,
+ PQK_Match,
+ PQK_Set,
+ PQK_Unlet,
+ PQK_Quit
+};
+
+enum ParsedQueryVariable { PQV_Invalid, PQV_Output, PQV_BindRoot };
+
+QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) {
+ std::string ErrStr;
+ llvm::raw_string_ostream OS(ErrStr);
+ Diag.printToStreamFull(OS);
+ return new InvalidQuery(OS.str());
+}
+
+} // namespace
+
+QueryRef QueryParser::completeMatcherExpression() {
+ std::vector<MatcherCompletion> Comps = Parser::completeExpression(
+ StringRef(Begin, End - Begin), CompletionPos - Begin, nullptr,
+ &QS.NamedValues);
+ for (auto I = Comps.begin(), E = Comps.end(); I != E; ++I) {
+ Completions.push_back(LineEditor::Completion(I->TypedText, I->MatcherDecl));
+ }
+ return QueryRef();
+}
+
+QueryRef QueryParser::doParse() {
+ StringRef CommandStr;
+ ParsedQueryKind QKind = LexOrCompleteWord<ParsedQueryKind>(this, CommandStr)
+ .Case("", PQK_NoOp)
+ .Case("help", PQK_Help)
+ .Case("m", PQK_Match, /*IsCompletion=*/false)
+ .Case("let", PQK_Let)
+ .Case("match", PQK_Match)
+ .Case("set", PQK_Set)
+ .Case("unlet", PQK_Unlet)
+ .Case("quit", PQK_Quit)
+ .Default(PQK_Invalid);
+
+ switch (QKind) {
+ case PQK_NoOp:
+ return new NoOpQuery;
+
+ case PQK_Help:
+ return endQuery(new HelpQuery);
+
+ case PQK_Quit:
+ return endQuery(new QuitQuery);
+
+ case PQK_Let: {
+ StringRef Name = lexWord();
+
+ if (Name.empty())
+ return new InvalidQuery("expected variable name");
+
+ if (CompletionPos)
+ return completeMatcherExpression();
+
+ Diagnostics Diag;
+ ast_matchers::dynamic::VariantValue Value;
+ if (!Parser::parseExpression(StringRef(Begin, End - Begin), nullptr,
+ &QS.NamedValues, &Value, &Diag)) {
+ return makeInvalidQueryFromDiagnostics(Diag);
+ }
+
+ return new LetQuery(Name, Value);
+ }
+
+ case PQK_Match: {
+ if (CompletionPos)
+ return completeMatcherExpression();
+
+ Diagnostics Diag;
+ Optional<DynTypedMatcher> Matcher = Parser::parseMatcherExpression(
+ StringRef(Begin, End - Begin), nullptr, &QS.NamedValues, &Diag);
+ if (!Matcher) {
+ return makeInvalidQueryFromDiagnostics(Diag);
+ }
+ return new MatchQuery(*Matcher);
+ }
+
+ case PQK_Set: {
+ StringRef VarStr;
+ ParsedQueryVariable Var = LexOrCompleteWord<ParsedQueryVariable>(this,
+ VarStr)
+ .Case("output", PQV_Output)
+ .Case("bind-root", PQV_BindRoot)
+ .Default(PQV_Invalid);
+ if (VarStr.empty())
+ return new InvalidQuery("expected variable name");
+ if (Var == PQV_Invalid)
+ return new InvalidQuery("unknown variable: '" + VarStr + "'");
+
+ QueryRef Q;
+ switch (Var) {
+ case PQV_Output:
+ Q = parseSetOutputKind();
+ break;
+ case PQV_BindRoot:
+ Q = parseSetBool(&QuerySession::BindRoot);
+ break;
+ case PQV_Invalid:
+ llvm_unreachable("Invalid query kind");
+ }
+
+ return endQuery(Q);
+ }
+
+ case PQK_Unlet: {
+ StringRef Name = lexWord();
+
+ if (Name.empty())
+ return new InvalidQuery("expected variable name");
+
+ return endQuery(new LetQuery(Name, VariantValue()));
+ }
+
+ case PQK_Invalid:
+ return new InvalidQuery("unknown command: " + CommandStr);
+ }
+
+ llvm_unreachable("Invalid query kind");
+}
+
+QueryRef QueryParser::parse(StringRef Line, const QuerySession &QS) {
+ return QueryParser(Line, QS).doParse();
+}
+
+std::vector<LineEditor::Completion>
+QueryParser::complete(StringRef Line, size_t Pos, const QuerySession &QS) {
+ QueryParser P(Line, QS);
+ P.CompletionPos = Line.data() + Pos;
+
+ P.doParse();
+ return P.Completions;
+}
+
+} // namespace query
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-query/QueryParser.h b/src/third_party/llvm-project/clang-tools-extra/clang-query/QueryParser.h
new file mode 100644
index 0000000..67f907d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-query/QueryParser.h
@@ -0,0 +1,70 @@
+//===--- QueryParser.h - clang-query ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_PARSER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_PARSER_H
+
+#include "Query.h"
+#include "QuerySession.h"
+#include "llvm/LineEditor/LineEditor.h"
+#include <cstddef>
+
+namespace clang {
+namespace query {
+
+class QuerySession;
+
+class QueryParser {
+public:
+ /// Parse \a Line as a query.
+ ///
+ /// \return A QueryRef representing the query, which may be an InvalidQuery.
+ static QueryRef parse(StringRef Line, const QuerySession &QS);
+
+ /// Compute a list of completions for \a Line assuming a cursor at
+ /// \param Pos characters past the start of \a Line, ordered from most
+ /// likely to least likely.
+ ///
+ /// \return A vector of completions for \a Line.
+ static std::vector<llvm::LineEditor::Completion>
+ complete(StringRef Line, size_t Pos, const QuerySession &QS);
+
+private:
+ QueryParser(StringRef Line, const QuerySession &QS)
+ : Begin(Line.begin()), End(Line.end()), CompletionPos(nullptr), QS(QS) {}
+
+ StringRef lexWord();
+
+ template <typename T> struct LexOrCompleteWord;
+
+ QueryRef parseSetBool(bool QuerySession::*Var);
+ QueryRef parseSetOutputKind();
+ QueryRef completeMatcherExpression();
+
+ QueryRef endQuery(QueryRef Q);
+
+ /// \brief Parse [\p Begin,\p End).
+ ///
+ /// \return A reference to the parsed query object, which may be an
+ /// \c InvalidQuery if a parse error occurs.
+ QueryRef doParse();
+
+ const char *Begin;
+ const char *End;
+
+ const char *CompletionPos;
+ std::vector<llvm::LineEditor::Completion> Completions;
+
+ const QuerySession &QS;
+};
+
+} // namespace query
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_PARSER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-query/QuerySession.h b/src/third_party/llvm-project/clang-tools-extra/clang-query/QuerySession.h
new file mode 100644
index 0000000..162289f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-query/QuerySession.h
@@ -0,0 +1,40 @@
+//===--- QuerySession.h - clang-query ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_SESSION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_SESSION_H
+
+#include "Query.h"
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace clang {
+
+class ASTUnit;
+
+namespace query {
+
+/// Represents the state for a particular clang-query session.
+class QuerySession {
+public:
+ QuerySession(llvm::ArrayRef<std::unique_ptr<ASTUnit>> ASTs)
+ : ASTs(ASTs), OutKind(OK_Diag), BindRoot(true), Terminate(false) {}
+
+ llvm::ArrayRef<std::unique_ptr<ASTUnit>> ASTs;
+ OutputKind OutKind;
+ bool BindRoot;
+ bool Terminate;
+ llvm::StringMap<ast_matchers::dynamic::VariantValue> NamedValues;
+};
+
+} // namespace query
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-query/tool/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-query/tool/CMakeLists.txt
new file mode 100644
index 0000000..a950931
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-query/tool/CMakeLists.txt
@@ -0,0 +1,15 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+add_clang_executable(clang-query ClangQuery.cpp)
+target_link_libraries(clang-query
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangDynamicASTMatchers
+ clangFrontend
+ clangQuery
+ clangTooling
+ )
+
+install(TARGETS clang-query RUNTIME DESTINATION bin)
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-query/tool/ClangQuery.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-query/tool/ClangQuery.cpp
new file mode 100644
index 0000000..669dc40
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-query/tool/ClangQuery.cpp
@@ -0,0 +1,116 @@
+//===---- ClangQuery.cpp - clang-query tool -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tool is for interactive exploration of the Clang AST using AST matchers.
+// It currently allows the user to enter a matcher at an interactive prompt and
+// view the resulting bindings as diagnostics, AST pretty prints or AST dumps.
+// Example session:
+//
+// $ cat foo.c
+// void foo(void) {}
+// $ clang-query foo.c --
+// clang-query> match functionDecl()
+//
+// Match #1:
+//
+// foo.c:1:1: note: "root" binds here
+// void foo(void) {}
+// ^~~~~~~~~~~~~~~~~
+// 1 match.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Query.h"
+#include "QueryParser.h"
+#include "QuerySession.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/LineEditor/LineEditor.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Signals.h"
+#include <fstream>
+#include <string>
+
+using namespace clang;
+using namespace clang::ast_matchers;
+using namespace clang::ast_matchers::dynamic;
+using namespace clang::query;
+using namespace clang::tooling;
+using namespace llvm;
+
+static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+static cl::OptionCategory ClangQueryCategory("clang-query options");
+
+static cl::list<std::string> Commands("c", cl::desc("Specify command to run"),
+ cl::value_desc("command"),
+ cl::cat(ClangQueryCategory));
+
+static cl::list<std::string> CommandFiles("f",
+ cl::desc("Read commands from file"),
+ cl::value_desc("file"),
+ cl::cat(ClangQueryCategory));
+
+int main(int argc, const char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+
+ CommonOptionsParser OptionsParser(argc, argv, ClangQueryCategory);
+
+ if (!Commands.empty() && !CommandFiles.empty()) {
+ llvm::errs() << argv[0] << ": cannot specify both -c and -f\n";
+ return 1;
+ }
+
+ ClangTool Tool(OptionsParser.getCompilations(),
+ OptionsParser.getSourcePathList());
+ std::vector<std::unique_ptr<ASTUnit>> ASTs;
+ if (Tool.buildASTs(ASTs) != 0)
+ return 1;
+
+ QuerySession QS(ASTs);
+
+ if (!Commands.empty()) {
+ for (auto I = Commands.begin(), E = Commands.end(); I != E; ++I) {
+ QueryRef Q = QueryParser::parse(*I, QS);
+ if (!Q->run(llvm::outs(), QS))
+ return 1;
+ }
+ } else if (!CommandFiles.empty()) {
+ for (auto I = CommandFiles.begin(), E = CommandFiles.end(); I != E; ++I) {
+ std::ifstream Input(I->c_str());
+ if (!Input.is_open()) {
+ llvm::errs() << argv[0] << ": cannot open " << *I << "\n";
+ return 1;
+ }
+ while (Input.good()) {
+ std::string Line;
+ std::getline(Input, Line);
+
+ QueryRef Q = QueryParser::parse(Line, QS);
+ if (!Q->run(llvm::outs(), QS))
+ return 1;
+ }
+ }
+ } else {
+ LineEditor LE("clang-query");
+ LE.setListCompleter([&QS](StringRef Line, size_t Pos) {
+ return QueryParser::complete(Line, Pos, QS);
+ });
+ while (llvm::Optional<std::string> Line = LE.readLine()) {
+ QueryRef Q = QueryParser::parse(*Line, QS);
+ Q->run(llvm::outs(), QS);
+ llvm::outs().flush();
+ if (QS.Terminate)
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
new file mode 100644
index 0000000..51cd4af
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangReorderFields
+ ReorderFieldsAction.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangIndex
+ clangLex
+ clangToolingCore
+ )
+
+add_subdirectory(tool)
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
new file mode 100644
index 0000000..7cb8abe
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
@@ -0,0 +1,311 @@
+//===-- tools/extra/clang-reorder-fields/ReorderFieldsAction.cpp -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the definition of the
+/// ReorderFieldsAction::newASTConsumer method
+///
+//===----------------------------------------------------------------------===//
+
+#include "ReorderFieldsAction.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Refactoring.h"
+#include "llvm/ADT/SetVector.h"
+#include <algorithm>
+#include <string>
+
+namespace clang {
+namespace reorder_fields {
+using namespace clang::ast_matchers;
+using llvm::SmallSetVector;
+
+/// \brief Finds the definition of a record by name.
+///
+/// \returns nullptr if the name is ambiguous or not found.
+static const RecordDecl *findDefinition(StringRef RecordName,
+ ASTContext &Context) {
+ auto Results =
+ match(recordDecl(hasName(RecordName), isDefinition()).bind("recordDecl"),
+ Context);
+ if (Results.empty()) {
+ llvm::errs() << "Definition of " << RecordName << " not found\n";
+ return nullptr;
+ }
+ if (Results.size() > 1) {
+ llvm::errs() << "The name " << RecordName
+ << " is ambiguous, several definitions found\n";
+ return nullptr;
+ }
+ return selectFirst<RecordDecl>("recordDecl", Results);
+}
+
+/// \brief Calculates the new order of fields.
+///
+/// \returns empty vector if the list of fields doesn't match the definition.
+static SmallVector<unsigned, 4>
+getNewFieldsOrder(const RecordDecl *Definition,
+ ArrayRef<std::string> DesiredFieldsOrder) {
+ assert(Definition && "Definition is null");
+
+ llvm::StringMap<unsigned> NameToIndex;
+ for (const auto *Field : Definition->fields())
+ NameToIndex[Field->getName()] = Field->getFieldIndex();
+
+ if (DesiredFieldsOrder.size() != NameToIndex.size()) {
+ llvm::errs() << "Number of provided fields doesn't match definition.\n";
+ return {};
+ }
+ SmallVector<unsigned, 4> NewFieldsOrder;
+ for (const auto &Name : DesiredFieldsOrder) {
+ if (!NameToIndex.count(Name)) {
+ llvm::errs() << "Field " << Name << " not found in definition.\n";
+ return {};
+ }
+ NewFieldsOrder.push_back(NameToIndex[Name]);
+ }
+ assert(NewFieldsOrder.size() == NameToIndex.size());
+ return NewFieldsOrder;
+}
+
+// FIXME: error-handling
+/// \brief Replaces one range of source code by another.
+static void
+addReplacement(SourceRange Old, SourceRange New, const ASTContext &Context,
+ std::map<std::string, tooling::Replacements> &Replacements) {
+ StringRef NewText =
+ Lexer::getSourceText(CharSourceRange::getTokenRange(New),
+ Context.getSourceManager(), Context.getLangOpts());
+ tooling::Replacement R(Context.getSourceManager(),
+ CharSourceRange::getTokenRange(Old), NewText,
+ Context.getLangOpts());
+ consumeError(Replacements[R.getFilePath()].add(R));
+}
+
+/// \brief Find all member fields used in the given init-list initializer expr
+/// that belong to the same record
+///
+/// \returns a set of field declarations, empty if none were present
+static SmallSetVector<FieldDecl *, 1>
+findMembersUsedInInitExpr(const CXXCtorInitializer *Initializer,
+ ASTContext &Context) {
+ SmallSetVector<FieldDecl *, 1> Results;
+ // Note that this does not pick up member fields of base classes since
+ // for those accesses Sema::PerformObjectMemberConversion always inserts an
+ // UncheckedDerivedToBase ImplicitCastExpr between the this expr and the
+ // object expression
+ auto FoundExprs =
+ match(findAll(memberExpr(hasObjectExpression(cxxThisExpr())).bind("ME")),
+ *Initializer->getInit(), Context);
+ for (BoundNodes &BN : FoundExprs)
+ if (auto *MemExpr = BN.getNodeAs<MemberExpr>("ME"))
+ if (auto *FD = dyn_cast<FieldDecl>(MemExpr->getMemberDecl()))
+ Results.insert(FD);
+ return Results;
+}
+
+/// \brief Reorders fields in the definition of a struct/class.
+///
+/// At the moment reodering of fields with
+/// different accesses (public/protected/private) is not supported.
+/// \returns true on success.
+static bool reorderFieldsInDefinition(
+ const RecordDecl *Definition, ArrayRef<unsigned> NewFieldsOrder,
+ const ASTContext &Context,
+ std::map<std::string, tooling::Replacements> &Replacements) {
+ assert(Definition && "Definition is null");
+
+ SmallVector<const FieldDecl *, 10> Fields;
+ for (const auto *Field : Definition->fields())
+ Fields.push_back(Field);
+
+ // Check that the permutation of the fields doesn't change the accesses
+ for (const auto *Field : Definition->fields()) {
+ const auto FieldIndex = Field->getFieldIndex();
+ if (Field->getAccess() != Fields[NewFieldsOrder[FieldIndex]]->getAccess()) {
+ llvm::errs() << "Currently reodering of fields with different accesses "
+ "is not supported\n";
+ return false;
+ }
+ }
+
+ for (const auto *Field : Definition->fields()) {
+ const auto FieldIndex = Field->getFieldIndex();
+ if (FieldIndex == NewFieldsOrder[FieldIndex])
+ continue;
+ addReplacement(Field->getSourceRange(),
+ Fields[NewFieldsOrder[FieldIndex]]->getSourceRange(),
+ Context, Replacements);
+ }
+ return true;
+}
+
+/// \brief Reorders initializers in a C++ struct/class constructor.
+///
+/// A constructor can have initializers for an arbitrary subset of the class's
+/// fields. Thus, we need to ensure that we reorder just the initializers that
+/// are present.
+static void reorderFieldsInConstructor(
+ const CXXConstructorDecl *CtorDecl, ArrayRef<unsigned> NewFieldsOrder,
+ ASTContext &Context,
+ std::map<std::string, tooling::Replacements> &Replacements) {
+ assert(CtorDecl && "Constructor declaration is null");
+ if (CtorDecl->isImplicit() || CtorDecl->getNumCtorInitializers() <= 1)
+ return;
+
+ // The method FunctionDecl::isThisDeclarationADefinition returns false
+ // for a defaulted function unless that function has been implicitly defined.
+ // Thus this assert needs to be after the previous checks.
+ assert(CtorDecl->isThisDeclarationADefinition() && "Not a definition");
+
+ SmallVector<unsigned, 10> NewFieldsPositions(NewFieldsOrder.size());
+ for (unsigned i = 0, e = NewFieldsOrder.size(); i < e; ++i)
+ NewFieldsPositions[NewFieldsOrder[i]] = i;
+
+ SmallVector<const CXXCtorInitializer *, 10> OldWrittenInitializersOrder;
+ SmallVector<const CXXCtorInitializer *, 10> NewWrittenInitializersOrder;
+ for (const auto *Initializer : CtorDecl->inits()) {
+ if (!Initializer->isMemberInitializer() || !Initializer->isWritten())
+ continue;
+
+ // Warn if this reordering violates initialization expr dependencies.
+ const FieldDecl *ThisM = Initializer->getMember();
+ const auto UsedMembers = findMembersUsedInInitExpr(Initializer, Context);
+ for (const FieldDecl *UM : UsedMembers) {
+ if (NewFieldsPositions[UM->getFieldIndex()] >
+ NewFieldsPositions[ThisM->getFieldIndex()]) {
+ DiagnosticsEngine &DiagEngine = Context.getDiagnostics();
+ auto Description = ("reordering field " + UM->getName() + " after " +
+ ThisM->getName() + " makes " + UM->getName() +
+ " uninitialized when used in init expression")
+ .str();
+ unsigned ID = DiagEngine.getDiagnosticIDs()->getCustomDiagID(
+ DiagnosticIDs::Warning, Description);
+ DiagEngine.Report(Initializer->getSourceLocation(), ID);
+ }
+ }
+
+ OldWrittenInitializersOrder.push_back(Initializer);
+ NewWrittenInitializersOrder.push_back(Initializer);
+ }
+ auto ByFieldNewPosition = [&](const CXXCtorInitializer *LHS,
+ const CXXCtorInitializer *RHS) {
+ assert(LHS && RHS);
+ return NewFieldsPositions[LHS->getMember()->getFieldIndex()] <
+ NewFieldsPositions[RHS->getMember()->getFieldIndex()];
+ };
+ std::sort(std::begin(NewWrittenInitializersOrder),
+ std::end(NewWrittenInitializersOrder), ByFieldNewPosition);
+ assert(OldWrittenInitializersOrder.size() ==
+ NewWrittenInitializersOrder.size());
+ for (unsigned i = 0, e = NewWrittenInitializersOrder.size(); i < e; ++i)
+ if (OldWrittenInitializersOrder[i] != NewWrittenInitializersOrder[i])
+ addReplacement(OldWrittenInitializersOrder[i]->getSourceRange(),
+ NewWrittenInitializersOrder[i]->getSourceRange(), Context,
+ Replacements);
+}
+
+/// \brief Reorders initializers in the brace initialization of an aggregate.
+///
+/// At the moment partial initialization is not supported.
+/// \returns true on success
+static bool reorderFieldsInInitListExpr(
+ const InitListExpr *InitListEx, ArrayRef<unsigned> NewFieldsOrder,
+ const ASTContext &Context,
+ std::map<std::string, tooling::Replacements> &Replacements) {
+ assert(InitListEx && "Init list expression is null");
+ // We care only about InitListExprs which originate from source code.
+ // Implicit InitListExprs are created by the semantic analyzer.
+ if (!InitListEx->isExplicit())
+ return true;
+ // The method InitListExpr::getSyntacticForm may return nullptr indicating
+ // that the current initializer list also serves as its syntactic form.
+ if (const auto *SyntacticForm = InitListEx->getSyntacticForm())
+ InitListEx = SyntacticForm;
+ // If there are no initializers we do not need to change anything.
+ if (!InitListEx->getNumInits())
+ return true;
+ if (InitListEx->getNumInits() != NewFieldsOrder.size()) {
+ llvm::errs() << "Currently only full initialization is supported\n";
+ return false;
+ }
+ for (unsigned i = 0, e = InitListEx->getNumInits(); i < e; ++i)
+ if (i != NewFieldsOrder[i])
+ addReplacement(InitListEx->getInit(i)->getSourceRange(),
+ InitListEx->getInit(NewFieldsOrder[i])->getSourceRange(),
+ Context, Replacements);
+ return true;
+}
+
+namespace {
+class ReorderingConsumer : public ASTConsumer {
+ StringRef RecordName;
+ ArrayRef<std::string> DesiredFieldsOrder;
+ std::map<std::string, tooling::Replacements> &Replacements;
+
+public:
+ ReorderingConsumer(StringRef RecordName,
+ ArrayRef<std::string> DesiredFieldsOrder,
+ std::map<std::string, tooling::Replacements> &Replacements)
+ : RecordName(RecordName), DesiredFieldsOrder(DesiredFieldsOrder),
+ Replacements(Replacements) {}
+
+ ReorderingConsumer(const ReorderingConsumer &) = delete;
+ ReorderingConsumer &operator=(const ReorderingConsumer &) = delete;
+
+ void HandleTranslationUnit(ASTContext &Context) override {
+ const RecordDecl *RD = findDefinition(RecordName, Context);
+ if (!RD)
+ return;
+ SmallVector<unsigned, 4> NewFieldsOrder =
+ getNewFieldsOrder(RD, DesiredFieldsOrder);
+ if (NewFieldsOrder.empty())
+ return;
+ if (!reorderFieldsInDefinition(RD, NewFieldsOrder, Context, Replacements))
+ return;
+
+ // CXXRD will be nullptr if C code (not C++) is being processed.
+ const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD);
+ if (CXXRD)
+ for (const auto *C : CXXRD->ctors())
+ if (const auto *D = dyn_cast<CXXConstructorDecl>(C->getDefinition()))
+ reorderFieldsInConstructor(cast<const CXXConstructorDecl>(D),
+ NewFieldsOrder, Context, Replacements);
+
+ // We only need to reorder init list expressions for
+ // plain C structs or C++ aggregate types.
+ // For other types the order of constructor parameters is used,
+ // which we don't change at the moment.
+ // Now (v0) partial initialization is not supported.
+ if (!CXXRD || CXXRD->isAggregate())
+ for (auto Result :
+ match(initListExpr(hasType(equalsNode(RD))).bind("initListExpr"),
+ Context))
+ if (!reorderFieldsInInitListExpr(
+ Result.getNodeAs<InitListExpr>("initListExpr"), NewFieldsOrder,
+ Context, Replacements)) {
+ Replacements.clear();
+ return;
+ }
+ }
+};
+} // end anonymous namespace
+
+std::unique_ptr<ASTConsumer> ReorderFieldsAction::newASTConsumer() {
+ return llvm::make_unique<ReorderingConsumer>(RecordName, DesiredFieldsOrder,
+ Replacements);
+}
+
+} // namespace reorder_fields
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.h b/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.h
new file mode 100644
index 0000000..f08c632
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.h
@@ -0,0 +1,47 @@
+//===-- tools/extra/clang-reorder-fields/ReorderFieldsAction.h -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declarations of the ReorderFieldsAction class and
+/// the FieldPosition struct.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_ACTION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_ACTION_H
+
+#include "clang/Tooling/Refactoring.h"
+
+namespace clang {
+class ASTConsumer;
+
+namespace reorder_fields {
+
+class ReorderFieldsAction {
+ llvm::StringRef RecordName;
+ llvm::ArrayRef<std::string> DesiredFieldsOrder;
+ std::map<std::string, tooling::Replacements> &Replacements;
+
+public:
+ ReorderFieldsAction(
+ llvm::StringRef RecordName,
+ llvm::ArrayRef<std::string> DesiredFieldsOrder,
+ std::map<std::string, tooling::Replacements> &Replacements)
+ : RecordName(RecordName), DesiredFieldsOrder(DesiredFieldsOrder),
+ Replacements(Replacements) {}
+
+ ReorderFieldsAction(const ReorderFieldsAction &) = delete;
+ ReorderFieldsAction &operator=(const ReorderFieldsAction &) = delete;
+
+ std::unique_ptr<ASTConsumer> newASTConsumer();
+};
+} // namespace reorder_fields
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_ACTION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/tool/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/tool/CMakeLists.txt
new file mode 100644
index 0000000..2de2cec
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/tool/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_clang_tool(clang-reorder-fields ClangReorderFields.cpp)
+
+target_link_libraries(clang-reorder-fields
+ PRIVATE
+ clangBasic
+ clangFrontend
+ clangReorderFields
+ clangRewrite
+ clangTooling
+ clangToolingCore
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
new file mode 100644
index 0000000..077e55e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
@@ -0,0 +1,88 @@
+//===-- tools/extra/clang-reorder-fields/tool/ClangReorderFields.cpp -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the implementation of clang-reorder-fields tool
+///
+//===----------------------------------------------------------------------===//
+
+#include "../ReorderFieldsAction.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include <cstdlib>
+#include <string>
+#include <system_error>
+
+using namespace llvm;
+using namespace clang;
+
+cl::OptionCategory ClangReorderFieldsCategory("clang-reorder-fields options");
+
+static cl::opt<std::string>
+ RecordName("record-name", cl::Required,
+ cl::desc("The name of the struct/class."),
+ cl::cat(ClangReorderFieldsCategory));
+
+static cl::list<std::string> FieldsOrder("fields-order", cl::CommaSeparated,
+ cl::OneOrMore,
+ cl::desc("The desired fields order."),
+ cl::cat(ClangReorderFieldsCategory));
+
+static cl::opt<bool> Inplace("i", cl::desc("Overwrite edited files."),
+ cl::cat(ClangReorderFieldsCategory));
+
+const char Usage[] = "A tool to reorder fields in C/C++ structs/classes.\n";
+
+int main(int argc, const char **argv) {
+ tooling::CommonOptionsParser OP(argc, argv, ClangReorderFieldsCategory,
+ Usage);
+
+ auto Files = OP.getSourcePathList();
+ tooling::RefactoringTool Tool(OP.getCompilations(), Files);
+
+ reorder_fields::ReorderFieldsAction Action(RecordName, FieldsOrder,
+ Tool.getReplacements());
+
+ auto Factory = tooling::newFrontendActionFactory(&Action);
+
+ if (Inplace)
+ return Tool.runAndSave(Factory.get());
+
+ int ExitCode = Tool.run(Factory.get());
+ LangOptions DefaultLangOptions;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+ TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+ &DiagnosticPrinter, false);
+
+ auto &FileMgr = Tool.getFiles();
+ SourceManager Sources(Diagnostics, FileMgr);
+ Rewriter Rewrite(Sources, DefaultLangOptions);
+ Tool.applyAllReplacements(Rewrite);
+
+ for (const auto &File : Files) {
+ const auto *Entry = FileMgr.getFile(File);
+ const auto ID = Sources.getOrCreateFileID(Entry, SrcMgr::C_User);
+ Rewrite.getEditBuffer(ID).write(outs());
+ }
+
+ return ExitCode;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/CMakeLists.txt
new file mode 100644
index 0000000..96381bd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/CMakeLists.txt
@@ -0,0 +1,28 @@
+option(BUILD_CLANG_TIDY_VS_PLUGIN "Build clang-tidy VS plugin" OFF)
+if (BUILD_CLANG_TIDY_VS_PLUGIN)
+ add_custom_target(clang_tidy_exe_for_vsix
+ ${CMAKE_COMMAND} -E copy_if_different
+ "${LLVM_TOOLS_BINARY_DIR}/clang-tidy.exe"
+ "${CMAKE_CURRENT_SOURCE_DIR}/ClangTidy/clang-tidy.exe"
+ DEPENDS clang-tidy)
+
+ add_custom_target(clang_tidy_license
+ ${CMAKE_COMMAND} -E copy_if_different
+ "${CLANG_SOURCE_DIR}/LICENSE.TXT"
+ "${CMAKE_CURRENT_SOURCE_DIR}/ClangTidy/license.txt")
+
+ if (NOT CLANG_TIDY_VS_VERSION)
+ set(CLANG_TIDY_VS_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}")
+ endif()
+
+ configure_file("source.extension.vsixmanifest.in"
+ "${CMAKE_CURRENT_SOURCE_DIR}/ClangTidy/source.extension.vsixmanifest")
+
+ add_custom_target(clang_tidy_vsix ALL
+ devenv "${CMAKE_CURRENT_SOURCE_DIR}/ClangTidy.sln" /Build Release
+ DEPENDS clang_tidy_exe_for_vsix "${CMAKE_CURRENT_SOURCE_DIR}/ClangTidy/source.extension.vsixmanifest"
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "${CMAKE_CURRENT_SOURCE_DIR}/ClangTidy/bin/Release/ClangTidy.vsix"
+ "${LLVM_TOOLS_BINARY_DIR}/ClangTidy.vsix"
+ DEPENDS clang_tidy_exe_for_vsix clang_tidy_license)
+endif()
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy.sln b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy.sln
new file mode 100644
index 0000000..345eb83
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25123.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClangTidy", "ClangTidy\ClangTidy.csproj", "{BE261DA1-36C6-449A-95C5-4653A549170A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {BE261DA1-36C6-449A-95C5-4653A549170A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BE261DA1-36C6-449A-95C5-4653A549170A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BE261DA1-36C6-449A-95C5-4653A549170A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BE261DA1-36C6-449A-95C5-4653A549170A}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/CategoryVerb.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/CategoryVerb.cs
new file mode 100644
index 0000000..ef07a89
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/CategoryVerb.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+ /// <summary>
+ /// Allows entire categories of properties to be enabled, disabled, or inherited
+ /// in one fell swoop. We add properties to each category with the value being
+ /// this enum, and when the value is selected, we use reflection to find all other
+ /// properties in the same category and perform the corresponding action.
+ /// </summary>
+ public enum CategoryVerb
+ {
+ None,
+ Disable,
+ Enable,
+ Inherit
+ }
+
+ public class CategoryVerbConverter : EnumConverter
+ {
+ public CategoryVerbConverter() : base(typeof(CategoryVerb))
+ {
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ if (value is string)
+ {
+ switch ((string)value)
+ {
+ case "Disable Category":
+ return CategoryVerb.Disable;
+ case "Enable Category":
+ return CategoryVerb.Enable;
+ case "Inherit Category":
+ return CategoryVerb.Inherit;
+ case "":
+ return CategoryVerb.None;
+ }
+ }
+ return base.ConvertFrom(context, culture, value);
+ }
+
+ public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
+ {
+ if (value is CategoryVerb && destinationType == typeof(string))
+ {
+ switch ((CategoryVerb)value)
+ {
+ case CategoryVerb.Disable:
+ return "Disable Category";
+ case CategoryVerb.Enable:
+ return "Enable Category";
+ case CategoryVerb.Inherit:
+ return "Inherit Category";
+ case CategoryVerb.None:
+ return String.Empty;
+ }
+ }
+
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/CheckDatabase.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/CheckDatabase.cs
new file mode 100644
index 0000000..6b76688
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/CheckDatabase.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using YamlDotNet.Serialization;
+using YamlDotNet.Serialization.NamingConventions;
+
+namespace LLVM.ClangTidy
+{
+ public class CheckInfo
+ {
+ [YamlAlias("Name")]
+ public string Name { get; set; }
+
+ [YamlAlias("Label")]
+ public string Label { get; set; }
+
+ [YamlAlias("Description")]
+ public string Desc { get; set; }
+
+ [YamlAlias("Category")]
+ public string Category { get; set; }
+ }
+
+ /// <summary>
+ /// Reads the list of checks from Yaml and builds a description of each one.
+ /// This list of checks is then used by the PropertyGrid to determine what
+ /// items to display.
+ /// </summary>
+ public static class CheckDatabase
+ {
+ static CheckInfo[] Checks_ = null;
+
+ class CheckRoot
+ {
+ [YamlAlias("Checks")]
+ public CheckInfo[] Checks { get; set; }
+ }
+
+ static CheckDatabase()
+ {
+ using (StringReader Reader = new StringReader(Resources.ClangTidyChecks))
+ {
+ Deserializer D = new Deserializer(namingConvention: new PascalCaseNamingConvention());
+ var Root = D.Deserialize<CheckRoot>(Reader);
+ Checks_ = Root.Checks;
+
+ HashSet<string> Names = new HashSet<string>();
+ foreach (var Check in Checks_)
+ {
+ if (Names.Contains(Check.Name))
+ continue;
+ Names.Add(Check.Name);
+ }
+ }
+ }
+
+ public static IEnumerable<CheckInfo> Checks
+ {
+ get
+ {
+ return Checks_;
+ }
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/CheckTree.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/CheckTree.cs
new file mode 100644
index 0000000..f3e2583
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/CheckTree.cs
@@ -0,0 +1,273 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+
+namespace LLVM.ClangTidy
+{
+ /// <summary>
+ /// CheckTree is used to group checks into categories and subcategories. For
+ /// example, given the following list of checks:
+ ///
+ /// llvm-include-order
+ /// llvm-namespace-comment
+ /// llvm-twine-local
+ /// llvm-header-guard
+ /// google-runtime-member-string-references
+ /// google-runtime-int
+ /// google-readability-namespace-comments
+ ///
+ /// the corresponding CheckTree would look like this:
+ ///
+ /// llvm
+ /// include-order
+ /// namespace-comment
+ /// twine-local
+ /// header-guard
+ /// google
+ /// runtime
+ /// member-string-references
+ /// int
+ /// readability
+ /// namespace-comments
+ /// redundant-smartptr-get
+ ///
+ /// This is useful when serializing a set of options out to a .clang-tidy file,
+ /// because we need to decide the most efficient way to serialize the sequence
+ /// of check commands, when to use wildcards, etc. For example, if everything
+ /// under google is inherited, we can simply leave that entry out entirely from
+ /// the .clang-tidy file. On the other hand, if anything is inherited, we *must
+ /// not* add or remove google-* by wildcard because that, by definition, means
+ /// the property is no longer inherited. When we can categorize the checks into
+ /// groups and subgroups like this, it is possible to efficiently serialize to
+ /// a minimal representative .clang-tidy file.
+ /// </summary>
+
+ public abstract class CheckTreeNode
+ {
+ private string Name_;
+ private CheckTreeNode Parent_;
+
+ protected CheckTreeNode(string Name, CheckTreeNode Parent)
+ {
+ Name_ = Name;
+ Parent_ = Parent;
+ }
+
+ public string Path
+ {
+ get
+ {
+ if (Parent_ == null)
+ return null;
+ string ParentPath = Parent_.Path;
+ if (ParentPath == null)
+ return Name_;
+ return ParentPath + "-" + Name_;
+ }
+ }
+
+ public string Name
+ {
+ get
+ {
+ return Name_;
+ }
+ }
+
+
+ public abstract int CountChecks { get; }
+ public abstract int CountExplicitlyDisabledChecks { get; }
+ public abstract int CountExplicitlyEnabledChecks { get; }
+ public abstract int CountInheritedChecks { get; }
+ }
+
+ public class CheckTree : CheckTreeNode
+ {
+ private Dictionary<string, CheckTreeNode> Children_ = new Dictionary<string, CheckTreeNode>();
+ public CheckTree()
+ : base(null, null)
+ {
+
+ }
+
+ private CheckTree(string Name, CheckTree Parent)
+ : base(Name, Parent)
+ {
+ }
+
+ private void AddLeaf(string Name, DynamicPropertyDescriptor<bool> Property)
+ {
+ Children_[Name] = new CheckLeaf(Name, this, Property);
+ }
+
+ private CheckTree AddOrCreateSubgroup(string Name)
+ {
+ CheckTreeNode Subgroup = null;
+ if (Children_.TryGetValue(Name, out Subgroup))
+ {
+ System.Diagnostics.Debug.Assert(Subgroup is CheckTree);
+ return (CheckTree)Subgroup;
+ }
+
+ CheckTree SG = new CheckTree(Name, this);
+ Children_[Name] = SG;
+ return SG;
+ }
+
+ public static CheckTree Build(ClangTidyProperties Config)
+ {
+ // Since some check names contain dashes in them, it doesn't make sense to
+ // simply split all check names by dash and construct a huge tree. For
+ // example, in the check called google-runtime-member-string-references,
+ // we don't need each of those to be a different subgroup. So instead we
+ // explicitly specify the common breaking points at which a user might want
+ // to use a -* and everything else falls as a leaf under one of these
+ // categories.
+ // FIXME: This should be configurable without recompilation
+ CheckTree Root = new CheckTree();
+ string[][] Groups = new string[][] {
+ new string[] {"boost"},
+ new string[] {"cert"},
+ new string[] {"clang", "diagnostic"},
+ new string[] {"cppcoreguidelines", "interfaces"},
+ new string[] {"cppcoreguidelines", "pro", "bounds"},
+ new string[] {"cppcoreguidelines", "pro", "type"},
+ new string[] {"google", "build"},
+ new string[] {"google", "readability"},
+ new string[] {"google", "runtime"},
+ new string[] {"llvm"},
+ new string[] {"misc"},
+ };
+
+ foreach (string[] Group in Groups)
+ {
+ CheckTree Subgroup = Root;
+ foreach (string Component in Group)
+ Subgroup = Subgroup.AddOrCreateSubgroup(Component);
+ }
+
+ var Props = Config.GetProperties()
+ .Cast<PropertyDescriptor>()
+ .OfType<DynamicPropertyDescriptor<bool>>()
+ .Where(x => x.Attributes.OfType<ClangTidyCheckAttribute>().Count() > 0)
+ .Select(x => new KeyValuePair<DynamicPropertyDescriptor<bool>, string>(
+ x, x.Attributes.OfType<ClangTidyCheckAttribute>().First().CheckName));
+ var PropArray = Props.ToArray();
+ foreach (var CheckInfo in PropArray)
+ {
+ string LeafName = null;
+ CheckTree Tree = Root.LocateCheckLeafGroup(CheckInfo.Value, out LeafName);
+ Tree.AddLeaf(LeafName, CheckInfo.Key);
+ }
+ return Root;
+ }
+
+ private CheckTree LocateCheckLeafGroup(string Check, out string LeafName)
+ {
+ string[] Components = Check.Split('-');
+ string FirstComponent = Components.FirstOrDefault();
+ if (FirstComponent == null)
+ {
+ LeafName = Check;
+ return this;
+ }
+
+ CheckTreeNode Subgroup = null;
+ if (!Children_.TryGetValue(FirstComponent, out Subgroup))
+ {
+ LeafName = Check;
+ return this;
+ }
+ System.Diagnostics.Debug.Assert(Subgroup is CheckTree);
+ CheckTree Child = (CheckTree)Subgroup;
+ string ChildName = Check.Substring(FirstComponent.Length + 1);
+ return Child.LocateCheckLeafGroup(ChildName, out LeafName);
+ }
+
+ public override int CountChecks
+ {
+ get
+ {
+ return Children_.Aggregate(0, (X, V) => { return X + V.Value.CountChecks; });
+ }
+ }
+
+ public override int CountExplicitlyDisabledChecks
+ {
+ get
+ {
+ return Children_.Aggregate(0, (X, V) => { return X + V.Value.CountExplicitlyDisabledChecks; });
+ }
+ }
+
+ public override int CountExplicitlyEnabledChecks
+ {
+ get
+ {
+ return Children_.Aggregate(0, (X, V) => { return X + V.Value.CountExplicitlyEnabledChecks; });
+ }
+ }
+ public override int CountInheritedChecks
+ {
+ get
+ {
+ return Children_.Aggregate(0, (X, V) => { return X + V.Value.CountInheritedChecks; });
+ }
+ }
+
+ public IDictionary<string, CheckTreeNode> Children
+ {
+ get { return Children_; }
+ }
+ }
+
+ public class CheckLeaf : CheckTreeNode
+ {
+ private DynamicPropertyDescriptor<bool> Property_;
+
+ public CheckLeaf(string Name, CheckTree Parent, DynamicPropertyDescriptor<bool> Property)
+ : base(Name, Parent)
+ {
+ Property_ = Property;
+ }
+
+ public override int CountChecks
+ {
+ get
+ {
+ return 1;
+ }
+ }
+
+ public override int CountExplicitlyDisabledChecks
+ {
+ get
+ {
+ if (Property_.IsInheriting)
+ return 0;
+ return (bool)Property_.GetValue(null) ? 0 : 1;
+ }
+ }
+
+ public override int CountExplicitlyEnabledChecks
+ {
+ get
+ {
+ if (Property_.IsInheriting)
+ return 0;
+ return (bool)Property_.GetValue(null) ? 1 : 0;
+ }
+ }
+
+ public override int CountInheritedChecks
+ {
+ get
+ {
+ return (Property_.IsInheriting) ? 1 : 0;
+ }
+ }
+
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidy.csproj b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidy.csproj
new file mode 100644
index 0000000..bf74717
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidy.csproj
@@ -0,0 +1,267 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{BE261DA1-36C6-449A-95C5-4653A549170A}</ProjectGuid>
+ <ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>LLVM.ClangTidy</RootNamespace>
+ <AssemblyName>ClangTidy</AssemblyName>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>Key.snk</AssemblyOriginatorKeyFile>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <OldToolsVersion>4.0</OldToolsVersion>
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ <TargetFrameworkProfile />
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>0</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <RunCodeAnalysis>true</RunCodeAnalysis>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="Microsoft.VisualStudio.CoreUtility, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+ <Reference Include="Microsoft.VisualStudio.Editor, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+ <Reference Include="Microsoft.VisualStudio.OLE.Interop" />
+ <Reference Include="Microsoft.VisualStudio.Settings.14.0, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=x86" />
+ <Reference Include="Microsoft.VisualStudio.Shell.14.0, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+ <Reference Include="Microsoft.VisualStudio.Shell.Immutable.10.0, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+ <Reference Include="Microsoft.VisualStudio.Shell.Immutable.14.0, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+ <Reference Include="Microsoft.VisualStudio.Shell.Interop" />
+ <Reference Include="Microsoft.VisualStudio.TextManager.Interop" />
+ <Reference Include="Microsoft.VisualStudio.TextManager.Interop" />
+ <Reference Include="Microsoft.VisualStudio.Utilities, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Design" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="YamlDotNet, Version=3.3.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\packages\YamlDotNet.3.3.0\lib\net35\YamlDotNet.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="YamlDotNet.Dynamic, Version=3.2.0.0, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\packages\YamlDotNet.Dynamic.3.2.3\lib\net40\YamlDotNet.Dynamic.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <COMReference Include="EnvDTE">
+ <Guid>{80CC9F66-E7D8-4DDD-85B6-D9E6CD0E93E2}</Guid>
+ <VersionMajor>8</VersionMajor>
+ <VersionMinor>0</VersionMinor>
+ <Lcid>0</Lcid>
+ <WrapperTool>primary</WrapperTool>
+ <Isolated>False</Isolated>
+ <EmbedInteropTypes>False</EmbedInteropTypes>
+ </COMReference>
+ <COMReference Include="EnvDTE100">
+ <Guid>{26AD1324-4B7C-44BC-84F8-B86AED45729F}</Guid>
+ <VersionMajor>10</VersionMajor>
+ <VersionMinor>0</VersionMinor>
+ <Lcid>0</Lcid>
+ <WrapperTool>primary</WrapperTool>
+ <Isolated>False</Isolated>
+ <EmbedInteropTypes>False</EmbedInteropTypes>
+ </COMReference>
+ <COMReference Include="EnvDTE80">
+ <Guid>{1A31287A-4D7D-413E-8E32-3B374931BD89}</Guid>
+ <VersionMajor>8</VersionMajor>
+ <VersionMinor>0</VersionMinor>
+ <Lcid>0</Lcid>
+ <WrapperTool>primary</WrapperTool>
+ <Isolated>False</Isolated>
+ <EmbedInteropTypes>False</EmbedInteropTypes>
+ </COMReference>
+ <COMReference Include="EnvDTE90">
+ <Guid>{2CE2370E-D744-4936-A090-3FFFE667B0E1}</Guid>
+ <VersionMajor>9</VersionMajor>
+ <VersionMinor>0</VersionMinor>
+ <Lcid>0</Lcid>
+ <WrapperTool>primary</WrapperTool>
+ <Isolated>False</Isolated>
+ <EmbedInteropTypes>False</EmbedInteropTypes>
+ </COMReference>
+ <COMReference Include="Microsoft.VisualStudio.CommandBars">
+ <Guid>{1CBA492E-7263-47BB-87FE-639000619B15}</Guid>
+ <VersionMajor>8</VersionMajor>
+ <VersionMinor>0</VersionMinor>
+ <Lcid>0</Lcid>
+ <WrapperTool>primary</WrapperTool>
+ <Isolated>False</Isolated>
+ <EmbedInteropTypes>False</EmbedInteropTypes>
+ </COMReference>
+ <COMReference Include="stdole">
+ <Guid>{00020430-0000-0000-C000-000000000046}</Guid>
+ <VersionMajor>2</VersionMajor>
+ <VersionMinor>0</VersionMinor>
+ <Lcid>0</Lcid>
+ <WrapperTool>primary</WrapperTool>
+ <Isolated>False</Isolated>
+ <EmbedInteropTypes>False</EmbedInteropTypes>
+ </COMReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="CategoryVerb.cs" />
+ <Compile Include="CheckDatabase.cs" />
+ <Compile Include="CheckTree.cs" />
+ <Compile Include="ClangTidyCheckAttribute.cs" />
+ <Compile Include="ClangTidyConfigurationPage.cs">
+ <SubType>Component</SubType>
+ </Compile>
+ <Compile Include="ClangTidyProperties.cs">
+ <SubType>Component</SubType>
+ </Compile>
+ <Compile Include="DynamicPropertyConverter.cs" />
+ <Compile Include="DynamicPropertyDescriptor.cs" />
+ <Compile Include="ForwardingPropertyDescriptor.cs" />
+ <Compile Include="Guids.cs" />
+ <Compile Include="DynamicPropertyComponent.cs">
+ <SubType>Component</SubType>
+ </Compile>
+ <Compile Include="DynamicPropertyComponent.Designer.cs" />
+ <Compile Include="ClangTidyConfigParser.cs" />
+ <Compile Include="Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
+ <Compile Include="GlobalSuppressions.cs" />
+ <Compile Include="ClangTidyPackage.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="PkgCmdID.cs" />
+ <Compile Include="ClangTidyPropertyGrid.cs">
+ <SubType>UserControl</SubType>
+ </Compile>
+ <Compile Include="ClangTidyPropertyGrid.Designer.cs">
+ <DependentUpon>ClangTidyPropertyGrid.cs</DependentUpon>
+ </Compile>
+ <Compile Include="Utility.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ <SubType>Designer</SubType>
+ </EmbeddedResource>
+ <EmbeddedResource Include="ClangTidyPropertyGrid.resx">
+ <DependentUpon>ClangTidyPropertyGrid.cs</DependentUpon>
+ </EmbeddedResource>
+ <EmbeddedResource Include="VSPackage.resx">
+ <MergeWithCTO>true</MergeWithCTO>
+ <ManifestResourceName>VSPackage</ManifestResourceName>
+ </EmbeddedResource>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Key.snk" />
+ <None Include="packages.config" />
+ <None Include="Resources\ClangTidyChecks.yaml" />
+ <None Include="source.extension.vsixmanifest">
+ <SubType>Designer</SubType>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <VSCTCompile Include="ClangTidy.vsct">
+ <ResourceName>Menus.ctmenu</ResourceName>
+ <SubType>Designer</SubType>
+ </VSCTCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Resources\Images_32bit.bmp" />
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="clang-tidy.exe">
+ <IncludeInVSIX>true</IncludeInVSIX>
+ </Content>
+ <Content Include="license.txt">
+ <IncludeInVSIX>true</IncludeInVSIX>
+ </Content>
+ <Content Include="Resources\Package.ico" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include=".NETFramework,Version=v4.0">
+ <Visible>False</Visible>
+ <ProductName>Microsoft .NET Framework 4 %28x86 and x64%29</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Windows.Installer.4.5">
+ <Visible>False</Visible>
+ <ProductName>Windows Installer 4.5</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <PropertyGroup>
+ <UseCodebase>true</UseCodebase>
+ </PropertyGroup>
+ <PropertyGroup>
+ <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
+ <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+ </PropertyGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
+ <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\VSSDK\Microsoft.VsSDK.targets" Condition="false" />
+ <PropertyGroup>
+ <PreBuildEvent>if not exist $(ProjectDir)Key.snk ("$(SDKToolsPath)\sn.exe" -k $(ProjectDir)Key.snk)</PreBuildEvent>
+ </PropertyGroup>
+ <Target Name="BeforeBuild">
+ <Exec ContinueOnError="false" Command=""..\packages\Brutal.Dev.StrongNameSigner.1.8.0\tools\StrongNameSigner.Console.exe" -in "..\packages" -l Summary" />
+ </Target>
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidy.vsct b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidy.vsct
new file mode 100644
index 0000000..8bdaeec
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidy.vsct
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?>
+<CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+ <!-- This is the file that defines the actual layout and type of the commands.
+ It is divided in different sections (e.g. command definition, command
+ placement, ...), with each defining a specific set of properties.
+ See the comment before each section for more details about how to
+ use it. -->
+
+ <!-- The VSCT compiler (the tool that translates this file into the binary
+ format that VisualStudio will consume) has the ability to run a preprocessor
+ on the vsct file; this preprocessor is (usually) the C++ preprocessor, so
+ it is possible to define includes and macros with the same syntax used
+ in C++ files. Using this ability of the compiler here, we include some files
+ defining some of the constants that we will use inside the file. -->
+
+ <!--This is the file that defines the IDs for all the commands exposed by VisualStudio. -->
+ <Extern href="stdidcmd.h"/>
+
+ <!--This header contains the command ids for the menus provided by the shell. -->
+ <Extern href="vsshlids.h"/>
+
+
+
+
+ <!--The Commands section is where we the commands, menus and menu groups are defined.
+ This section uses a Guid to identify the package that provides the command defined inside it. -->
+ <Commands package="guidClangTidyPkg">
+ <!-- Inside this section we have different sub-sections: one for the menus, another
+ for the menu groups, one for the buttons (the actual commands), one for the combos
+ and the last one for the bitmaps used. Each element is identified by a command id that
+ is a unique pair of guid and numeric identifier; the guid part of the identifier is usually
+ called "command set" and is used to group different command inside a logically related
+ group; your package should define its own command set in order to avoid collisions
+ with command ids defined by other packages. -->
+
+
+ <!-- In this section you can define new menu groups. A menu group is a container for
+ other menus or buttons (commands); from a visual point of view you can see the
+ group as the part of a menu contained between two lines. The parent of a group
+ must be a menu. -->
+ <Groups>
+
+ <Group guid="guidClangTidyCmdSet" id="MyMenuGroup" priority="0x0600">
+ <Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
+ </Group>
+
+
+
+ </Groups>
+
+ <!--Buttons section. -->
+ <!--This section defines the elements the user can interact with, like a menu command or a button
+ or combo box in a toolbar. -->
+ <Buttons>
+ <!--To define a menu group you have to specify its ID, the parent menu and its display priority.
+ The command is visible and enabled by default. If you need to change the visibility, status, etc, you can use
+ the CommandFlag node.
+ You can add more than one CommandFlag node e.g.:
+ <CommandFlag>DefaultInvisible</CommandFlag>
+ <CommandFlag>DynamicVisibility</CommandFlag>
+ If you do not want an image next to your command, remove the Icon node /> -->
+
+ <Button guid="guidClangTidyCmdSet" id="cmdidClangTidy" priority="0x0100" type="Button">
+ <Parent guid="guidClangTidyCmdSet" id="MyMenuGroup" />
+ <Icon guid="guidImages" id="bmpPic1" />
+ <Strings>
+ <ButtonText>ClangTidy</ButtonText>
+ </Strings>
+ </Button>
+
+
+
+ </Buttons>
+
+ <!--The bitmaps section is used to define the bitmaps that are used for the commands.-->
+ <Bitmaps>
+ <!-- The bitmap id is defined in a way that is a little bit different from the others:
+ the declaration starts with a guid for the bitmap strip, then there is the resource id of the
+ bitmap strip containing the bitmaps and then there are the numeric ids of the elements used
+ inside a button definition. An important aspect of this declaration is that the element id
+ must be the actual index (1-based) of the bitmap inside the bitmap strip. -->
+ <Bitmap guid="guidImages" href="Resources\Images_32bit.bmp" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/>
+
+ </Bitmaps>
+
+ </Commands>
+
+
+ <KeyBindings>
+ <KeyBinding guid="guidClangTidyCmdSet" id="cmdidClangTidy" editor="guidTextEditor" key1="R" mod1="Control" key2="T" mod2="Control"/>
+ </KeyBindings>
+
+
+
+ <Symbols>
+ <!-- This is the package guid. -->
+ <GuidSymbol name="guidClangTidyPkg" value="{AE4956BE-3DB8-430E-BBAB-7E2E9A014E9C}" />
+
+ <!-- This is the guid used to group the menu commands together -->
+ <GuidSymbol name="guidClangTidyCmdSet" value="{9E0F0493-6493-46DE-AEE1-ACD8F60F265E}">
+ <IDSymbol name="MyMenuGroup" value="0x1020" />
+ <IDSymbol name="cmdidClangTidy" value="0x0100" />
+ </GuidSymbol>
+
+ <GuidSymbol name="guidTextEditor" value="{E10FAD35-7FB8-4991-A269-EF88F12166C9}" />
+
+
+ <GuidSymbol name="guidImages" value="{942F126F-942D-428A-84B4-4AC7C523D0B2}" >
+ <IDSymbol name="bmpPic1" value="1" />
+ <IDSymbol name="bmpPic2" value="2" />
+ <IDSymbol name="bmpPicSearch" value="3" />
+ <IDSymbol name="bmpPicX" value="4" />
+ <IDSymbol name="bmpPicArrows" value="5" />
+ </GuidSymbol>
+ </Symbols>
+
+</CommandTable>
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyCheckAttribute.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyCheckAttribute.cs
new file mode 100644
index 0000000..59234d7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyCheckAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+ public class ClangTidyCheckAttribute : Attribute
+ {
+ private string CheckName_;
+ public ClangTidyCheckAttribute(string CheckName)
+ {
+ this.CheckName_ = CheckName;
+ }
+
+ public string CheckName
+ {
+ get { return CheckName_; }
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyConfigParser.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyConfigParser.cs
new file mode 100644
index 0000000..db5b055
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyConfigParser.cs
@@ -0,0 +1,214 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using YamlDotNet.Serialization;
+using YamlDotNet.Serialization.NamingConventions;
+
+namespace LLVM.ClangTidy
+{
+ static class ClangTidyConfigParser
+ {
+ public class CheckOption
+ {
+ [YamlAlias("key")]
+ public string Key { get; set; }
+
+ [YamlAlias("value")]
+ public string Value { get; set; }
+ }
+ public class ClangTidyYaml
+ {
+ [YamlAlias("Checks")]
+ public string Checks { get; set; }
+
+ [YamlAlias("CheckOptions")]
+ public List<CheckOption> CheckOptions { get; set; }
+ }
+
+ public static List<KeyValuePair<string, ClangTidyProperties>> ParseConfigurationChain(string ClangTidyFile)
+ {
+ List<KeyValuePair<string, ClangTidyProperties>> Result = new List<KeyValuePair<string, ClangTidyProperties>>();
+ Result.Add(new KeyValuePair<string, ClangTidyProperties>(null, ClangTidyProperties.RootProperties));
+
+ foreach (string P in Utility.SplitPath(ClangTidyFile).Reverse())
+ {
+ if (!Utility.HasClangTidyFile(P))
+ continue;
+
+ string ConfigFile = Path.Combine(P, ".clang-tidy");
+
+ using (StreamReader Reader = new StreamReader(ConfigFile))
+ {
+ Deserializer D = new Deserializer(namingConvention: new PascalCaseNamingConvention());
+ ClangTidyYaml Y = D.Deserialize<ClangTidyYaml>(Reader);
+ ClangTidyProperties Parent = Result[Result.Count - 1].Value;
+ ClangTidyProperties NewProps = new ClangTidyProperties(Parent);
+ SetPropertiesFromYaml(Y, NewProps);
+ Result.Add(new KeyValuePair<string, ClangTidyProperties>(P, NewProps));
+ }
+ }
+ return Result;
+ }
+
+ enum TreeLevelOp
+ {
+ Enable,
+ Disable,
+ Inherit
+ }
+
+ public static void SerializeClangTidyFile(ClangTidyProperties Props, string ClangTidyFilePath)
+ {
+ List<string> CommandList = new List<string>();
+ SerializeCheckTree(CommandList, Props.GetCheckTree(), TreeLevelOp.Inherit);
+
+ CommandList.Sort((x, y) =>
+ {
+ bool LeftSub = x.StartsWith("-");
+ bool RightSub = y.StartsWith("-");
+ if (LeftSub && !RightSub)
+ return -1;
+ if (RightSub && !LeftSub)
+ return 1;
+ return StringComparer.CurrentCulture.Compare(x, y);
+ });
+
+ string ConfigFile = Path.Combine(ClangTidyFilePath, ".clang-tidy");
+ using (StreamWriter Writer = new StreamWriter(ConfigFile))
+ {
+ Serializer S = new Serializer(namingConvention: new PascalCaseNamingConvention());
+ ClangTidyYaml Yaml = new ClangTidyYaml();
+ Yaml.Checks = String.Join(",", CommandList.ToArray());
+ S.Serialize(Writer, Yaml);
+ }
+ }
+
+ /// <summary>
+ /// Convert the given check tree into serialized list of commands that can be written to
+ /// the Yaml. The goal here is to determine the minimal sequence of check commands that
+ /// will produce the exact configuration displayed in the UI. This is complicated by the
+ /// fact that an inherited True is not the same as an explicitly specified True. If the
+ /// user has chosen to inherit a setting in a .clang-tidy file, then changing it in the
+ /// parent should show the reflected changes in the current file as well. So we cannot
+ /// simply -* everything and then add in the checks we need, because -* immediately marks
+ /// every single check as explicitly false, thus disabling inheritance.
+ /// </summary>
+ /// <param name="CommandList">State passed through this recursive algorithm representing
+ /// the sequence of commands we have determined so far.
+ /// </param>
+ /// <param name="Tree">The check tree to serialize. This is the parameter that will be
+ /// recursed on as successive subtrees get serialized to `CommandList`.
+ /// </param>
+ /// <param name="CurrentOp">The current state of the subtree. For example, if the
+ /// algorithm decides to -* an entire subtree and then add back one single check,
+ /// after adding a -subtree-* command to CommandList, it would pass in a value of
+ /// CurrentOp=TreeLevelOp.Disable when it recurses down. This allows deeper iterations
+ /// of the algorithm to know what kind of command (if any) needs to be added to CommandList
+ /// in order to put a particular check into a particular state.
+ /// </param>
+ private static void SerializeCheckTree(List<string> CommandList, CheckTree Tree, TreeLevelOp CurrentOp)
+ {
+ int NumChecks = Tree.CountChecks;
+ int NumDisabled = Tree.CountExplicitlyDisabledChecks;
+ int NumEnabled = Tree.CountExplicitlyEnabledChecks;
+ int NumInherited = Tree.CountInheritedChecks;
+
+ if (NumChecks == 0)
+ return;
+
+ if (NumInherited > 0)
+ System.Diagnostics.Debug.Assert(CurrentOp == TreeLevelOp.Inherit);
+
+ // If this entire tree is inherited, just exit, nothing about this needs to
+ // go in the clang-tidy file.
+ if (NumInherited == NumChecks)
+ return;
+
+ TreeLevelOp NewOp = CurrentOp;
+ // If there are no inherited properties in this subtree, decide whether to
+ // explicitly enable or disable this subtree. Decide by looking at whether
+ // there is a larger proportion of disabled or enabled descendants. If
+ // there are more disabled items in this subtree for example, disabling the
+ // subtree will lead to a smaller configuration file.
+ if (NumInherited == 0)
+ {
+ if (NumDisabled >= NumEnabled)
+ NewOp = TreeLevelOp.Disable;
+ else
+ NewOp = TreeLevelOp.Enable;
+ }
+
+ if (NewOp == TreeLevelOp.Disable)
+ {
+ // Only add an explicit disable command if the tree was not already disabled
+ // to begin with.
+ if (CurrentOp != TreeLevelOp.Disable)
+ {
+ string WildcardPath = "*";
+ if (Tree.Path != null)
+ WildcardPath = Tree.Path + "-" + WildcardPath;
+ CommandList.Add("-" + WildcardPath);
+ }
+ // If the entire subtree was disabled, there's no point descending.
+ if (NumDisabled == NumChecks)
+ return;
+ }
+ else if (NewOp == TreeLevelOp.Enable)
+ {
+ // Only add an explicit enable command if the tree was not already enabled
+ // to begin with. Note that if we're at the root, all checks are already
+ // enabled by default, so there's no need to explicitly include *
+ if (CurrentOp != TreeLevelOp.Enable && Tree.Path != null)
+ {
+ string WildcardPath = Tree.Path + "-*";
+ CommandList.Add(WildcardPath);
+ }
+ // If the entire subtree was enabled, there's no point descending.
+ if (NumEnabled == NumChecks)
+ return;
+ }
+
+ foreach (var Child in Tree.Children)
+ {
+ if (Child.Value is CheckLeaf)
+ {
+ CheckLeaf Leaf = (CheckLeaf)Child.Value;
+ if (Leaf.CountExplicitlyEnabledChecks == 1 && NewOp != TreeLevelOp.Enable)
+ CommandList.Add(Leaf.Path);
+ else if (Leaf.CountExplicitlyDisabledChecks == 1 && NewOp != TreeLevelOp.Disable)
+ CommandList.Add("-" + Leaf.Path);
+ continue;
+ }
+
+ System.Diagnostics.Debug.Assert(Child.Value is CheckTree);
+ CheckTree ChildTree = (CheckTree)Child.Value;
+ SerializeCheckTree(CommandList, ChildTree, NewOp);
+ }
+ }
+
+ private static void SetPropertiesFromYaml(ClangTidyYaml Yaml, ClangTidyProperties Props)
+ {
+ string[] CheckCommands = Yaml.Checks.Split(',');
+ foreach (string Command in CheckCommands)
+ {
+ if (Command == null || Command.Length == 0)
+ continue;
+ bool Add = true;
+ string Pattern = Command;
+ if (Pattern[0] == '-')
+ {
+ Pattern = Pattern.Substring(1);
+ Add = false;
+ }
+
+ foreach (var Match in CheckDatabase.Checks.Where(x => Utility.MatchWildcardString(x.Name, Pattern)))
+ {
+ Props.SetDynamicValue(Match.Name, Add);
+ }
+ }
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyConfigurationPage.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyConfigurationPage.cs
new file mode 100644
index 0000000..0f7a8e9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyConfigurationPage.cs
@@ -0,0 +1,61 @@
+using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace LLVM.ClangTidy
+{
+ [ClassInterface(ClassInterfaceType.AutoDual)]
+ [CLSCompliant(false), ComVisible(true)]
+ public class ClangTidyConfigurationPage : DialogPage
+ {
+ ClangTidyPropertyGrid Grid = null;
+ protected override IWin32Window Window
+ {
+ get
+ {
+ if (Grid == null)
+ Grid = new ClangTidyPropertyGrid();
+ return Grid;
+ }
+ }
+
+ protected override void SaveSetting(PropertyDescriptor property)
+ {
+ base.SaveSetting(property);
+ }
+
+ public override void SaveSettingsToStorage()
+ {
+ if (Grid != null)
+ Grid.SaveSettingsToStorage();
+
+ base.SaveSettingsToStorage();
+ }
+
+ public override void ResetSettings()
+ {
+ base.ResetSettings();
+ }
+
+ protected override void LoadSettingFromStorage(PropertyDescriptor prop)
+ {
+ base.LoadSettingFromStorage(prop);
+ }
+
+ public override void LoadSettingsFromStorage()
+ {
+ if (Grid != null)
+ Grid.InitializeSettings();
+ base.LoadSettingsFromStorage();
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyPackage.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyPackage.cs
new file mode 100644
index 0000000..9a0c9b6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyPackage.cs
@@ -0,0 +1,56 @@
+//===-- ClangTidyPackages.cs - VSPackage for clang-tidy ----------*- C# -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class contains a VS extension package that runs clang-tidy over a
+// file in a VS text editor.
+//
+//===----------------------------------------------------------------------===//
+
+using Microsoft.VisualStudio.Editor;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.TextManager.Interop;
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.ComponentModel.Design;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+using System.Xml.Linq;
+
+namespace LLVM.ClangTidy
+{
+ [PackageRegistration(UseManagedResourcesOnly = true)]
+ [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
+ [ProvideMenuResource("Menus.ctmenu", 1)]
+ [Guid(GuidList.guidClangTidyPkgString)]
+ [ProvideOptionPage(typeof(ClangTidyConfigurationPage), "LLVM/Clang", "ClangTidy", 0, 0, true)]
+ public sealed class ClangTidyPackage : Package
+ {
+ #region Package Members
+ protected override void Initialize()
+ {
+ base.Initialize();
+
+ var commandService = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
+ if (commandService != null)
+ {
+ var menuCommandID = new CommandID(GuidList.guidClangTidyCmdSet, (int)PkgCmdIDList.cmdidClangTidy);
+ var menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
+ commandService.AddCommand(menuItem);
+ }
+ }
+ #endregion
+
+ private void MenuItemCallback(object sender, EventArgs args)
+ {
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyProperties.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyProperties.cs
new file mode 100644
index 0000000..c6597c1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyProperties.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+
+ public class ClangTidyProperties : DynamicPropertyComponent
+ {
+ private static ClangTidyProperties RootProperties_ = null;
+ private CheckTree CheckTree_;
+ private bool HasUnsavedChanges_ = false;
+
+ public struct CheckMapping
+ {
+ public string CheckName;
+ public string Property;
+ }
+
+ public ClangTidyProperties()
+ : base(null)
+ {
+ AddClangCheckProperties();
+ CheckTree_ = CheckTree.Build(this);
+ }
+
+ public ClangTidyProperties(DynamicPropertyComponent Parent)
+ : base(Parent)
+ {
+ AddClangCheckProperties();
+ CheckTree_ = CheckTree.Build(this);
+ }
+
+ static ClangTidyProperties()
+ {
+ RootProperties_ = new ClangTidyProperties(null);
+ }
+
+ public static ClangTidyProperties RootProperties
+ {
+ get { return RootProperties_; }
+ }
+
+ private void AddClangCheckProperties()
+ {
+ // Add each check in the check database
+ HashSet<string> Categories = new HashSet<string>();
+ foreach (var Check in CheckDatabase.Checks)
+ {
+ string Name = Check.Name.Replace('-', '_');
+ List<Attribute> Attrs = new List<Attribute>();
+ Attrs.Add(new CategoryAttribute(Check.Category));
+ Attrs.Add(new DisplayNameAttribute(Check.Label));
+ Attrs.Add(new DefaultValueAttribute(true));
+ Attrs.Add(new DescriptionAttribute(Check.Desc));
+ Attrs.Add(new ClangTidyCheckAttribute(Check.Name));
+ Categories.Add(Check.Category);
+ AddDynamicProperty<bool>(Check.Name, Attrs.ToArray());
+ }
+
+ // Add a category verb for each unique category.
+ foreach (string Cat in Categories)
+ {
+ List<Attribute> Attrs = new List<Attribute>();
+ Attrs.Add(new CategoryAttribute(Cat));
+ Attrs.Add(new DisplayNameAttribute("(Category Verbs)"));
+ Attrs.Add(new TypeConverterAttribute(typeof(CategoryVerbConverter)));
+ Attrs.Add(new DefaultValueAttribute(CategoryVerb.None));
+ AddDynamicProperty<CategoryVerb>(Cat + "Verb", Attrs.ToArray());
+ }
+ }
+
+ public CheckTree GetCheckTree() { return CheckTree_; }
+ public bool GetHasUnsavedChanges() { return HasUnsavedChanges_; }
+ public void SetHasUnsavedChanges(bool Value) { HasUnsavedChanges_ = Value; }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.Designer.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.Designer.cs
new file mode 100644
index 0000000..ce9324a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.Designer.cs
@@ -0,0 +1,119 @@
+namespace LLVM.ClangTidy
+{
+ partial class ClangTidyPropertyGrid
+ {
+ /// <summary>
+ /// Required designer variable.
+ /// </summary>
+ private System.ComponentModel.IContainer components = null;
+
+ /// <summary>
+ /// Clean up any resources being used.
+ /// </summary>
+ /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ /// <summary>
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ /// </summary>
+ private void InitializeComponent()
+ {
+ this.label1 = new System.Windows.Forms.Label();
+ this.textBox1 = new System.Windows.Forms.TextBox();
+ this.button1 = new System.Windows.Forms.Button();
+ this.propertyGrid1 = new System.Windows.Forms.PropertyGrid();
+ this.clangTidyProperties1 = new LLVM.ClangTidy.ClangTidyProperties();
+ this.clangTidyConfigurationPage1 = new LLVM.ClangTidy.ClangTidyConfigurationPage();
+ this.linkLabelPath = new System.Windows.Forms.LinkLabel();
+ this.SuspendLayout();
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(14, 17);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(88, 13);
+ this.label1.TabIndex = 0;
+ this.label1.Text = "Configuration File";
+ //
+ // textBox1
+ //
+ this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.textBox1.Location = new System.Drawing.Point(108, 14);
+ this.textBox1.Name = "textBox1";
+ this.textBox1.Size = new System.Drawing.Size(222, 20);
+ this.textBox1.TabIndex = 1;
+ //
+ // button1
+ //
+ this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.button1.Location = new System.Drawing.Point(336, 14);
+ this.button1.Name = "button1";
+ this.button1.Size = new System.Drawing.Size(78, 20);
+ this.button1.TabIndex = 2;
+ this.button1.Text = "Browse";
+ this.button1.UseVisualStyleBackColor = true;
+ this.button1.Click += new System.EventHandler(this.button1_Click);
+ //
+ // propertyGrid1
+ //
+ this.propertyGrid1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.propertyGrid1.Location = new System.Drawing.Point(20, 73);
+ this.propertyGrid1.Name = "propertyGrid1";
+ this.propertyGrid1.SelectedObject = this.clangTidyProperties1;
+ this.propertyGrid1.Size = new System.Drawing.Size(391, 384);
+ this.propertyGrid1.TabIndex = 6;
+ this.propertyGrid1.ViewBorderColor = System.Drawing.SystemColors.ControlDarkDark;
+ this.propertyGrid1.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.propertyGrid1_PropertyValueChanged);
+ //
+ // linkLabelPath
+ //
+ this.linkLabelPath.AutoSize = true;
+ this.linkLabelPath.Location = new System.Drawing.Point(29, 50);
+ this.linkLabelPath.Name = "linkLabelPath";
+ this.linkLabelPath.Size = new System.Drawing.Size(55, 13);
+ this.linkLabelPath.TabIndex = 7;
+ this.linkLabelPath.TabStop = true;
+ this.linkLabelPath.Text = "linkLabel1";
+ this.linkLabelPath.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelPath_LinkClicked);
+ //
+ // ClangTidyPropertyGrid
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.Controls.Add(this.linkLabelPath);
+ this.Controls.Add(this.propertyGrid1);
+ this.Controls.Add(this.button1);
+ this.Controls.Add(this.textBox1);
+ this.Controls.Add(this.label1);
+ this.Name = "ClangTidyPropertyGrid";
+ this.Size = new System.Drawing.Size(444, 469);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.TextBox textBox1;
+ private System.Windows.Forms.Button button1;
+ private System.Windows.Forms.PropertyGrid propertyGrid1;
+ private ClangTidyProperties clangTidyProperties1;
+ private ClangTidyConfigurationPage clangTidyConfigurationPage1;
+ private System.Windows.Forms.LinkLabel linkLabelPath;
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.cs
new file mode 100644
index 0000000..20c8a8f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.cs
@@ -0,0 +1,208 @@
+//===-- ClangTidyPropertyGrid.cs - UI for configuring clang-tidy -*- C# -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class contains a UserControl consisting of a .NET PropertyGrid control
+// allowing configuration of checks and check options for ClangTidy.
+//
+//===----------------------------------------------------------------------===//
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.IO;
+using Microsoft.VisualStudio.Shell;
+
+namespace LLVM.ClangTidy
+{
+ /// <summary>
+ /// A UserControl displaying a PropertyGrid allowing configuration of clang-tidy
+ /// checks and check options, as well as serialization and deserialization of
+ /// clang-tidy configuration files. When a configuration file is loaded, the
+ /// entire chain of configuration files is analyzed based on the file path,
+ /// and quick access is provided to edit or view any of the files in the
+ /// configuration chain, allowing easy visualization of where values come from
+ /// (similar in spirit to the -explain-config option of clang-tidy).
+ /// </summary>
+ public partial class ClangTidyPropertyGrid : UserControl
+ {
+ /// <summary>
+ /// The sequence of .clang-tidy configuration files, starting from the root
+ /// of the filesystem, down to the selected file.
+ /// </summary>
+ List<KeyValuePair<string, ClangTidyProperties>> PropertyChain_ = null;
+
+ public ClangTidyPropertyGrid()
+ {
+ InitializeComponent();
+ InitializeSettings();
+ }
+
+ private enum ShouldCancel
+ {
+ Yes,
+ No,
+ }
+
+ public void SaveSettingsToStorage()
+ {
+ PersistUnsavedChanges(false);
+ }
+
+ private ShouldCancel PersistUnsavedChanges(bool PromptFirst)
+ {
+ var UnsavedResults = PropertyChain_.Where(x => x.Key != null && x.Value.GetHasUnsavedChanges());
+ if (UnsavedResults.Count() == 0)
+ return ShouldCancel.No;
+
+ bool ShouldSave = false;
+ if (PromptFirst)
+ {
+ var Response = MessageBox.Show(
+ "You have unsaved changes! Do you want to save before loading a new file?",
+ "clang-tidy",
+ MessageBoxButtons.YesNoCancel);
+
+ ShouldSave = (Response == DialogResult.Yes);
+ if (Response == DialogResult.Cancel)
+ return ShouldCancel.Yes;
+ }
+ else
+ ShouldSave = true;
+
+ if (ShouldSave)
+ {
+ foreach (var Result in UnsavedResults)
+ {
+ ClangTidyConfigParser.SerializeClangTidyFile(Result.Value, Result.Key);
+ Result.Value.SetHasUnsavedChanges(false);
+ }
+ }
+ return ShouldCancel.No;
+ }
+
+ public void InitializeSettings()
+ {
+ PropertyChain_ = new List<KeyValuePair<string, ClangTidyProperties>>();
+ PropertyChain_.Add(new KeyValuePair<string, ClangTidyProperties>(null, ClangTidyProperties.RootProperties));
+ reloadPropertyChain();
+ }
+
+ private void button1_Click(object sender, EventArgs e)
+ {
+ ShouldCancel Cancel = PersistUnsavedChanges(true);
+ if (Cancel == ShouldCancel.Yes)
+ return;
+
+ using (OpenFileDialog D = new OpenFileDialog())
+ {
+ D.Filter = "Clang Tidy files|.clang-tidy";
+ D.CheckPathExists = true;
+ D.CheckFileExists = true;
+
+ if (D.ShowDialog() == DialogResult.OK)
+ {
+ PropertyChain_.Clear();
+ PropertyChain_ = ClangTidyConfigParser.ParseConfigurationChain(D.FileName);
+ textBox1.Text = D.FileName;
+ reloadPropertyChain();
+ }
+ }
+ }
+
+ private static readonly string DefaultText = "(Default)";
+ private static readonly string BrowseText = "Browse for a file to edit its properties";
+
+ /// <summary>
+ /// After a new configuration file is chosen, analyzes the directory hierarchy
+ /// and finds all .clang-tidy files in the path, parses them and updates the
+ /// PropertyGrid and quick-access LinkLabel control to reflect the new property
+ /// chain.
+ /// </summary>
+ private void reloadPropertyChain()
+ {
+ StringBuilder LinkBuilder = new StringBuilder();
+ LinkBuilder.Append(DefaultText);
+ LinkBuilder.Append(" > ");
+ int PrefixLength = LinkBuilder.Length;
+
+ if (PropertyChain_.Count == 1)
+ LinkBuilder.Append(BrowseText);
+ else
+ LinkBuilder.Append(PropertyChain_[PropertyChain_.Count - 1].Key);
+
+ linkLabelPath.Text = LinkBuilder.ToString();
+
+ // Given a path like D:\Foo\Bar\Baz, construct a LinkLabel where individual
+ // components of the path are clickable iff they contain a .clang-tidy file.
+ // Clicking one of the links then updates the PropertyGrid to display the
+ // selected .clang-tidy file.
+ ClangTidyProperties LastProps = ClangTidyProperties.RootProperties;
+ linkLabelPath.Links.Clear();
+ linkLabelPath.Links.Add(0, DefaultText.Length, LastProps);
+ foreach (var Prop in PropertyChain_.Skip(1))
+ {
+ LastProps = Prop.Value;
+ string ClangTidyFolder = Path.GetFileName(Prop.Key);
+ int ClangTidyFolderOffset = Prop.Key.Length - ClangTidyFolder.Length;
+ linkLabelPath.Links.Add(PrefixLength + ClangTidyFolderOffset, ClangTidyFolder.Length, LastProps);
+ }
+ propertyGrid1.SelectedObject = LastProps;
+ }
+
+ private void propertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
+ {
+ ClangTidyProperties Props = (ClangTidyProperties)propertyGrid1.SelectedObject;
+ Props.SetHasUnsavedChanges(true);
+
+ // When a CategoryVerb is selected, perform the corresponding action.
+ PropertyDescriptor Property = e.ChangedItem.PropertyDescriptor;
+ if (!(e.ChangedItem.Value is CategoryVerb))
+ return;
+
+ CategoryVerb Action = (CategoryVerb)e.ChangedItem.Value;
+ if (Action == CategoryVerb.None)
+ return;
+
+ var Category = Property.Attributes.OfType<CategoryAttribute>().FirstOrDefault();
+ if (Category == null)
+ return;
+ var SameCategoryProps = Props.GetProperties(new Attribute[] { Category });
+ foreach (PropertyDescriptor P in SameCategoryProps)
+ {
+ if (P == Property)
+ continue;
+ switch (Action)
+ {
+ case CategoryVerb.Disable:
+ P.SetValue(propertyGrid1.SelectedObject, false);
+ break;
+ case CategoryVerb.Enable:
+ P.SetValue(propertyGrid1.SelectedObject, true);
+ break;
+ case CategoryVerb.Inherit:
+ P.ResetValue(propertyGrid1.SelectedObject);
+ break;
+ }
+ }
+ Property.ResetValue(propertyGrid1.SelectedObject);
+ propertyGrid1.Invalidate();
+ }
+
+ private void linkLabelPath_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+ {
+ ClangTidyProperties Props = (ClangTidyProperties)e.Link.LinkData;
+ propertyGrid1.SelectedObject = Props;
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.resx b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.resx
new file mode 100644
index 0000000..22dfde0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ClangTidyPropertyGrid.resx
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <metadata name="clangTidyConfigurationPage1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <value>183, 17</value>
+ </metadata>
+</root>
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/DynamicPropertyComponent.Designer.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/DynamicPropertyComponent.Designer.cs
new file mode 100644
index 0000000..099f1c0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/DynamicPropertyComponent.Designer.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+ partial class DynamicPropertyComponent
+ {
+ /// <summary>
+ /// Required designer variable.
+ /// </summary>
+ private System.ComponentModel.IContainer components = null;
+
+ /// <summary>
+ /// Clean up any resources being used.
+ /// </summary>
+ /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ /// <summary>
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ /// </summary>
+ private void InitializeComponent()
+ {
+ components = new System.ComponentModel.Container();
+ }
+
+ #endregion
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/DynamicPropertyComponent.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/DynamicPropertyComponent.cs
new file mode 100644
index 0000000..e8843db
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/DynamicPropertyComponent.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+ /// <summary>
+ /// The goal of this class is to enable displaying of a PropertyGrid in much the
+ /// same way that Visual Studio's C++ project system does. A project or file can
+ /// have properties which might inherit from their parent, or be overridden.
+ /// It turns out this is somewhat non-trivial. The .NET PropertyGrid is good makes
+ /// displaying simple properties with a static notion of what constitutes a
+ /// "default" value very easy. You simply apply an Attribute to the class that says
+ /// what the default value is and you're done. But when you try to introduce the idea
+ /// that a property's default value depends on some other factor, things get much more
+ /// complicated due to the static nature of Attributes.
+ ///
+ /// The solution to this is to inherit from ICustomTypeDescriptor. This is the mechanism
+ /// by which you can inject or modify attributes or properties at runtime. The .NET
+ /// PropertyGrid is designed in such a way that instead of using simple .NET Reflection to
+ /// look for the properties and attributes on a class, it will invoke the methods of
+ /// ICustomTypeDescriptor (if your type inherits from it), and ask those methods. Our
+ /// implementation of ICustomTypeDescriptor works by waiting until the PropertyGrid requests
+ /// PropertyDescriptors for each of the properties, and then "decorating" them with our
+ /// own custom PropertyDescriptor implementation which understands the proeprty inheritance
+ /// model we wish to implement.
+ /// </summary>
+ public partial class DynamicPropertyComponent : Component, ICustomTypeDescriptor
+ {
+ PropertyDescriptorCollection DynamicProperties_ = new PropertyDescriptorCollection(null);
+ private DynamicPropertyComponent Parent_;
+
+ public DynamicPropertyComponent(DynamicPropertyComponent Parent)
+ {
+ Parent_ = Parent;
+ }
+
+ public DynamicPropertyComponent(DynamicPropertyComponent Parent, IContainer container)
+ {
+ Parent_ = Parent;
+
+ container.Add(this);
+ InitializeComponent();
+ }
+
+ public AttributeCollection GetAttributes()
+ {
+ return TypeDescriptor.GetAttributes(GetType());
+ }
+
+ public string GetClassName()
+ {
+ return TypeDescriptor.GetClassName(GetType());
+ }
+
+ public string GetComponentName()
+ {
+ return TypeDescriptor.GetComponentName(GetType());
+ }
+
+ public TypeConverter GetConverter()
+ {
+ return TypeDescriptor.GetConverter(GetType());
+ }
+
+ public EventDescriptor GetDefaultEvent()
+ {
+ return TypeDescriptor.GetDefaultEvent(GetType());
+ }
+
+ public PropertyDescriptor GetDefaultProperty()
+ {
+ return TypeDescriptor.GetDefaultProperty(GetType());
+ }
+
+ public object GetEditor(Type editorBaseType)
+ {
+ return TypeDescriptor.GetEditor(GetType(), editorBaseType);
+ }
+
+ public EventDescriptorCollection GetEvents()
+ {
+ return TypeDescriptor.GetEvents(GetType());
+ }
+
+ public EventDescriptorCollection GetEvents(Attribute[] attributes)
+ {
+ return TypeDescriptor.GetEvents(GetType(), attributes);
+ }
+
+ public PropertyDescriptorCollection GetProperties()
+ {
+ return DynamicProperties_;
+ }
+
+ public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
+ {
+ var Props = DynamicProperties_.OfType<PropertyDescriptor>();
+ var Filtered = Props.Where(x => x.Attributes.Contains(attributes)).ToArray();
+ return new PropertyDescriptorCollection(Filtered);
+ }
+
+ public object GetPropertyOwner(PropertyDescriptor pd)
+ {
+ return this;
+ }
+
+ public void SetDynamicValue<T>(string Name, T Value)
+ {
+ Name = Name.Replace('-', '_');
+ DynamicPropertyDescriptor<T> Descriptor = (DynamicPropertyDescriptor<T>)DynamicProperties_.Find(Name, false);
+ Descriptor.SetValue(this, Value);
+ }
+
+ public T GetDynamicValue<T>(string Name)
+ {
+ Name = Name.Replace('-', '_');
+ DynamicPropertyDescriptor<T> Descriptor = (DynamicPropertyDescriptor<T>)DynamicProperties_.Find(Name, false);
+ return (T)Descriptor.GetValue(this);
+ }
+
+ protected void AddDynamicProperty<T>(string Name, Attribute[] Attributes)
+ {
+ Name = Name.Replace('-', '_');
+
+ // If we have a parent, find the corresponding PropertyDescriptor with the same
+ // name from the parent.
+ DynamicPropertyDescriptor<T> ParentDescriptor = null;
+ if (Parent_ != null)
+ ParentDescriptor = (DynamicPropertyDescriptor<T>)Parent_.GetProperties().Find(Name, false);
+
+ DynamicProperties_.Add(new DynamicPropertyDescriptor<T>(Name, ParentDescriptor, Name, Attributes));
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/DynamicPropertyConverter.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/DynamicPropertyConverter.cs
new file mode 100644
index 0000000..9442667
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/DynamicPropertyConverter.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+ class MagicInheritance
+ {
+ public static readonly string Value = "{3A27184D-1774-489B-9BB7-7191B8E8E622}";
+ public static readonly string Text = "<Inherit from project or parent>";
+ }
+
+
+ class DynamicPropertyConverter<T> : TypeConverter
+ {
+ private DynamicPropertyDescriptor<T> Descriptor_;
+ private TypeConverter Root_;
+
+ public DynamicPropertyConverter(DynamicPropertyDescriptor<T> Descriptor, TypeConverter Root)
+ {
+ Descriptor_ = Descriptor;
+ Root_ = Root;
+ }
+
+ /// <summary>
+ /// Returns true if there are specific values that can be chosen from a dropdown
+ /// for this property. Regardless of whether standard values are supported for
+ /// the underlying type, we always support standard values because we need to
+ /// display the inheritance option.
+ /// </summary>
+ /// <returns>true</returns>
+ public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+
+ /// <summary>
+ /// Get the set of all standard values that can be chosen from a dropdown for this
+ /// property. If the underlying type supports standard values, we want to include
+ /// all those. Additionally, we want to display the option to inherit the value,
+ /// but only if the value is not already inheriting.
+ /// </summary>
+ public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
+ {
+ List<object> Values = new List<object>();
+ if (Root_.GetStandardValuesSupported(context))
+ {
+ StandardValuesCollection RootValues = Root_.GetStandardValues(context);
+ Values.AddRange(RootValues.Cast<object>());
+ }
+ if (!Descriptor_.IsInheriting)
+ Values.Add(MagicInheritance.Value);
+ StandardValuesCollection Result = new StandardValuesCollection(Values);
+ return Result;
+ }
+
+ /// <summary>
+ /// Determines whether this property can accept values other than those specified
+ /// in the dropdown (for example by manually typing into the field).
+ /// </summary>
+ public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
+ {
+ // Although we add items to the dropdown list, we do not change whether or not
+ // the set of values are exclusive. If the user could type into the field before
+ // they still can. And if they couldn't before, they still can't.
+ return Root_.GetStandardValuesExclusive(context);
+ }
+
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ {
+ return Root_.CanConvertFrom(context, sourceType);
+ }
+
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ return Root_.CanConvertTo(context, destinationType);
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ if (value.Equals(MagicInheritance.Value))
+ return MagicInheritance.Text;
+ return Root_.ConvertFrom(context, culture, value);
+ }
+
+ public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
+ {
+ if (value.GetType() == destinationType)
+ return value;
+
+ return Root_.ConvertTo(context, culture, value, destinationType);
+ }
+
+ public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
+ {
+ return Root_.CreateInstance(context, propertyValues);
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Root_.Equals(obj);
+ }
+
+ public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
+ {
+ return Root_.GetCreateInstanceSupported(context);
+ }
+
+ public override int GetHashCode()
+ {
+ return Root_.GetHashCode();
+ }
+
+ public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
+ {
+ return Root_.GetProperties(context, value, attributes);
+ }
+
+ public override bool GetPropertiesSupported(ITypeDescriptorContext context)
+ {
+ return Root_.GetPropertiesSupported(context);
+ }
+
+ public override bool IsValid(ITypeDescriptorContext context, object value)
+ {
+ return Root_.IsValid(context, value);
+ }
+
+ public override string ToString()
+ {
+ return Root_.ToString();
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/DynamicPropertyDescriptor.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/DynamicPropertyDescriptor.cs
new file mode 100644
index 0000000..f0d7691
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/DynamicPropertyDescriptor.cs
@@ -0,0 +1,137 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+ public class DynamicPropertyDescriptor<T> : PropertyDescriptor
+ {
+ T Value_;
+ DynamicPropertyDescriptor<T> Parent_;
+ bool IsInheriting_;
+ object Component_;
+
+ public DynamicPropertyDescriptor(object Component, DynamicPropertyDescriptor<T> Parent, string Name, Attribute[] Attrs)
+ : base(Name, Attrs)
+ {
+ foreach (DefaultValueAttribute Attr in Attrs.OfType<DefaultValueAttribute>())
+ {
+ Value_ = (T)Attr.Value;
+ }
+ Parent_ = Parent;
+ IsInheriting_ = true;
+ Component_ = Component;
+ }
+
+ public bool IsInheriting { get { return IsInheriting_; } set { IsInheriting_ = value; } }
+ public DynamicPropertyDescriptor<T> Parent { get { return Parent_; } }
+
+ /// <summary>
+ /// Determines whether this property's value should be considered "default" (e.g.
+ /// displayed in bold in the property grid). Root properties are unmodifiable and
+ /// always default. Non-root properties are default iff they are inheriting.
+ /// That is to say, if a property is explicitly set to False, the property should
+ /// be serialized even if the parent is also False. It would only not be serialized
+ /// if the user had explicitly chosen to inherit it.
+ /// </summary>
+ /// <param name="component"></param>
+ /// <returns></returns>
+ public override bool ShouldSerializeValue(object component)
+ {
+ return (Parent_ != null) && !IsInheriting;
+ }
+
+ /// <summary>
+ /// Set the value back to the default. For root properties, this essentially does
+ /// nothing as they are read-only anyway. For non-root properties, this only means
+ /// that the property is now inheriting.
+ /// </summary>
+ /// <param name="component"></param>
+ public override void ResetValue(object component)
+ {
+ IsInheriting_ = true;
+ }
+
+ public override void SetValue(object component, object value)
+ {
+ // This is a bit of a trick. If the user chose the inheritance option from the
+ // dropdown, we will try to set the value to that string. So look for that and
+ // then just reset the value.
+ if (value.Equals(MagicInheritance.Text))
+ ResetValue(component);
+ else
+ {
+ // By explicitly setting the value, this property is no longer inheriting,
+ // even if the value the property is being set to is the same as that of
+ // the parent.
+ IsInheriting_ = false;
+ Value_ = (T)value;
+ }
+ }
+
+ public override TypeConverter Converter
+ {
+ get
+ {
+ // We need to return a DynamicPropertyConverter<> that can deal with our requirement
+ // to inject the inherit property option into the dropdown. But we still need to use
+ // the "real" converter to do the actual work for the underlying type. Therefore,
+ // we need to look for a TypeConverter<> attribute on the property, and if it is present
+ // forward an instance of that converter to the DynamicPropertyConverter<>. Otherwise,
+ // forward an instance of the default converter for type T to the DynamicPropertyConverter<>.
+ TypeConverter UnderlyingConverter = null;
+ var ConverterAttr = this.Attributes.OfType<TypeConverterAttribute>().LastOrDefault();
+ if (ConverterAttr != null)
+ {
+ Type ConverterType = Type.GetType(ConverterAttr.ConverterTypeName);
+ UnderlyingConverter = (TypeConverter)Activator.CreateInstance(ConverterType);
+ }
+ else
+ UnderlyingConverter = TypeDescriptor.GetConverter(typeof(T));
+
+ return new DynamicPropertyConverter<T>(this, UnderlyingConverter);
+ }
+ }
+
+ public override bool IsReadOnly
+ {
+ get
+ {
+ return (Parent_ == null);
+ }
+ }
+
+ public override Type ComponentType
+ {
+ get
+ {
+ return Component_.GetType();
+ }
+ }
+
+ public override object GetValue(object component)
+ {
+ // Return either this property's value or the parents value, depending on
+ // whether or not this property is inheriting.
+ if (IsInheriting_ && Parent != null)
+ return Parent.GetValue(component);
+ return Value_;
+ }
+
+ public override bool CanResetValue(object component)
+ {
+ return !IsReadOnly;
+ }
+
+ public override Type PropertyType
+ {
+ get
+ {
+ return typeof(T);
+ }
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ForwardingPropertyDescriptor.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ForwardingPropertyDescriptor.cs
new file mode 100644
index 0000000..22b08fb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/ForwardingPropertyDescriptor.cs
@@ -0,0 +1,191 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+ /// <summary>
+ /// A decorator of sorts. Accepts a PropertyDescriptor to its constructor
+ /// and forwards all calls to the underlying PropertyDescriptor. In this way
+ /// we can inherit from ForwardingPropertyDescriptor and override only the
+ /// few methods we need to customize the behavior of, while allowing the
+ /// underlying PropertyDescriptor to do the real work.
+ /// </summary>
+ public abstract class ForwardingPropertyDescriptor : PropertyDescriptor
+ {
+ private readonly PropertyDescriptor root;
+ protected PropertyDescriptor Root { get { return root; } }
+ protected ForwardingPropertyDescriptor(PropertyDescriptor root)
+ : base(root)
+ {
+ this.root = root;
+ }
+
+ public override void AddValueChanged(object component, EventHandler handler)
+ {
+ root.AddValueChanged(component, handler);
+ }
+
+ public override AttributeCollection Attributes
+ {
+ get
+ {
+ return root.Attributes;
+ }
+ }
+
+ public override bool CanResetValue(object component)
+ {
+ return root.CanResetValue(component);
+ }
+
+ public override string Category
+ {
+ get
+ {
+ return root.Category;
+ }
+ }
+
+ public override Type ComponentType
+ {
+ get
+ {
+ return root.ComponentType;
+ }
+ }
+
+ public override TypeConverter Converter
+ {
+ get
+ {
+ return root.Converter;
+ }
+ }
+
+ public override string Description
+ {
+ get
+ {
+ return root.Description;
+ }
+ }
+
+ public override bool DesignTimeOnly
+ {
+ get
+ {
+ return root.DesignTimeOnly;
+ }
+ }
+
+ public override string DisplayName
+ {
+ get
+ {
+ return root.DisplayName;
+ }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return root.Equals(obj);
+ }
+
+ public override PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter)
+ {
+ return root.GetChildProperties(instance, filter);
+ }
+
+ public override object GetEditor(Type editorBaseType)
+ {
+ return root.GetEditor(editorBaseType);
+ }
+
+ public override int GetHashCode()
+ {
+ return root.GetHashCode();
+ }
+
+ public override object GetValue(object component)
+ {
+ return root.GetValue(component);
+ }
+
+ public override bool IsBrowsable
+ {
+ get
+ {
+ return root.IsBrowsable;
+ }
+ }
+
+ public override bool IsLocalizable
+ {
+ get
+ {
+ return root.IsLocalizable;
+ }
+ }
+
+ public override bool IsReadOnly
+ {
+ get
+ {
+ return root.IsReadOnly;
+ }
+ }
+
+ public override string Name
+ {
+ get
+ {
+ return root.Name;
+ }
+ }
+
+ public override Type PropertyType
+ {
+ get
+ {
+ return root.PropertyType;
+ }
+ }
+
+ public override void RemoveValueChanged(object component, EventHandler handler)
+ {
+ root.RemoveValueChanged(component, handler);
+ }
+
+ public override void ResetValue(object component)
+ {
+ root.ResetValue(component);
+ }
+
+ public override void SetValue(object component, object value)
+ {
+ root.SetValue(component, value);
+ }
+
+ public override bool ShouldSerializeValue(object component)
+ {
+ return root.ShouldSerializeValue(component);
+ }
+
+ public override bool SupportsChangeEvents
+ {
+ get
+ {
+ return root.SupportsChangeEvents;
+ }
+ }
+
+ public override string ToString()
+ {
+ return root.ToString();
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/GlobalSuppressions.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/GlobalSuppressions.cs
new file mode 100644
index 0000000..175a74e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/GlobalSuppressions.cs
@@ -0,0 +1,11 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project. Project-level
+// suppressions either have no target or are given a specific target
+// and scoped to a namespace, type, member, etc.
+//
+// To add a suppression to this file, right-click the message in the
+// Error List, point to "Suppress Message(s)", and click "In Project
+// Suppression File". You do not need to add suppressions to this
+// file manually.
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")]
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Guids.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Guids.cs
new file mode 100644
index 0000000..0c99a6f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Guids.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace LLVM.ClangTidy
+{
+ static class GuidList
+ {
+ public const string guidClangTidyPkgString = "AE4956BE-3DB8-430E-BBAB-7E2E9A014E9C";
+ public const string guidClangTidyCmdSetString = "9E0F0493-6493-46DE-AEE1-ACD8F60F265E";
+
+ public static readonly Guid guidClangTidyCmdSet = new Guid(guidClangTidyCmdSetString);
+ };
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/PkgCmdID.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/PkgCmdID.cs
new file mode 100644
index 0000000..3faf403
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/PkgCmdID.cs
@@ -0,0 +1,7 @@
+namespace LLVM.ClangTidy
+{
+ static class PkgCmdIDList
+ {
+ public const uint cmdidClangTidy = 0x100;
+ };
+}
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Properties/AssemblyInfo.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..7105305
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ClangFormat")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("LLVM")]
+[assembly: AssemblyProduct("ClangFormat")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+[assembly: CLSCompliant(false)]
+[assembly: NeutralResourcesLanguage("en-US")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+// FIXME: Add a way to have this generated automatically by CMake
+[assembly: AssemblyVersion("1.1.0.0")]
+[assembly: AssemblyFileVersion("1.1.0.0")]
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources.Designer.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources.Designer.cs
new file mode 100644
index 0000000..b601fb3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources.Designer.cs
@@ -0,0 +1,81 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace LLVM.ClangTidy {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LLVM.ClangTidy.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to ---
+ ///Checks:
+ ///Checks:
+ /// - Name: cert-dcl54-cpp
+ /// Label: Overloaded allocation function pairs
+ /// Description: Checks for violations of CERT DCL54-CPP - Overload allocation and deallocation functions as a pair in the same scope
+ /// Category: CERT Secure Coding Standards
+ /// - Name: cppcoreguidelines-interfaces-global-init
+ /// Label: I.22 - Complex Global Initializers
+ /// Description: Checks for violations of Core Guideline I.22 - Avoid complex initializers of global object [rest of string was truncated]";.
+ /// </summary>
+ internal static string ClangTidyChecks {
+ get {
+ return ResourceManager.GetString("ClangTidyChecks", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources.resx b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources.resx
new file mode 100644
index 0000000..7f63475
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources.resx
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+ <data name="ClangTidyChecks" type="System.Resources.ResXFileRef, System.Windows.Forms">
+ <value>Resources\ClangTidyChecks.yaml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
+ </data>
+</root>
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources/ClangTidyChecks.yaml b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources/ClangTidyChecks.yaml
new file mode 100644
index 0000000..7b06aba
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources/ClangTidyChecks.yaml
@@ -0,0 +1,317 @@
+---
+Checks:
+ # This file should be updated when new checks are added, and eventually we should
+ # generate this file automatically from the .rst files in clang-tidy.
+ - Category: CERT Secure Coding Standards
+ Label: Overloaded allocation function pairs
+ Description: Checks for violations of CERT DCL54-CPP - Overload allocation and deallocation functions as a pair in the same scope
+ Name: cert-dcl54-cpp
+ - Category: C++ Core Guidelines
+ Label: I.22 - Complex Global Initializers
+ Description: Checks for violations of Core Guideline I.22 - Avoid complex initializers of global objects
+ Name: cppcoreguidelines-interfaces-global-init
+ - Category: CERT Secure Coding Standards
+ Label: DCL50-CPP
+ Description: Checks for violations of CERT DCL50-CPP - Do not define a C-style variadic function
+ Name: cert-dcl50-cpp
+ - Category: C++ Core Guidelines
+ Label: Bounds.1 - No pointer arithmetic
+ Description: Checks for violations of Core Guideline Bounds.3 - Don't use pointer arithmetic. Use span<> instead.
+ Name: cppcoreguidelines-pro-bounds-pointer-arithmetic
+ - Category: C++ Core Guidelines
+ Label: Bounds.2 - Constant array indices
+ Description: Checks for violations of Core Bounds.2 - Only index into arrays using constant expressions.
+ Name: cppcoreguidelines-pro-bounds-constant-array-index
+ - Category: C++ Core Guidelines
+ Label: Bounds.3 - Array to Pointer Decay
+ Description: Checks for violations of Core Guideline Bounds.3 - No array-to-pointer decay
+ Name: cppcoreguidelines-pro-bounds-array-to-pointer-decay
+ - Category: C++ Core Guidelines
+ Label: const_cast (Type.3)
+ Description: Checks for violations of Core Guideline Type.3 - Don't use const_cast to cast away const
+ Name: cppcoreguidelines-pro-type-const-cast
+ - Category: C++ Core Guidelines
+ Label: C style casts (Type.4)
+ Description: Checks for violations of Core Guideline Type.3 - Don't use C-style (T)expression casts that would perform a static downcast, const_cast, or reinterpret_cast
+ Name: cppcoreguidelines-pro-type-cstyle-cast
+ - Category: C++ Core Guidelines
+ Label: reinterpret_cast (Type.1)
+ Description: Checks for violations of Core Guideline Type.1 - Don't use reinterpret_cast.
+ Name: cppcoreguidelines-pro-type-reinterpret-cast
+ - Category: C++ Core Guidelines
+ Label: Prefer dynamic_cast (Type.2)
+ Description: Checks for violations of Core Guideline Type.2 - Don't use static_cast downcasts. Use dynamic_cast instead.
+ Name: cppcoreguidelines-pro-type-static-cast-downcast
+ - Category: C++ Core Guidelines
+ Label: Member variable initialization (Type.6)
+ Description: Checks for violations of Core Guideline Type.6 - Always initialize a member variable.
+ Name: cppcoreguidelines-pro-type-member-init
+ - Category: C++ Core Guidelines
+ Label: Avoid unions (Type.7)
+ Description: Checks for violations of Core Guideline Type.7 - Avoid accessing members of raw unions. Use variant instead.
+ Name: cppcoreguidelines-pro-type-union-access
+ - Category: C++ Core Guidelines
+ Label: Don't use varargs (Type.8)
+ Description: Checks for violations of Core Guideline Type.8 - Avoid reading varargs or passing vararg arguments. Prefer variadic templates instead.
+ Name: cppcoreguidelines-pro-type-vararg
+ - Category: C++ Core Guidelines
+ Label: Don't slice (ES.63 & C.145)
+ Description: Checks for violations of Core Guidelines ES.63 (Don't slice) and C.145 (Access polymorphic objects through pointers and references)
+ Name: cppcoreguidelines-slicing
+ - Category: C++ Core Guidelines
+ Label: Detect unsafe special functions (C.21)
+ Description: Checks for violations of Core Guidelines C.21 - If you define or =delete any default operation, define or =delete them all.
+ Name: cppcoreguidelines-special-member-functions
+ - Category: Google Style Guide
+ Label: Forbid explicitly parameterized make_pair
+ Description:
+ Name: google-build-explicit-make-pair
+ - Category: Google Style Guide
+ Label: Anonymous namespace in headers
+ Description:
+ Name: google-build-namespaces
+ - Category: Google Style Guide
+ Label: Find using namespace directives
+ Description:
+ Name: google-build-using-namespace
+ - Category: Google Style Guide
+ Label: Default arguments in virtual methods
+ Description:
+ Name: google-default-arguments
+ - Category: Google Style Guide
+ Label: explicit constructors
+ Description:
+ Name: google-explicit-constructor
+ - Category: Google Style Guide
+ Label: Global namespace pollution in headers
+ Description:
+ Name: google-global-names-in-headers
+ - Category: Google Style Guide
+ Label: Braces around statements
+ Description:
+ Name: google-readability-braces-around-statements
+ - Category: Google Style Guide
+ Label: No C-style casts
+ Description:
+ Name: google-readability-casting
+ - Category: Google Style Guide
+ Label: Find large functions
+ Description:
+ Name: google-readability-function-size
+ - Category: Google Style Guide
+ Label: Namespace closing comments
+ Description:
+ Name: google-readability-namespace-comments
+ - Category: Google Style Guide
+ Label: Find unnecessary calls to .get()
+ Description:
+ Name: google-readability-redundant-smartptr-get
+ - Category: Google Style Guide
+ Label: Find noncomformant TODO comments
+ Description:
+ Name: google-readability-todo
+ - Category: Google Style Guide
+ Label: Find implementation-specific integral types
+ Description:
+ Name: google-runtime-int
+ - Category: Google Style Guide
+ Label: Find zero-length memsets
+ Description:
+ Name: google-runtime-memset
+ - Category: Google Style Guide
+ Label: Find overloads of operator&
+ Description:
+ Name: google-runtime-operator
+ - Category: Google Style Guide
+ Label: Check usage of non-const references
+ Description:
+ Name: google-runtime-references
+ - Category: LLVM Style Guide
+ Label: LLVM header guards
+ Description:
+ Name: llvm-header-guard
+ - Category: LLVM Style Guide
+ Label: LLVM include order
+ Description:
+ Name: llvm-include-order
+ - Category: LLVM Style Guide
+ Label: LLVM namespace comments
+ Description:
+ Name: llvm-namespace-comment
+ - Category: LLVM Style Guide
+ Label: Find local twines
+ Description:
+ Name: llvm-twine-local
+ - Category: Clang Diagnostics
+ Label: Warnings
+ Description:
+ Name: clang-diagnostic-warning
+ - Category: Clang Diagnostics
+ Label: Errors
+ Description:
+ Name: clang-diagnostic-error
+ - Category: Clang Diagnostics
+ Label: Unknown
+ Description:
+ Name: clang-diagnostic-unknown
+ - Category: Miscellaneous
+ Label: Validate argument comments
+ Description:
+ Name: misc-argument-comment
+ - Category: Miscellaneous
+ Label: Side effects in assert()
+ Description:
+ Name: misc-assert-side-effect
+ - Category: Miscellaneous
+ Label: bool / pointer implicit conversions
+ Description:
+ Name: misc-bool-pointer-implicit-conversion
+ - Category: Miscellaneous
+ Label: Dangling handles
+ Description:
+ Name: misc-dangling-handle
+ - Category: Miscellaneous
+ Label: Definitions in headers
+ Description:
+ Name: misc-definitions-in-headers
+ - Category: Miscellaneous
+ Label: Type mismatch in fold operations
+ Description:
+ Name: misc-fold-init-type
+ - Category: Miscellaneous
+ Label: Forward declaration namespace
+ Description:
+ Name: misc-forward-declaration-namespace
+ - Category: Miscellaneous
+ Label: Inaccurate erase
+ Description:
+ Name: misc-inaccurate-erase
+ - Category: Miscellaneous
+ Label: Incorrect rounding
+ Description:
+ Name: misc-incorrect-roundings
+ - Category: Miscellaneous
+ Label: Inefficient STL algorithms
+ Description:
+ Name: misc-inefficient-algorithm
+ - Category: Miscellaneous
+ Label: Macro parentheses
+ Description:
+ Name: misc-macro-parentheses
+ - Category: Miscellaneous
+ Label: Macro repeated side effects
+ Description:
+ Name: misc-macro-repeated-side-effects
+ - Category: Miscellaneous
+ Label: Misplaced const
+ Description:
+ Name: misc-misplaced-const
+ - Category: Miscellaneous
+ Label: Misplaced widening casts
+ Description:
+ Name: misc-misplaced-widening-cast
+ - Category: Miscellaneous
+ Label: Move constructor const arguments
+ Description:
+ Name: misc-move-const-arg
+ - Category: Miscellaneous
+ Label: Move constructor initialization
+ Description:
+ Name: misc-move-constructor-init
+ - Category: Miscellaneous
+ Label: Multi-statement macros
+ Description:
+ Name: misc-multiple-statement-macro
+ - Category: Miscellaneous
+ Label: Verify new / delete overloads
+ Description:
+ Name: misc-new-delete-overloads
+ - Category: Miscellaneous
+ Label: Ensure move constructors are noexcept
+ Description:
+ Name: misc-noexcept-move-constructor
+ - Category: Miscellaneous
+ Label: Copying of non-copyable objects
+ Description:
+ Name: misc-non-copyable-objects
+ - Category: Miscellaneous
+ Label: Find redundant expressions
+ Description:
+ Name: misc-redundant-expression
+ - Category: Miscellaneous
+ Label: sizeof() on stl containers
+ Description:
+ Name: misc-sizeof-container
+ - Category: Miscellaneous
+ Label: Suspicious sizeof() usage
+ Description:
+ Name: misc-sizeof-expression
+ - Category: Miscellaneous
+ Label: Replace assert with static_assert
+ Description:
+ Name: misc-static-assert
+ - Category: Miscellaneous
+ Label: Suspicious string constructor
+ Description:
+ Name: misc-string-constructor
+ - Category: Miscellaneous
+ Label: String integer assignment
+ Description:
+ Name: misc-string-integer-assignment
+ - Category: Miscellaneous
+ Label: String literal with embedded null
+ Description:
+ Name: misc-string-literal-with-embedded-nul
+ - Category: Miscellaneous
+ Label: Suspicious missing comma
+ Description:
+ Name: misc-suspicious-missing-comma
+ - Category: Miscellaneous
+ Label: Suspicious semicolon
+ Description:
+ Name: misc-suspicious-semicolon
+ - Category: Miscellaneous
+ Label: Suspicious string compare
+ Description:
+ Name: misc-suspicious-string-compare
+ - Category: Miscellaneous
+ Label: Swapped arguments
+ Description:
+ Name: misc-swapped-arguments
+ - Category: Miscellaneous
+ Label: Throw by value / catch by reference
+ Description:
+ Name: misc-throw-by-value-catch-by-reference
+ - Category: Miscellaneous
+ Label: Unconventional operator=()
+ Description:
+ Name: misc-unconventional-assign-operator
+ - Category: Miscellaneous
+ Label: Undelegated constructor
+ Description:
+ Name: misc-undelegated-constructor
+ - Category: Miscellaneous
+ Label: unique_ptr<> reset / release
+ Description:
+ Name: misc-uniqueptr-reset-release
+ - Category: Miscellaneous
+ Label: Unused Alias Decls
+ Description:
+ Name: misc-unused-alias-decls
+ - Category: Miscellaneous
+ Label: Unused Params
+ Description:
+ Name: misc-unused-parameters
+ - Category: Miscellaneous
+ Label: Unused Raii
+ Description:
+ Name: misc-unused-raii
+ - Category: Miscellaneous
+ Label: Unused Using Decls
+ Description:
+ Name: misc-unused-using-decls
+ - Category: Miscellaneous
+ Label: Virtual Near Miss
+ Description:
+ Name: misc-virtual-near-miss
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources/Images_32bit.bmp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources/Images_32bit.bmp
new file mode 100644
index 0000000..2fa7ab0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources/Images_32bit.bmp
Binary files differ
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources/Package.ico b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources/Package.ico
new file mode 100644
index 0000000..ea3b23f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Resources/Package.ico
Binary files differ
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Utility.cs b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Utility.cs
new file mode 100644
index 0000000..5a220e6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/Utility.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace LLVM.ClangTidy
+{
+ static class Utility
+ {
+ public static IEnumerable<string> SplitPath(string FileOrDir)
+ {
+ string P = Path.GetDirectoryName(FileOrDir);
+ do
+ {
+ yield return P;
+ P = Path.GetDirectoryName(P);
+ } while (P != null);
+ }
+
+ public static bool HasClangTidyFile(string Folder)
+ {
+ string ClangTidy = Path.Combine(Folder, ".clang-tidy");
+ return File.Exists(ClangTidy);
+ }
+
+ public static bool MatchWildcardString(string Value, string Pattern)
+ {
+ string RE = Regex.Escape(Pattern).Replace(@"\*", ".*");
+ return Regex.IsMatch(Value, RE);
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/VSPackage.resx b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/VSPackage.resx
new file mode 100644
index 0000000..932b062
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/VSPackage.resx
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="110" xml:space="preserve">
+ <value>ClangTidy</value>
+ </data>
+ <data name="112" xml:space="preserve">
+ <value>Analyzes code by calling the clang-tidy executable.</value>
+ </data>
+ <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+ <data name="400" type="System.Resources.ResXFileRef, System.Windows.Forms">
+ <value>Resources\Package.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+ </data>
+</root>
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/license.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/license.txt
new file mode 100644
index 0000000..547f6a4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/license.txt
@@ -0,0 +1,63 @@
+==============================================================================
+LLVM Release License
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2007-2018 University of Illinois at Urbana-Champaign.
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at
+ Urbana-Champaign, nor the names of its contributors may be used to
+ endorse or promote products derived from this Software without specific
+ prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+The LLVM software contains code written by third parties. Such software will
+have its own individual LICENSE.TXT file in the directory in which it appears.
+This file will describe the copyrights, license, and restrictions which apply
+to that code.
+
+The disclaimer of warranty in the University of Illinois Open Source License
+applies to all code in the LLVM Distribution, and nothing in any of the
+other licenses gives permission to use the names of the LLVM Team or the
+University of Illinois to endorse or promote products derived from this
+Software.
+
+The following pieces of software have additional or alternate copyrights,
+licenses, and/or restrictions:
+
+Program Directory
+------- ---------
+<none yet>
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/packages.config b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/packages.config
new file mode 100644
index 0000000..75d7faf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/packages.config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Brutal.Dev.StrongNameSigner" version="1.8.0" targetFramework="net45" />
+ <package id="YamlDotNet" version="3.3.0" targetFramework="net45" />
+ <package id="YamlDotNet.Dynamic" version="3.2.3" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/source.extension.vsixmanifest b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/source.extension.vsixmanifest
new file mode 100644
index 0000000..cd0e863
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/source.extension.vsixmanifest
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Vsix Version="1.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
+ <Identifier Id="405594C3-042A-4155-B9A6-E25DAB8B1924">
+ <Name>ClangFormat</Name>
+ <Author>LLVM</Author>
+ <Version>4.0.0</Version>
+ <Description xml:space="preserve">A static analysis tool for C/C++ code.</Description>
+ <Locale>1033</Locale>
+ <MoreInfoUrl>http://clang.llvm.org/extra/clang-tidy/</MoreInfoUrl>
+ <License>license.txt</License>
+ <InstalledByMsi>false</InstalledByMsi>
+ <SupportedProducts>
+ <VisualStudio Version="10.0">
+ <Edition>Pro</Edition>
+ </VisualStudio>
+ <VisualStudio Version="11.0">
+ <Edition>Pro</Edition>
+ </VisualStudio>
+ <VisualStudio Version="12.0">
+ <Edition>Pro</Edition>
+ </VisualStudio>
+ <VisualStudio Version="14.0">
+ <Edition>Pro</Edition>
+ </VisualStudio>
+ </SupportedProducts>
+ <SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="4.0" />
+ </Identifier>
+ <References>
+ <Reference Id="Microsoft.VisualStudio.MPF" MinVersion="10.0">
+ <Name>Visual Studio MPF</Name>
+ </Reference>
+ </References>
+ <Content>
+ <VsPackage>|%CurrentProject%;PkgdefProjectOutputGroup|</VsPackage>
+ </Content>
+</Vsix>
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/README.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/README.txt
new file mode 100644
index 0000000..d8785c9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/README.txt
@@ -0,0 +1,17 @@
+This directory contains a VSPackage project to generate a Visual Studio extension
+for clang-tidy.
+
+Build prerequisites are:
+- Visual Studio 2013 Professional
+- Visual Studio 2013 SDK
+- Visual Studio 2010 Professional (?)
+- Visual Studio 2010 SDK (?)
+
+The extension is built using CMake by setting BUILD_CLANG_TIDY_VS_PLUGIN=ON
+when configuring a Clang build, and building the clang_tidy_vsix target.
+
+The CMake build will copy clang-tidy.exe and LICENSE.TXT into the ClangTidy/
+directory so they can be bundled with the plug-in, as well as creating
+ClangTidy/source.extension.vsixmanifest. Once the plug-in has been built with
+CMake once, it can be built manually from the ClangTidy.sln solution in Visual
+Studio.
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/source.extension.vsixmanifest.in b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/source.extension.vsixmanifest.in
new file mode 100644
index 0000000..86ee571
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy-vs/source.extension.vsixmanifest.in
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Vsix Version="1.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
+ <Identifier Id="405594C3-042A-4155-B9A6-E25DAB8B1924">
+ <Name>ClangTidy</Name>
+ <Author>LLVM</Author>
+ <Version>@CLANG_TIDY_VS_VERSION@</Version>
+ <Description xml:space="preserve">A static analysis tool for C/C++ code.</Description>
+ <Locale>1033</Locale>
+ <MoreInfoUrl>http://clang.llvm.org/extra/clang-tidy/</MoreInfoUrl>
+ <License>license.txt</License>
+ <InstalledByMsi>false</InstalledByMsi>
+ <SupportedProducts>
+ <VisualStudio Version="10.0">
+ <Edition>Pro</Edition>
+ </VisualStudio>
+ <VisualStudio Version="11.0">
+ <Edition>Pro</Edition>
+ </VisualStudio>
+ <VisualStudio Version="12.0">
+ <Edition>Pro</Edition>
+ </VisualStudio>
+ <VisualStudio Version="14.0">
+ <Edition>Pro</Edition>
+ </VisualStudio>
+ </SupportedProducts>
+ <SupportedFrameworkRuntimeEdition MinVersion="4.0" MaxVersion="4.0" />
+ </Identifier>
+ <References>
+ <Reference Id="Microsoft.VisualStudio.MPF" MinVersion="10.0">
+ <Name>Visual Studio MPF</Name>
+ </Reference>
+ </References>
+ <Content>
+ <VsPackage>|%CurrentProject%;PkgdefProjectOutputGroup|</VsPackage>
+ </Content>
+</Vsix>
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/CMakeLists.txt
new file mode 100644
index 0000000..a872469
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/CMakeLists.txt
@@ -0,0 +1,50 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_library(clangTidy
+ ClangTidy.cpp
+ ClangTidyModule.cpp
+ ClangTidyDiagnosticConsumer.cpp
+ ClangTidyOptions.cpp
+ ClangTidyProfiling.cpp
+
+ DEPENDS
+ ClangSACheckers
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFormat
+ clangFrontend
+ clangLex
+ clangRewrite
+ clangSema
+ clangStaticAnalyzerCore
+ clangStaticAnalyzerFrontend
+ clangTooling
+ clangToolingCore
+ )
+
+add_subdirectory(android)
+add_subdirectory(abseil)
+add_subdirectory(boost)
+add_subdirectory(bugprone)
+add_subdirectory(cert)
+add_subdirectory(cppcoreguidelines)
+add_subdirectory(fuchsia)
+add_subdirectory(google)
+add_subdirectory(hicpp)
+add_subdirectory(llvm)
+add_subdirectory(misc)
+add_subdirectory(modernize)
+add_subdirectory(mpi)
+add_subdirectory(objc)
+add_subdirectory(performance)
+add_subdirectory(plugin)
+add_subdirectory(portability)
+add_subdirectory(readability)
+add_subdirectory(tool)
+add_subdirectory(utils)
+add_subdirectory(zircon)
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidy.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidy.cpp
new file mode 100644
index 0000000..f497fd7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -0,0 +1,621 @@
+//===--- tools/extra/clang-tidy/ClangTidy.cpp - Clang tidy tool -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file implements a clang-tidy tool.
+///
+/// This tool uses the Clang Tooling infrastructure, see
+/// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+/// for details on setting it up with LLVM source tree.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ClangTidy.h"
+#include "ClangTidyDiagnosticConsumer.h"
+#include "ClangTidyModuleRegistry.h"
+#include "ClangTidyProfiling.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Rewrite/Frontend/FixItRewriter.h"
+#include "clang/Rewrite/Frontend/FrontendActions.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
+#include "clang/Tooling/DiagnosticsYaml.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/ReplacementsYaml.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include <algorithm>
+#include <utility>
+
+using namespace clang::ast_matchers;
+using namespace clang::driver;
+using namespace clang::tooling;
+using namespace llvm;
+
+LLVM_INSTANTIATE_REGISTRY(clang::tidy::ClangTidyModuleRegistry)
+
+namespace clang {
+namespace tidy {
+
+namespace {
+static const char *AnalyzerCheckNamePrefix = "clang-analyzer-";
+
+class AnalyzerDiagnosticConsumer : public ento::PathDiagnosticConsumer {
+public:
+ AnalyzerDiagnosticConsumer(ClangTidyContext &Context) : Context(Context) {}
+
+ void FlushDiagnosticsImpl(std::vector<const ento::PathDiagnostic *> &Diags,
+ FilesMade *filesMade) override {
+ for (const ento::PathDiagnostic *PD : Diags) {
+ SmallString<64> CheckName(AnalyzerCheckNamePrefix);
+ CheckName += PD->getCheckName();
+ Context.diag(CheckName, PD->getLocation().asLocation(),
+ PD->getShortDescription())
+ << PD->path.back()->getRanges();
+
+ for (const auto &DiagPiece :
+ PD->path.flatten(/*ShouldFlattenMacros=*/true)) {
+ Context.diag(CheckName, DiagPiece->getLocation().asLocation(),
+ DiagPiece->getString(), DiagnosticIDs::Note)
+ << DiagPiece->getRanges();
+ }
+ }
+ }
+
+ StringRef getName() const override { return "ClangTidyDiags"; }
+ bool supportsLogicalOpControlFlow() const override { return true; }
+ bool supportsCrossFileDiagnostics() const override { return true; }
+
+private:
+ ClangTidyContext &Context;
+};
+
+class ErrorReporter {
+public:
+ ErrorReporter(ClangTidyContext &Context, bool ApplyFixes,
+ llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS)
+ : Files(FileSystemOptions(), BaseFS), DiagOpts(new DiagnosticOptions()),
+ DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)),
+ Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
+ DiagPrinter),
+ SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes),
+ TotalFixes(0), AppliedFixes(0), WarningsAsErrors(0) {
+ DiagOpts->ShowColors = llvm::sys::Process::StandardOutHasColors();
+ DiagPrinter->BeginSourceFile(LangOpts);
+ }
+
+ SourceManager &getSourceManager() { return SourceMgr; }
+
+ void reportDiagnostic(const ClangTidyError &Error) {
+ const tooling::DiagnosticMessage &Message = Error.Message;
+ SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset);
+ // Contains a pair for each attempted fix: location and whether the fix was
+ // applied successfully.
+ SmallVector<std::pair<SourceLocation, bool>, 4> FixLocations;
+ {
+ auto Level = static_cast<DiagnosticsEngine::Level>(Error.DiagLevel);
+ std::string Name = Error.DiagnosticName;
+ if (Error.IsWarningAsError) {
+ Name += ",-warnings-as-errors";
+ Level = DiagnosticsEngine::Error;
+ WarningsAsErrors++;
+ }
+ auto Diag = Diags.Report(Loc, Diags.getCustomDiagID(Level, "%0 [%1]"))
+ << Message.Message << Name;
+ for (const auto &FileAndReplacements : Error.Fix) {
+ for (const auto &Repl : FileAndReplacements.second) {
+ // Retrieve the source range for applicable fixes. Macro definitions
+ // on the command line have locations in a virtual buffer and don't
+ // have valid file paths and are therefore not applicable.
+ SourceRange Range;
+ SourceLocation FixLoc;
+ ++TotalFixes;
+ bool CanBeApplied = false;
+ if (Repl.isApplicable()) {
+ SmallString<128> FixAbsoluteFilePath = Repl.getFilePath();
+ Files.makeAbsolutePath(FixAbsoluteFilePath);
+ if (ApplyFixes) {
+ tooling::Replacement R(FixAbsoluteFilePath, Repl.getOffset(),
+ Repl.getLength(),
+ Repl.getReplacementText());
+ Replacements &Replacements = FileReplacements[R.getFilePath()];
+ llvm::Error Err = Replacements.add(R);
+ if (Err) {
+ // FIXME: Implement better conflict handling.
+ llvm::errs() << "Trying to resolve conflict: "
+ << llvm::toString(std::move(Err)) << "\n";
+ unsigned NewOffset =
+ Replacements.getShiftedCodePosition(R.getOffset());
+ unsigned NewLength = Replacements.getShiftedCodePosition(
+ R.getOffset() + R.getLength()) -
+ NewOffset;
+ if (NewLength == R.getLength()) {
+ R = Replacement(R.getFilePath(), NewOffset, NewLength,
+ R.getReplacementText());
+ Replacements = Replacements.merge(tooling::Replacements(R));
+ CanBeApplied = true;
+ ++AppliedFixes;
+ } else {
+ llvm::errs()
+ << "Can't resolve conflict, skipping the replacement.\n";
+ }
+
+ } else {
+ CanBeApplied = true;
+ ++AppliedFixes;
+ }
+ }
+ FixLoc = getLocation(FixAbsoluteFilePath, Repl.getOffset());
+ SourceLocation FixEndLoc =
+ FixLoc.getLocWithOffset(Repl.getLength());
+ Range = SourceRange(FixLoc, FixEndLoc);
+ Diag << FixItHint::CreateReplacement(Range,
+ Repl.getReplacementText());
+ }
+
+ if (ApplyFixes)
+ FixLocations.push_back(std::make_pair(FixLoc, CanBeApplied));
+ }
+ }
+ }
+ for (auto Fix : FixLocations) {
+ Diags.Report(Fix.first, Fix.second ? diag::note_fixit_applied
+ : diag::note_fixit_failed);
+ }
+ for (const auto &Note : Error.Notes)
+ reportNote(Note);
+ }
+
+ void Finish() {
+ if (ApplyFixes && TotalFixes > 0) {
+ Rewriter Rewrite(SourceMgr, LangOpts);
+ for (const auto &FileAndReplacements : FileReplacements) {
+ StringRef File = FileAndReplacements.first();
+ llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
+ SourceMgr.getFileManager().getBufferForFile(File);
+ if (!Buffer) {
+ llvm::errs() << "Can't get buffer for file " << File << ": "
+ << Buffer.getError().message() << "\n";
+ // FIXME: Maybe don't apply fixes for other files as well.
+ continue;
+ }
+ StringRef Code = Buffer.get()->getBuffer();
+ auto Style = format::getStyle(
+ *Context.getOptionsForFile(File).FormatStyle, File, "none");
+ if (!Style) {
+ llvm::errs() << llvm::toString(Style.takeError()) << "\n";
+ continue;
+ }
+ llvm::Expected<tooling::Replacements> Replacements =
+ format::cleanupAroundReplacements(Code, FileAndReplacements.second,
+ *Style);
+ if (!Replacements) {
+ llvm::errs() << llvm::toString(Replacements.takeError()) << "\n";
+ continue;
+ }
+ if (llvm::Expected<tooling::Replacements> FormattedReplacements =
+ format::formatReplacements(Code, *Replacements, *Style)) {
+ Replacements = std::move(FormattedReplacements);
+ if (!Replacements)
+ llvm_unreachable("!Replacements");
+ } else {
+ llvm::errs() << llvm::toString(FormattedReplacements.takeError())
+ << ". Skipping formatting.\n";
+ }
+ if (!tooling::applyAllReplacements(Replacements.get(), Rewrite)) {
+ llvm::errs() << "Can't apply replacements for file " << File << "\n";
+ }
+ }
+ if (Rewrite.overwriteChangedFiles()) {
+ llvm::errs() << "clang-tidy failed to apply suggested fixes.\n";
+ } else {
+ llvm::errs() << "clang-tidy applied " << AppliedFixes << " of "
+ << TotalFixes << " suggested fixes.\n";
+ }
+ }
+ }
+
+ unsigned getWarningsAsErrorsCount() const { return WarningsAsErrors; }
+
+private:
+ SourceLocation getLocation(StringRef FilePath, unsigned Offset) {
+ if (FilePath.empty())
+ return SourceLocation();
+
+ const FileEntry *File = SourceMgr.getFileManager().getFile(FilePath);
+ FileID ID = SourceMgr.getOrCreateFileID(File, SrcMgr::C_User);
+ return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset);
+ }
+
+ void reportNote(const tooling::DiagnosticMessage &Message) {
+ SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset);
+ Diags.Report(Loc, Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0"))
+ << Message.Message;
+ }
+
+ FileManager Files;
+ LangOptions LangOpts; // FIXME: use langopts from each original file
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+ DiagnosticConsumer *DiagPrinter;
+ DiagnosticsEngine Diags;
+ SourceManager SourceMgr;
+ llvm::StringMap<Replacements> FileReplacements;
+ ClangTidyContext &Context;
+ bool ApplyFixes;
+ unsigned TotalFixes;
+ unsigned AppliedFixes;
+ unsigned WarningsAsErrors;
+};
+
+class ClangTidyASTConsumer : public MultiplexConsumer {
+public:
+ ClangTidyASTConsumer(std::vector<std::unique_ptr<ASTConsumer>> Consumers,
+ std::unique_ptr<ClangTidyProfiling> Profiling,
+ std::unique_ptr<ast_matchers::MatchFinder> Finder,
+ std::vector<std::unique_ptr<ClangTidyCheck>> Checks)
+ : MultiplexConsumer(std::move(Consumers)),
+ Profiling(std::move(Profiling)), Finder(std::move(Finder)),
+ Checks(std::move(Checks)) {}
+
+private:
+ // Destructor order matters! Profiling must be destructed last.
+ // Or at least after Finder.
+ std::unique_ptr<ClangTidyProfiling> Profiling;
+ std::unique_ptr<ast_matchers::MatchFinder> Finder;
+ std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
+};
+
+} // namespace
+
+ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
+ ClangTidyContext &Context)
+ : Context(Context), CheckFactories(new ClangTidyCheckFactories) {
+ for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(),
+ E = ClangTidyModuleRegistry::end();
+ I != E; ++I) {
+ std::unique_ptr<ClangTidyModule> Module(I->instantiate());
+ Module->addCheckFactories(*CheckFactories);
+ }
+}
+
+static void setStaticAnalyzerCheckerOpts(const ClangTidyOptions &Opts,
+ AnalyzerOptionsRef AnalyzerOptions) {
+ StringRef AnalyzerPrefix(AnalyzerCheckNamePrefix);
+ for (const auto &Opt : Opts.CheckOptions) {
+ StringRef OptName(Opt.first);
+ if (!OptName.startswith(AnalyzerPrefix))
+ continue;
+ AnalyzerOptions->Config[OptName.substr(AnalyzerPrefix.size())] = Opt.second;
+ }
+}
+
+typedef std::vector<std::pair<std::string, bool>> CheckersList;
+
+static CheckersList getCheckersControlList(ClangTidyContext &Context,
+ bool IncludeExperimental) {
+ CheckersList List;
+
+ const auto &RegisteredCheckers =
+ AnalyzerOptions::getRegisteredCheckers(IncludeExperimental);
+ bool AnalyzerChecksEnabled = false;
+ for (StringRef CheckName : RegisteredCheckers) {
+ std::string ClangTidyCheckName((AnalyzerCheckNamePrefix + CheckName).str());
+ AnalyzerChecksEnabled |= Context.isCheckEnabled(ClangTidyCheckName);
+ }
+
+ if (!AnalyzerChecksEnabled)
+ return List;
+
+ // List all static analyzer checkers that our filter enables.
+ //
+ // Always add all core checkers if any other static analyzer check is enabled.
+ // This is currently necessary, as other path sensitive checks rely on the
+ // core checkers.
+ for (StringRef CheckName : RegisteredCheckers) {
+ std::string ClangTidyCheckName((AnalyzerCheckNamePrefix + CheckName).str());
+
+ if (CheckName.startswith("core") ||
+ Context.isCheckEnabled(ClangTidyCheckName)) {
+ List.emplace_back(CheckName, true);
+ }
+ }
+ return List;
+}
+
+std::unique_ptr<clang::ASTConsumer>
+ClangTidyASTConsumerFactory::CreateASTConsumer(
+ clang::CompilerInstance &Compiler, StringRef File) {
+ // FIXME: Move this to a separate method, so that CreateASTConsumer doesn't
+ // modify Compiler.
+ Context.setSourceManager(&Compiler.getSourceManager());
+ Context.setCurrentFile(File);
+ Context.setASTContext(&Compiler.getASTContext());
+
+ auto WorkingDir = Compiler.getSourceManager()
+ .getFileManager()
+ .getVirtualFileSystem()
+ ->getCurrentWorkingDirectory();
+ if (WorkingDir)
+ Context.setCurrentBuildDirectory(WorkingDir.get());
+
+ std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
+ CheckFactories->createChecks(&Context, Checks);
+
+ ast_matchers::MatchFinder::MatchFinderOptions FinderOptions;
+
+ std::unique_ptr<ClangTidyProfiling> Profiling;
+ if (Context.getEnableProfiling()) {
+ Profiling = llvm::make_unique<ClangTidyProfiling>(
+ Context.getProfileStorageParams());
+ FinderOptions.CheckProfiling.emplace(Profiling->Records);
+ }
+
+ std::unique_ptr<ast_matchers::MatchFinder> Finder(
+ new ast_matchers::MatchFinder(std::move(FinderOptions)));
+
+ for (auto &Check : Checks) {
+ Check->registerMatchers(&*Finder);
+ Check->registerPPCallbacks(Compiler);
+ }
+
+ std::vector<std::unique_ptr<ASTConsumer>> Consumers;
+ if (!Checks.empty())
+ Consumers.push_back(Finder->newASTConsumer());
+
+ AnalyzerOptionsRef AnalyzerOptions = Compiler.getAnalyzerOpts();
+ AnalyzerOptions->CheckersControlList =
+ getCheckersControlList(Context, Context.canEnableAnalyzerAlphaCheckers());
+ if (!AnalyzerOptions->CheckersControlList.empty()) {
+ setStaticAnalyzerCheckerOpts(Context.getOptions(), AnalyzerOptions);
+ AnalyzerOptions->AnalysisStoreOpt = RegionStoreModel;
+ AnalyzerOptions->AnalysisDiagOpt = PD_NONE;
+ AnalyzerOptions->AnalyzeNestedBlocks = true;
+ AnalyzerOptions->eagerlyAssumeBinOpBifurcation = true;
+ std::unique_ptr<ento::AnalysisASTConsumer> AnalysisConsumer =
+ ento::CreateAnalysisConsumer(Compiler);
+ AnalysisConsumer->AddDiagnosticConsumer(
+ new AnalyzerDiagnosticConsumer(Context));
+ Consumers.push_back(std::move(AnalysisConsumer));
+ }
+ return llvm::make_unique<ClangTidyASTConsumer>(
+ std::move(Consumers), std::move(Profiling), std::move(Finder),
+ std::move(Checks));
+}
+
+std::vector<std::string> ClangTidyASTConsumerFactory::getCheckNames() {
+ std::vector<std::string> CheckNames;
+ for (const auto &CheckFactory : *CheckFactories) {
+ if (Context.isCheckEnabled(CheckFactory.first))
+ CheckNames.push_back(CheckFactory.first);
+ }
+
+ for (const auto &AnalyzerCheck : getCheckersControlList(
+ Context, Context.canEnableAnalyzerAlphaCheckers()))
+ CheckNames.push_back(AnalyzerCheckNamePrefix + AnalyzerCheck.first);
+
+ std::sort(CheckNames.begin(), CheckNames.end());
+ return CheckNames;
+}
+
+ClangTidyOptions::OptionMap ClangTidyASTConsumerFactory::getCheckOptions() {
+ ClangTidyOptions::OptionMap Options;
+ std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
+ CheckFactories->createChecks(&Context, Checks);
+ for (const auto &Check : Checks)
+ Check->storeOptions(Options);
+ return Options;
+}
+
+DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc, StringRef Message,
+ DiagnosticIDs::Level Level) {
+ return Context->diag(CheckName, Loc, Message, Level);
+}
+
+void ClangTidyCheck::run(const ast_matchers::MatchFinder::MatchResult &Result) {
+ Context->setSourceManager(Result.SourceManager);
+ check(Result);
+}
+
+OptionsView::OptionsView(StringRef CheckName,
+ const ClangTidyOptions::OptionMap &CheckOptions)
+ : NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions) {}
+
+std::string OptionsView::get(StringRef LocalName, StringRef Default) const {
+ const auto &Iter = CheckOptions.find(NamePrefix + LocalName.str());
+ if (Iter != CheckOptions.end())
+ return Iter->second;
+ return Default;
+}
+
+std::string OptionsView::getLocalOrGlobal(StringRef LocalName,
+ StringRef Default) const {
+ auto Iter = CheckOptions.find(NamePrefix + LocalName.str());
+ if (Iter != CheckOptions.end())
+ return Iter->second;
+ // Fallback to global setting, if present.
+ Iter = CheckOptions.find(LocalName.str());
+ if (Iter != CheckOptions.end())
+ return Iter->second;
+ return Default;
+}
+
+void OptionsView::store(ClangTidyOptions::OptionMap &Options,
+ StringRef LocalName, StringRef Value) const {
+ Options[NamePrefix + LocalName.str()] = Value;
+}
+
+void OptionsView::store(ClangTidyOptions::OptionMap &Options,
+ StringRef LocalName, int64_t Value) const {
+ store(Options, LocalName, llvm::itostr(Value));
+}
+
+std::vector<std::string>
+getCheckNames(const ClangTidyOptions &Options,
+ bool AllowEnablingAnalyzerAlphaCheckers) {
+ clang::tidy::ClangTidyContext Context(
+ llvm::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(),
+ Options),
+ AllowEnablingAnalyzerAlphaCheckers);
+ ClangTidyASTConsumerFactory Factory(Context);
+ return Factory.getCheckNames();
+}
+
+ClangTidyOptions::OptionMap
+getCheckOptions(const ClangTidyOptions &Options,
+ bool AllowEnablingAnalyzerAlphaCheckers) {
+ clang::tidy::ClangTidyContext Context(
+ llvm::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(),
+ Options),
+ AllowEnablingAnalyzerAlphaCheckers);
+ ClangTidyASTConsumerFactory Factory(Context);
+ return Factory.getCheckOptions();
+}
+
+void runClangTidy(clang::tidy::ClangTidyContext &Context,
+ const CompilationDatabase &Compilations,
+ ArrayRef<std::string> InputFiles,
+ llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS,
+ bool EnableCheckProfile, llvm::StringRef StoreCheckProfile) {
+ ClangTool Tool(Compilations, InputFiles,
+ std::make_shared<PCHContainerOperations>(), BaseFS);
+
+ // Add extra arguments passed by the clang-tidy command-line.
+ ArgumentsAdjuster PerFileExtraArgumentsInserter =
+ [&Context](const CommandLineArguments &Args, StringRef Filename) {
+ ClangTidyOptions Opts = Context.getOptionsForFile(Filename);
+ CommandLineArguments AdjustedArgs = Args;
+ if (Opts.ExtraArgsBefore) {
+ auto I = AdjustedArgs.begin();
+ if (I != AdjustedArgs.end() && !StringRef(*I).startswith("-"))
+ ++I; // Skip compiler binary name, if it is there.
+ AdjustedArgs.insert(I, Opts.ExtraArgsBefore->begin(),
+ Opts.ExtraArgsBefore->end());
+ }
+ if (Opts.ExtraArgs)
+ AdjustedArgs.insert(AdjustedArgs.end(), Opts.ExtraArgs->begin(),
+ Opts.ExtraArgs->end());
+ return AdjustedArgs;
+ };
+
+ // Remove plugins arguments.
+ ArgumentsAdjuster PluginArgumentsRemover =
+ [](const CommandLineArguments &Args, StringRef Filename) {
+ CommandLineArguments AdjustedArgs;
+ for (size_t I = 0, E = Args.size(); I < E; ++I) {
+ if (I + 4 < Args.size() && Args[I] == "-Xclang" &&
+ (Args[I + 1] == "-load" || Args[I + 1] == "-add-plugin" ||
+ StringRef(Args[I + 1]).startswith("-plugin-arg-")) &&
+ Args[I + 2] == "-Xclang") {
+ I += 3;
+ } else
+ AdjustedArgs.push_back(Args[I]);
+ }
+ return AdjustedArgs;
+ };
+
+ Tool.appendArgumentsAdjuster(PerFileExtraArgumentsInserter);
+ Tool.appendArgumentsAdjuster(PluginArgumentsRemover);
+ Context.setEnableProfiling(EnableCheckProfile);
+ Context.setProfileStoragePrefix(StoreCheckProfile);
+
+ ClangTidyDiagnosticConsumer DiagConsumer(Context);
+
+ Tool.setDiagnosticConsumer(&DiagConsumer);
+
+ class ActionFactory : public FrontendActionFactory {
+ public:
+ ActionFactory(ClangTidyContext &Context) : ConsumerFactory(Context) {}
+ FrontendAction *create() override { return new Action(&ConsumerFactory); }
+
+ bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
+ FileManager *Files,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+ DiagnosticConsumer *DiagConsumer) override {
+ // Explicitly set ProgramAction to RunAnalysis to make the preprocessor
+ // define __clang_analyzer__ macro. The frontend analyzer action will not
+ // be called here.
+ Invocation->getFrontendOpts().ProgramAction = frontend::RunAnalysis;
+ return FrontendActionFactory::runInvocation(
+ Invocation, Files, PCHContainerOps, DiagConsumer);
+ }
+
+ private:
+ class Action : public ASTFrontendAction {
+ public:
+ Action(ClangTidyASTConsumerFactory *Factory) : Factory(Factory) {}
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef File) override {
+ return Factory->CreateASTConsumer(Compiler, File);
+ }
+
+ private:
+ ClangTidyASTConsumerFactory *Factory;
+ };
+
+ ClangTidyASTConsumerFactory ConsumerFactory;
+ };
+
+ ActionFactory Factory(Context);
+ Tool.run(&Factory);
+}
+
+void handleErrors(ClangTidyContext &Context, bool Fix,
+ unsigned &WarningsAsErrorsCount,
+ llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) {
+ ErrorReporter Reporter(Context, Fix, BaseFS);
+ vfs::FileSystem &FileSystem =
+ *Reporter.getSourceManager().getFileManager().getVirtualFileSystem();
+ auto InitialWorkingDir = FileSystem.getCurrentWorkingDirectory();
+ if (!InitialWorkingDir)
+ llvm::report_fatal_error("Cannot get current working path.");
+
+ for (const ClangTidyError &Error : Context.getErrors()) {
+ if (!Error.BuildDirectory.empty()) {
+ // By default, the working directory of file system is the current
+ // clang-tidy running directory.
+ //
+ // Change the directory to the one used during the analysis.
+ FileSystem.setCurrentWorkingDirectory(Error.BuildDirectory);
+ }
+ Reporter.reportDiagnostic(Error);
+ // Return to the initial directory to correctly resolve next Error.
+ FileSystem.setCurrentWorkingDirectory(InitialWorkingDir.get());
+ }
+ Reporter.Finish();
+ WarningsAsErrorsCount += Reporter.getWarningsAsErrorsCount();
+}
+
+void exportReplacements(const llvm::StringRef MainFilePath,
+ const std::vector<ClangTidyError> &Errors,
+ raw_ostream &OS) {
+ TranslationUnitDiagnostics TUD;
+ TUD.MainSourceFile = MainFilePath;
+ for (const auto &Error : Errors) {
+ tooling::Diagnostic Diag = Error;
+ TUD.Diagnostics.insert(TUD.Diagnostics.end(), Diag);
+ }
+
+ yaml::Output YAML(OS);
+ YAML << TUD;
+}
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidy.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidy.h
new file mode 100644
index 0000000..0ea9a70
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidy.h
@@ -0,0 +1,259 @@
+//===--- ClangTidy.h - clang-tidy -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDY_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDY_H
+
+#include "ClangTidyDiagnosticConsumer.h"
+#include "ClangTidyOptions.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Refactoring.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <type_traits>
+#include <vector>
+
+namespace clang {
+
+class CompilerInstance;
+namespace tooling {
+class CompilationDatabase;
+}
+
+namespace tidy {
+
+/// \brief Provides access to the ``ClangTidyCheck`` options via check-local
+/// names.
+///
+/// Methods of this class prepend ``CheckName + "."`` to translate check-local
+/// option names to global option names.
+class OptionsView {
+public:
+ /// \brief Initializes the instance using \p CheckName + "." as a prefix.
+ OptionsView(StringRef CheckName,
+ const ClangTidyOptions::OptionMap &CheckOptions);
+
+ /// \brief Read a named option from the ``Context``.
+ ///
+ /// Reads the option with the check-local name \p LocalName from the
+ /// ``CheckOptions``. If the corresponding key is not present, returns
+ /// \p Default.
+ std::string get(StringRef LocalName, StringRef Default) const;
+
+ /// \brief Read a named option from the ``Context``.
+ ///
+ /// Reads the option with the check-local name \p LocalName from local or
+ /// global ``CheckOptions``. Gets local option first. If local is not present,
+ /// falls back to get global option. If global option is not present either,
+ /// returns Default.
+ std::string getLocalOrGlobal(StringRef LocalName, StringRef Default) const;
+
+ /// \brief Read a named option from the ``Context`` and parse it as an
+ /// integral type ``T``.
+ ///
+ /// Reads the option with the check-local name \p LocalName from the
+ /// ``CheckOptions``. If the corresponding key is not present, returns
+ /// \p Default.
+ template <typename T>
+ typename std::enable_if<std::is_integral<T>::value, T>::type
+ get(StringRef LocalName, T Default) const {
+ std::string Value = get(LocalName, "");
+ T Result = Default;
+ if (!Value.empty())
+ StringRef(Value).getAsInteger(10, Result);
+ return Result;
+ }
+
+ /// \brief Read a named option from the ``Context`` and parse it as an
+ /// integral type ``T``.
+ ///
+ /// Reads the option with the check-local name \p LocalName from local or
+ /// global ``CheckOptions``. Gets local option first. If local is not present,
+ /// falls back to get global option. If global option is not present either,
+ /// returns Default.
+ template <typename T>
+ typename std::enable_if<std::is_integral<T>::value, T>::type
+ getLocalOrGlobal(StringRef LocalName, T Default) const {
+ std::string Value = getLocalOrGlobal(LocalName, "");
+ T Result = Default;
+ if (!Value.empty())
+ StringRef(Value).getAsInteger(10, Result);
+ return Result;
+ }
+
+ /// \brief Stores an option with the check-local name \p LocalName with string
+ /// value \p Value to \p Options.
+ void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName,
+ StringRef Value) const;
+
+ /// \brief Stores an option with the check-local name \p LocalName with
+ /// ``int64_t`` value \p Value to \p Options.
+ void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName,
+ int64_t Value) const;
+
+private:
+ std::string NamePrefix;
+ const ClangTidyOptions::OptionMap &CheckOptions;
+};
+
+/// \brief Base class for all clang-tidy checks.
+///
+/// To implement a ``ClangTidyCheck``, write a subclass and override some of the
+/// base class's methods. E.g. to implement a check that validates namespace
+/// declarations, override ``registerMatchers``:
+///
+/// ~~~{.cpp}
+/// void registerMatchers(ast_matchers::MatchFinder *Finder) override {
+/// Finder->addMatcher(namespaceDecl().bind("namespace"), this);
+/// }
+/// ~~~
+///
+/// and then override ``check(const MatchResult &Result)`` to do the actual
+/// check for each match.
+///
+/// A new ``ClangTidyCheck`` instance is created per translation unit.
+///
+/// FIXME: Figure out whether carrying information from one TU to another is
+/// useful/necessary.
+class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback {
+public:
+ /// \brief Initializes the check with \p CheckName and \p Context.
+ ///
+ /// Derived classes must implement the constructor with this signature or
+ /// delegate it. If a check needs to read options, it can do this in the
+ /// constructor using the Options.get() methods below.
+ ClangTidyCheck(StringRef CheckName, ClangTidyContext *Context)
+ : CheckName(CheckName), Context(Context),
+ Options(CheckName, Context->getOptions().CheckOptions) {
+ assert(Context != nullptr);
+ assert(!CheckName.empty());
+ }
+
+ /// \brief Override this to register ``PPCallbacks`` with ``Compiler``.
+ ///
+ /// This should be used for clang-tidy checks that analyze preprocessor-
+ /// dependent properties, e.g. the order of include directives.
+ virtual void registerPPCallbacks(CompilerInstance &Compiler) {}
+
+ /// \brief Override this to register AST matchers with \p Finder.
+ ///
+ /// This should be used by clang-tidy checks that analyze code properties that
+ /// dependent on AST knowledge.
+ ///
+ /// You can register as many matchers as necessary with \p Finder. Usually,
+ /// "this" will be used as callback, but you can also specify other callback
+ /// classes. Thereby, different matchers can trigger different callbacks.
+ ///
+ /// If you need to merge information between the different matchers, you can
+ /// store these as members of the derived class. However, note that all
+ /// matches occur in the order of the AST traversal.
+ virtual void registerMatchers(ast_matchers::MatchFinder *Finder) {}
+
+ /// \brief ``ClangTidyChecks`` that register ASTMatchers should do the actual
+ /// work in here.
+ virtual void check(const ast_matchers::MatchFinder::MatchResult &Result) {}
+
+ /// \brief Add a diagnostic with the check's name.
+ DiagnosticBuilder diag(SourceLocation Loc, StringRef Description,
+ DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
+
+ /// \brief Should store all options supported by this check with their
+ /// current values or default values for options that haven't been overridden.
+ ///
+ /// The check should use ``Options.store()`` to store each option it supports
+ /// whether it has the default value or it has been overridden.
+ virtual void storeOptions(ClangTidyOptions::OptionMap &Options) {}
+
+private:
+ void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ StringRef getID() const override { return CheckName; }
+ std::string CheckName;
+ ClangTidyContext *Context;
+
+protected:
+ OptionsView Options;
+ /// \brief Returns the main file name of the current translation unit.
+ StringRef getCurrentMainFile() const { return Context->getCurrentFile(); }
+ /// \brief Returns the language options from the context.
+ LangOptions getLangOpts() const { return Context->getLangOpts(); }
+};
+
+class ClangTidyCheckFactories;
+
+class ClangTidyASTConsumerFactory {
+public:
+ ClangTidyASTConsumerFactory(ClangTidyContext &Context);
+
+ /// \brief Returns an ASTConsumer that runs the specified clang-tidy checks.
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &Compiler, StringRef File);
+
+ /// \brief Get the list of enabled checks.
+ std::vector<std::string> getCheckNames();
+
+ /// \brief Get the union of options from all checks.
+ ClangTidyOptions::OptionMap getCheckOptions();
+
+private:
+ ClangTidyContext &Context;
+ std::unique_ptr<ClangTidyCheckFactories> CheckFactories;
+};
+
+/// \brief Fills the list of check names that are enabled when the provided
+/// filters are applied.
+std::vector<std::string> getCheckNames(const ClangTidyOptions &Options,
+ bool AllowEnablingAnalyzerAlphaCheckers);
+
+/// \brief Returns the effective check-specific options.
+///
+/// The method configures ClangTidy with the specified \p Options and collects
+/// effective options from all created checks. The returned set of options
+/// includes default check-specific options for all keys not overridden by \p
+/// Options.
+ClangTidyOptions::OptionMap
+getCheckOptions(const ClangTidyOptions &Options,
+ bool AllowEnablingAnalyzerAlphaCheckers);
+
+/// \brief Run a set of clang-tidy checks on a set of files.
+///
+/// \param EnableCheckProfile If provided, it enables check profile collection
+/// in MatchFinder, and will contain the result of the profile.
+/// \param StoreCheckProfile If provided, and EnableCheckProfile is true,
+/// the profile will not be output to stderr, but will instead be stored
+/// as a JSON file in the specified directory.
+void runClangTidy(clang::tidy::ClangTidyContext &Context,
+ const tooling::CompilationDatabase &Compilations,
+ ArrayRef<std::string> InputFiles,
+ llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS,
+ bool EnableCheckProfile = false,
+ llvm::StringRef StoreCheckProfile = StringRef());
+
+// FIXME: This interface will need to be significantly extended to be useful.
+// FIXME: Implement confidence levels for displaying/fixing errors.
+//
+/// \brief Displays the found \p Errors to the users. If \p Fix is true, \p
+/// Errors containing fixes are automatically applied and reformatted. If no
+/// clang-format configuration file is found, the given \P FormatStyle is used.
+void handleErrors(ClangTidyContext &Context, bool Fix,
+ unsigned &WarningsAsErrorsCount,
+ llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS);
+
+/// \brief Serializes replacements into YAML and writes them to the specified
+/// output stream.
+void exportReplacements(StringRef MainFilePath,
+ const std::vector<ClangTidyError> &Errors,
+ raw_ostream &OS);
+
+} // end namespace tidy
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDY_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
new file mode 100644
index 0000000..a1c76fb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -0,0 +1,690 @@
+//===--- tools/extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp ----------=== //
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file implements ClangTidyDiagnosticConsumer, ClangTidyContext
+/// and ClangTidyError classes.
+///
+/// This tool uses the Clang Tooling infrastructure, see
+/// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+/// for details on setting it up with LLVM source tree.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ClangTidyDiagnosticConsumer.h"
+#include "ClangTidyOptions.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Frontend/DiagnosticRenderer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include <tuple>
+#include <vector>
+using namespace clang;
+using namespace tidy;
+
+namespace {
+class ClangTidyDiagnosticRenderer : public DiagnosticRenderer {
+public:
+ ClangTidyDiagnosticRenderer(const LangOptions &LangOpts,
+ DiagnosticOptions *DiagOpts,
+ ClangTidyError &Error)
+ : DiagnosticRenderer(LangOpts, DiagOpts), Error(Error) {}
+
+protected:
+ void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level, StringRef Message,
+ ArrayRef<CharSourceRange> Ranges,
+ DiagOrStoredDiag Info) override {
+ // Remove check name from the message.
+ // FIXME: Remove this once there's a better way to pass check names than
+ // appending the check name to the message in ClangTidyContext::diag and
+ // using getCustomDiagID.
+ std::string CheckNameInMessage = " [" + Error.DiagnosticName + "]";
+ if (Message.endswith(CheckNameInMessage))
+ Message = Message.substr(0, Message.size() - CheckNameInMessage.size());
+
+ auto TidyMessage =
+ Loc.isValid()
+ ? tooling::DiagnosticMessage(Message, Loc.getManager(), Loc)
+ : tooling::DiagnosticMessage(Message);
+ if (Level == DiagnosticsEngine::Note) {
+ Error.Notes.push_back(TidyMessage);
+ return;
+ }
+ assert(Error.Message.Message.empty() && "Overwriting a diagnostic message");
+ Error.Message = TidyMessage;
+ }
+
+ void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges) override {}
+
+ void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints) override {
+ assert(Loc.isValid());
+ for (const auto &FixIt : Hints) {
+ CharSourceRange Range = FixIt.RemoveRange;
+ assert(Range.getBegin().isValid() && Range.getEnd().isValid() &&
+ "Invalid range in the fix-it hint.");
+ assert(Range.getBegin().isFileID() && Range.getEnd().isFileID() &&
+ "Only file locations supported in fix-it hints.");
+
+ tooling::Replacement Replacement(Loc.getManager(), Range,
+ FixIt.CodeToInsert);
+ llvm::Error Err = Error.Fix[Replacement.getFilePath()].add(Replacement);
+ // FIXME: better error handling (at least, don't let other replacements be
+ // applied).
+ if (Err) {
+ llvm::errs() << "Fix conflicts with existing fix! "
+ << llvm::toString(std::move(Err)) << "\n";
+ assert(false && "Fix conflicts with existing fix!");
+ }
+ }
+ }
+
+ void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override {}
+
+ void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) override {}
+
+ void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) override {}
+
+ void endDiagnostic(DiagOrStoredDiag D,
+ DiagnosticsEngine::Level Level) override {
+ assert(!Error.Message.Message.empty() && "Message has not been set");
+ }
+
+private:
+ ClangTidyError &Error;
+};
+} // end anonymous namespace
+
+ClangTidyError::ClangTidyError(StringRef CheckName,
+ ClangTidyError::Level DiagLevel,
+ StringRef BuildDirectory, bool IsWarningAsError)
+ : tooling::Diagnostic(CheckName, DiagLevel, BuildDirectory),
+ IsWarningAsError(IsWarningAsError) {}
+
+// Returns true if GlobList starts with the negative indicator ('-'), removes it
+// from the GlobList.
+static bool ConsumeNegativeIndicator(StringRef &GlobList) {
+ GlobList = GlobList.trim(" \r\n");
+ if (GlobList.startswith("-")) {
+ GlobList = GlobList.substr(1);
+ return true;
+ }
+ return false;
+}
+// Converts first glob from the comma-separated list of globs to Regex and
+// removes it and the trailing comma from the GlobList.
+static llvm::Regex ConsumeGlob(StringRef &GlobList) {
+ StringRef UntrimmedGlob = GlobList.substr(0, GlobList.find(','));
+ StringRef Glob = UntrimmedGlob.trim(' ');
+ GlobList = GlobList.substr(UntrimmedGlob.size() + 1);
+ SmallString<128> RegexText("^");
+ StringRef MetaChars("()^$|*+?.[]\\{}");
+ for (char C : Glob) {
+ if (C == '*')
+ RegexText.push_back('.');
+ else if (MetaChars.find(C) != StringRef::npos)
+ RegexText.push_back('\\');
+ RegexText.push_back(C);
+ }
+ RegexText.push_back('$');
+ return llvm::Regex(RegexText);
+}
+
+GlobList::GlobList(StringRef Globs)
+ : Positive(!ConsumeNegativeIndicator(Globs)), Regex(ConsumeGlob(Globs)),
+ NextGlob(Globs.empty() ? nullptr : new GlobList(Globs)) {}
+
+bool GlobList::contains(StringRef S, bool Contains) {
+ if (Regex.match(S))
+ Contains = Positive;
+
+ if (NextGlob)
+ Contains = NextGlob->contains(S, Contains);
+ return Contains;
+}
+
+class ClangTidyContext::CachedGlobList {
+public:
+ CachedGlobList(StringRef Globs) : Globs(Globs) {}
+
+ bool contains(StringRef S) {
+ switch (auto &Result = Cache[S]) {
+ case Yes: return true;
+ case No: return false;
+ case None:
+ Result = Globs.contains(S) ? Yes : No;
+ return Result == Yes;
+ }
+ llvm_unreachable("invalid enum");
+ }
+
+private:
+ GlobList Globs;
+ enum Tristate { None, Yes, No };
+ llvm::StringMap<Tristate> Cache;
+};
+
+ClangTidyContext::ClangTidyContext(
+ std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
+ bool AllowEnablingAnalyzerAlphaCheckers)
+ : DiagEngine(nullptr), OptionsProvider(std::move(OptionsProvider)),
+ Profile(false),
+ AllowEnablingAnalyzerAlphaCheckers(AllowEnablingAnalyzerAlphaCheckers) {
+ // Before the first translation unit we can get errors related to command-line
+ // parsing, use empty string for the file name in this case.
+ setCurrentFile("");
+}
+
+ClangTidyContext::~ClangTidyContext() = default;
+
+DiagnosticBuilder ClangTidyContext::diag(
+ StringRef CheckName, SourceLocation Loc, StringRef Description,
+ DiagnosticIDs::Level Level /* = DiagnosticIDs::Warning*/) {
+ assert(Loc.isValid());
+ unsigned ID = DiagEngine->getDiagnosticIDs()->getCustomDiagID(
+ Level, (Description + " [" + CheckName + "]").str());
+ CheckNamesByDiagnosticID.try_emplace(ID, CheckName);
+ return DiagEngine->Report(Loc, ID);
+}
+
+void ClangTidyContext::setDiagnosticsEngine(DiagnosticsEngine *Engine) {
+ DiagEngine = Engine;
+}
+
+void ClangTidyContext::setSourceManager(SourceManager *SourceMgr) {
+ DiagEngine->setSourceManager(SourceMgr);
+}
+
+void ClangTidyContext::setCurrentFile(StringRef File) {
+ CurrentFile = File;
+ CurrentOptions = getOptionsForFile(CurrentFile);
+ CheckFilter = llvm::make_unique<CachedGlobList>(*getOptions().Checks);
+ WarningAsErrorFilter =
+ llvm::make_unique<CachedGlobList>(*getOptions().WarningsAsErrors);
+}
+
+void ClangTidyContext::setASTContext(ASTContext *Context) {
+ DiagEngine->SetArgToStringFn(&FormatASTNodeDiagnosticArgument, Context);
+ LangOpts = Context->getLangOpts();
+}
+
+const ClangTidyGlobalOptions &ClangTidyContext::getGlobalOptions() const {
+ return OptionsProvider->getGlobalOptions();
+}
+
+const ClangTidyOptions &ClangTidyContext::getOptions() const {
+ return CurrentOptions;
+}
+
+ClangTidyOptions ClangTidyContext::getOptionsForFile(StringRef File) const {
+ // Merge options on top of getDefaults() as a safeguard against options with
+ // unset values.
+ return ClangTidyOptions::getDefaults().mergeWith(
+ OptionsProvider->getOptions(File));
+}
+
+void ClangTidyContext::setEnableProfiling(bool P) { Profile = P; }
+
+void ClangTidyContext::setProfileStoragePrefix(StringRef Prefix) {
+ ProfilePrefix = Prefix;
+}
+
+llvm::Optional<ClangTidyProfiling::StorageParams>
+ClangTidyContext::getProfileStorageParams() const {
+ if (ProfilePrefix.empty())
+ return llvm::None;
+
+ return ClangTidyProfiling::StorageParams(ProfilePrefix, CurrentFile);
+}
+
+bool ClangTidyContext::isCheckEnabled(StringRef CheckName) const {
+ assert(CheckFilter != nullptr);
+ return CheckFilter->contains(CheckName);
+}
+
+bool ClangTidyContext::treatAsError(StringRef CheckName) const {
+ assert(WarningAsErrorFilter != nullptr);
+ return WarningAsErrorFilter->contains(CheckName);
+}
+
+/// \brief Store a \c ClangTidyError.
+void ClangTidyContext::storeError(const ClangTidyError &Error) {
+ Errors.push_back(Error);
+}
+
+StringRef ClangTidyContext::getCheckName(unsigned DiagnosticID) const {
+ llvm::DenseMap<unsigned, std::string>::const_iterator I =
+ CheckNamesByDiagnosticID.find(DiagnosticID);
+ if (I != CheckNamesByDiagnosticID.end())
+ return I->second;
+ return "";
+}
+
+ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer(
+ ClangTidyContext &Ctx, bool RemoveIncompatibleErrors)
+ : Context(Ctx), RemoveIncompatibleErrors(RemoveIncompatibleErrors),
+ LastErrorRelatesToUserCode(false), LastErrorPassesLineFilter(false),
+ LastErrorWasIgnored(false) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ Diags = llvm::make_unique<DiagnosticsEngine>(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts, this,
+ /*ShouldOwnClient=*/false);
+ Context.setDiagnosticsEngine(Diags.get());
+}
+
+void ClangTidyDiagnosticConsumer::finalizeLastError() {
+ if (!Errors.empty()) {
+ ClangTidyError &Error = Errors.back();
+ if (!Context.isCheckEnabled(Error.DiagnosticName) &&
+ Error.DiagLevel != ClangTidyError::Error) {
+ ++Context.Stats.ErrorsIgnoredCheckFilter;
+ Errors.pop_back();
+ } else if (!LastErrorRelatesToUserCode) {
+ ++Context.Stats.ErrorsIgnoredNonUserCode;
+ Errors.pop_back();
+ } else if (!LastErrorPassesLineFilter) {
+ ++Context.Stats.ErrorsIgnoredLineFilter;
+ Errors.pop_back();
+ } else {
+ ++Context.Stats.ErrorsDisplayed;
+ }
+ }
+ LastErrorRelatesToUserCode = false;
+ LastErrorPassesLineFilter = false;
+}
+
+static bool IsNOLINTFound(StringRef NolintDirectiveText, StringRef Line,
+ unsigned DiagID, const ClangTidyContext &Context) {
+ const size_t NolintIndex = Line.find(NolintDirectiveText);
+ if (NolintIndex == StringRef::npos)
+ return false;
+
+ size_t BracketIndex = NolintIndex + NolintDirectiveText.size();
+ // Check if the specific checks are specified in brackets.
+ if (BracketIndex < Line.size() && Line[BracketIndex] == '(') {
+ ++BracketIndex;
+ const size_t BracketEndIndex = Line.find(')', BracketIndex);
+ if (BracketEndIndex != StringRef::npos) {
+ StringRef ChecksStr =
+ Line.substr(BracketIndex, BracketEndIndex - BracketIndex);
+ // Allow disabling all the checks with "*".
+ if (ChecksStr != "*") {
+ StringRef CheckName = Context.getCheckName(DiagID);
+ // Allow specifying a few check names, delimited with comma.
+ SmallVector<StringRef, 1> Checks;
+ ChecksStr.split(Checks, ',', -1, false);
+ llvm::transform(Checks, Checks.begin(),
+ [](StringRef S) { return S.trim(); });
+ return llvm::find(Checks, CheckName) != Checks.end();
+ }
+ }
+ }
+ return true;
+}
+
+static bool LineIsMarkedWithNOLINT(SourceManager &SM, SourceLocation Loc,
+ unsigned DiagID,
+ const ClangTidyContext &Context) {
+ bool Invalid;
+ const char *CharacterData = SM.getCharacterData(Loc, &Invalid);
+ if (Invalid)
+ return false;
+
+ // Check if there's a NOLINT on this line.
+ const char *P = CharacterData;
+ while (*P != '\0' && *P != '\r' && *P != '\n')
+ ++P;
+ StringRef RestOfLine(CharacterData, P - CharacterData + 1);
+ if (IsNOLINTFound("NOLINT", RestOfLine, DiagID, Context))
+ return true;
+
+ // Check if there's a NOLINTNEXTLINE on the previous line.
+ const char *BufBegin =
+ SM.getCharacterData(SM.getLocForStartOfFile(SM.getFileID(Loc)), &Invalid);
+ if (Invalid || P == BufBegin)
+ return false;
+
+ // Scan backwards over the current line.
+ P = CharacterData;
+ while (P != BufBegin && *P != '\n')
+ --P;
+
+ // If we reached the begin of the file there is no line before it.
+ if (P == BufBegin)
+ return false;
+
+ // Skip over the newline.
+ --P;
+ const char *LineEnd = P;
+
+ // Now we're on the previous line. Skip to the beginning of it.
+ while (P != BufBegin && *P != '\n')
+ --P;
+
+ RestOfLine = StringRef(P, LineEnd - P + 1);
+ if (IsNOLINTFound("NOLINTNEXTLINE", RestOfLine, DiagID, Context))
+ return true;
+
+ return false;
+}
+
+static bool LineIsMarkedWithNOLINTinMacro(SourceManager &SM, SourceLocation Loc,
+ unsigned DiagID,
+ const ClangTidyContext &Context) {
+ while (true) {
+ if (LineIsMarkedWithNOLINT(SM, Loc, DiagID, Context))
+ return true;
+ if (!Loc.isMacroID())
+ return false;
+ Loc = SM.getImmediateExpansionRange(Loc).getBegin();
+ }
+ return false;
+}
+
+void ClangTidyDiagnosticConsumer::HandleDiagnostic(
+ DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
+ if (LastErrorWasIgnored && DiagLevel == DiagnosticsEngine::Note)
+ return;
+
+ if (Info.getLocation().isValid() && DiagLevel != DiagnosticsEngine::Error &&
+ DiagLevel != DiagnosticsEngine::Fatal &&
+ LineIsMarkedWithNOLINTinMacro(Diags->getSourceManager(),
+ Info.getLocation(), Info.getID(),
+ Context)) {
+ ++Context.Stats.ErrorsIgnoredNOLINT;
+ // Ignored a warning, should ignore related notes as well
+ LastErrorWasIgnored = true;
+ return;
+ }
+
+ LastErrorWasIgnored = false;
+ // Count warnings/errors.
+ DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
+
+ if (DiagLevel == DiagnosticsEngine::Note) {
+ assert(!Errors.empty() &&
+ "A diagnostic note can only be appended to a message.");
+ } else {
+ finalizeLastError();
+ StringRef WarningOption =
+ Context.DiagEngine->getDiagnosticIDs()->getWarningOptionForDiag(
+ Info.getID());
+ std::string CheckName = !WarningOption.empty()
+ ? ("clang-diagnostic-" + WarningOption).str()
+ : Context.getCheckName(Info.getID()).str();
+
+ if (CheckName.empty()) {
+ // This is a compiler diagnostic without a warning option. Assign check
+ // name based on its level.
+ switch (DiagLevel) {
+ case DiagnosticsEngine::Error:
+ case DiagnosticsEngine::Fatal:
+ CheckName = "clang-diagnostic-error";
+ break;
+ case DiagnosticsEngine::Warning:
+ CheckName = "clang-diagnostic-warning";
+ break;
+ default:
+ CheckName = "clang-diagnostic-unknown";
+ break;
+ }
+ }
+
+ ClangTidyError::Level Level = ClangTidyError::Warning;
+ if (DiagLevel == DiagnosticsEngine::Error ||
+ DiagLevel == DiagnosticsEngine::Fatal) {
+ // Force reporting of Clang errors regardless of filters and non-user
+ // code.
+ Level = ClangTidyError::Error;
+ LastErrorRelatesToUserCode = true;
+ LastErrorPassesLineFilter = true;
+ }
+ bool IsWarningAsError = DiagLevel == DiagnosticsEngine::Warning &&
+ Context.treatAsError(CheckName);
+ Errors.emplace_back(CheckName, Level, Context.getCurrentBuildDirectory(),
+ IsWarningAsError);
+ }
+
+ ClangTidyDiagnosticRenderer Converter(
+ Context.getLangOpts(), &Context.DiagEngine->getDiagnosticOptions(),
+ Errors.back());
+ SmallString<100> Message;
+ Info.FormatDiagnostic(Message);
+ FullSourceLoc Loc =
+ (Info.getLocation().isInvalid())
+ ? FullSourceLoc()
+ : FullSourceLoc(Info.getLocation(), Info.getSourceManager());
+ Converter.emitDiagnostic(Loc, DiagLevel, Message, Info.getRanges(),
+ Info.getFixItHints());
+
+ checkFilters(Info.getLocation());
+}
+
+bool ClangTidyDiagnosticConsumer::passesLineFilter(StringRef FileName,
+ unsigned LineNumber) const {
+ if (Context.getGlobalOptions().LineFilter.empty())
+ return true;
+ for (const FileFilter &Filter : Context.getGlobalOptions().LineFilter) {
+ if (FileName.endswith(Filter.Name)) {
+ if (Filter.LineRanges.empty())
+ return true;
+ for (const FileFilter::LineRange &Range : Filter.LineRanges) {
+ if (Range.first <= LineNumber && LineNumber <= Range.second)
+ return true;
+ }
+ return false;
+ }
+ }
+ return false;
+}
+
+void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location) {
+ // Invalid location may mean a diagnostic in a command line, don't skip these.
+ if (!Location.isValid()) {
+ LastErrorRelatesToUserCode = true;
+ LastErrorPassesLineFilter = true;
+ return;
+ }
+
+ const SourceManager &Sources = Diags->getSourceManager();
+ if (!*Context.getOptions().SystemHeaders &&
+ Sources.isInSystemHeader(Location))
+ return;
+
+ // FIXME: We start with a conservative approach here, but the actual type of
+ // location needed depends on the check (in particular, where this check wants
+ // to apply fixes).
+ FileID FID = Sources.getDecomposedExpansionLoc(Location).first;
+ const FileEntry *File = Sources.getFileEntryForID(FID);
+
+ // -DMACRO definitions on the command line have locations in a virtual buffer
+ // that doesn't have a FileEntry. Don't skip these as well.
+ if (!File) {
+ LastErrorRelatesToUserCode = true;
+ LastErrorPassesLineFilter = true;
+ return;
+ }
+
+ StringRef FileName(File->getName());
+ LastErrorRelatesToUserCode = LastErrorRelatesToUserCode ||
+ Sources.isInMainFile(Location) ||
+ getHeaderFilter()->match(FileName);
+
+ unsigned LineNumber = Sources.getExpansionLineNumber(Location);
+ LastErrorPassesLineFilter =
+ LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber);
+}
+
+llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() {
+ if (!HeaderFilter)
+ HeaderFilter =
+ llvm::make_unique<llvm::Regex>(*Context.getOptions().HeaderFilterRegex);
+ return HeaderFilter.get();
+}
+
+void ClangTidyDiagnosticConsumer::removeIncompatibleErrors(
+ SmallVectorImpl<ClangTidyError> &Errors) const {
+ // Each error is modelled as the set of intervals in which it applies
+ // replacements. To detect overlapping replacements, we use a sweep line
+ // algorithm over these sets of intervals.
+ // An event here consists of the opening or closing of an interval. During the
+ // process, we maintain a counter with the amount of open intervals. If we
+ // find an endpoint of an interval and this counter is different from 0, it
+ // means that this interval overlaps with another one, so we set it as
+ // inapplicable.
+ struct Event {
+ // An event can be either the begin or the end of an interval.
+ enum EventType {
+ ET_Begin = 1,
+ ET_End = -1,
+ };
+
+ Event(unsigned Begin, unsigned End, EventType Type, unsigned ErrorId,
+ unsigned ErrorSize)
+ : Type(Type), ErrorId(ErrorId) {
+ // The events are going to be sorted by their position. In case of draw:
+ //
+ // * If an interval ends at the same position at which other interval
+ // begins, this is not an overlapping, so we want to remove the ending
+ // interval before adding the starting one: end events have higher
+ // priority than begin events.
+ //
+ // * If we have several begin points at the same position, we will mark as
+ // inapplicable the ones that we process later, so the first one has to
+ // be the one with the latest end point, because this one will contain
+ // all the other intervals. For the same reason, if we have several end
+ // points in the same position, the last one has to be the one with the
+ // earliest begin point. In both cases, we sort non-increasingly by the
+ // position of the complementary.
+ //
+ // * In case of two equal intervals, the one whose error is bigger can
+ // potentially contain the other one, so we want to process its begin
+ // points before and its end points later.
+ //
+ // * Finally, if we have two equal intervals whose errors have the same
+ // size, none of them will be strictly contained inside the other.
+ // Sorting by ErrorId will guarantee that the begin point of the first
+ // one will be processed before, disallowing the second one, and the
+ // end point of the first one will also be processed before,
+ // disallowing the first one.
+ if (Type == ET_Begin)
+ Priority = std::make_tuple(Begin, Type, -End, -ErrorSize, ErrorId);
+ else
+ Priority = std::make_tuple(End, Type, -Begin, ErrorSize, ErrorId);
+ }
+
+ bool operator<(const Event &Other) const {
+ return Priority < Other.Priority;
+ }
+
+ // Determines if this event is the begin or the end of an interval.
+ EventType Type;
+ // The index of the error to which the interval that generated this event
+ // belongs.
+ unsigned ErrorId;
+ // The events will be sorted based on this field.
+ std::tuple<unsigned, EventType, int, int, unsigned> Priority;
+ };
+
+ // Compute error sizes.
+ std::vector<int> Sizes;
+ for (const auto &Error : Errors) {
+ int Size = 0;
+ for (const auto &FileAndReplaces : Error.Fix) {
+ for (const auto &Replace : FileAndReplaces.second)
+ Size += Replace.getLength();
+ }
+ Sizes.push_back(Size);
+ }
+
+ // Build events from error intervals.
+ std::map<std::string, std::vector<Event>> FileEvents;
+ for (unsigned I = 0; I < Errors.size(); ++I) {
+ for (const auto &FileAndReplace : Errors[I].Fix) {
+ for (const auto &Replace : FileAndReplace.second) {
+ unsigned Begin = Replace.getOffset();
+ unsigned End = Begin + Replace.getLength();
+ const std::string &FilePath = Replace.getFilePath();
+ // FIXME: Handle empty intervals, such as those from insertions.
+ if (Begin == End)
+ continue;
+ auto &Events = FileEvents[FilePath];
+ Events.emplace_back(Begin, End, Event::ET_Begin, I, Sizes[I]);
+ Events.emplace_back(Begin, End, Event::ET_End, I, Sizes[I]);
+ }
+ }
+ }
+
+ std::vector<bool> Apply(Errors.size(), true);
+ for (auto &FileAndEvents : FileEvents) {
+ std::vector<Event> &Events = FileAndEvents.second;
+ // Sweep.
+ std::sort(Events.begin(), Events.end());
+ int OpenIntervals = 0;
+ for (const auto &Event : Events) {
+ if (Event.Type == Event::ET_End)
+ --OpenIntervals;
+ // This has to be checked after removing the interval from the count if it
+ // is an end event, or before adding it if it is a begin event.
+ if (OpenIntervals != 0)
+ Apply[Event.ErrorId] = false;
+ if (Event.Type == Event::ET_Begin)
+ ++OpenIntervals;
+ }
+ assert(OpenIntervals == 0 && "Amount of begin/end points doesn't match");
+ }
+
+ for (unsigned I = 0; I < Errors.size(); ++I) {
+ if (!Apply[I]) {
+ Errors[I].Fix.clear();
+ Errors[I].Notes.emplace_back(
+ "this fix will not be applied because it overlaps with another fix");
+ }
+ }
+}
+
+namespace {
+struct LessClangTidyError {
+ bool operator()(const ClangTidyError &LHS, const ClangTidyError &RHS) const {
+ const tooling::DiagnosticMessage &M1 = LHS.Message;
+ const tooling::DiagnosticMessage &M2 = RHS.Message;
+
+ return std::tie(M1.FilePath, M1.FileOffset, M1.Message) <
+ std::tie(M2.FilePath, M2.FileOffset, M2.Message);
+ }
+};
+struct EqualClangTidyError {
+ bool operator()(const ClangTidyError &LHS, const ClangTidyError &RHS) const {
+ LessClangTidyError Less;
+ return !Less(LHS, RHS) && !Less(RHS, LHS);
+ }
+};
+} // end anonymous namespace
+
+// Flushes the internal diagnostics buffer to the ClangTidyContext.
+void ClangTidyDiagnosticConsumer::finish() {
+ finalizeLastError();
+
+ std::sort(Errors.begin(), Errors.end(), LessClangTidyError());
+ Errors.erase(std::unique(Errors.begin(), Errors.end(), EqualClangTidyError()),
+ Errors.end());
+
+ if (RemoveIncompatibleErrors)
+ removeIncompatibleErrors(Errors);
+
+ for (const ClangTidyError &Error : Errors)
+ Context.storeError(Error);
+ Errors.clear();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
new file mode 100644
index 0000000..ae25013
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -0,0 +1,276 @@
+//===--- ClangTidyDiagnosticConsumer.h - clang-tidy -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
+
+#include "ClangTidyOptions.h"
+#include "ClangTidyProfiling.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Core/Diagnostic.h"
+#include "clang/Tooling/Refactoring.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/Timer.h"
+
+namespace clang {
+
+class ASTContext;
+class CompilerInstance;
+namespace ast_matchers {
+class MatchFinder;
+}
+namespace tooling {
+class CompilationDatabase;
+}
+
+namespace tidy {
+
+/// \brief A detected error complete with information to display diagnostic and
+/// automatic fix.
+///
+/// This is used as an intermediate format to transport Diagnostics without a
+/// dependency on a SourceManager.
+///
+/// FIXME: Make Diagnostics flexible enough to support this directly.
+struct ClangTidyError : tooling::Diagnostic {
+ ClangTidyError(StringRef CheckName, Level DiagLevel, StringRef BuildDirectory,
+ bool IsWarningAsError);
+
+ bool IsWarningAsError;
+};
+
+/// \brief Read-only set of strings represented as a list of positive and
+/// negative globs. Positive globs add all matched strings to the set, negative
+/// globs remove them in the order of appearance in the list.
+class GlobList {
+public:
+ /// \brief \p GlobList is a comma-separated list of globs (only '*'
+ /// metacharacter is supported) with optional '-' prefix to denote exclusion.
+ GlobList(StringRef Globs);
+
+ /// \brief Returns \c true if the pattern matches \p S. The result is the last
+ /// matching glob's Positive flag.
+ bool contains(StringRef S) { return contains(S, false); }
+
+private:
+ bool contains(StringRef S, bool Contains);
+
+ bool Positive;
+ llvm::Regex Regex;
+ std::unique_ptr<GlobList> NextGlob;
+};
+
+/// \brief Contains displayed and ignored diagnostic counters for a ClangTidy
+/// run.
+struct ClangTidyStats {
+ ClangTidyStats()
+ : ErrorsDisplayed(0), ErrorsIgnoredCheckFilter(0), ErrorsIgnoredNOLINT(0),
+ ErrorsIgnoredNonUserCode(0), ErrorsIgnoredLineFilter(0) {}
+
+ unsigned ErrorsDisplayed;
+ unsigned ErrorsIgnoredCheckFilter;
+ unsigned ErrorsIgnoredNOLINT;
+ unsigned ErrorsIgnoredNonUserCode;
+ unsigned ErrorsIgnoredLineFilter;
+
+ unsigned errorsIgnored() const {
+ return ErrorsIgnoredNOLINT + ErrorsIgnoredCheckFilter +
+ ErrorsIgnoredNonUserCode + ErrorsIgnoredLineFilter;
+ }
+};
+
+/// \brief Every \c ClangTidyCheck reports errors through a \c DiagnosticsEngine
+/// provided by this context.
+///
+/// A \c ClangTidyCheck always has access to the active context to report
+/// warnings like:
+/// \code
+/// Context->Diag(Loc, "Single-argument constructors must be explicit")
+/// << FixItHint::CreateInsertion(Loc, "explicit ");
+/// \endcode
+class ClangTidyContext {
+public:
+ /// \brief Initializes \c ClangTidyContext instance.
+ ClangTidyContext(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
+ bool AllowEnablingAnalyzerAlphaCheckers = false);
+
+ ~ClangTidyContext();
+
+ /// \brief Report any errors detected using this method.
+ ///
+ /// This is still under heavy development and will likely change towards using
+ /// tablegen'd diagnostic IDs.
+ /// FIXME: Figure out a way to manage ID spaces.
+ DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc,
+ StringRef Message,
+ DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
+
+ /// \brief Sets the \c SourceManager of the used \c DiagnosticsEngine.
+ ///
+ /// This is called from the \c ClangTidyCheck base class.
+ void setSourceManager(SourceManager *SourceMgr);
+
+ /// \brief Should be called when starting to process new translation unit.
+ void setCurrentFile(StringRef File);
+
+ /// \brief Returns the main file name of the current translation unit.
+ StringRef getCurrentFile() const { return CurrentFile; }
+
+ /// \brief Sets ASTContext for the current translation unit.
+ void setASTContext(ASTContext *Context);
+
+ /// \brief Gets the language options from the AST context.
+ const LangOptions &getLangOpts() const { return LangOpts; }
+
+ /// \brief Returns the name of the clang-tidy check which produced this
+ /// diagnostic ID.
+ StringRef getCheckName(unsigned DiagnosticID) const;
+
+ /// \brief Returns \c true if the check is enabled for the \c CurrentFile.
+ ///
+ /// The \c CurrentFile can be changed using \c setCurrentFile.
+ bool isCheckEnabled(StringRef CheckName) const;
+
+ /// \brief Returns \c true if the check should be upgraded to error for the
+ /// \c CurrentFile.
+ bool treatAsError(StringRef CheckName) const;
+
+ /// \brief Returns global options.
+ const ClangTidyGlobalOptions &getGlobalOptions() const;
+
+ /// \brief Returns options for \c CurrentFile.
+ ///
+ /// The \c CurrentFile can be changed using \c setCurrentFile.
+ const ClangTidyOptions &getOptions() const;
+
+ /// \brief Returns options for \c File. Does not change or depend on
+ /// \c CurrentFile.
+ ClangTidyOptions getOptionsForFile(StringRef File) const;
+
+ /// \brief Returns \c ClangTidyStats containing issued and ignored diagnostic
+ /// counters.
+ const ClangTidyStats &getStats() const { return Stats; }
+
+ /// \brief Returns all collected errors.
+ ArrayRef<ClangTidyError> getErrors() const { return Errors; }
+
+ /// \brief Clears collected errors.
+ void clearErrors() { Errors.clear(); }
+
+ /// \brief Control profile collection in clang-tidy.
+ void setEnableProfiling(bool Profile);
+ bool getEnableProfiling() const { return Profile; }
+
+ /// \brief Control storage of profile date.
+ void setProfileStoragePrefix(StringRef ProfilePrefix);
+ llvm::Optional<ClangTidyProfiling::StorageParams>
+ getProfileStorageParams() const;
+
+ /// \brief Should be called when starting to process new translation unit.
+ void setCurrentBuildDirectory(StringRef BuildDirectory) {
+ CurrentBuildDirectory = BuildDirectory;
+ }
+
+ /// \brief Returns build directory of the current translation unit.
+ const std::string &getCurrentBuildDirectory() {
+ return CurrentBuildDirectory;
+ }
+
+ /// \brief If the experimental alpha checkers from the static analyzer can be
+ /// enabled.
+ bool canEnableAnalyzerAlphaCheckers() const {
+ return AllowEnablingAnalyzerAlphaCheckers;
+ }
+
+private:
+ // Calls setDiagnosticsEngine() and storeError().
+ friend class ClangTidyDiagnosticConsumer;
+ friend class ClangTidyPluginAction;
+
+ /// \brief Sets the \c DiagnosticsEngine so that Diagnostics can be generated
+ /// correctly.
+ void setDiagnosticsEngine(DiagnosticsEngine *Engine);
+
+ /// \brief Store an \p Error.
+ void storeError(const ClangTidyError &Error);
+
+ std::vector<ClangTidyError> Errors;
+ DiagnosticsEngine *DiagEngine;
+ std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
+
+ std::string CurrentFile;
+ ClangTidyOptions CurrentOptions;
+ class CachedGlobList;
+ std::unique_ptr<CachedGlobList> CheckFilter;
+ std::unique_ptr<CachedGlobList> WarningAsErrorFilter;
+
+ LangOptions LangOpts;
+
+ ClangTidyStats Stats;
+
+ std::string CurrentBuildDirectory;
+
+ llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID;
+
+ bool Profile;
+ std::string ProfilePrefix;
+
+ bool AllowEnablingAnalyzerAlphaCheckers;
+};
+
+/// \brief A diagnostic consumer that turns each \c Diagnostic into a
+/// \c SourceManager-independent \c ClangTidyError.
+//
+// FIXME: If we move away from unit-tests, this can be moved to a private
+// implementation file.
+class ClangTidyDiagnosticConsumer : public DiagnosticConsumer {
+public:
+ ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx,
+ bool RemoveIncompatibleErrors = true);
+
+ // FIXME: The concept of converting between FixItHints and Replacements is
+ // more generic and should be pulled out into a more useful Diagnostics
+ // library.
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) override;
+
+ /// \brief Flushes the internal diagnostics buffer to the ClangTidyContext.
+ void finish() override;
+
+private:
+ void finalizeLastError();
+
+ void removeIncompatibleErrors(SmallVectorImpl<ClangTidyError> &Errors) const;
+
+ /// \brief Returns the \c HeaderFilter constructed for the options set in the
+ /// context.
+ llvm::Regex *getHeaderFilter();
+
+ /// \brief Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter
+ /// according to the diagnostic \p Location.
+ void checkFilters(SourceLocation Location);
+ bool passesLineFilter(StringRef FileName, unsigned LineNumber) const;
+
+ ClangTidyContext &Context;
+ bool RemoveIncompatibleErrors;
+ std::unique_ptr<DiagnosticsEngine> Diags;
+ SmallVector<ClangTidyError, 8> Errors;
+ std::unique_ptr<llvm::Regex> HeaderFilter;
+ bool LastErrorRelatesToUserCode;
+ bool LastErrorPassesLineFilter;
+ bool LastErrorWasIgnored;
+};
+
+} // end namespace tidy
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYDIAGNOSTICCONSUMER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyModule.cpp
new file mode 100644
index 0000000..9dbf016
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyModule.cpp
@@ -0,0 +1,38 @@
+//===--- tools/extra/clang-tidy/ClangTidyModule.cpp - Clang tidy tool -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file Implements classes required to build clang-tidy modules.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ClangTidyModule.h"
+
+namespace clang {
+namespace tidy {
+
+void ClangTidyCheckFactories::registerCheckFactory(StringRef Name,
+ CheckFactory Factory) {
+ Factories[Name] = std::move(Factory);
+}
+
+void ClangTidyCheckFactories::createChecks(
+ ClangTidyContext *Context,
+ std::vector<std::unique_ptr<ClangTidyCheck>> &Checks) {
+ for (const auto &Factory : Factories) {
+ if (Context->isCheckEnabled(Factory.first))
+ Checks.emplace_back(Factory.second(Factory.first, Context));
+ }
+}
+
+ClangTidyOptions ClangTidyModule::getModuleOptions() {
+ return ClangTidyOptions();
+}
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyModule.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyModule.h
new file mode 100644
index 0000000..4721636
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyModule.h
@@ -0,0 +1,99 @@
+//===--- ClangTidyModule.h - clang-tidy -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYMODULE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYMODULE_H
+
+#include "ClangTidy.h"
+#include "llvm/ADT/StringRef.h"
+#include <functional>
+#include <map>
+#include <string>
+#include <utility>
+
+namespace clang {
+namespace tidy {
+
+/// \brief A collection of \c ClangTidyCheckFactory instances.
+///
+/// All clang-tidy modules register their check factories with an instance of
+/// this object.
+class ClangTidyCheckFactories {
+public:
+ typedef std::function<ClangTidyCheck *(StringRef Name,
+ ClangTidyContext *Context)>
+ CheckFactory;
+
+ /// \brief Registers check \p Factory with name \p Name.
+ ///
+ /// For all checks that have default constructors, use \c registerCheck.
+ void registerCheckFactory(StringRef Name, CheckFactory Factory);
+
+ /// \brief Registers the \c CheckType with the name \p Name.
+ ///
+ /// This method should be used for all \c ClangTidyChecks that don't require
+ /// constructor parameters.
+ ///
+ /// For example, if have a clang-tidy check like:
+ /// \code
+ /// class MyTidyCheck : public ClangTidyCheck {
+ /// void registerMatchers(ast_matchers::MatchFinder *Finder) override {
+ /// ..
+ /// }
+ /// };
+ /// \endcode
+ /// you can register it with:
+ /// \code
+ /// class MyModule : public ClangTidyModule {
+ /// void addCheckFactories(ClangTidyCheckFactories &Factories) override {
+ /// Factories.registerCheck<MyTidyCheck>("myproject-my-check");
+ /// }
+ /// };
+ /// \endcode
+ template <typename CheckType> void registerCheck(StringRef CheckName) {
+ registerCheckFactory(CheckName,
+ [](StringRef Name, ClangTidyContext *Context) {
+ return new CheckType(Name, Context);
+ });
+ }
+
+ /// \brief Create instances of all checks matching \p CheckRegexString and
+ /// store them in \p Checks.
+ ///
+ /// The caller takes ownership of the return \c ClangTidyChecks.
+ void createChecks(ClangTidyContext *Context,
+ std::vector<std::unique_ptr<ClangTidyCheck>> &Checks);
+
+ typedef std::map<std::string, CheckFactory> FactoryMap;
+ FactoryMap::const_iterator begin() const { return Factories.begin(); }
+ FactoryMap::const_iterator end() const { return Factories.end(); }
+ bool empty() const { return Factories.empty(); }
+
+private:
+ FactoryMap Factories;
+};
+
+/// \brief A clang-tidy module groups a number of \c ClangTidyChecks and gives
+/// them a prefixed name.
+class ClangTidyModule {
+public:
+ virtual ~ClangTidyModule() {}
+
+ /// \brief Implement this function in order to register all \c CheckFactories
+ /// belonging to this module.
+ virtual void addCheckFactories(ClangTidyCheckFactories &CheckFactories) = 0;
+
+ /// \brief Gets default options for checks defined in this module.
+ virtual ClangTidyOptions getModuleOptions();
+};
+
+} // end namespace tidy
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYMODULE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h
new file mode 100644
index 0000000..dc44d14
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyModuleRegistry.h
@@ -0,0 +1,24 @@
+//===--- ClangTidyModuleRegistry.h - clang-tidy -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYMODULEREGISTRY_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYMODULEREGISTRY_H
+
+#include "ClangTidyModule.h"
+#include "llvm/Support/Registry.h"
+
+namespace clang {
+namespace tidy {
+
+typedef llvm::Registry<ClangTidyModule> ClangTidyModuleRegistry;
+
+} // end namespace tidy
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYMODULEREGISTRY_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
new file mode 100644
index 0000000..430f8b3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
@@ -0,0 +1,349 @@
+//===--- ClangTidyOptions.cpp - clang-tidy ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangTidyOptions.h"
+#include "ClangTidyModuleRegistry.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <utility>
+
+#define DEBUG_TYPE "clang-tidy-options"
+
+using clang::tidy::ClangTidyOptions;
+using clang::tidy::FileFilter;
+using OptionsSource = clang::tidy::ClangTidyOptionsProvider::OptionsSource;
+
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FileFilter)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FileFilter::LineRange)
+
+namespace llvm {
+namespace yaml {
+
+// Map std::pair<int, int> to a JSON array of size 2.
+template <> struct SequenceTraits<FileFilter::LineRange> {
+ static size_t size(IO &IO, FileFilter::LineRange &Range) {
+ return Range.first == 0 ? 0 : Range.second == 0 ? 1 : 2;
+ }
+ static unsigned &element(IO &IO, FileFilter::LineRange &Range, size_t Index) {
+ if (Index > 1)
+ IO.setError("Too many elements in line range.");
+ return Index == 0 ? Range.first : Range.second;
+ }
+};
+
+template <> struct MappingTraits<FileFilter> {
+ static void mapping(IO &IO, FileFilter &File) {
+ IO.mapRequired("name", File.Name);
+ IO.mapOptional("lines", File.LineRanges);
+ }
+ static StringRef validate(IO &io, FileFilter &File) {
+ if (File.Name.empty())
+ return "No file name specified";
+ for (const FileFilter::LineRange &Range : File.LineRanges) {
+ if (Range.first <= 0 || Range.second <= 0)
+ return "Invalid line range";
+ }
+ return StringRef();
+ }
+};
+
+template <> struct MappingTraits<ClangTidyOptions::StringPair> {
+ static void mapping(IO &IO, ClangTidyOptions::StringPair &KeyValue) {
+ IO.mapRequired("key", KeyValue.first);
+ IO.mapRequired("value", KeyValue.second);
+ }
+};
+
+struct NOptionMap {
+ NOptionMap(IO &) {}
+ NOptionMap(IO &, const ClangTidyOptions::OptionMap &OptionMap)
+ : Options(OptionMap.begin(), OptionMap.end()) {}
+ ClangTidyOptions::OptionMap denormalize(IO &) {
+ ClangTidyOptions::OptionMap Map;
+ for (const auto &KeyValue : Options)
+ Map[KeyValue.first] = KeyValue.second;
+ return Map;
+ }
+ std::vector<ClangTidyOptions::StringPair> Options;
+};
+
+template <> struct MappingTraits<ClangTidyOptions> {
+ static void mapping(IO &IO, ClangTidyOptions &Options) {
+ MappingNormalization<NOptionMap, ClangTidyOptions::OptionMap> NOpts(
+ IO, Options.CheckOptions);
+ bool Ignored = false;
+ IO.mapOptional("Checks", Options.Checks);
+ IO.mapOptional("WarningsAsErrors", Options.WarningsAsErrors);
+ IO.mapOptional("HeaderFilterRegex", Options.HeaderFilterRegex);
+ IO.mapOptional("AnalyzeTemporaryDtors", Ignored); // legacy compatibility
+ IO.mapOptional("FormatStyle", Options.FormatStyle);
+ IO.mapOptional("User", Options.User);
+ IO.mapOptional("CheckOptions", NOpts->Options);
+ IO.mapOptional("ExtraArgs", Options.ExtraArgs);
+ IO.mapOptional("ExtraArgsBefore", Options.ExtraArgsBefore);
+ }
+};
+
+} // namespace yaml
+} // namespace llvm
+
+namespace clang {
+namespace tidy {
+
+ClangTidyOptions ClangTidyOptions::getDefaults() {
+ ClangTidyOptions Options;
+ Options.Checks = "";
+ Options.WarningsAsErrors = "";
+ Options.HeaderFilterRegex = "";
+ Options.SystemHeaders = false;
+ Options.FormatStyle = "none";
+ Options.User = llvm::None;
+ for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(),
+ E = ClangTidyModuleRegistry::end();
+ I != E; ++I)
+ Options = Options.mergeWith(I->instantiate()->getModuleOptions());
+ return Options;
+}
+
+template <typename T>
+static void mergeVectors(Optional<T> &Dest, const Optional<T> &Src) {
+ if (Src) {
+ if (Dest)
+ Dest->insert(Dest->end(), Src->begin(), Src->end());
+ else
+ Dest = Src;
+ }
+}
+
+static void mergeCommaSeparatedLists(Optional<std::string> &Dest,
+ const Optional<std::string> &Src) {
+ if (Src)
+ Dest = (Dest && !Dest->empty() ? *Dest + "," : "") + *Src;
+}
+
+template <typename T>
+static void overrideValue(Optional<T> &Dest, const Optional<T> &Src) {
+ if (Src)
+ Dest = Src;
+}
+
+ClangTidyOptions
+ClangTidyOptions::mergeWith(const ClangTidyOptions &Other) const {
+ ClangTidyOptions Result = *this;
+
+ mergeCommaSeparatedLists(Result.Checks, Other.Checks);
+ mergeCommaSeparatedLists(Result.WarningsAsErrors, Other.WarningsAsErrors);
+ overrideValue(Result.HeaderFilterRegex, Other.HeaderFilterRegex);
+ overrideValue(Result.SystemHeaders, Other.SystemHeaders);
+ overrideValue(Result.FormatStyle, Other.FormatStyle);
+ overrideValue(Result.User, Other.User);
+ mergeVectors(Result.ExtraArgs, Other.ExtraArgs);
+ mergeVectors(Result.ExtraArgsBefore, Other.ExtraArgsBefore);
+
+ for (const auto &KeyValue : Other.CheckOptions)
+ Result.CheckOptions[KeyValue.first] = KeyValue.second;
+
+ return Result;
+}
+
+const char ClangTidyOptionsProvider::OptionsSourceTypeDefaultBinary[] =
+ "clang-tidy binary";
+const char ClangTidyOptionsProvider::OptionsSourceTypeCheckCommandLineOption[] =
+ "command-line option '-checks'";
+const char
+ ClangTidyOptionsProvider::OptionsSourceTypeConfigCommandLineOption[] =
+ "command-line option '-config'";
+
+ClangTidyOptions
+ClangTidyOptionsProvider::getOptions(llvm::StringRef FileName) {
+ ClangTidyOptions Result;
+ for (const auto &Source : getRawOptions(FileName))
+ Result = Result.mergeWith(Source.first);
+ return Result;
+}
+
+std::vector<OptionsSource>
+DefaultOptionsProvider::getRawOptions(llvm::StringRef FileName) {
+ std::vector<OptionsSource> Result;
+ Result.emplace_back(DefaultOptions, OptionsSourceTypeDefaultBinary);
+ return Result;
+}
+
+ConfigOptionsProvider::ConfigOptionsProvider(
+ const ClangTidyGlobalOptions &GlobalOptions,
+ const ClangTidyOptions &DefaultOptions,
+ const ClangTidyOptions &ConfigOptions,
+ const ClangTidyOptions &OverrideOptions)
+ : DefaultOptionsProvider(GlobalOptions, DefaultOptions),
+ ConfigOptions(ConfigOptions), OverrideOptions(OverrideOptions) {}
+
+std::vector<OptionsSource>
+ConfigOptionsProvider::getRawOptions(llvm::StringRef FileName) {
+ std::vector<OptionsSource> RawOptions =
+ DefaultOptionsProvider::getRawOptions(FileName);
+ RawOptions.emplace_back(ConfigOptions,
+ OptionsSourceTypeConfigCommandLineOption);
+ RawOptions.emplace_back(OverrideOptions,
+ OptionsSourceTypeCheckCommandLineOption);
+ return RawOptions;
+}
+
+FileOptionsProvider::FileOptionsProvider(
+ const ClangTidyGlobalOptions &GlobalOptions,
+ const ClangTidyOptions &DefaultOptions,
+ const ClangTidyOptions &OverrideOptions,
+ llvm::IntrusiveRefCntPtr<vfs::FileSystem> VFS)
+ : DefaultOptionsProvider(GlobalOptions, DefaultOptions),
+ OverrideOptions(OverrideOptions), FS(std::move(VFS)) {
+ if (!FS)
+ FS = vfs::getRealFileSystem();
+ ConfigHandlers.emplace_back(".clang-tidy", parseConfiguration);
+}
+
+FileOptionsProvider::FileOptionsProvider(
+ const ClangTidyGlobalOptions &GlobalOptions,
+ const ClangTidyOptions &DefaultOptions,
+ const ClangTidyOptions &OverrideOptions,
+ const FileOptionsProvider::ConfigFileHandlers &ConfigHandlers)
+ : DefaultOptionsProvider(GlobalOptions, DefaultOptions),
+ OverrideOptions(OverrideOptions), ConfigHandlers(ConfigHandlers) {}
+
+// FIXME: This method has some common logic with clang::format::getStyle().
+// Consider pulling out common bits to a findParentFileWithName function or
+// similar.
+std::vector<OptionsSource>
+FileOptionsProvider::getRawOptions(StringRef FileName) {
+ LLVM_DEBUG(llvm::dbgs() << "Getting options for file " << FileName
+ << "...\n");
+ assert(FS && "FS must be set.");
+
+ llvm::SmallString<128> AbsoluteFilePath(FileName);
+
+ if (FS->makeAbsolute(AbsoluteFilePath))
+ return {};
+
+ std::vector<OptionsSource> RawOptions =
+ DefaultOptionsProvider::getRawOptions(AbsoluteFilePath.str());
+ OptionsSource CommandLineOptions(OverrideOptions,
+ OptionsSourceTypeCheckCommandLineOption);
+ // Look for a suitable configuration file in all parent directories of the
+ // file. Start with the immediate parent directory and move up.
+ StringRef Path = llvm::sys::path::parent_path(AbsoluteFilePath.str());
+ for (StringRef CurrentPath = Path; !CurrentPath.empty();
+ CurrentPath = llvm::sys::path::parent_path(CurrentPath)) {
+ llvm::Optional<OptionsSource> Result;
+
+ auto Iter = CachedOptions.find(CurrentPath);
+ if (Iter != CachedOptions.end())
+ Result = Iter->second;
+
+ if (!Result)
+ Result = tryReadConfigFile(CurrentPath);
+
+ if (Result) {
+ // Store cached value for all intermediate directories.
+ while (Path != CurrentPath) {
+ LLVM_DEBUG(llvm::dbgs()
+ << "Caching configuration for path " << Path << ".\n");
+ CachedOptions[Path] = *Result;
+ Path = llvm::sys::path::parent_path(Path);
+ }
+ CachedOptions[Path] = *Result;
+
+ RawOptions.push_back(*Result);
+ break;
+ }
+ }
+ RawOptions.push_back(CommandLineOptions);
+ return RawOptions;
+}
+
+llvm::Optional<OptionsSource>
+FileOptionsProvider::tryReadConfigFile(StringRef Directory) {
+ assert(!Directory.empty());
+
+ if (!llvm::sys::fs::is_directory(Directory)) {
+ llvm::errs() << "Error reading configuration from " << Directory
+ << ": directory doesn't exist.\n";
+ return llvm::None;
+ }
+
+ for (const ConfigFileHandler &ConfigHandler : ConfigHandlers) {
+ SmallString<128> ConfigFile(Directory);
+ llvm::sys::path::append(ConfigFile, ConfigHandler.first);
+ LLVM_DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
+
+ bool IsFile = false;
+ // Ignore errors from is_regular_file: we only need to know if we can read
+ // the file or not.
+ llvm::sys::fs::is_regular_file(Twine(ConfigFile), IsFile);
+ if (!IsFile)
+ continue;
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
+ llvm::MemoryBuffer::getFile(ConfigFile.c_str());
+ if (std::error_code EC = Text.getError()) {
+ llvm::errs() << "Can't read " << ConfigFile << ": " << EC.message()
+ << "\n";
+ continue;
+ }
+
+ // Skip empty files, e.g. files opened for writing via shell output
+ // redirection.
+ if ((*Text)->getBuffer().empty())
+ continue;
+ llvm::ErrorOr<ClangTidyOptions> ParsedOptions =
+ ConfigHandler.second((*Text)->getBuffer());
+ if (!ParsedOptions) {
+ if (ParsedOptions.getError())
+ llvm::errs() << "Error parsing " << ConfigFile << ": "
+ << ParsedOptions.getError().message() << "\n";
+ continue;
+ }
+ return OptionsSource(*ParsedOptions, ConfigFile.c_str());
+ }
+ return llvm::None;
+}
+
+/// \brief Parses -line-filter option and stores it to the \c Options.
+std::error_code parseLineFilter(StringRef LineFilter,
+ clang::tidy::ClangTidyGlobalOptions &Options) {
+ llvm::yaml::Input Input(LineFilter);
+ Input >> Options.LineFilter;
+ return Input.error();
+}
+
+llvm::ErrorOr<ClangTidyOptions> parseConfiguration(StringRef Config) {
+ llvm::yaml::Input Input(Config);
+ ClangTidyOptions Options;
+ Input >> Options;
+ if (Input.error())
+ return Input.error();
+ return Options;
+}
+
+std::string configurationAsText(const ClangTidyOptions &Options) {
+ std::string Text;
+ llvm::raw_string_ostream Stream(Text);
+ llvm::yaml::Output Output(Stream);
+ // We use the same mapping method for input and output, so we need a non-const
+ // reference here.
+ ClangTidyOptions NonConstValue = Options;
+ Output << NonConstValue;
+ return Stream.str();
+}
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyOptions.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyOptions.h
new file mode 100644
index 0000000..b2a4ce4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyOptions.h
@@ -0,0 +1,275 @@
+//===--- ClangTidyOptions.h - clang-tidy ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/Support/ErrorOr.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include <functional>
+#include <map>
+#include <string>
+#include <system_error>
+#include <utility>
+#include <vector>
+
+namespace clang {
+namespace tidy {
+
+/// \brief Contains a list of line ranges in a single file.
+struct FileFilter {
+ /// \brief File name.
+ std::string Name;
+
+ /// \brief LineRange is a pair<start, end> (inclusive).
+ typedef std::pair<unsigned, unsigned> LineRange;
+
+ /// \brief A list of line ranges in this file, for which we show warnings.
+ std::vector<LineRange> LineRanges;
+};
+
+/// \brief Global options. These options are neither stored nor read from
+/// configuration files.
+struct ClangTidyGlobalOptions {
+ /// \brief Output warnings from certain line ranges of certain files only.
+ /// If empty, no warnings will be filtered.
+ std::vector<FileFilter> LineFilter;
+};
+
+/// \brief Contains options for clang-tidy. These options may be read from
+/// configuration files, and may be different for different translation units.
+struct ClangTidyOptions {
+ /// \brief These options are used for all settings that haven't been
+ /// overridden by the \c OptionsProvider.
+ ///
+ /// Allow no checks and no headers by default. This method initializes
+ /// check-specific options by calling \c ClangTidyModule::getModuleOptions()
+ /// of each registered \c ClangTidyModule.
+ static ClangTidyOptions getDefaults();
+
+ /// \brief Creates a new \c ClangTidyOptions instance combined from all fields
+ /// of this instance overridden by the fields of \p Other that have a value.
+ ClangTidyOptions mergeWith(const ClangTidyOptions &Other) const;
+
+ /// \brief Checks filter.
+ llvm::Optional<std::string> Checks;
+
+ /// \brief WarningsAsErrors filter.
+ llvm::Optional<std::string> WarningsAsErrors;
+
+ /// \brief Output warnings from headers matching this filter. Warnings from
+ /// main files will always be displayed.
+ llvm::Optional<std::string> HeaderFilterRegex;
+
+ /// \brief Output warnings from system headers matching \c HeaderFilterRegex.
+ llvm::Optional<bool> SystemHeaders;
+
+ /// \brief Format code around applied fixes with clang-format using this
+ /// style.
+ ///
+ /// Can be one of:
+ /// * 'none' - don't format code around applied fixes;
+ /// * 'llvm', 'google', 'mozilla' or other predefined clang-format style
+ /// names;
+ /// * 'file' - use the .clang-format file in the closest parent directory of
+ /// each source file;
+ /// * '{inline-formatting-style-in-yaml-format}'.
+ ///
+ /// See clang-format documentation for more about configuring format style.
+ llvm::Optional<std::string> FormatStyle;
+
+ /// \brief Specifies the name or e-mail of the user running clang-tidy.
+ ///
+ /// This option is used, for example, to place the correct user name in TODO()
+ /// comments in the relevant check.
+ llvm::Optional<std::string> User;
+
+ typedef std::pair<std::string, std::string> StringPair;
+ typedef std::map<std::string, std::string> OptionMap;
+
+ /// \brief Key-value mapping used to store check-specific options.
+ OptionMap CheckOptions;
+
+ typedef std::vector<std::string> ArgList;
+
+ /// \brief Add extra compilation arguments to the end of the list.
+ llvm::Optional<ArgList> ExtraArgs;
+
+ /// \brief Add extra compilation arguments to the start of the list.
+ llvm::Optional<ArgList> ExtraArgsBefore;
+};
+
+/// \brief Abstract interface for retrieving various ClangTidy options.
+class ClangTidyOptionsProvider {
+public:
+ static const char OptionsSourceTypeDefaultBinary[];
+ static const char OptionsSourceTypeCheckCommandLineOption[];
+ static const char OptionsSourceTypeConfigCommandLineOption[];
+
+ virtual ~ClangTidyOptionsProvider() {}
+
+ /// \brief Returns global options, which are independent of the file.
+ virtual const ClangTidyGlobalOptions &getGlobalOptions() = 0;
+
+ /// \brief ClangTidyOptions and its source.
+ //
+ /// clang-tidy has 3 types of the sources in order of increasing priority:
+ /// * clang-tidy binary.
+ /// * '-config' commandline option or a specific configuration file. If the
+ /// commandline option is specified, clang-tidy will ignore the
+ /// configuration file.
+ /// * '-checks' commandline option.
+ typedef std::pair<ClangTidyOptions, std::string> OptionsSource;
+
+ /// \brief Returns an ordered vector of OptionsSources, in order of increasing
+ /// priority.
+ virtual std::vector<OptionsSource>
+ getRawOptions(llvm::StringRef FileName) = 0;
+
+ /// \brief Returns options applying to a specific translation unit with the
+ /// specified \p FileName.
+ ClangTidyOptions getOptions(llvm::StringRef FileName);
+};
+
+/// \brief Implementation of the \c ClangTidyOptionsProvider interface, which
+/// returns the same options for all files.
+class DefaultOptionsProvider : public ClangTidyOptionsProvider {
+public:
+ DefaultOptionsProvider(const ClangTidyGlobalOptions &GlobalOptions,
+ const ClangTidyOptions &Options)
+ : GlobalOptions(GlobalOptions), DefaultOptions(Options) {}
+ const ClangTidyGlobalOptions &getGlobalOptions() override {
+ return GlobalOptions;
+ }
+ std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override;
+
+private:
+ ClangTidyGlobalOptions GlobalOptions;
+ ClangTidyOptions DefaultOptions;
+};
+
+/// \brief Implementation of ClangTidyOptions interface, which is used for
+/// '-config' command-line option.
+class ConfigOptionsProvider : public DefaultOptionsProvider {
+public:
+ ConfigOptionsProvider(const ClangTidyGlobalOptions &GlobalOptions,
+ const ClangTidyOptions &DefaultOptions,
+ const ClangTidyOptions &ConfigOptions,
+ const ClangTidyOptions &OverrideOptions);
+ std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override;
+
+private:
+ ClangTidyOptions ConfigOptions;
+ ClangTidyOptions OverrideOptions;
+};
+
+/// \brief Implementation of the \c ClangTidyOptionsProvider interface, which
+/// tries to find a configuration file in the closest parent directory of each
+/// source file.
+///
+/// By default, files named ".clang-tidy" will be considered, and the
+/// \c clang::tidy::parseConfiguration function will be used for parsing, but a
+/// custom set of configuration file names and parsing functions can be
+/// specified using the appropriate constructor.
+class FileOptionsProvider : public DefaultOptionsProvider {
+public:
+ // \brief A pair of configuration file base name and a function parsing
+ // configuration from text in the corresponding format.
+ typedef std::pair<std::string, std::function<llvm::ErrorOr<ClangTidyOptions>(
+ llvm::StringRef)>>
+ ConfigFileHandler;
+
+ /// \brief Configuration file handlers listed in the order of priority.
+ ///
+ /// Custom configuration file formats can be supported by constructing the
+ /// list of handlers and passing it to the appropriate \c FileOptionsProvider
+ /// constructor. E.g. initialization of a \c FileOptionsProvider with support
+ /// of a custom configuration file format for files named ".my-tidy-config"
+ /// could look similar to this:
+ /// \code
+ /// FileOptionsProvider::ConfigFileHandlers ConfigHandlers;
+ /// ConfigHandlers.emplace_back(".my-tidy-config", parseMyConfigFormat);
+ /// ConfigHandlers.emplace_back(".clang-tidy", parseConfiguration);
+ /// return llvm::make_unique<FileOptionsProvider>(
+ /// GlobalOptions, DefaultOptions, OverrideOptions, ConfigHandlers);
+ /// \endcode
+ ///
+ /// With the order of handlers shown above, the ".my-tidy-config" file would
+ /// take precedence over ".clang-tidy" if both reside in the same directory.
+ typedef std::vector<ConfigFileHandler> ConfigFileHandlers;
+
+ /// \brief Initializes the \c FileOptionsProvider instance.
+ ///
+ /// \param GlobalOptions are just stored and returned to the caller of
+ /// \c getGlobalOptions.
+ ///
+ /// \param DefaultOptions are used for all settings not specified in a
+ /// configuration file.
+ ///
+ /// If any of the \param OverrideOptions fields are set, they will override
+ /// whatever options are read from the configuration file.
+ FileOptionsProvider(const ClangTidyGlobalOptions &GlobalOptions,
+ const ClangTidyOptions &DefaultOptions,
+ const ClangTidyOptions &OverrideOptions,
+ llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS = nullptr);
+
+ /// \brief Initializes the \c FileOptionsProvider instance with a custom set
+ /// of configuration file handlers.
+ ///
+ /// \param GlobalOptions are just stored and returned to the caller of
+ /// \c getGlobalOptions.
+ ///
+ /// \param DefaultOptions are used for all settings not specified in a
+ /// configuration file.
+ ///
+ /// If any of the \param OverrideOptions fields are set, they will override
+ /// whatever options are read from the configuration file.
+ ///
+ /// \param ConfigHandlers specifies a custom set of configuration file
+ /// handlers. Each handler is a pair of configuration file name and a function
+ /// that can parse configuration from this file type. The configuration files
+ /// in each directory are searched for in the order of appearance in
+ /// \p ConfigHandlers.
+ FileOptionsProvider(const ClangTidyGlobalOptions &GlobalOptions,
+ const ClangTidyOptions &DefaultOptions,
+ const ClangTidyOptions &OverrideOptions,
+ const ConfigFileHandlers &ConfigHandlers);
+
+ std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override;
+
+protected:
+ /// \brief Try to read configuration files from \p Directory using registered
+ /// \c ConfigHandlers.
+ llvm::Optional<OptionsSource> tryReadConfigFile(llvm::StringRef Directory);
+
+ llvm::StringMap<OptionsSource> CachedOptions;
+ ClangTidyOptions OverrideOptions;
+ ConfigFileHandlers ConfigHandlers;
+ llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS;
+};
+
+/// \brief Parses LineFilter from JSON and stores it to the \p Options.
+std::error_code parseLineFilter(llvm::StringRef LineFilter,
+ ClangTidyGlobalOptions &Options);
+
+/// \brief Parses configuration from JSON and returns \c ClangTidyOptions or an
+/// error.
+llvm::ErrorOr<ClangTidyOptions> parseConfiguration(llvm::StringRef Config);
+
+/// \brief Serializes configuration to a YAML-encoded string.
+std::string configurationAsText(const ClangTidyOptions &Options);
+
+} // end namespace tidy
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp
new file mode 100644
index 0000000..fc0a969
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp
@@ -0,0 +1,93 @@
+//===--- ClangTidyProfiling.cpp - clang-tidy --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangTidyProfiling.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <system_error>
+#include <utility>
+
+#define DEBUG_TYPE "clang-tidy-profiling"
+
+namespace clang {
+namespace tidy {
+
+ClangTidyProfiling::StorageParams::StorageParams(llvm::StringRef ProfilePrefix,
+ llvm::StringRef SourceFile)
+ : Timestamp(std::chrono::system_clock::now()), SourceFilename(SourceFile) {
+ llvm::SmallString<32> TimestampStr;
+ llvm::raw_svector_ostream OS(TimestampStr);
+ llvm::format_provider<decltype(Timestamp)>::format(Timestamp, OS,
+ "%Y%m%d%H%M%S%N");
+
+ llvm::SmallString<256> FinalPrefix(ProfilePrefix);
+ llvm::sys::path::append(FinalPrefix, TimestampStr);
+
+ // So the full output name is: /ProfilePrefix/timestamp-inputfilename.json
+ StoreFilename = llvm::Twine(FinalPrefix + "-" +
+ llvm::sys::path::filename(SourceFile) + ".json")
+ .str();
+}
+
+void ClangTidyProfiling::printUserFriendlyTable(llvm::raw_ostream &OS) {
+ TG->print(OS);
+ OS.flush();
+}
+
+void ClangTidyProfiling::printAsJSON(llvm::raw_ostream &OS) {
+ OS << "{\n";
+ OS << "\"file\": \"" << Storage->SourceFilename << "\",\n";
+ OS << "\"timestamp\": \"" << Storage->Timestamp << "\",\n";
+ OS << "\"profile\": {\n";
+ TG->printJSONValues(OS, "");
+ OS << "\n}\n";
+ OS << "}\n";
+ OS.flush();
+}
+
+void ClangTidyProfiling::storeProfileData() {
+ assert(Storage.hasValue() && "We should have a filename.");
+
+ llvm::SmallString<256> OutputDirectory(Storage->StoreFilename);
+ llvm::sys::path::remove_filename(OutputDirectory);
+ if (std::error_code EC = llvm::sys::fs::create_directories(OutputDirectory)) {
+ llvm::errs() << "Unable to create output directory '" << OutputDirectory
+ << "': " << EC.message() << "\n";
+ return;
+ }
+
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(Storage->StoreFilename, EC, llvm::sys::fs::F_None);
+ if (EC) {
+ llvm::errs() << "Error opening output file '" << Storage->StoreFilename
+ << "': " << EC.message() << "\n";
+ return;
+ }
+
+ printAsJSON(OS);
+}
+
+ClangTidyProfiling::ClangTidyProfiling(llvm::Optional<StorageParams> Storage)
+ : Storage(std::move(Storage)) {}
+
+ClangTidyProfiling::~ClangTidyProfiling() {
+ TG.emplace("clang-tidy", "clang-tidy checks profiling", Records);
+
+ if (!Storage.hasValue())
+ printUserFriendlyTable(llvm::errs());
+ else
+ storeProfileData();
+}
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyProfiling.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyProfiling.h
new file mode 100644
index 0000000..9d86b8e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/ClangTidyProfiling.h
@@ -0,0 +1,60 @@
+//===--- ClangTidyProfiling.h - clang-tidy ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYPROFILING_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYPROFILING_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace clang {
+namespace tidy {
+
+class ClangTidyProfiling {
+public:
+ struct StorageParams {
+ llvm::sys::TimePoint<> Timestamp;
+ std::string SourceFilename;
+ std::string StoreFilename;
+
+ StorageParams() = default;
+
+ StorageParams(llvm::StringRef ProfilePrefix, llvm::StringRef SourceFile);
+ };
+
+private:
+ llvm::Optional<llvm::TimerGroup> TG;
+
+ llvm::Optional<StorageParams> Storage;
+
+ void printUserFriendlyTable(llvm::raw_ostream &OS);
+ void printAsJSON(llvm::raw_ostream &OS);
+
+ void storeProfileData();
+
+public:
+ llvm::StringMap<llvm::TimeRecord> Records;
+
+ ClangTidyProfiling() = default;
+
+ ClangTidyProfiling(llvm::Optional<StorageParams> Storage);
+
+ ~ClangTidyProfiling();
+};
+
+} // end namespace tidy
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYPROFILING_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/abseil/AbseilTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/abseil/AbseilTidyModule.cpp
new file mode 100644
index 0000000..8e427f0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/abseil/AbseilTidyModule.cpp
@@ -0,0 +1,38 @@
+//===------- AbseilTidyModule.cpp - clang-tidy ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "StringFindStartswithCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace abseil {
+
+class AbseilModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<StringFindStartswithCheck>(
+ "abseil-string-find-startswith");
+ }
+};
+
+// Register the AbseilModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<AbseilModule> X("abseil-module",
+ "Add Abseil checks.");
+
+} // namespace abseil
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the AbseilModule.
+volatile int AbseilModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/abseil/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/abseil/CMakeLists.txt
new file mode 100644
index 0000000..dd59dcf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/abseil/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyAbseilModule
+ AbseilTidyModule.cpp
+ StringFindStartswithCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyUtils
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/abseil/StringFindStartswithCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/abseil/StringFindStartswithCheck.cpp
new file mode 100644
index 0000000..7a94c10
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/abseil/StringFindStartswithCheck.cpp
@@ -0,0 +1,136 @@
+//===--- StringFindStartswithCheck.cc - clang-tidy---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StringFindStartswithCheck.h"
+
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Frontend/CompilerInstance.h"
+
+#include <cassert>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace abseil {
+
+StringFindStartswithCheck::StringFindStartswithCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ StringLikeClasses(utils::options::parseStringList(
+ Options.get("StringLikeClasses", "::std::basic_string"))),
+ IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
+ Options.getLocalOrGlobal("IncludeStyle", "llvm"))),
+ AbseilStringsMatchHeader(
+ Options.get("AbseilStringsMatchHeader", "absl/strings/match.h")) {}
+
+void StringFindStartswithCheck::registerMatchers(MatchFinder *Finder) {
+ auto ZeroLiteral = integerLiteral(equals(0));
+ auto StringClassMatcher = cxxRecordDecl(hasAnyName(SmallVector<StringRef, 4>(
+ StringLikeClasses.begin(), StringLikeClasses.end())));
+ auto StringType = hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(StringClassMatcher)));
+
+ auto StringFind = cxxMemberCallExpr(
+ // .find()-call on a string...
+ callee(cxxMethodDecl(hasName("find"))),
+ on(hasType(StringType)),
+ // ... with some search expression ...
+ hasArgument(0, expr().bind("needle")),
+ // ... and either "0" as second argument or the default argument (also 0).
+ anyOf(hasArgument(1, ZeroLiteral), hasArgument(1, cxxDefaultArgExpr())));
+
+ Finder->addMatcher(
+ // Match [=!]= with a zero on one side and a string.find on the other.
+ binaryOperator(
+ anyOf(hasOperatorName("=="), hasOperatorName("!=")),
+ hasEitherOperand(ignoringParenImpCasts(ZeroLiteral)),
+ hasEitherOperand(ignoringParenImpCasts(StringFind.bind("findexpr"))))
+ .bind("expr"),
+ this);
+}
+
+void StringFindStartswithCheck::check(const MatchFinder::MatchResult &Result) {
+ const ASTContext &Context = *Result.Context;
+ const SourceManager &Source = Context.getSourceManager();
+
+ // Extract matching (sub)expressions
+ const auto *ComparisonExpr = Result.Nodes.getNodeAs<BinaryOperator>("expr");
+ assert(ComparisonExpr != nullptr);
+ const auto *Needle = Result.Nodes.getNodeAs<Expr>("needle");
+ assert(Needle != nullptr);
+ const Expr *Haystack = Result.Nodes.getNodeAs<CXXMemberCallExpr>("findexpr")
+ ->getImplicitObjectArgument();
+ assert(Haystack != nullptr);
+
+ if (ComparisonExpr->getLocStart().isMacroID())
+ return;
+
+ // Get the source code blocks (as characters) for both the string object
+ // and the search expression
+ const StringRef NeedleExprCode = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(Needle->getSourceRange()), Source,
+ Context.getLangOpts());
+ const StringRef HaystackExprCode = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(Haystack->getSourceRange()), Source,
+ Context.getLangOpts());
+
+ // Create the StartsWith string, negating if comparison was "!=".
+ bool Neg = ComparisonExpr->getOpcodeStr() == "!=";
+ StringRef StartswithStr;
+ if (Neg) {
+ StartswithStr = "!absl::StartsWith";
+ } else {
+ StartswithStr = "absl::StartsWith";
+ }
+
+ // Create the warning message and a FixIt hint replacing the original expr.
+ auto Diagnostic =
+ diag(ComparisonExpr->getLocStart(),
+ (StringRef("use ") + StartswithStr + " instead of find() " +
+ ComparisonExpr->getOpcodeStr() + " 0")
+ .str());
+
+ Diagnostic << FixItHint::CreateReplacement(
+ ComparisonExpr->getSourceRange(),
+ (StartswithStr + "(" + HaystackExprCode + ", " + NeedleExprCode + ")")
+ .str());
+
+ // Create a preprocessor #include FixIt hint (CreateIncludeInsertion checks
+ // whether this already exists).
+ auto IncludeHint = IncludeInserter->CreateIncludeInsertion(
+ Source.getFileID(ComparisonExpr->getLocStart()), AbseilStringsMatchHeader,
+ false);
+ if (IncludeHint) {
+ Diagnostic << *IncludeHint;
+ }
+}
+
+void StringFindStartswithCheck::registerPPCallbacks(
+ CompilerInstance &Compiler) {
+ IncludeInserter = llvm::make_unique<clang::tidy::utils::IncludeInserter>(
+ Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle);
+ Compiler.getPreprocessor().addPPCallbacks(
+ IncludeInserter->CreatePPCallbacks());
+}
+
+void StringFindStartswithCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "StringLikeClasses",
+ utils::options::serializeStringList(StringLikeClasses));
+ Options.store(Opts, "IncludeStyle",
+ utils::IncludeSorter::toString(IncludeStyle));
+ Options.store(Opts, "AbseilStringsMatchHeader", AbseilStringsMatchHeader);
+}
+
+} // namespace abseil
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/abseil/StringFindStartswithCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/abseil/StringFindStartswithCheck.h
new file mode 100644
index 0000000..1c04e80
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/abseil/StringFindStartswithCheck.h
@@ -0,0 +1,48 @@
+//===--- StringFindStartswithCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_STRINGFINDSTARTSWITHCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_STRINGFINDSTARTSWITHCHECK_H
+
+#include "../ClangTidy.h"
+#include "../utils/IncludeInserter.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tidy {
+namespace abseil {
+
+// Find string.find(...) == 0 comparisons and suggest replacing with StartsWith.
+// FIXME(niko): Add similar check for EndsWith
+// FIXME(niko): Add equivalent modernize checks for C++20's std::starts_With
+class StringFindStartswithCheck : public ClangTidyCheck {
+public:
+ using ClangTidyCheck::ClangTidyCheck;
+ StringFindStartswithCheck(StringRef Name, ClangTidyContext *Context);
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ std::unique_ptr<clang::tidy::utils::IncludeInserter> IncludeInserter;
+ const std::vector<std::string> StringLikeClasses;
+ const utils::IncludeSorter::IncludeStyle IncludeStyle;
+ const std::string AbseilStringsMatchHeader;
+};
+
+} // namespace abseil
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_STRINGFINDSTARTSWITHCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/add_new_check.py b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/add_new_check.py
new file mode 100755
index 0000000..4d811aa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/add_new_check.py
@@ -0,0 +1,368 @@
+#!/usr/bin/env python
+#
+#===- add_new_check.py - clang-tidy check generator ----------*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+from __future__ import print_function
+
+import argparse
+import os
+import re
+import sys
+
+# Adapts the module's CMakelist file. Returns 'True' if it could add a new entry
+# and 'False' if the entry already existed.
+def adapt_cmake(module_path, check_name_camel):
+ filename = os.path.join(module_path, 'CMakeLists.txt')
+ with open(filename, 'r') as f:
+ lines = f.readlines()
+
+ cpp_file = check_name_camel + '.cpp'
+
+ # Figure out whether this check already exists.
+ for line in lines:
+ if line.strip() == cpp_file:
+ return False
+
+ print('Updating %s...' % filename)
+ with open(filename, 'w') as f:
+ cpp_found = False
+ file_added = False
+ for line in lines:
+ cpp_line = line.strip().endswith('.cpp')
+ if (not file_added) and (cpp_line or cpp_found):
+ cpp_found = True
+ if (line.strip() > cpp_file) or (not cpp_line):
+ f.write(' ' + cpp_file + '\n')
+ file_added = True
+ f.write(line)
+
+ return True
+
+
+# Adds a header for the new check.
+def write_header(module_path, module, check_name, check_name_camel):
+ check_name_dashes = module + '-' + check_name
+ filename = os.path.join(module_path, check_name_camel) + '.h'
+ print('Creating %s...' % filename)
+ with open(filename, 'w') as f:
+ header_guard = ('LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_' + module.upper() + '_'
+ + check_name_camel.upper() + '_H')
+ f.write('//===--- ')
+ f.write(os.path.basename(filename))
+ f.write(' - clang-tidy')
+ f.write('-' * max(0, 43 - len(os.path.basename(filename))))
+ f.write('*- C++ -*-===//')
+ f.write("""
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef %(header_guard)s
+#define %(header_guard)s
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace %(module)s {
+
+/// FIXME: Write a short description.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/%(check_name_dashes)s.html
+class %(check_name)s : public ClangTidyCheck {
+public:
+ %(check_name)s(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace %(module)s
+} // namespace tidy
+} // namespace clang
+
+#endif // %(header_guard)s
+""" % {'header_guard': header_guard,
+ 'check_name': check_name_camel,
+ 'check_name_dashes': check_name_dashes,
+ 'module': module})
+
+
+# Adds the implementation of the new check.
+def write_implementation(module_path, module, check_name_camel):
+ filename = os.path.join(module_path, check_name_camel) + '.cpp'
+ print('Creating %s...' % filename)
+ with open(filename, 'w') as f:
+ f.write('//===--- ')
+ f.write(os.path.basename(filename))
+ f.write(' - clang-tidy')
+ f.write('-' * max(0, 52 - len(os.path.basename(filename))))
+ f.write('-===//')
+ f.write("""
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "%(check_name)s.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace %(module)s {
+
+void %(check_name)s::registerMatchers(MatchFinder *Finder) {
+ // FIXME: Add matchers.
+ Finder->addMatcher(functionDecl().bind("x"), this);
+}
+
+void %(check_name)s::check(const MatchFinder::MatchResult &Result) {
+ // FIXME: Add callback implementation.
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>("x");
+ if (MatchedDecl->getName().startswith("awesome_"))
+ return;
+ diag(MatchedDecl->getLocation(), "function %%0 is insufficiently awesome")
+ << MatchedDecl
+ << FixItHint::CreateInsertion(MatchedDecl->getLocation(), "awesome_");
+}
+
+} // namespace %(module)s
+} // namespace tidy
+} // namespace clang
+""" % {'check_name': check_name_camel,
+ 'module': module})
+
+
+# Modifies the module to include the new check.
+def adapt_module(module_path, module, check_name, check_name_camel):
+ modulecpp = list(filter(
+ lambda p: p.lower() == module.lower() + 'tidymodule.cpp',
+ os.listdir(module_path)))[0]
+ filename = os.path.join(module_path, modulecpp)
+ with open(filename, 'r') as f:
+ lines = f.readlines()
+
+ print('Updating %s...' % filename)
+ with open(filename, 'w') as f:
+ header_added = False
+ header_found = False
+ check_added = False
+ check_decl = (' CheckFactories.registerCheck<' + check_name_camel +
+ '>(\n "' + module + '-' + check_name + '");\n')
+
+ for line in lines:
+ if not header_added:
+ match = re.search('#include "(.*)"', line)
+ if match:
+ header_found = True
+ if match.group(1) > check_name_camel:
+ header_added = True
+ f.write('#include "' + check_name_camel + '.h"\n')
+ elif header_found:
+ header_added = True
+ f.write('#include "' + check_name_camel + '.h"\n')
+
+ if not check_added:
+ if line.strip() == '}':
+ check_added = True
+ f.write(check_decl)
+ else:
+ match = re.search('registerCheck<(.*)>', line)
+ if match and match.group(1) > check_name_camel:
+ check_added = True
+ f.write(check_decl)
+ f.write(line)
+
+
+# Adds a release notes entry.
+def add_release_notes(module_path, module, check_name):
+ check_name_dashes = module + '-' + check_name
+ filename = os.path.normpath(os.path.join(module_path,
+ '../../docs/ReleaseNotes.rst'))
+ with open(filename, 'r') as f:
+ lines = f.readlines()
+
+ print('Updating %s...' % filename)
+ with open(filename, 'w') as f:
+ note_added = False
+ header_found = False
+
+ for line in lines:
+ if not note_added:
+ match = re.search('Improvements to clang-tidy', line)
+ if match:
+ header_found = True
+ elif header_found:
+ if not line.startswith('----'):
+ f.write("""
+- New :doc:`%s
+ <clang-tidy/checks/%s>` check.
+
+ FIXME: add release notes.
+""" % (check_name_dashes, check_name_dashes))
+ note_added = True
+
+ f.write(line)
+
+
+# Adds a test for the check.
+def write_test(module_path, module, check_name, test_extension):
+ check_name_dashes = module + '-' + check_name
+ filename = os.path.normpath(os.path.join(module_path, '../../test/clang-tidy',
+ check_name_dashes + '.' + test_extension))
+ print('Creating %s...' % filename)
+ with open(filename, 'w') as f:
+ f.write("""// RUN: %%check_clang_tidy %%s %(check_name_dashes)s %%t
+
+// FIXME: Add something that triggers the check here.
+void f();
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'f' is insufficiently awesome [%(check_name_dashes)s]
+
+// FIXME: Verify the applied fix.
+// * Make the CHECK patterns specific enough and try to make verified lines
+// unique to avoid incorrect matches.
+// * Use {{}} for regular expressions.
+// CHECK-FIXES: {{^}}void awesome_f();{{$}}
+
+// FIXME: Add something that doesn't trigger the check here.
+void awesome_f2();
+""" % {'check_name_dashes': check_name_dashes})
+
+
+# Recreates the list of checks in the docs/clang-tidy/checks directory.
+def update_checks_list(clang_tidy_path):
+ docs_dir = os.path.join(clang_tidy_path, '../docs/clang-tidy/checks')
+ filename = os.path.normpath(os.path.join(docs_dir, 'list.rst'))
+ with open(filename, 'r') as f:
+ lines = f.readlines()
+ doc_files = list(filter(lambda s: s.endswith('.rst') and s != 'list.rst',
+ os.listdir(docs_dir)))
+ doc_files.sort()
+
+ def format_link(doc_file):
+ check_name = doc_file.replace('.rst', '')
+ with open(os.path.join(docs_dir, doc_file), 'r') as doc:
+ content = doc.read()
+ match = re.search('.*:orphan:.*', content)
+ if match:
+ return ''
+
+ match = re.search('.*:http-equiv=refresh: \d+;URL=(.*).html.*',
+ content)
+ if match:
+ return ' %(check)s (redirects to %(target)s) <%(check)s>\n' % {
+ 'check': check_name,
+ 'target': match.group(1)
+ }
+ return ' %s\n' % check_name
+
+ checks = map(format_link, doc_files)
+
+ print('Updating %s...' % filename)
+ with open(filename, 'w') as f:
+ for line in lines:
+ f.write(line)
+ if line.startswith('.. toctree::'):
+ f.writelines(checks)
+ break
+
+
+# Adds a documentation for the check.
+def write_docs(module_path, module, check_name):
+ check_name_dashes = module + '-' + check_name
+ filename = os.path.normpath(os.path.join(
+ module_path, '../../docs/clang-tidy/checks/', check_name_dashes + '.rst'))
+ print('Creating %s...' % filename)
+ with open(filename, 'w') as f:
+ f.write(""".. title:: clang-tidy - %(check_name_dashes)s
+
+%(check_name_dashes)s
+%(underline)s
+
+FIXME: Describe what patterns does the check detect and why. Give examples.
+""" % {'check_name_dashes': check_name_dashes,
+ 'underline': '=' * len(check_name_dashes)})
+
+
+def main():
+ language_to_extension = {
+ 'c': 'c',
+ 'c++': 'cpp',
+ 'objc': 'm',
+ 'objc++': 'mm',
+ }
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--update-docs',
+ action='store_true',
+ help='just update the list of documentation files, then exit')
+ parser.add_argument(
+ '--language',
+ help='language to use for new check (defaults to c++)',
+ choices=language_to_extension.keys(),
+ default='c++',
+ metavar='LANG')
+ parser.add_argument(
+ 'module',
+ nargs='?',
+ help='module directory under which to place the new tidy check (e.g., misc)')
+ parser.add_argument(
+ 'check',
+ nargs='?',
+ help='name of new tidy check to add (e.g. foo-do-the-stuff)')
+ args = parser.parse_args()
+
+ if args.update_docs:
+ update_checks_list(os.path.dirname(sys.argv[0]))
+ return
+
+ if not args.module or not args.check:
+ print('Module and check must be specified.')
+ parser.print_usage()
+ return
+
+ module = args.module
+ check_name = args.check
+
+ if check_name.startswith(module):
+ print('Check name "%s" must not start with the module "%s". Exiting.' % (
+ check_name, module))
+ return
+ check_name_camel = ''.join(map(lambda elem: elem.capitalize(),
+ check_name.split('-'))) + 'Check'
+ clang_tidy_path = os.path.dirname(sys.argv[0])
+ module_path = os.path.join(clang_tidy_path, module)
+
+ if not adapt_cmake(module_path, check_name_camel):
+ return
+ write_header(module_path, module, check_name, check_name_camel)
+ write_implementation(module_path, module, check_name_camel)
+ adapt_module(module_path, module, check_name, check_name_camel)
+ add_release_notes(module_path, module, check_name)
+ test_extension = language_to_extension.get(args.language)
+ write_test(module_path, module, check_name, test_extension)
+ write_docs(module_path, module, check_name)
+ update_checks_list(clang_tidy_path)
+ print('Done. Now it\'s your turn!')
+
+
+if __name__ == '__main__':
+ main()
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/AndroidTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/AndroidTidyModule.cpp
new file mode 100644
index 0000000..64d35c7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/AndroidTidyModule.cpp
@@ -0,0 +1,70 @@
+//===--- AndroidTidyModule.cpp - clang-tidy--------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "CloexecAccept4Check.h"
+#include "CloexecAcceptCheck.h"
+#include "CloexecCreatCheck.h"
+#include "CloexecDupCheck.h"
+#include "CloexecEpollCreate1Check.h"
+#include "CloexecEpollCreateCheck.h"
+#include "CloexecFopenCheck.h"
+#include "CloexecInotifyInit1Check.h"
+#include "CloexecInotifyInitCheck.h"
+#include "CloexecMemfdCreateCheck.h"
+#include "CloexecOpenCheck.h"
+#include "CloexecSocketCheck.h"
+#include "ComparisonInTempFailureRetryCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// This module is for Android specific checks.
+class AndroidModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<CloexecAccept4Check>("android-cloexec-accept4");
+ CheckFactories.registerCheck<CloexecAcceptCheck>("android-cloexec-accept");
+ CheckFactories.registerCheck<CloexecCreatCheck>("android-cloexec-creat");
+ CheckFactories.registerCheck<CloexecEpollCreate1Check>(
+ "android-cloexec-epoll-create1");
+ CheckFactories.registerCheck<CloexecEpollCreateCheck>(
+ "android-cloexec-epoll-create");
+ CheckFactories.registerCheck<CloexecDupCheck>("android-cloexec-dup");
+ CheckFactories.registerCheck<CloexecFopenCheck>("android-cloexec-fopen");
+ CheckFactories.registerCheck<CloexecInotifyInitCheck>(
+ "android-cloexec-inotify-init");
+ CheckFactories.registerCheck<CloexecInotifyInit1Check>(
+ "android-cloexec-inotify-init1");
+ CheckFactories.registerCheck<CloexecMemfdCreateCheck>(
+ "android-cloexec-memfd-create");
+ CheckFactories.registerCheck<CloexecOpenCheck>("android-cloexec-open");
+ CheckFactories.registerCheck<CloexecSocketCheck>("android-cloexec-socket");
+ CheckFactories.registerCheck<ComparisonInTempFailureRetryCheck>(
+ "android-comparison-in-temp-failure-retry");
+ }
+};
+
+// Register the AndroidTidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<AndroidModule>
+ X("android-module", "Adds Android platform checks.");
+
+} // namespace android
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the AndroidModule.
+volatile int AndroidModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CMakeLists.txt
new file mode 100644
index 0000000..37aebac
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CMakeLists.txt
@@ -0,0 +1,27 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyAndroidModule
+ AndroidTidyModule.cpp
+ CloexecAccept4Check.cpp
+ CloexecAcceptCheck.cpp
+ CloexecCheck.cpp
+ CloexecCreatCheck.cpp
+ CloexecEpollCreate1Check.cpp
+ CloexecEpollCreateCheck.cpp
+ CloexecDupCheck.cpp
+ CloexecFopenCheck.cpp
+ CloexecInotifyInit1Check.cpp
+ CloexecInotifyInitCheck.cpp
+ CloexecMemfdCreateCheck.cpp
+ CloexecOpenCheck.cpp
+ CloexecSocketCheck.cpp
+ ComparisonInTempFailureRetryCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyUtils
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecAccept4Check.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecAccept4Check.cpp
new file mode 100644
index 0000000..3d172ef
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecAccept4Check.cpp
@@ -0,0 +1,40 @@
+//===--- CloexecAccept4Check.cpp - clang-tidy------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CloexecAccept4Check.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+void CloexecAccept4Check::registerMatchers(MatchFinder *Finder) {
+ auto SockAddrPointerType =
+ hasType(pointsTo(recordDecl(isStruct(), hasName("sockaddr"))));
+ auto SockLenPointerType = hasType(pointsTo(namedDecl(hasName("socklen_t"))));
+
+ registerMatchersImpl(Finder,
+ functionDecl(returns(isInteger()), hasName("accept4"),
+ hasParameter(0, hasType(isInteger())),
+ hasParameter(1, SockAddrPointerType),
+ hasParameter(2, SockLenPointerType),
+ hasParameter(3, hasType(isInteger()))));
+}
+
+void CloexecAccept4Check::check(const MatchFinder::MatchResult &Result) {
+ insertMacroFlag(Result, /*MacroFlag=*/"SOCK_CLOEXEC", /*ArgPos=*/3);
+}
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecAccept4Check.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecAccept4Check.h
new file mode 100644
index 0000000..0cf3215
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecAccept4Check.h
@@ -0,0 +1,35 @@
+//===--- CloexecAccept4Check.h - clang-tidy----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_ACCEPT4_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_ACCEPT4_H
+
+#include "CloexecCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// Finds code that uses accept4() without using the SOCK_CLOEXEC flag.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/android-cloexec-accept4.html
+class CloexecAccept4Check : public CloexecCheck {
+public:
+ CloexecAccept4Check(StringRef Name, ClangTidyContext *Context)
+ : CloexecCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_ACCEPT4_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecAcceptCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecAcceptCheck.cpp
new file mode 100644
index 0000000..f583bd0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecAcceptCheck.cpp
@@ -0,0 +1,47 @@
+//===--- CloexecAcceptCheck.cpp - clang-tidy-------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CloexecAcceptCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+void CloexecAcceptCheck::registerMatchers(MatchFinder *Finder) {
+ auto SockAddrPointerType =
+ hasType(pointsTo(recordDecl(isStruct(), hasName("sockaddr"))));
+ auto SockLenPointerType = hasType(pointsTo(namedDecl(hasName("socklen_t"))));
+
+ registerMatchersImpl(Finder,
+ functionDecl(returns(isInteger()), hasName("accept"),
+ hasParameter(0, hasType(isInteger())),
+ hasParameter(1, SockAddrPointerType),
+ hasParameter(2, SockLenPointerType)));
+}
+
+void CloexecAcceptCheck::check(const MatchFinder::MatchResult &Result) {
+ const std::string &ReplacementText =
+ (Twine("accept4(") + getSpellingArg(Result, 0) + ", " +
+ getSpellingArg(Result, 1) + ", " + getSpellingArg(Result, 2) +
+ ", SOCK_CLOEXEC)")
+ .str();
+
+ replaceFunc(
+ Result,
+ "prefer accept4() to accept() because accept4() allows SOCK_CLOEXEC",
+ ReplacementText);
+}
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecAcceptCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecAcceptCheck.h
new file mode 100644
index 0000000..cba1c09
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecAcceptCheck.h
@@ -0,0 +1,35 @@
+//===--- CloexecAcceptCheck.h - clang-tidy-----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_ACCEPT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_ACCEPT_H
+
+#include "CloexecCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// accept() is better to be replaced by accept4().
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/android-cloexec-accept.html
+class CloexecAcceptCheck : public CloexecCheck {
+public:
+ CloexecAcceptCheck(StringRef Name, ClangTidyContext *Context)
+ : CloexecCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_ACCEPT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecCheck.cpp
new file mode 100644
index 0000000..8473f1a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecCheck.cpp
@@ -0,0 +1,114 @@
+//===--- CloexecCheck.cpp - clang-tidy-------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CloexecCheck.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+namespace {
+// Helper function to form the correct string mode for Type3.
+// Build the replace text. If it's string constant, add <Mode> directly in the
+// end of the string. Else, add <Mode>.
+std::string buildFixMsgForStringFlag(const Expr *Arg, const SourceManager &SM,
+ const LangOptions &LangOpts, char Mode) {
+ if (Arg->getLocStart().isMacroID())
+ return (Lexer::getSourceText(
+ CharSourceRange::getTokenRange(Arg->getSourceRange()), SM,
+ LangOpts) +
+ " \"" + Twine(Mode) + "\"")
+ .str();
+
+ StringRef SR = cast<StringLiteral>(Arg->IgnoreParenCasts())->getString();
+ return ("\"" + SR + Twine(Mode) + "\"").str();
+}
+} // namespace
+
+const char *CloexecCheck::FuncDeclBindingStr = "funcDecl";
+
+const char *CloexecCheck::FuncBindingStr ="func";
+
+void CloexecCheck::registerMatchersImpl(
+ MatchFinder *Finder, internal::Matcher<FunctionDecl> Function) {
+ // We assume all the checked APIs are C functions.
+ Finder->addMatcher(
+ callExpr(
+ callee(functionDecl(isExternC(), Function).bind(FuncDeclBindingStr)))
+ .bind(FuncBindingStr),
+ this);
+}
+
+void CloexecCheck::insertMacroFlag(const MatchFinder::MatchResult &Result,
+ StringRef MacroFlag, int ArgPos) {
+ const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(FuncBindingStr);
+ const auto *FlagArg = MatchedCall->getArg(ArgPos);
+ const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>(FuncDeclBindingStr);
+ SourceManager &SM = *Result.SourceManager;
+
+ if (utils::exprHasBitFlagWithSpelling(FlagArg->IgnoreParenCasts(), SM,
+ Result.Context->getLangOpts(),
+ MacroFlag))
+ return;
+
+ SourceLocation EndLoc =
+ Lexer::getLocForEndOfToken(SM.getFileLoc(FlagArg->getLocEnd()), 0, SM,
+ Result.Context->getLangOpts());
+
+ diag(EndLoc, "%0 should use %1 where possible")
+ << FD << MacroFlag
+ << FixItHint::CreateInsertion(EndLoc, (Twine(" | ") + MacroFlag).str());
+}
+
+void CloexecCheck::replaceFunc(const MatchFinder::MatchResult &Result,
+ StringRef WarningMsg, StringRef FixMsg) {
+ const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(FuncBindingStr);
+ diag(MatchedCall->getLocStart(), WarningMsg)
+ << FixItHint::CreateReplacement(MatchedCall->getSourceRange(), FixMsg);
+}
+
+void CloexecCheck::insertStringFlag(
+ const ast_matchers::MatchFinder::MatchResult &Result, const char Mode,
+ const int ArgPos) {
+ const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(FuncBindingStr);
+ const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>(FuncDeclBindingStr);
+ const auto *ModeArg = MatchedCall->getArg(ArgPos);
+
+ // Check if the <Mode> may be in the mode string.
+ const auto *ModeStr = dyn_cast<StringLiteral>(ModeArg->IgnoreParenCasts());
+ if (!ModeStr || (ModeStr->getString().find(Mode) != StringRef::npos))
+ return;
+
+ const std::string &ReplacementText = buildFixMsgForStringFlag(
+ ModeArg, *Result.SourceManager, Result.Context->getLangOpts(), Mode);
+
+ diag(ModeArg->getLocStart(), "use %0 mode '%1' to set O_CLOEXEC")
+ << FD << std::string(1, Mode)
+ << FixItHint::CreateReplacement(ModeArg->getSourceRange(),
+ ReplacementText);
+}
+
+StringRef CloexecCheck::getSpellingArg(const MatchFinder::MatchResult &Result,
+ int N) const {
+ const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(FuncBindingStr);
+ const SourceManager &SM = *Result.SourceManager;
+ return Lexer::getSourceText(
+ CharSourceRange::getTokenRange(MatchedCall->getArg(N)->getSourceRange()),
+ SM, Result.Context->getLangOpts());
+}
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecCheck.h
new file mode 100644
index 0000000..1c58a31
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecCheck.h
@@ -0,0 +1,105 @@
+//===--- CloexecCheck.h - clang-tidy-----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declaration of the CloexecCheck class, which is the
+/// base class for all of the close-on-exec checks in Android module.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// \brief The base class for all close-on-exec checks in Android module.
+/// To be specific, there are some functions that need the close-on-exec flag to
+/// prevent the file descriptor leakage on fork+exec and this class provides
+/// utilities to identify and fix these C functions.
+class CloexecCheck : public ClangTidyCheck {
+public:
+ CloexecCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+
+protected:
+ void
+ registerMatchersImpl(ast_matchers::MatchFinder *Finder,
+ ast_matchers::internal::Matcher<FunctionDecl> Function);
+
+ /// Currently, we have three types of fixes.
+ ///
+ /// Type1 is to insert the necessary macro flag in the flag argument. For
+ /// example, 'O_CLOEXEC' is required in function 'open()', so
+ /// \code
+ /// open(file, O_RDONLY);
+ /// \endcode
+ /// should be
+ /// \code
+ /// open(file, O_RDONLY | O_CLOEXE);
+ /// \endcode
+ ///
+ /// \param [out] Result MatchResult from AST matcher.
+ /// \param MacroFlag The macro name of the flag.
+ /// \param ArgPos The 0-based position of the flag argument.
+ void insertMacroFlag(const ast_matchers::MatchFinder::MatchResult &Result,
+ StringRef MacroFlag, int ArgPos);
+
+ /// Type2 is to replace the API to another function that has required the
+ /// ability. For example:
+ /// \code
+ /// creat(path, mode);
+ /// \endcode
+ /// should be
+ /// \code
+ /// open(path, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, mode)
+ /// \endcode
+ ///
+ /// \param [out] Result MatchResult from AST matcher.
+ /// \param WarningMsg The warning message.
+ /// \param FixMsg The fix message.
+ void replaceFunc(const ast_matchers::MatchFinder::MatchResult &Result,
+ StringRef WarningMsg, StringRef FixMsg);
+
+ /// Type3 is also to add a flag to the corresponding argument, but this time,
+ /// the flag is some string and each char represents a mode rather than a
+ /// macro. For example, 'fopen' needs char 'e' in its mode argument string, so
+ /// \code
+ /// fopen(in_file, "r");
+ /// \endcode
+ /// should be
+ /// \code
+ /// fopen(in_file, "re");
+ /// \endcode
+ ///
+ /// \param [out] Result MatchResult from AST matcher.
+ /// \param Mode The required mode char.
+ /// \param ArgPos The 0-based position of the flag argument.
+ void insertStringFlag(const ast_matchers::MatchFinder::MatchResult &Result,
+ const char Mode, const int ArgPos);
+
+ /// Helper function to get the spelling of a particular argument.
+ StringRef getSpellingArg(const ast_matchers::MatchFinder::MatchResult &Result,
+ int N) const;
+
+ /// Binding name of the FuncDecl of a function call.
+ static const char *FuncDeclBindingStr;
+
+ /// Binding name of the function call expression.
+ static const char *FuncBindingStr;
+};
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecCreatCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecCreatCheck.cpp
new file mode 100644
index 0000000..83ca49a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecCreatCheck.cpp
@@ -0,0 +1,43 @@
+//===--- CloexecCreatCheck.cpp - clang-tidy--------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CloexecCreatCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+void CloexecCreatCheck::registerMatchers(MatchFinder *Finder) {
+ auto CharPointerType = hasType(pointerType(pointee(isAnyCharacter())));
+ auto MODETType = hasType(namedDecl(hasName("mode_t")));
+ registerMatchersImpl(Finder,
+ functionDecl(isExternC(), returns(isInteger()),
+ hasName("creat"),
+ hasParameter(0, CharPointerType),
+ hasParameter(1, MODETType)));
+}
+
+void CloexecCreatCheck::check(const MatchFinder::MatchResult &Result) {
+ const std::string &ReplacementText =
+ (Twine("open (") + getSpellingArg(Result, 0) +
+ ", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, " +
+ getSpellingArg(Result, 1) + ")")
+ .str();
+ replaceFunc(Result,
+ "prefer open() to creat() because open() allows O_CLOEXEC",
+ ReplacementText);
+}
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecCreatCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecCreatCheck.h
new file mode 100644
index 0000000..335990c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecCreatCheck.h
@@ -0,0 +1,35 @@
+//===--- CloexecCreatCheck.h - clang-tidy------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_CREAT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_CREAT_H
+
+#include "CloexecCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// creat() is better to be replaced by open().
+/// Find the usage of creat() and redirect user to use open().
+
+/// http://clang.llvm.org/extra/clang-tidy/checks/android-cloexec-creat.html
+class CloexecCreatCheck : public CloexecCheck {
+public:
+ CloexecCreatCheck(StringRef Name, ClangTidyContext *Context)
+ : CloexecCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_CREAT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecDupCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecDupCheck.cpp
new file mode 100644
index 0000000..ec4ff0a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecDupCheck.cpp
@@ -0,0 +1,38 @@
+//===--- CloexecDupCheck.cpp - clang-tidy----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CloexecDupCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+void CloexecDupCheck::registerMatchers(MatchFinder *Finder) {
+ registerMatchersImpl(Finder,
+ functionDecl(returns(isInteger()), hasName("dup"),
+ hasParameter(0, hasType(isInteger()))));
+}
+
+void CloexecDupCheck::check(const MatchFinder::MatchResult &Result) {
+ const std::string &ReplacementText =
+ (Twine("fcntl(") + getSpellingArg(Result, 0) + ", F_DUPFD_CLOEXEC)")
+ .str();
+
+ replaceFunc(Result,
+ "prefer fcntl() to dup() because fcntl() allows F_DUPFD_CLOEXEC",
+ ReplacementText);
+}
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecDupCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecDupCheck.h
new file mode 100644
index 0000000..c040b38
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecDupCheck.h
@@ -0,0 +1,36 @@
+//===--- CloexecDupCheck.h - clang-tidy-------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_DUP_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_DUP_H
+
+#include "CloexecCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// dup() is better to be replaced by fcntl(), which has close-on-exec flag.
+/// Find the usage of dup() and redirect user to use fcntl().
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/android-cloexec-dup.html
+class CloexecDupCheck : public CloexecCheck {
+public:
+ CloexecDupCheck(StringRef Name, ClangTidyContext *Context)
+ : CloexecCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_DUP_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecEpollCreate1Check.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecEpollCreate1Check.cpp
new file mode 100644
index 0000000..d94b4a0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecEpollCreate1Check.cpp
@@ -0,0 +1,33 @@
+//===--- CloexecEpollCreate1Check.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CloexecEpollCreate1Check.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+void CloexecEpollCreate1Check::registerMatchers(MatchFinder *Finder) {
+ registerMatchersImpl(
+ Finder, functionDecl(returns(isInteger()), hasName("epoll_create1"),
+ hasParameter(0, hasType(isInteger()))));
+}
+
+void CloexecEpollCreate1Check::check(const MatchFinder::MatchResult &Result) {
+ insertMacroFlag(Result, /*MacroFlag=*/"EPOLL_CLOEXEC", /*ArgPos=*/0);
+}
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecEpollCreate1Check.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecEpollCreate1Check.h
new file mode 100644
index 0000000..9890d5f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecEpollCreate1Check.h
@@ -0,0 +1,35 @@
+//===--- CloexecEpollCreate1Check.h - clang-tidy-----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_EPOLL_CREATE1_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_EPOLL_CREATE1_H
+
+#include "CloexecCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// Finds code that uses epoll_create1() without using the EPOLL_CLOEXEC flag.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/android-cloexec-epoll-create1.html
+class CloexecEpollCreate1Check : public CloexecCheck {
+public:
+ CloexecEpollCreate1Check(StringRef Name, ClangTidyContext *Context)
+ : CloexecCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_EPOLL_CREATE1_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecEpollCreateCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecEpollCreateCheck.cpp
new file mode 100644
index 0000000..7165d24
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecEpollCreateCheck.cpp
@@ -0,0 +1,36 @@
+//===--- CloexecEpollCreateCheck.cpp - clang-tidy--------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CloexecEpollCreateCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+void CloexecEpollCreateCheck::registerMatchers(MatchFinder *Finder) {
+ registerMatchersImpl(
+ Finder, functionDecl(returns(isInteger()), hasName("epoll_create"),
+ hasParameter(0, hasType(isInteger()))));
+}
+
+void CloexecEpollCreateCheck::check(const MatchFinder::MatchResult &Result) {
+ replaceFunc(Result,
+ "prefer epoll_create() to epoll_create1() "
+ "because epoll_create1() allows "
+ "EPOLL_CLOEXEC",
+ "epoll_create1(EPOLL_CLOEXEC)");
+}
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecEpollCreateCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecEpollCreateCheck.h
new file mode 100644
index 0000000..21d2b2a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecEpollCreateCheck.h
@@ -0,0 +1,35 @@
+//===--- CloexecEpollCreateCheck.h - clang-tidy------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_EPOLL_CREATE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_EPOLL_CREATE_H
+
+#include "CloexecCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// epoll_create() is better to be replaced by epoll_create1().
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/android-cloexec-epoll-create.html
+class CloexecEpollCreateCheck : public CloexecCheck {
+public:
+ CloexecEpollCreateCheck(StringRef Name, ClangTidyContext *Context)
+ : CloexecCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_EPOLL_CREATE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecFopenCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecFopenCheck.cpp
new file mode 100644
index 0000000..33058d6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecFopenCheck.cpp
@@ -0,0 +1,36 @@
+//===--- CloexecFopenCheck.cpp - clang-tidy--------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details. //
+//===----------------------------------------------------------------------===//
+
+#include "CloexecFopenCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Type.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+void CloexecFopenCheck::registerMatchers(MatchFinder *Finder) {
+ auto CharPointerType = hasType(pointerType(pointee(isAnyCharacter())));
+ registerMatchersImpl(Finder,
+ functionDecl(isExternC(), returns(asString("FILE *")),
+ hasName("fopen"),
+ hasParameter(0, CharPointerType),
+ hasParameter(1, CharPointerType)));
+}
+
+void CloexecFopenCheck::check(const MatchFinder::MatchResult &Result) {
+ insertStringFlag(Result, /*Mode=*/'e', /*ArgPos=*/1);
+}
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecFopenCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecFopenCheck.h
new file mode 100644
index 0000000..1c82b8b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecFopenCheck.h
@@ -0,0 +1,38 @@
+//===--- CloexecFopenCheck.h - clang-tidy------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source //
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_FOPEN_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_FOPEN_H
+
+#include "CloexecCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// fopen() is suggested to include "e" in their mode string; like "re" would be
+/// better than "r".
+///
+/// This check only works when corresponding argument is StringLiteral. No
+/// constant propagation.
+///
+/// http://clang.llvm.org/extra/clang-tidy/checks/android-cloexec-fopen.html
+class CloexecFopenCheck : public CloexecCheck {
+public:
+ CloexecFopenCheck(StringRef Name, ClangTidyContext *Context)
+ : CloexecCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_FOPEN_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecInotifyInit1Check.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecInotifyInit1Check.cpp
new file mode 100644
index 0000000..ca0aeb8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecInotifyInit1Check.cpp
@@ -0,0 +1,33 @@
+//===--- CloexecInotifyInit1Check.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CloexecInotifyInit1Check.h"
+#include "../utils/ASTUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+void CloexecInotifyInit1Check::registerMatchers(MatchFinder *Finder) {
+ registerMatchersImpl(
+ Finder, functionDecl(returns(isInteger()), hasName("inotify_init1"),
+ hasParameter(0, hasType(isInteger()))));
+}
+
+void CloexecInotifyInit1Check::check(const MatchFinder::MatchResult &Result) {
+ insertMacroFlag(Result, /*MacroFlag=*/"IN_CLOEXEC", /*ArgPos=*/0);
+}
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecInotifyInit1Check.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecInotifyInit1Check.h
new file mode 100644
index 0000000..deb04f2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecInotifyInit1Check.h
@@ -0,0 +1,35 @@
+//===--- CloexecInotifyInit1Check.h - clang-tidy-----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_INOTIFY_INIT1_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_INOTIFY_INIT1_H
+
+#include "CloexecCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// Finds code that uses inotify_init1() without using the IN_CLOEXEC flag.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/android-cloexec-inotify-init1.html
+class CloexecInotifyInit1Check : public CloexecCheck {
+public:
+ CloexecInotifyInit1Check(StringRef Name, ClangTidyContext *Context)
+ : CloexecCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_INOTIFY_INIT1_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecInotifyInitCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecInotifyInitCheck.cpp
new file mode 100644
index 0000000..0d5a56d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecInotifyInitCheck.cpp
@@ -0,0 +1,34 @@
+//===--- CloexecInotifyInitCheck.cpp - clang-tidy--------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CloexecInotifyInitCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+void CloexecInotifyInitCheck::registerMatchers(MatchFinder *Finder) {
+ registerMatchersImpl(
+ Finder, functionDecl(returns(isInteger()), hasName("inotify_init")));
+}
+
+void CloexecInotifyInitCheck::check(const MatchFinder::MatchResult &Result) {
+ replaceFunc(Result, /*WarningMsg=*/
+ "prefer inotify_init() to inotify_init1() "
+ "because inotify_init1() allows IN_CLOEXEC",
+ /*FixMsg=*/"inotify_init1(IN_CLOEXEC)");
+}
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecInotifyInitCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecInotifyInitCheck.h
new file mode 100644
index 0000000..ceeecbe
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecInotifyInitCheck.h
@@ -0,0 +1,35 @@
+//===--- CloexecInotifyInitCheck.h - clang-tidy------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_INOTIFY_INIT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_INOTIFY_INIT_H
+
+#include "CloexecCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// inotify_init() is better to be replaced by inotify_init1().
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/android-cloexec-inotify-init.html
+class CloexecInotifyInitCheck : public CloexecCheck {
+public:
+ CloexecInotifyInitCheck(StringRef Name, ClangTidyContext *Context)
+ : CloexecCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_INOTIFY_INIT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecMemfdCreateCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecMemfdCreateCheck.cpp
new file mode 100644
index 0000000..4820e2b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecMemfdCreateCheck.cpp
@@ -0,0 +1,32 @@
+//===--- CloexecMemfdCreateCheck.cpp - clang-tidy--------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CloexecMemfdCreateCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+void CloexecMemfdCreateCheck::registerMatchers(MatchFinder *Finder) {
+ auto CharPointerType = hasType(pointerType(pointee(isAnyCharacter())));
+ registerMatchersImpl(
+ Finder, functionDecl(returns(isInteger()), hasName("memfd_create"),
+ hasParameter(0, CharPointerType),
+ hasParameter(1, hasType(isInteger()))));
+}
+
+void CloexecMemfdCreateCheck::check(const MatchFinder::MatchResult &Result) {
+ insertMacroFlag(Result, "MFD_CLOEXEC", /*ArgPos=*/1);
+}
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecMemfdCreateCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecMemfdCreateCheck.h
new file mode 100644
index 0000000..0fe96f4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecMemfdCreateCheck.h
@@ -0,0 +1,35 @@
+//===--- CloexecMemfdCreateCheck.h - clang-tidy-----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_MEMFD_CREATE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_MEMFD_CREATE_H
+
+#include "CloexecCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// Finds code that uses memfd_create() without using the MFD_CLOEXEC flag.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/android-cloexec-memfd-create.html
+class CloexecMemfdCreateCheck : public CloexecCheck {
+public:
+ CloexecMemfdCreateCheck(StringRef Name, ClangTidyContext *Context)
+ : CloexecCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_MEMFD_CREATE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecOpenCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecOpenCheck.cpp
new file mode 100644
index 0000000..a4d3bc6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecOpenCheck.cpp
@@ -0,0 +1,44 @@
+//===--- CloexecOpenCheck.cpp - clang-tidy---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CloexecOpenCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+void CloexecOpenCheck::registerMatchers(MatchFinder *Finder) {
+ auto CharPointerType = hasType(pointerType(pointee(isAnyCharacter())));
+ registerMatchersImpl(Finder,
+ functionDecl(isExternC(), returns(isInteger()),
+ hasAnyName("open", "open64"),
+ hasParameter(0, CharPointerType),
+ hasParameter(1, hasType(isInteger()))));
+ registerMatchersImpl(Finder,
+ functionDecl(isExternC(), returns(isInteger()),
+ hasName("openat"),
+ hasParameter(0, hasType(isInteger())),
+ hasParameter(1, CharPointerType),
+ hasParameter(2, hasType(isInteger()))));
+}
+
+void CloexecOpenCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>(FuncDeclBindingStr);
+ assert(FD->param_size() > 1);
+ int ArgPos = (FD->param_size() > 2) ? 2 : 1;
+ insertMacroFlag(Result, /*MacroFlag=*/"O_CLOEXEC", ArgPos);
+}
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecOpenCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecOpenCheck.h
new file mode 100644
index 0000000..c221087
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecOpenCheck.h
@@ -0,0 +1,40 @@
+//===--- CloexecOpenCheck.h - clang-tidy-----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_OPEN_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_OPEN_H
+
+#include "CloexecCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// Finds code that opens file without using the O_CLOEXEC flag.
+///
+/// open(), openat(), and open64() had better to include O_CLOEXEC in their
+/// flags argument. Only consider simple cases that the corresponding argument
+/// is constant or binary operation OR among constants like 'O_CLOEXEC' or
+/// 'O_CLOEXEC | O_RDONLY'. No constant propagation is performed.
+///
+/// Only the symbolic 'O_CLOEXEC' macro definition is checked, not the concrete
+/// value.
+class CloexecOpenCheck : public CloexecCheck {
+public:
+ CloexecOpenCheck(StringRef Name, ClangTidyContext *Context)
+ : CloexecCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_OPEN_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecSocketCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecSocketCheck.cpp
new file mode 100644
index 0000000..b223918
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecSocketCheck.cpp
@@ -0,0 +1,35 @@
+//===--- CloexecSocketCheck.cpp - clang-tidy-------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CloexecSocketCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+void CloexecSocketCheck::registerMatchers(MatchFinder *Finder) {
+ registerMatchersImpl(Finder,
+ functionDecl(isExternC(), returns(isInteger()),
+ hasName("socket"),
+ hasParameter(0, hasType(isInteger())),
+ hasParameter(1, hasType(isInteger())),
+ hasParameter(2, hasType(isInteger()))));
+}
+
+void CloexecSocketCheck::check(const MatchFinder::MatchResult &Result) {
+ insertMacroFlag(Result, /*MacroFlag=*/"SOCK_CLOEXEC", /*ArgPos=*/1);
+}
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecSocketCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecSocketCheck.h
new file mode 100644
index 0000000..c1fd01f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/CloexecSocketCheck.h
@@ -0,0 +1,35 @@
+//===--- CloexecSocketCheck.h - clang-tidy-----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_SOCKET_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_SOCKET_H
+
+#include "CloexecCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// Finds code that uses socket() without using the SOCK_CLOEXEC flag.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/android-cloexec-socket.html
+class CloexecSocketCheck : public CloexecCheck {
+public:
+ CloexecSocketCheck(StringRef Name, ClangTidyContext *Context)
+ : CloexecCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_SOCKET_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/ComparisonInTempFailureRetryCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/ComparisonInTempFailureRetryCheck.cpp
new file mode 100644
index 0000000..49db53a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/ComparisonInTempFailureRetryCheck.cpp
@@ -0,0 +1,84 @@
+//===--- ComparisonInTempFailureRetryCheck.cpp - clang-tidy----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../utils/Matchers.h"
+#include "ComparisonInTempFailureRetryCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+namespace {
+AST_MATCHER(BinaryOperator, isRHSATempFailureRetryArg) {
+ if (!Node.getLocStart().isMacroID())
+ return false;
+
+ const SourceManager &SM = Finder->getASTContext().getSourceManager();
+ if (!SM.isMacroArgExpansion(Node.getRHS()->IgnoreParenCasts()->getLocStart()))
+ return false;
+
+ const LangOptions &Opts = Finder->getASTContext().getLangOpts();
+ SourceLocation LocStart = Node.getLocStart();
+ while (LocStart.isMacroID()) {
+ SourceLocation Invocation = SM.getImmediateMacroCallerLoc(LocStart);
+ Token Tok;
+ if (!Lexer::getRawToken(SM.getSpellingLoc(Invocation), Tok, SM, Opts,
+ /*IgnoreWhiteSpace=*/true)) {
+ if (Tok.getKind() == tok::raw_identifier &&
+ Tok.getRawIdentifier() == "TEMP_FAILURE_RETRY")
+ return true;
+ }
+
+ LocStart = Invocation;
+ }
+ return false;
+}
+} // namespace
+
+void ComparisonInTempFailureRetryCheck::registerMatchers(MatchFinder *Finder) {
+ // Both glibc's and Bionic's TEMP_FAILURE_RETRY macros structurally look like:
+ //
+ // #define TEMP_FAILURE_RETRY(x) ({ \
+ // typeof(x) y; \
+ // do y = (x); \
+ // while (y == -1 && errno == EINTR); \
+ // y; \
+ // })
+ //
+ // (glibc uses `long int` instead of `typeof(x)` for the type of y).
+ //
+ // It's unclear how to walk up the AST from inside the expansion of `x`, and
+ // we need to not complain about things like TEMP_FAILURE_RETRY(foo(x == 1)),
+ // so we just match the assignment of `y = (x)` and inspect `x` from there.
+ Finder->addMatcher(
+ binaryOperator(
+ hasOperatorName("="),
+ hasRHS(ignoringParenCasts(
+ binaryOperator(matchers::isComparisonOperator()).bind("binop"))),
+ isRHSATempFailureRetryArg()),
+ this);
+}
+
+void ComparisonInTempFailureRetryCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto &BinOp = *Result.Nodes.getNodeAs<BinaryOperator>("binop");
+ diag(BinOp.getOperatorLoc(), "top-level comparison in TEMP_FAILURE_RETRY");
+
+ // FIXME: FixIts would be nice, but potentially nontrivial when nested macros
+ // happen, e.g. `TEMP_FAILURE_RETRY(IS_ZERO(foo()))`
+}
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/ComparisonInTempFailureRetryCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/ComparisonInTempFailureRetryCheck.h
new file mode 100644
index 0000000..de81232
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/android/ComparisonInTempFailureRetryCheck.h
@@ -0,0 +1,36 @@
+//===--- ComparisonInTempFailureRetryCheck.h - clang-tidy--------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_COMPARISONINTEMPFAILURERETRYCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_COMPARISONINTEMPFAILURERETRYCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace android {
+
+/// Attempts to catch calls to TEMP_FAILURE_RETRY with a top-level comparison
+/// operation, like `TEMP_FAILURE_RETRY(read(...) != N)`. In these cases, the
+/// comparison should go outside of the TEMP_FAILURE_RETRY.
+///
+/// TEMP_FAILURE_RETRY is a macro provided by both glibc and Bionic.
+class ComparisonInTempFailureRetryCheck : public ClangTidyCheck {
+public:
+ ComparisonInTempFailureRetryCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace android
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_COMPARISONINTEMPFAILURERETRYCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/boost/BoostTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/boost/BoostTidyModule.cpp
new file mode 100644
index 0000000..28eb1d6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/boost/BoostTidyModule.cpp
@@ -0,0 +1,38 @@
+//===------- BoostTidyModule.cpp - clang-tidy -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "UseToStringCheck.h"
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace boost {
+
+class BoostModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<UseToStringCheck>("boost-use-to-string");
+ }
+};
+
+// Register the BoostModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<BoostModule> X("boost-module",
+ "Add boost checks.");
+
+} // namespace boost
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the BoostModule.
+volatile int BoostModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/boost/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/boost/CMakeLists.txt
new file mode 100644
index 0000000..059f6e9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/boost/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyBoostModule
+ BoostTidyModule.cpp
+ UseToStringCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyUtils
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/boost/UseToStringCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/boost/UseToStringCheck.cpp
new file mode 100644
index 0000000..1775440
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/boost/UseToStringCheck.cpp
@@ -0,0 +1,75 @@
+//===--- UseToStringCheck.cpp - clang-tidy---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseToStringCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace boost {
+
+namespace {
+AST_MATCHER(Type, isStrictlyInteger) {
+ return Node.isIntegerType() && !Node.isAnyCharacterType() &&
+ !Node.isBooleanType();
+}
+} // namespace
+
+void UseToStringCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(
+ callExpr(
+ hasDeclaration(functionDecl(
+ returns(hasDeclaration(classTemplateSpecializationDecl(
+ hasName("std::basic_string"),
+ hasTemplateArgument(0,
+ templateArgument().bind("char_type"))))),
+ hasName("boost::lexical_cast"),
+ hasParameter(0, hasType(qualType(has(substTemplateTypeParmType(
+ isStrictlyInteger()))))))),
+ argumentCountIs(1), unless(isInTemplateInstantiation()))
+ .bind("to_string"),
+ this);
+}
+
+void UseToStringCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("to_string");
+ auto CharType =
+ Result.Nodes.getNodeAs<TemplateArgument>("char_type")->getAsType();
+
+ StringRef StringType;
+ if (CharType->isSpecificBuiltinType(BuiltinType::Char_S) ||
+ CharType->isSpecificBuiltinType(BuiltinType::Char_U))
+ StringType = "string";
+ else if (CharType->isSpecificBuiltinType(BuiltinType::WChar_S) ||
+ CharType->isSpecificBuiltinType(BuiltinType::WChar_U))
+ StringType = "wstring";
+ else
+ return;
+
+ auto Loc = Call->getLocStart();
+ auto Diag =
+ diag(Loc, "use std::to_%0 instead of boost::lexical_cast<std::%0>")
+ << StringType;
+
+ if (Loc.isMacroID())
+ return;
+
+ Diag << FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(Call->getLocStart(),
+ Call->getArg(0)->getLocStart()),
+ (llvm::Twine("std::to_") + StringType + "(").str());
+}
+
+} // namespace boost
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/boost/UseToStringCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/boost/UseToStringCheck.h
new file mode 100644
index 0000000..76e7823
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/boost/UseToStringCheck.h
@@ -0,0 +1,37 @@
+//===--- UseToStringCheck.h - clang-tidy-------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BOOST_USE_TO_STRING_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BOOST_USE_TO_STRING_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace boost {
+
+/// Finds calls to ``boost::lexical_cast<std::string>`` and
+/// ``boost::lexical_cast<std::wstring>`` and replaces them with
+/// ``std::to_string`` and ``std::to_wstring`` calls.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/boost-use-to-string.html
+class UseToStringCheck : public ClangTidyCheck {
+public:
+ UseToStringCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace boost
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BOOST_USE_TO_STRING_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp
new file mode 100644
index 0000000..a8da703
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.cpp
@@ -0,0 +1,308 @@
+//===--- ArgumentCommentCheck.cpp - clang-tidy ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArgumentCommentCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Token.h"
+#include "../utils/LexerUtils.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+ArgumentCommentCheck::ArgumentCommentCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ StrictMode(Options.getLocalOrGlobal("StrictMode", 0) != 0),
+ IdentRE("^(/\\* *)([_A-Za-z][_A-Za-z0-9]*)( *= *\\*/)$") {}
+
+void ArgumentCommentCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "StrictMode", StrictMode);
+}
+
+void ArgumentCommentCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ callExpr(unless(cxxOperatorCallExpr()),
+ // NewCallback's arguments relate to the pointed function, don't
+ // check them against NewCallback's parameter names.
+ // FIXME: Make this configurable.
+ unless(hasDeclaration(functionDecl(
+ hasAnyName("NewCallback", "NewPermanentCallback")))))
+ .bind("expr"),
+ this);
+ Finder->addMatcher(cxxConstructExpr().bind("expr"), this);
+}
+
+static std::vector<std::pair<SourceLocation, StringRef>>
+getCommentsInRange(ASTContext *Ctx, CharSourceRange Range) {
+ std::vector<std::pair<SourceLocation, StringRef>> Comments;
+ auto &SM = Ctx->getSourceManager();
+ std::pair<FileID, unsigned> BeginLoc = SM.getDecomposedLoc(Range.getBegin()),
+ EndLoc = SM.getDecomposedLoc(Range.getEnd());
+
+ if (BeginLoc.first != EndLoc.first)
+ return Comments;
+
+ bool Invalid = false;
+ StringRef Buffer = SM.getBufferData(BeginLoc.first, &Invalid);
+ if (Invalid)
+ return Comments;
+
+ const char *StrData = Buffer.data() + BeginLoc.second;
+
+ Lexer TheLexer(SM.getLocForStartOfFile(BeginLoc.first), Ctx->getLangOpts(),
+ Buffer.begin(), StrData, Buffer.end());
+ TheLexer.SetCommentRetentionState(true);
+
+ while (true) {
+ Token Tok;
+ if (TheLexer.LexFromRawLexer(Tok))
+ break;
+ if (Tok.getLocation() == Range.getEnd() || Tok.is(tok::eof))
+ break;
+
+ if (Tok.is(tok::comment)) {
+ std::pair<FileID, unsigned> CommentLoc =
+ SM.getDecomposedLoc(Tok.getLocation());
+ assert(CommentLoc.first == BeginLoc.first);
+ Comments.emplace_back(
+ Tok.getLocation(),
+ StringRef(Buffer.begin() + CommentLoc.second, Tok.getLength()));
+ } else {
+ // Clear comments found before the different token, e.g. comma.
+ Comments.clear();
+ }
+ }
+
+ return Comments;
+}
+
+static std::vector<std::pair<SourceLocation, StringRef>>
+getCommentsBeforeLoc(ASTContext *Ctx, SourceLocation Loc) {
+ std::vector<std::pair<SourceLocation, StringRef>> Comments;
+ while (Loc.isValid()) {
+ clang::Token Tok =
+ utils::lexer::getPreviousToken(*Ctx, Loc, /*SkipComments=*/false);
+ if (Tok.isNot(tok::comment))
+ break;
+ Loc = Tok.getLocation();
+ Comments.emplace_back(
+ Loc,
+ Lexer::getSourceText(CharSourceRange::getCharRange(
+ Loc, Loc.getLocWithOffset(Tok.getLength())),
+ Ctx->getSourceManager(), Ctx->getLangOpts()));
+ }
+ return Comments;
+}
+
+static bool isLikelyTypo(llvm::ArrayRef<ParmVarDecl *> Params,
+ StringRef ArgName, unsigned ArgIndex) {
+ std::string ArgNameLowerStr = ArgName.lower();
+ StringRef ArgNameLower = ArgNameLowerStr;
+ // The threshold is arbitrary.
+ unsigned UpperBound = (ArgName.size() + 2) / 3 + 1;
+ unsigned ThisED = ArgNameLower.edit_distance(
+ Params[ArgIndex]->getIdentifier()->getName().lower(),
+ /*AllowReplacements=*/true, UpperBound);
+ if (ThisED >= UpperBound)
+ return false;
+
+ for (unsigned I = 0, E = Params.size(); I != E; ++I) {
+ if (I == ArgIndex)
+ continue;
+ IdentifierInfo *II = Params[I]->getIdentifier();
+ if (!II)
+ continue;
+
+ const unsigned Threshold = 2;
+ // Other parameters must be an edit distance at least Threshold more away
+ // from this parameter. This gives us greater confidence that this is a typo
+ // of this parameter and not one with a similar name.
+ unsigned OtherED = ArgNameLower.edit_distance(II->getName().lower(),
+ /*AllowReplacements=*/true,
+ ThisED + Threshold);
+ if (OtherED < ThisED + Threshold)
+ return false;
+ }
+
+ return true;
+}
+
+static bool sameName(StringRef InComment, StringRef InDecl, bool StrictMode) {
+ if (StrictMode)
+ return InComment == InDecl;
+ InComment = InComment.trim('_');
+ InDecl = InDecl.trim('_');
+ // FIXME: compare_lower only works for ASCII.
+ return InComment.compare_lower(InDecl) == 0;
+}
+
+static bool looksLikeExpectMethod(const CXXMethodDecl *Expect) {
+ return Expect != nullptr && Expect->getLocation().isMacroID() &&
+ Expect->getNameInfo().getName().isIdentifier() &&
+ Expect->getName().startswith("gmock_");
+}
+static bool areMockAndExpectMethods(const CXXMethodDecl *Mock,
+ const CXXMethodDecl *Expect) {
+ assert(looksLikeExpectMethod(Expect));
+ return Mock != nullptr && Mock->getNextDeclInContext() == Expect &&
+ Mock->getNumParams() == Expect->getNumParams() &&
+ Mock->getLocation().isMacroID() &&
+ Mock->getNameInfo().getName().isIdentifier() &&
+ Mock->getName() == Expect->getName().substr(strlen("gmock_"));
+}
+
+// This uses implementation details of MOCK_METHODx_ macros: for each mocked
+// method M it defines M() with appropriate signature and a method used to set
+// up expectations - gmock_M() - with each argument's type changed the
+// corresponding matcher. This function returns M when given either M or
+// gmock_M.
+static const CXXMethodDecl *findMockedMethod(const CXXMethodDecl *Method) {
+ if (looksLikeExpectMethod(Method)) {
+ const DeclContext *Ctx = Method->getDeclContext();
+ if (Ctx == nullptr || !Ctx->isRecord())
+ return nullptr;
+ for (const auto *D : Ctx->decls()) {
+ if (D->getNextDeclInContext() == Method) {
+ const auto *Previous = dyn_cast<CXXMethodDecl>(D);
+ return areMockAndExpectMethods(Previous, Method) ? Previous : nullptr;
+ }
+ }
+ return nullptr;
+ }
+ if (const auto *Next = dyn_cast_or_null<CXXMethodDecl>(
+ Method->getNextDeclInContext())) {
+ if (looksLikeExpectMethod(Next) && areMockAndExpectMethods(Method, Next))
+ return Method;
+ }
+ return nullptr;
+}
+
+// For gmock expectation builder method (the target of the call generated by
+// `EXPECT_CALL(obj, Method(...))`) tries to find the real method being mocked
+// (returns nullptr, if the mock method doesn't override anything). For other
+// functions returns the function itself.
+static const FunctionDecl *resolveMocks(const FunctionDecl *Func) {
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(Func)) {
+ if (const auto *MockedMethod = findMockedMethod(Method)) {
+ // If mocked method overrides the real one, we can use its parameter
+ // names, otherwise we're out of luck.
+ if (MockedMethod->size_overridden_methods() > 0) {
+ return *MockedMethod->begin_overridden_methods();
+ }
+ return nullptr;
+ }
+ }
+ return Func;
+}
+
+void ArgumentCommentCheck::checkCallArgs(ASTContext *Ctx,
+ const FunctionDecl *OriginalCallee,
+ SourceLocation ArgBeginLoc,
+ llvm::ArrayRef<const Expr *> Args) {
+ const FunctionDecl *Callee = resolveMocks(OriginalCallee);
+ if (!Callee)
+ return;
+
+ Callee = Callee->getFirstDecl();
+ unsigned NumArgs = std::min<unsigned>(Args.size(), Callee->getNumParams());
+ if (NumArgs == 0)
+ return;
+
+ auto makeFileCharRange = [Ctx](SourceLocation Begin, SourceLocation End) {
+ return Lexer::makeFileCharRange(CharSourceRange::getCharRange(Begin, End),
+ Ctx->getSourceManager(),
+ Ctx->getLangOpts());
+ };
+
+ for (unsigned I = 0; I < NumArgs; ++I) {
+ const ParmVarDecl *PVD = Callee->getParamDecl(I);
+ IdentifierInfo *II = PVD->getIdentifier();
+ if (!II)
+ continue;
+ if (auto Template = Callee->getTemplateInstantiationPattern()) {
+ // Don't warn on arguments for parameters instantiated from template
+ // parameter packs. If we find more arguments than the template
+ // definition has, it also means that they correspond to a parameter
+ // pack.
+ if (Template->getNumParams() <= I ||
+ Template->getParamDecl(I)->isParameterPack()) {
+ continue;
+ }
+ }
+
+ CharSourceRange BeforeArgument =
+ makeFileCharRange(ArgBeginLoc, Args[I]->getLocStart());
+ ArgBeginLoc = Args[I]->getLocEnd();
+
+ std::vector<std::pair<SourceLocation, StringRef>> Comments;
+ if (BeforeArgument.isValid()) {
+ Comments = getCommentsInRange(Ctx, BeforeArgument);
+ } else {
+ // Fall back to parsing back from the start of the argument.
+ CharSourceRange ArgsRange = makeFileCharRange(
+ Args[I]->getLocStart(), Args[NumArgs - 1]->getLocEnd());
+ Comments = getCommentsBeforeLoc(Ctx, ArgsRange.getBegin());
+ }
+
+ for (auto Comment : Comments) {
+ llvm::SmallVector<StringRef, 2> Matches;
+ if (IdentRE.match(Comment.second, &Matches) &&
+ !sameName(Matches[2], II->getName(), StrictMode)) {
+ {
+ DiagnosticBuilder Diag =
+ diag(Comment.first, "argument name '%0' in comment does not "
+ "match parameter name %1")
+ << Matches[2] << II;
+ if (isLikelyTypo(Callee->parameters(), Matches[2], I)) {
+ Diag << FixItHint::CreateReplacement(
+ Comment.first, (Matches[1] + II->getName() + Matches[3]).str());
+ }
+ }
+ diag(PVD->getLocation(), "%0 declared here", DiagnosticIDs::Note) << II;
+ if (OriginalCallee != Callee) {
+ diag(OriginalCallee->getLocation(),
+ "actual callee (%0) is declared here", DiagnosticIDs::Note)
+ << OriginalCallee;
+ }
+ }
+ }
+ }
+}
+
+void ArgumentCommentCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *E = Result.Nodes.getNodeAs<Expr>("expr");
+ if (const auto *Call = dyn_cast<CallExpr>(E)) {
+ const FunctionDecl *Callee = Call->getDirectCallee();
+ if (!Callee)
+ return;
+
+ checkCallArgs(Result.Context, Callee, Call->getCallee()->getLocEnd(),
+ llvm::makeArrayRef(Call->getArgs(), Call->getNumArgs()));
+ } else {
+ const auto *Construct = cast<CXXConstructExpr>(E);
+ if (Construct->getNumArgs() == 1 &&
+ Construct->getArg(0)->getSourceRange() == Construct->getSourceRange()) {
+ // Ignore implicit construction.
+ return;
+ }
+ checkCallArgs(
+ Result.Context, Construct->getConstructor(),
+ Construct->getParenOrBraceRange().getBegin(),
+ llvm::makeArrayRef(Construct->getArgs(), Construct->getNumArgs()));
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.h
new file mode 100644
index 0000000..2f5a751
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ArgumentCommentCheck.h
@@ -0,0 +1,55 @@
+//===--- ArgumentCommentCheck.h - clang-tidy --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_ARGUMENTCOMMENTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_ARGUMENTCOMMENTCHECK_H
+
+#include "../ClangTidy.h"
+#include "llvm/Support/Regex.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Checks that argument comments match parameter names.
+///
+/// The check understands argument comments in the form `/*parameter_name=*/`
+/// that are placed right before the argument.
+///
+/// \code
+/// void f(bool foo);
+///
+/// ...
+/// f(/*bar=*/true);
+/// // warning: argument name 'bar' in comment does not match parameter name 'foo'
+/// \endcode
+///
+/// The check tries to detect typos and suggest automated fixes for them.
+class ArgumentCommentCheck : public ClangTidyCheck {
+public:
+ ArgumentCommentCheck(StringRef Name, ClangTidyContext *Context);
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ const bool StrictMode;
+ llvm::Regex IdentRE;
+
+ void checkCallArgs(ASTContext *Ctx, const FunctionDecl *Callee,
+ SourceLocation ArgBeginLoc,
+ llvm::ArrayRef<const Expr *> Args);
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_ARGUMENTCOMMENTCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp
new file mode 100644
index 0000000..244e755
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp
@@ -0,0 +1,127 @@
+//===--- AssertSideEffectCheck.cpp - clang-tidy ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AssertSideEffectCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include <algorithm>
+#include <string>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+
+AST_MATCHER_P(Expr, hasSideEffect, bool, CheckFunctionCalls) {
+ const Expr *E = &Node;
+
+ if (const auto *Op = dyn_cast<UnaryOperator>(E)) {
+ UnaryOperator::Opcode OC = Op->getOpcode();
+ return OC == UO_PostInc || OC == UO_PostDec || OC == UO_PreInc ||
+ OC == UO_PreDec;
+ }
+
+ if (const auto *Op = dyn_cast<BinaryOperator>(E)) {
+ return Op->isAssignmentOp();
+ }
+
+ if (const auto *OpCallExpr = dyn_cast<CXXOperatorCallExpr>(E)) {
+ OverloadedOperatorKind OpKind = OpCallExpr->getOperator();
+ return OpKind == OO_Equal || OpKind == OO_PlusEqual ||
+ OpKind == OO_MinusEqual || OpKind == OO_StarEqual ||
+ OpKind == OO_SlashEqual || OpKind == OO_AmpEqual ||
+ OpKind == OO_PipeEqual || OpKind == OO_CaretEqual ||
+ OpKind == OO_LessLessEqual || OpKind == OO_GreaterGreaterEqual ||
+ OpKind == OO_PlusPlus || OpKind == OO_MinusMinus ||
+ OpKind == OO_PercentEqual || OpKind == OO_New ||
+ OpKind == OO_Delete || OpKind == OO_Array_New ||
+ OpKind == OO_Array_Delete;
+ }
+
+ if (const auto *CExpr = dyn_cast<CallExpr>(E)) {
+ bool Result = CheckFunctionCalls;
+ if (const auto *FuncDecl = CExpr->getDirectCallee()) {
+ if (FuncDecl->getDeclName().isIdentifier() &&
+ FuncDecl->getName() == "__builtin_expect") // exceptions come here
+ Result = false;
+ else if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FuncDecl))
+ Result &= !MethodDecl->isConst();
+ }
+ return Result;
+ }
+
+ return isa<CXXNewExpr>(E) || isa<CXXDeleteExpr>(E) || isa<CXXThrowExpr>(E);
+}
+
+} // namespace
+
+AssertSideEffectCheck::AssertSideEffectCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ CheckFunctionCalls(Options.get("CheckFunctionCalls", false)),
+ RawAssertList(Options.get("AssertMacros", "assert")) {
+ StringRef(RawAssertList).split(AssertMacros, ",", -1, false);
+}
+
+// The options are explained in AssertSideEffectCheck.h.
+void AssertSideEffectCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "CheckFunctionCalls", CheckFunctionCalls);
+ Options.store(Opts, "AssertMacros", RawAssertList);
+}
+
+void AssertSideEffectCheck::registerMatchers(MatchFinder *Finder) {
+ auto DescendantWithSideEffect =
+ hasDescendant(expr(hasSideEffect(CheckFunctionCalls)));
+ auto ConditionWithSideEffect = hasCondition(DescendantWithSideEffect);
+ Finder->addMatcher(
+ stmt(
+ anyOf(conditionalOperator(ConditionWithSideEffect),
+ ifStmt(ConditionWithSideEffect),
+ unaryOperator(hasOperatorName("!"),
+ hasUnaryOperand(unaryOperator(
+ hasOperatorName("!"),
+ hasUnaryOperand(DescendantWithSideEffect))))))
+ .bind("condStmt"),
+ this);
+}
+
+void AssertSideEffectCheck::check(const MatchFinder::MatchResult &Result) {
+ const SourceManager &SM = *Result.SourceManager;
+ const LangOptions LangOpts = getLangOpts();
+ SourceLocation Loc = Result.Nodes.getNodeAs<Stmt>("condStmt")->getLocStart();
+
+ StringRef AssertMacroName;
+ while (Loc.isValid() && Loc.isMacroID()) {
+ StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, LangOpts);
+
+ // Check if this macro is an assert.
+ if (std::find(AssertMacros.begin(), AssertMacros.end(), MacroName) !=
+ AssertMacros.end()) {
+ AssertMacroName = MacroName;
+ break;
+ }
+ Loc = SM.getImmediateMacroCallerLoc(Loc);
+ }
+ if (AssertMacroName.empty())
+ return;
+
+ diag(Loc, "found %0() with side effect") << AssertMacroName;
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.h
new file mode 100644
index 0000000..0f386c9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.h
@@ -0,0 +1,52 @@
+//===--- AssertSideEffectCheck.h - clang-tidy -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_ASSERTSIDEEFFECTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_ASSERTSIDEEFFECTCHECK_H
+
+#include "../ClangTidy.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds `assert()` with side effect.
+///
+/// The condition of `assert()` is evaluated only in debug builds so a
+/// condition with side effect can cause different behavior in debug / release
+/// builds.
+///
+/// There are two options:
+///
+/// - `AssertMacros`: A comma-separated list of the names of assert macros to
+/// be checked.
+/// - `CheckFunctionCalls`: Whether to treat non-const member and non-member
+/// functions as they produce side effects. Disabled by default because it
+/// can increase the number of false positive warnings.
+class AssertSideEffectCheck : public ClangTidyCheck {
+public:
+ AssertSideEffectCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const bool CheckFunctionCalls;
+ const std::string RawAssertList;
+ SmallVector<StringRef, 5> AssertMacros;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_ASSERTSIDEEFFECTCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp
new file mode 100644
index 0000000..ed2c2db
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp
@@ -0,0 +1,73 @@
+//===--- BoolPointerImplicitConversionCheck.cpp - clang-tidy --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BoolPointerImplicitConversionCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void BoolPointerImplicitConversionCheck::registerMatchers(MatchFinder *Finder) {
+ // Look for ifs that have an implicit bool* to bool conversion in the
+ // condition. Filter negations.
+ Finder->addMatcher(
+ ifStmt(hasCondition(findAll(implicitCastExpr(
+ allOf(unless(hasParent(unaryOperator(hasOperatorName("!")))),
+ hasSourceExpression(expr(
+ hasType(pointerType(pointee(booleanType()))),
+ ignoringParenImpCasts(declRefExpr().bind("expr")))),
+ hasCastKind(CK_PointerToBoolean))))),
+ unless(isInTemplateInstantiation()))
+ .bind("if"),
+ this);
+}
+
+void BoolPointerImplicitConversionCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ auto *If = Result.Nodes.getNodeAs<IfStmt>("if");
+ auto *Var = Result.Nodes.getNodeAs<DeclRefExpr>("expr");
+
+ // Ignore macros.
+ if (Var->getLocStart().isMacroID())
+ return;
+
+ // Only allow variable accesses for now, no function calls or member exprs.
+ // Check that we don't dereference the variable anywhere within the if. This
+ // avoids false positives for checks of the pointer for nullptr before it is
+ // dereferenced. If there is a dereferencing operator on this variable don't
+ // emit a diagnostic. Also ignore array subscripts.
+ const Decl *D = Var->getDecl();
+ auto DeclRef = ignoringParenImpCasts(declRefExpr(to(equalsNode(D))));
+ if (!match(findAll(
+ unaryOperator(hasOperatorName("*"), hasUnaryOperand(DeclRef))),
+ *If, *Result.Context)
+ .empty() ||
+ !match(findAll(arraySubscriptExpr(hasBase(DeclRef))), *If,
+ *Result.Context)
+ .empty() ||
+ // FIXME: We should still warn if the paremater is implicitly converted to
+ // bool.
+ !match(findAll(callExpr(hasAnyArgument(ignoringParenImpCasts(DeclRef)))),
+ *If, *Result.Context)
+ .empty() ||
+ !match(findAll(cxxDeleteExpr(has(ignoringParenImpCasts(expr(DeclRef))))),
+ *If, *Result.Context)
+ .empty())
+ return;
+
+ diag(Var->getLocStart(), "dubious check of 'bool *' against 'nullptr', did "
+ "you mean to dereference it?")
+ << FixItHint::CreateInsertion(Var->getLocStart(), "*");
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.h
new file mode 100644
index 0000000..b3416a9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.h
@@ -0,0 +1,42 @@
+//===--- BoolPointerImplicitConversionCheck.h - clang-tidy ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_BOOLPOINTERIMPLICITCONVERSIONCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_BOOLPOINTERIMPLICITCONVERSIONCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Checks for conditions based on implicit conversion from a bool pointer to
+/// bool.
+///
+/// Example:
+///
+/// \code
+/// bool *p;
+/// if (p) {
+/// // Never used in a pointer-specific way.
+/// }
+/// \endcode
+class BoolPointerImplicitConversionCheck : public ClangTidyCheck {
+public:
+ BoolPointerImplicitConversionCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_BOOLPOINTERIMPLICITCONVERSIONCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
new file mode 100644
index 0000000..09a252b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -0,0 +1,155 @@
+//===--- BugproneTidyModule.cpp - clang-tidy ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "../cppcoreguidelines/NarrowingConversionsCheck.h"
+#include "ArgumentCommentCheck.h"
+#include "AssertSideEffectCheck.h"
+#include "BoolPointerImplicitConversionCheck.h"
+#include "CopyConstructorInitCheck.h"
+#include "DanglingHandleCheck.h"
+#include "ExceptionEscapeCheck.h"
+#include "FoldInitTypeCheck.h"
+#include "ForwardDeclarationNamespaceCheck.h"
+#include "ForwardingReferenceOverloadCheck.h"
+#include "InaccurateEraseCheck.h"
+#include "IncorrectRoundingsCheck.h"
+#include "IntegerDivisionCheck.h"
+#include "LambdaFunctionNameCheck.h"
+#include "MacroParenthesesCheck.h"
+#include "MacroRepeatedSideEffectsCheck.h"
+#include "MisplacedOperatorInStrlenInAllocCheck.h"
+#include "MisplacedWideningCastCheck.h"
+#include "MoveForwardingReferenceCheck.h"
+#include "MultipleStatementMacroCheck.h"
+#include "ParentVirtualCallCheck.h"
+#include "SizeofContainerCheck.h"
+#include "SizeofExpressionCheck.h"
+#include "StringConstructorCheck.h"
+#include "StringIntegerAssignmentCheck.h"
+#include "StringLiteralWithEmbeddedNulCheck.h"
+#include "SuspiciousEnumUsageCheck.h"
+#include "SuspiciousMemsetUsageCheck.h"
+#include "SuspiciousMissingCommaCheck.h"
+#include "SuspiciousSemicolonCheck.h"
+#include "SuspiciousStringCompareCheck.h"
+#include "SwappedArgumentsCheck.h"
+#include "TerminatingContinueCheck.h"
+#include "ThrowKeywordMissingCheck.h"
+#include "UndefinedMemoryManipulationCheck.h"
+#include "UndelegatedConstructorCheck.h"
+#include "UnusedRaiiCheck.h"
+#include "UnusedReturnValueCheck.h"
+#include "UseAfterMoveCheck.h"
+#include "VirtualNearMissCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+class BugproneModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<ArgumentCommentCheck>(
+ "bugprone-argument-comment");
+ CheckFactories.registerCheck<AssertSideEffectCheck>(
+ "bugprone-assert-side-effect");
+ CheckFactories.registerCheck<BoolPointerImplicitConversionCheck>(
+ "bugprone-bool-pointer-implicit-conversion");
+ CheckFactories.registerCheck<CopyConstructorInitCheck>(
+ "bugprone-copy-constructor-init");
+ CheckFactories.registerCheck<DanglingHandleCheck>(
+ "bugprone-dangling-handle");
+ CheckFactories.registerCheck<ExceptionEscapeCheck>(
+ "bugprone-exception-escape");
+ CheckFactories.registerCheck<FoldInitTypeCheck>(
+ "bugprone-fold-init-type");
+ CheckFactories.registerCheck<ForwardDeclarationNamespaceCheck>(
+ "bugprone-forward-declaration-namespace");
+ CheckFactories.registerCheck<ForwardingReferenceOverloadCheck>(
+ "bugprone-forwarding-reference-overload");
+ CheckFactories.registerCheck<InaccurateEraseCheck>(
+ "bugprone-inaccurate-erase");
+ CheckFactories.registerCheck<IncorrectRoundingsCheck>(
+ "bugprone-incorrect-roundings");
+ CheckFactories.registerCheck<IntegerDivisionCheck>(
+ "bugprone-integer-division");
+ CheckFactories.registerCheck<LambdaFunctionNameCheck>(
+ "bugprone-lambda-function-name");
+ CheckFactories.registerCheck<MacroParenthesesCheck>(
+ "bugprone-macro-parentheses");
+ CheckFactories.registerCheck<MacroRepeatedSideEffectsCheck>(
+ "bugprone-macro-repeated-side-effects");
+ CheckFactories.registerCheck<MisplacedOperatorInStrlenInAllocCheck>(
+ "bugprone-misplaced-operator-in-strlen-in-alloc");
+ CheckFactories.registerCheck<MisplacedWideningCastCheck>(
+ "bugprone-misplaced-widening-cast");
+ CheckFactories.registerCheck<MoveForwardingReferenceCheck>(
+ "bugprone-move-forwarding-reference");
+ CheckFactories.registerCheck<MultipleStatementMacroCheck>(
+ "bugprone-multiple-statement-macro");
+ CheckFactories.registerCheck<cppcoreguidelines::NarrowingConversionsCheck>(
+ "bugprone-narrowing-conversions");
+ CheckFactories.registerCheck<ParentVirtualCallCheck>(
+ "bugprone-parent-virtual-call");
+ CheckFactories.registerCheck<SizeofContainerCheck>(
+ "bugprone-sizeof-container");
+ CheckFactories.registerCheck<SizeofExpressionCheck>(
+ "bugprone-sizeof-expression");
+ CheckFactories.registerCheck<StringConstructorCheck>(
+ "bugprone-string-constructor");
+ CheckFactories.registerCheck<StringIntegerAssignmentCheck>(
+ "bugprone-string-integer-assignment");
+ CheckFactories.registerCheck<StringLiteralWithEmbeddedNulCheck>(
+ "bugprone-string-literal-with-embedded-nul");
+ CheckFactories.registerCheck<SuspiciousEnumUsageCheck>(
+ "bugprone-suspicious-enum-usage");
+ CheckFactories.registerCheck<SuspiciousMemsetUsageCheck>(
+ "bugprone-suspicious-memset-usage");
+ CheckFactories.registerCheck<SuspiciousMissingCommaCheck>(
+ "bugprone-suspicious-missing-comma");
+ CheckFactories.registerCheck<SuspiciousSemicolonCheck>(
+ "bugprone-suspicious-semicolon");
+ CheckFactories.registerCheck<SuspiciousStringCompareCheck>(
+ "bugprone-suspicious-string-compare");
+ CheckFactories.registerCheck<SwappedArgumentsCheck>(
+ "bugprone-swapped-arguments");
+ CheckFactories.registerCheck<TerminatingContinueCheck>(
+ "bugprone-terminating-continue");
+ CheckFactories.registerCheck<ThrowKeywordMissingCheck>(
+ "bugprone-throw-keyword-missing");
+ CheckFactories.registerCheck<UndefinedMemoryManipulationCheck>(
+ "bugprone-undefined-memory-manipulation");
+ CheckFactories.registerCheck<UndelegatedConstructorCheck>(
+ "bugprone-undelegated-constructor");
+ CheckFactories.registerCheck<UnusedRaiiCheck>(
+ "bugprone-unused-raii");
+ CheckFactories.registerCheck<UnusedReturnValueCheck>(
+ "bugprone-unused-return-value");
+ CheckFactories.registerCheck<UseAfterMoveCheck>(
+ "bugprone-use-after-move");
+ CheckFactories.registerCheck<VirtualNearMissCheck>(
+ "bugprone-virtual-near-miss");
+ }
+};
+
+} // namespace bugprone
+
+// Register the BugproneTidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<bugprone::BugproneModule>
+ X("bugprone-module", "Adds checks for bugprone code constructs.");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the BugproneModule.
+volatile int BugproneModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
new file mode 100644
index 0000000..b20997c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -0,0 +1,55 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyBugproneModule
+ ArgumentCommentCheck.cpp
+ AssertSideEffectCheck.cpp
+ BoolPointerImplicitConversionCheck.cpp
+ BugproneTidyModule.cpp
+ CopyConstructorInitCheck.cpp
+ DanglingHandleCheck.cpp
+ ExceptionEscapeCheck.cpp
+ FoldInitTypeCheck.cpp
+ ForwardDeclarationNamespaceCheck.cpp
+ ForwardingReferenceOverloadCheck.cpp
+ InaccurateEraseCheck.cpp
+ IncorrectRoundingsCheck.cpp
+ IntegerDivisionCheck.cpp
+ LambdaFunctionNameCheck.cpp
+ MacroParenthesesCheck.cpp
+ MacroRepeatedSideEffectsCheck.cpp
+ MisplacedOperatorInStrlenInAllocCheck.cpp
+ MisplacedWideningCastCheck.cpp
+ MoveForwardingReferenceCheck.cpp
+ MultipleStatementMacroCheck.cpp
+ ParentVirtualCallCheck.cpp
+ SizeofContainerCheck.cpp
+ SizeofExpressionCheck.cpp
+ StringConstructorCheck.cpp
+ StringIntegerAssignmentCheck.cpp
+ StringLiteralWithEmbeddedNulCheck.cpp
+ SuspiciousEnumUsageCheck.cpp
+ SuspiciousMemsetUsageCheck.cpp
+ SuspiciousMissingCommaCheck.cpp
+ SuspiciousSemicolonCheck.cpp
+ SuspiciousStringCompareCheck.cpp
+ SwappedArgumentsCheck.cpp
+ TerminatingContinueCheck.cpp
+ ThrowKeywordMissingCheck.cpp
+ UndefinedMemoryManipulationCheck.cpp
+ UndelegatedConstructorCheck.cpp
+ UnusedRaiiCheck.cpp
+ UnusedReturnValueCheck.cpp
+ UseAfterMoveCheck.cpp
+ VirtualNearMissCheck.cpp
+
+ LINK_LIBS
+ clangAnalysis
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyCppCoreGuidelinesModule
+ clangTidyUtils
+ clangTooling
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/CopyConstructorInitCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/CopyConstructorInitCheck.cpp
new file mode 100644
index 0000000..151e56c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/CopyConstructorInitCheck.cpp
@@ -0,0 +1,121 @@
+//===--- CopyConstructorInitCheck.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CopyConstructorInitCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void CopyConstructorInitCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // In the future this might be extended to move constructors?
+ Finder->addMatcher(
+ cxxConstructorDecl(
+ isCopyConstructor(),
+ hasAnyConstructorInitializer(cxxCtorInitializer(
+ isBaseInitializer(),
+ withInitializer(cxxConstructExpr(hasDeclaration(
+ cxxConstructorDecl(isDefaultConstructor())))))),
+ unless(isInstantiated()))
+ .bind("ctor"),
+ this);
+}
+
+void CopyConstructorInitCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
+ std::string ParamName = Ctor->getParamDecl(0)->getNameAsString();
+
+ // We want only one warning (and FixIt) for each ctor.
+ std::string FixItInitList;
+ bool HasRelevantBaseInit = false;
+ bool ShouldNotDoFixit = false;
+ bool HasWrittenInitializer = false;
+ SmallVector<FixItHint, 2> SafeFixIts;
+ for (const auto *Init : Ctor->inits()) {
+ bool CtorInitIsWritten = Init->isWritten();
+ HasWrittenInitializer = HasWrittenInitializer || CtorInitIsWritten;
+ if (!Init->isBaseInitializer())
+ continue;
+ const Type *BaseType = Init->getBaseClass();
+ // Do not do fixits if there is a type alias involved or one of the bases
+ // are explicitly initialized. In the latter case we not do fixits to avoid
+ // -Wreorder warnings.
+ if (const auto *TempSpecTy = dyn_cast<TemplateSpecializationType>(BaseType))
+ ShouldNotDoFixit = ShouldNotDoFixit || TempSpecTy->isTypeAlias();
+ ShouldNotDoFixit = ShouldNotDoFixit || isa<TypedefType>(BaseType);
+ ShouldNotDoFixit = ShouldNotDoFixit || CtorInitIsWritten;
+ const CXXRecordDecl *BaseClass =
+ BaseType->getAsCXXRecordDecl()->getDefinition();
+ if (BaseClass->field_empty() &&
+ BaseClass->forallBases(
+ [](const CXXRecordDecl *Class) { return Class->field_empty(); }))
+ continue;
+ bool NonCopyableBase = false;
+ for (const auto *Ctor : BaseClass->ctors()) {
+ if (Ctor->isCopyConstructor() &&
+ (Ctor->getAccess() == AS_private || Ctor->isDeleted())) {
+ NonCopyableBase = true;
+ break;
+ }
+ }
+ if (NonCopyableBase)
+ continue;
+ const auto *CExpr = dyn_cast<CXXConstructExpr>(Init->getInit());
+ if (!CExpr || !CExpr->getConstructor()->isDefaultConstructor())
+ continue;
+ HasRelevantBaseInit = true;
+ if (CtorInitIsWritten) {
+ if (!ParamName.empty())
+ SafeFixIts.push_back(
+ FixItHint::CreateInsertion(CExpr->getLocEnd(), ParamName));
+ } else {
+ if (Init->getSourceLocation().isMacroID() ||
+ Ctor->getLocation().isMacroID() || ShouldNotDoFixit)
+ break;
+ FixItInitList += BaseClass->getNameAsString();
+ FixItInitList += "(" + ParamName + "), ";
+ }
+ }
+ if (!HasRelevantBaseInit)
+ return;
+
+ auto Diag = diag(Ctor->getLocation(),
+ "calling a base constructor other than the copy constructor")
+ << SafeFixIts;
+
+ if (FixItInitList.empty() || ParamName.empty() || ShouldNotDoFixit)
+ return;
+
+ std::string FixItMsg{FixItInitList.substr(0, FixItInitList.size() - 2)};
+ SourceLocation FixItLoc;
+ // There is no initialization list in this constructor.
+ if (!HasWrittenInitializer) {
+ FixItLoc = Ctor->getBody()->getLocStart();
+ FixItMsg = " : " + FixItMsg;
+ } else {
+ // We apply the missing ctors at the beginning of the initialization list.
+ FixItLoc = (*Ctor->init_begin())->getSourceLocation();
+ FixItMsg += ',';
+ }
+ FixItMsg += ' ';
+
+ Diag << FixItHint::CreateInsertion(FixItLoc, FixItMsg);
+} // namespace misc
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/CopyConstructorInitCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/CopyConstructorInitCheck.h
new file mode 100644
index 0000000..4d13da4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/CopyConstructorInitCheck.h
@@ -0,0 +1,36 @@
+//===--- CopyConstructorInitCheck.h - clang-tidy--------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_COPY_CONSTRUCTOR_INIT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_COPY_CONSTRUCTOR_INIT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds copy constructors where the ctor don't call the copy constructor of
+/// the base class.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-copy-constructor-init.html
+class CopyConstructorInitCheck : public ClangTidyCheck {
+public:
+ CopyConstructorInitCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_COPY_CONSTRUCTOR_INIT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp
new file mode 100644
index 0000000..a22dcad
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp
@@ -0,0 +1,188 @@
+//===--- DanglingHandleCheck.cpp - clang-tidy------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DanglingHandleCheck.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::tidy::matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+
+ast_matchers::internal::BindableMatcher<Stmt>
+handleFrom(const ast_matchers::internal::Matcher<RecordDecl> &IsAHandle,
+ const ast_matchers::internal::Matcher<Expr> &Arg) {
+ return expr(
+ anyOf(cxxConstructExpr(hasDeclaration(cxxMethodDecl(ofClass(IsAHandle))),
+ hasArgument(0, Arg)),
+ cxxMemberCallExpr(hasType(cxxRecordDecl(IsAHandle)),
+ callee(memberExpr(member(cxxConversionDecl()))),
+ on(Arg))));
+}
+
+ast_matchers::internal::Matcher<Stmt> handleFromTemporaryValue(
+ const ast_matchers::internal::Matcher<RecordDecl> &IsAHandle) {
+ // If a ternary operator returns a temporary value, then both branches hold a
+ // temporary value. If one of them is not a temporary then it must be copied
+ // into one to satisfy the type of the operator.
+ const auto TemporaryTernary =
+ conditionalOperator(hasTrueExpression(cxxBindTemporaryExpr()),
+ hasFalseExpression(cxxBindTemporaryExpr()));
+
+ return handleFrom(IsAHandle, anyOf(cxxBindTemporaryExpr(), TemporaryTernary));
+}
+
+ast_matchers::internal::Matcher<RecordDecl> isASequence() {
+ return hasAnyName("::std::deque", "::std::forward_list", "::std::list",
+ "::std::vector");
+}
+
+ast_matchers::internal::Matcher<RecordDecl> isASet() {
+ return hasAnyName("::std::set", "::std::multiset", "::std::unordered_set",
+ "::std::unordered_multiset");
+}
+
+ast_matchers::internal::Matcher<RecordDecl> isAMap() {
+ return hasAnyName("::std::map", "::std::multimap", "::std::unordered_map",
+ "::std::unordered_multimap");
+}
+
+ast_matchers::internal::BindableMatcher<Stmt> makeContainerMatcher(
+ const ast_matchers::internal::Matcher<RecordDecl> &IsAHandle) {
+ // This matcher could be expanded to detect:
+ // - Constructors: eg. vector<string_view>(3, string("A"));
+ // - emplace*(): This requires a different logic to determine that
+ // the conversion will happen inside the container.
+ // - map's insert: This requires detecting that the pair conversion triggers
+ // the bug. A little more complicated than what we have now.
+ return callExpr(
+ hasAnyArgument(
+ ignoringParenImpCasts(handleFromTemporaryValue(IsAHandle))),
+ anyOf(
+ // For sequences: assign, push_back, resize.
+ cxxMemberCallExpr(
+ callee(functionDecl(hasAnyName("assign", "push_back", "resize"))),
+ on(expr(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(recordDecl(isASequence())))))))),
+ // For sequences and sets: insert.
+ cxxMemberCallExpr(callee(functionDecl(hasName("insert"))),
+ on(expr(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(recordDecl(
+ anyOf(isASequence(), isASet()))))))))),
+ // For maps: operator[].
+ cxxOperatorCallExpr(callee(cxxMethodDecl(ofClass(isAMap()))),
+ hasOverloadedOperatorName("[]"))));
+}
+
+} // anonymous namespace
+
+DanglingHandleCheck::DanglingHandleCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ HandleClasses(utils::options::parseStringList(Options.get(
+ "HandleClasses",
+ "std::basic_string_view;std::experimental::basic_string_view"))),
+ IsAHandle(cxxRecordDecl(hasAnyName(std::vector<StringRef>(
+ HandleClasses.begin(), HandleClasses.end())))
+ .bind("handle")) {}
+
+void DanglingHandleCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "HandleClasses",
+ utils::options::serializeStringList(HandleClasses));
+}
+
+void DanglingHandleCheck::registerMatchersForVariables(MatchFinder *Finder) {
+ const auto ConvertedHandle = handleFromTemporaryValue(IsAHandle);
+
+ // Find 'Handle foo(ReturnsAValue());'
+ Finder->addMatcher(
+ varDecl(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(cxxRecordDecl(IsAHandle))))),
+ hasInitializer(
+ exprWithCleanups(has(ignoringParenImpCasts(ConvertedHandle)))
+ .bind("bad_stmt"))),
+ this);
+
+ // Find 'Handle foo = ReturnsAValue();'
+ Finder->addMatcher(
+ varDecl(
+ hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(cxxRecordDecl(IsAHandle))))),
+ unless(parmVarDecl()),
+ hasInitializer(exprWithCleanups(has(ignoringParenImpCasts(handleFrom(
+ IsAHandle, ConvertedHandle))))
+ .bind("bad_stmt"))),
+ this);
+ // Find 'foo = ReturnsAValue(); // foo is Handle'
+ Finder->addMatcher(
+ cxxOperatorCallExpr(callee(cxxMethodDecl(ofClass(IsAHandle))),
+ hasOverloadedOperatorName("="),
+ hasArgument(1, ConvertedHandle))
+ .bind("bad_stmt"),
+ this);
+
+ // Container insertions that will dangle.
+ Finder->addMatcher(makeContainerMatcher(IsAHandle).bind("bad_stmt"), this);
+}
+
+void DanglingHandleCheck::registerMatchersForReturn(MatchFinder *Finder) {
+ // Return a local.
+ Finder->addMatcher(
+ returnStmt(
+ // The AST contains two constructor calls:
+ // 1. Value to Handle conversion.
+ // 2. Handle copy construction.
+ // We have to match both.
+ has(ignoringImplicit(handleFrom(
+ IsAHandle,
+ handleFrom(IsAHandle,
+ declRefExpr(to(varDecl(
+ // Is function scope ...
+ hasAutomaticStorageDuration(),
+ // ... and it is a local array or Value.
+ anyOf(hasType(arrayType()),
+ hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(recordDecl(
+ unless(IsAHandle)))))))))))))),
+ // Temporary fix for false positives inside lambdas.
+ unless(hasAncestor(lambdaExpr())))
+ .bind("bad_stmt"),
+ this);
+
+ // Return a temporary.
+ Finder->addMatcher(
+ returnStmt(
+ has(ignoringParenImpCasts(exprWithCleanups(has(ignoringParenImpCasts(
+ handleFrom(IsAHandle, handleFromTemporaryValue(IsAHandle))))))))
+ .bind("bad_stmt"),
+ this);
+}
+
+void DanglingHandleCheck::registerMatchers(MatchFinder *Finder) {
+ registerMatchersForVariables(Finder);
+ registerMatchersForReturn(Finder);
+}
+
+void DanglingHandleCheck::check(const MatchFinder::MatchResult &Result) {
+ auto *Handle = Result.Nodes.getNodeAs<CXXRecordDecl>("handle");
+ diag(Result.Nodes.getNodeAs<Stmt>("bad_stmt")->getLocStart(),
+ "%0 outlives its value")
+ << Handle->getQualifiedNameAsString();
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.h
new file mode 100644
index 0000000..add8d42
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.h
@@ -0,0 +1,43 @@
+//===--- DanglingHandleCheck.h - clang-tidy----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DANGLING_HANDLE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DANGLING_HANDLE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Detect dangling references in value handlers like
+/// std::experimental::string_view.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-dangling-handle.html
+class DanglingHandleCheck : public ClangTidyCheck {
+public:
+ DanglingHandleCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ void registerMatchersForVariables(ast_matchers::MatchFinder *Finder);
+ void registerMatchersForReturn(ast_matchers::MatchFinder *Finder);
+
+ const std::vector<std::string> HandleClasses;
+ const ast_matchers::internal::Matcher<RecordDecl> IsAHandle;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DANGLING_HANDLE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp
new file mode 100644
index 0000000..416cf3f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp
@@ -0,0 +1,214 @@
+//===--- ExceptionEscapeCheck.cpp - clang-tidy-----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExceptionEscapeCheck.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringSet.h"
+
+using namespace clang::ast_matchers;
+
+namespace {
+typedef llvm::SmallVector<const clang::Type *, 8> TypeVec;
+} // namespace
+
+namespace clang {
+
+static bool isBaseOf(const Type *DerivedType, const Type *BaseType) {
+ const auto *DerivedClass = DerivedType->getAsCXXRecordDecl();
+ const auto *BaseClass = BaseType->getAsCXXRecordDecl();
+ if (!DerivedClass || !BaseClass)
+ return false;
+
+ return !DerivedClass->forallBases(
+ [BaseClass](const CXXRecordDecl *Cur) { return Cur != BaseClass; });
+}
+
+static const TypeVec
+throwsException(const Stmt *St, const TypeVec &Caught,
+ llvm::SmallSet<const FunctionDecl *, 32> &CallStack);
+
+static const TypeVec
+throwsException(const FunctionDecl *Func,
+ llvm::SmallSet<const FunctionDecl *, 32> &CallStack) {
+ if (CallStack.count(Func))
+ return TypeVec();
+
+ if (const Stmt *Body = Func->getBody()) {
+ CallStack.insert(Func);
+ const TypeVec Result = throwsException(Body, TypeVec(), CallStack);
+ CallStack.erase(Func);
+ return Result;
+ }
+
+ TypeVec Result;
+ if (const auto *FPT = Func->getType()->getAs<FunctionProtoType>()) {
+ for (const QualType Ex : FPT->exceptions()) {
+ Result.push_back(Ex.getTypePtr());
+ }
+ }
+ return Result;
+}
+
+static const TypeVec
+throwsException(const Stmt *St, const TypeVec &Caught,
+ llvm::SmallSet<const FunctionDecl *, 32> &CallStack) {
+ TypeVec Results;
+
+ if (!St)
+ return Results;
+
+ if (const auto *Throw = dyn_cast<CXXThrowExpr>(St)) {
+ if (const auto *ThrownExpr = Throw->getSubExpr()) {
+ const auto *ThrownType =
+ ThrownExpr->getType()->getUnqualifiedDesugaredType();
+ if (ThrownType->isReferenceType()) {
+ ThrownType = ThrownType->castAs<ReferenceType>()
+ ->getPointeeType()
+ ->getUnqualifiedDesugaredType();
+ }
+ if (const auto *TD = ThrownType->getAsTagDecl()) {
+ if (TD->getDeclName().isIdentifier() && TD->getName() == "bad_alloc"
+ && TD->isInStdNamespace())
+ return Results;
+ }
+ Results.push_back(ThrownExpr->getType()->getUnqualifiedDesugaredType());
+ } else {
+ Results.append(Caught.begin(), Caught.end());
+ }
+ } else if (const auto *Try = dyn_cast<CXXTryStmt>(St)) {
+ TypeVec Uncaught = throwsException(Try->getTryBlock(), Caught, CallStack);
+ for (unsigned i = 0; i < Try->getNumHandlers(); ++i) {
+ const CXXCatchStmt *Catch = Try->getHandler(i);
+ if (!Catch->getExceptionDecl()) {
+ const TypeVec Rethrown =
+ throwsException(Catch->getHandlerBlock(), Uncaught, CallStack);
+ Results.append(Rethrown.begin(), Rethrown.end());
+ Uncaught.clear();
+ } else {
+ const auto *CaughtType =
+ Catch->getCaughtType()->getUnqualifiedDesugaredType();
+ if (CaughtType->isReferenceType()) {
+ CaughtType = CaughtType->castAs<ReferenceType>()
+ ->getPointeeType()
+ ->getUnqualifiedDesugaredType();
+ }
+ auto NewEnd =
+ llvm::remove_if(Uncaught, [&CaughtType](const Type *ThrownType) {
+ return ThrownType == CaughtType ||
+ isBaseOf(ThrownType, CaughtType);
+ });
+ if (NewEnd != Uncaught.end()) {
+ Uncaught.erase(NewEnd, Uncaught.end());
+ const TypeVec Rethrown = throwsException(
+ Catch->getHandlerBlock(), TypeVec(1, CaughtType), CallStack);
+ Results.append(Rethrown.begin(), Rethrown.end());
+ }
+ }
+ }
+ Results.append(Uncaught.begin(), Uncaught.end());
+ } else if (const auto *Call = dyn_cast<CallExpr>(St)) {
+ if (const FunctionDecl *Func = Call->getDirectCallee()) {
+ TypeVec Excs = throwsException(Func, CallStack);
+ Results.append(Excs.begin(), Excs.end());
+ }
+ } else {
+ for (const Stmt *Child : St->children()) {
+ TypeVec Excs = throwsException(Child, Caught, CallStack);
+ Results.append(Excs.begin(), Excs.end());
+ }
+ }
+ return Results;
+}
+
+static const TypeVec throwsException(const FunctionDecl *Func) {
+ llvm::SmallSet<const FunctionDecl *, 32> CallStack;
+ return throwsException(Func, CallStack);
+}
+
+namespace ast_matchers {
+AST_MATCHER_P(FunctionDecl, throws, internal::Matcher<Type>, InnerMatcher) {
+ TypeVec ExceptionList = throwsException(&Node);
+ auto NewEnd = llvm::remove_if(
+ ExceptionList, [this, Finder, Builder](const Type *Exception) {
+ return !InnerMatcher.matches(*Exception, Finder, Builder);
+ });
+ ExceptionList.erase(NewEnd, ExceptionList.end());
+ return ExceptionList.size();
+}
+
+AST_MATCHER_P(Type, isIgnored, llvm::StringSet<>, IgnoredExceptions) {
+ if (const auto *TD = Node.getAsTagDecl()) {
+ if (TD->getDeclName().isIdentifier())
+ return IgnoredExceptions.count(TD->getName()) > 0;
+ }
+ return false;
+}
+
+AST_MATCHER_P(FunctionDecl, isEnabled, llvm::StringSet<>,
+ FunctionsThatShouldNotThrow) {
+ return FunctionsThatShouldNotThrow.count(Node.getNameAsString()) > 0;
+}
+} // namespace ast_matchers
+
+namespace tidy {
+namespace bugprone {
+
+ExceptionEscapeCheck::ExceptionEscapeCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context), RawFunctionsThatShouldNotThrow(Options.get(
+ "FunctionsThatShouldNotThrow", "")),
+ RawIgnoredExceptions(Options.get("IgnoredExceptions", "")) {
+ llvm::SmallVector<StringRef, 8> FunctionsThatShouldNotThrowVec,
+ IgnoredExceptionsVec;
+ StringRef(RawFunctionsThatShouldNotThrow)
+ .split(FunctionsThatShouldNotThrowVec, ",", -1, false);
+ FunctionsThatShouldNotThrow.insert(FunctionsThatShouldNotThrowVec.begin(),
+ FunctionsThatShouldNotThrowVec.end());
+ StringRef(RawIgnoredExceptions).split(IgnoredExceptionsVec, ",", -1, false);
+ IgnoredExceptions.insert(IgnoredExceptionsVec.begin(),
+ IgnoredExceptionsVec.end());
+}
+
+void ExceptionEscapeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "FunctionsThatShouldNotThrow",
+ RawFunctionsThatShouldNotThrow);
+ Options.store(Opts, "IgnoredExceptions", RawIgnoredExceptions);
+}
+
+void ExceptionEscapeCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ functionDecl(allOf(anyOf(isNoThrow(), cxxDestructorDecl(),
+ cxxConstructorDecl(isMoveConstructor()),
+ cxxMethodDecl(isMoveAssignmentOperator()),
+ hasName("main"), hasName("swap"),
+ isEnabled(FunctionsThatShouldNotThrow)),
+ throws(unless(isIgnored(IgnoredExceptions)))))
+ .bind("thrower"),
+ this);
+}
+
+void ExceptionEscapeCheck::check(const MatchFinder::MatchResult &Result) {
+ const FunctionDecl *MatchedDecl =
+ Result.Nodes.getNodeAs<FunctionDecl>("thrower");
+ if (!MatchedDecl)
+ return;
+
+ // FIXME: We should provide more information about the exact location where
+ // the exception is thrown, maybe the full path the exception escapes
+ diag(MatchedDecl->getLocation(), "an exception may be thrown in function %0 "
+ "which should not throw exceptions") << MatchedDecl;
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.h
new file mode 100644
index 0000000..d690022
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.h
@@ -0,0 +1,47 @@
+//===--- ExceptionEscapeCheck.h - clang-tidy---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_EXCEPTION_ESCAPE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_EXCEPTION_ESCAPE_H
+
+#include "../ClangTidy.h"
+
+#include "llvm/ADT/StringSet.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds functions which should not throw exceptions: Destructors, move
+/// constructors, move assignment operators, the main() function,
+/// swap() functions, functions marked with throw() or noexcept and functions
+/// given as option to the checker.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-exception-escape.html
+class ExceptionEscapeCheck : public ClangTidyCheck {
+public:
+ ExceptionEscapeCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ std::string RawFunctionsThatShouldNotThrow;
+ std::string RawIgnoredExceptions;
+
+ llvm::StringSet<> FunctionsThatShouldNotThrow;
+ llvm::StringSet<> IgnoredExceptions;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_EXCEPTION_ESCAPE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/FoldInitTypeCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/FoldInitTypeCheck.cpp
new file mode 100644
index 0000000..6d7fd28
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/FoldInitTypeCheck.cpp
@@ -0,0 +1,140 @@
+//===--- FoldInitTypeCheck.cpp - clang-tidy--------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FoldInitTypeCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void FoldInitTypeCheck::registerMatchers(MatchFinder *Finder) {
+ // We match functions of interest and bind the iterator and init value types.
+ // Note: Right now we check only builtin types.
+ const auto BuiltinTypeWithId = [](const char *ID) {
+ return hasCanonicalType(builtinType().bind(ID));
+ };
+ const auto IteratorWithValueType = [&BuiltinTypeWithId](const char *ID) {
+ return anyOf(
+ // Pointer types.
+ pointsTo(BuiltinTypeWithId(ID)),
+ // Iterator types.
+ recordType(hasDeclaration(has(typedefNameDecl(
+ hasName("value_type"), hasType(BuiltinTypeWithId(ID)))))));
+ };
+
+ const auto IteratorParam = parmVarDecl(
+ hasType(hasCanonicalType(IteratorWithValueType("IterValueType"))));
+ const auto Iterator2Param = parmVarDecl(
+ hasType(hasCanonicalType(IteratorWithValueType("Iter2ValueType"))));
+ const auto InitParam = parmVarDecl(hasType(BuiltinTypeWithId("InitType")));
+
+ // std::accumulate, std::reduce.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(
+ hasAnyName("::std::accumulate", "::std::reduce"),
+ hasParameter(0, IteratorParam), hasParameter(2, InitParam))),
+ argumentCountIs(3))
+ .bind("Call"),
+ this);
+ // std::inner_product.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasName("::std::inner_product"),
+ hasParameter(0, IteratorParam),
+ hasParameter(2, Iterator2Param),
+ hasParameter(3, InitParam))),
+ argumentCountIs(4))
+ .bind("Call"),
+ this);
+ // std::reduce with a policy.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasName("::std::reduce"),
+ hasParameter(1, IteratorParam),
+ hasParameter(3, InitParam))),
+ argumentCountIs(4))
+ .bind("Call"),
+ this);
+ // std::inner_product with a policy.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasName("::std::inner_product"),
+ hasParameter(1, IteratorParam),
+ hasParameter(3, Iterator2Param),
+ hasParameter(4, InitParam))),
+ argumentCountIs(5))
+ .bind("Call"),
+ this);
+}
+
+/// Returns true if ValueType is allowed to fold into InitType, i.e. if:
+/// static_cast<InitType>(ValueType{some_value})
+/// does not result in trucation.
+static bool isValidBuiltinFold(const BuiltinType &ValueType,
+ const BuiltinType &InitType,
+ const ASTContext &Context) {
+ const auto ValueTypeSize = Context.getTypeSize(&ValueType);
+ const auto InitTypeSize = Context.getTypeSize(&InitType);
+ // It's OK to fold a float into a float of bigger or equal size, but not OK to
+ // fold into an int.
+ if (ValueType.isFloatingPoint())
+ return InitType.isFloatingPoint() && InitTypeSize >= ValueTypeSize;
+ // It's OK to fold an int into:
+ // - an int of the same size and signedness.
+ // - a bigger int, regardless of signedness.
+ // - FIXME: should it be a warning to fold into floating point?
+ if (ValueType.isInteger()) {
+ if (InitType.isInteger()) {
+ if (InitType.isSignedInteger() == ValueType.isSignedInteger())
+ return InitTypeSize >= ValueTypeSize;
+ return InitTypeSize > ValueTypeSize;
+ }
+ if (InitType.isFloatingPoint())
+ return InitTypeSize >= ValueTypeSize;
+ }
+ return false;
+}
+
+/// Prints a diagnostic if IterValueType doe snot fold into IterValueType (see
+// isValidBuiltinFold for details).
+void FoldInitTypeCheck::doCheck(const BuiltinType &IterValueType,
+ const BuiltinType &InitType,
+ const ASTContext &Context,
+ const CallExpr &CallNode) {
+ if (!isValidBuiltinFold(IterValueType, InitType, Context)) {
+ diag(CallNode.getExprLoc(), "folding type %0 into type %1 might result in "
+ "loss of precision")
+ << IterValueType.desugar() << InitType.desugar();
+ }
+}
+
+void FoldInitTypeCheck::check(const MatchFinder::MatchResult &Result) {
+ // Given the iterator and init value type retreived by the matchers,
+ // we check that the ::value_type of the iterator is compatible with
+ // the init value type.
+ const auto *InitType = Result.Nodes.getNodeAs<BuiltinType>("InitType");
+ const auto *IterValueType =
+ Result.Nodes.getNodeAs<BuiltinType>("IterValueType");
+ assert(InitType != nullptr);
+ assert(IterValueType != nullptr);
+
+ const auto *CallNode = Result.Nodes.getNodeAs<CallExpr>("Call");
+ assert(CallNode != nullptr);
+
+ doCheck(*IterValueType, *InitType, *Result.Context, *CallNode);
+
+ if (const auto *Iter2ValueType =
+ Result.Nodes.getNodeAs<BuiltinType>("Iter2ValueType"))
+ doCheck(*Iter2ValueType, *InitType, *Result.Context, *CallNode);
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/FoldInitTypeCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/FoldInitTypeCheck.h
new file mode 100644
index 0000000..e6170de
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/FoldInitTypeCheck.h
@@ -0,0 +1,44 @@
+//===--- FoldInitTypeCheck.h - clang-tidy------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_FOLD_INIT_TYPE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_FOLD_INIT_TYPE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Find and flag invalid initializer values in folds, e.g. std::accumulate.
+/// Example:
+/// \code
+/// auto v = {65536L * 65536 * 65536};
+/// std::accumulate(begin(v), end(v), 0 /* int type is too small */);
+/// \endcode
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-fold-init-type.html
+class FoldInitTypeCheck : public ClangTidyCheck {
+public:
+ FoldInitTypeCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void doCheck(const BuiltinType &IterValueType, const BuiltinType &InitType,
+ const ASTContext &Context, const CallExpr &CallNode);
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_FOLD_INIT_TYPE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp
new file mode 100644
index 0000000..9ea5b55
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp
@@ -0,0 +1,174 @@
+//===--- ForwardDeclarationNamespaceCheck.cpp - clang-tidy ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ForwardDeclarationNamespaceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include <stack>
+#include <string>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void ForwardDeclarationNamespaceCheck::registerMatchers(MatchFinder *Finder) {
+ // Match all class declarations/definitions *EXCEPT*
+ // 1. implicit classes, e.g. `class A {};` has implicit `class A` inside `A`.
+ // 2. nested classes declared/defined inside another class.
+ // 3. template class declaration, template instantiation or
+ // specialization (NOTE: extern specialization is filtered out by
+ // `unless(hasAncestor(cxxRecordDecl()))`).
+ auto IsInSpecialization = hasAncestor(
+ decl(anyOf(cxxRecordDecl(isExplicitTemplateSpecialization()),
+ functionDecl(isExplicitTemplateSpecialization()))));
+ Finder->addMatcher(
+ cxxRecordDecl(
+ hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))),
+ unless(isImplicit()), unless(hasAncestor(cxxRecordDecl())),
+ unless(isInstantiated()), unless(IsInSpecialization),
+ unless(classTemplateSpecializationDecl()))
+ .bind("record_decl"),
+ this);
+
+ // Match all friend declarations. Classes used in friend declarations are not
+ // marked as referenced in AST. We need to record all record classes used in
+ // friend declarations.
+ Finder->addMatcher(friendDecl().bind("friend_decl"), this);
+}
+
+void ForwardDeclarationNamespaceCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ if (const auto *RecordDecl =
+ Result.Nodes.getNodeAs<CXXRecordDecl>("record_decl")) {
+ StringRef DeclName = RecordDecl->getName();
+ if (RecordDecl->isThisDeclarationADefinition()) {
+ DeclNameToDefinitions[DeclName].push_back(RecordDecl);
+ } else {
+ // If a declaration has no definition, the definition could be in another
+ // namespace (a wrong namespace).
+ // NOTE: even a declaration does have definition, we still need it to
+ // compare with other declarations.
+ DeclNameToDeclarations[DeclName].push_back(RecordDecl);
+ }
+ } else {
+ const auto *Decl = Result.Nodes.getNodeAs<FriendDecl>("friend_decl");
+ assert(Decl && "Decl is neither record_decl nor friend decl!");
+
+ // Classes used in friend delarations are not marked referenced in AST,
+ // so we need to check classes used in friend declarations manually to
+ // reduce the rate of false positive.
+ // For example, in
+ // \code
+ // struct A;
+ // struct B { friend A; };
+ // \endcode
+ // `A` will not be marked as "referenced" in the AST.
+ if (const TypeSourceInfo *Tsi = Decl->getFriendType()) {
+ QualType Desugared = Tsi->getType().getDesugaredType(*Result.Context);
+ FriendTypes.insert(Desugared.getTypePtr());
+ }
+ }
+}
+
+static bool haveSameNamespaceOrTranslationUnit(const CXXRecordDecl *Decl1,
+ const CXXRecordDecl *Decl2) {
+ const DeclContext *ParentDecl1 = Decl1->getLexicalParent();
+ const DeclContext *ParentDecl2 = Decl2->getLexicalParent();
+
+ // Since we only matched declarations whose parent is Namespace or
+ // TranslationUnit declaration, the parent should be either a translation unit
+ // or namespace.
+ if (ParentDecl1->getDeclKind() == Decl::TranslationUnit ||
+ ParentDecl2->getDeclKind() == Decl::TranslationUnit) {
+ return ParentDecl1 == ParentDecl2;
+ }
+ assert(ParentDecl1->getDeclKind() == Decl::Namespace &&
+ "ParentDecl1 declaration must be a namespace");
+ assert(ParentDecl2->getDeclKind() == Decl::Namespace &&
+ "ParentDecl2 declaration must be a namespace");
+ auto *Ns1 = NamespaceDecl::castFromDeclContext(ParentDecl1);
+ auto *Ns2 = NamespaceDecl::castFromDeclContext(ParentDecl2);
+ return Ns1->getOriginalNamespace() == Ns2->getOriginalNamespace();
+}
+
+static std::string getNameOfNamespace(const CXXRecordDecl *Decl) {
+ const auto *ParentDecl = Decl->getLexicalParent();
+ if (ParentDecl->getDeclKind() == Decl::TranslationUnit) {
+ return "(global)";
+ }
+ const auto *NsDecl = cast<NamespaceDecl>(ParentDecl);
+ std::string Ns;
+ llvm::raw_string_ostream OStream(Ns);
+ NsDecl->printQualifiedName(OStream);
+ OStream.flush();
+ return Ns.empty() ? "(global)" : Ns;
+}
+
+void ForwardDeclarationNamespaceCheck::onEndOfTranslationUnit() {
+ // Iterate each group of declarations by name.
+ for (const auto &KeyValuePair : DeclNameToDeclarations) {
+ const auto &Declarations = KeyValuePair.second;
+ // If more than 1 declaration exists, we check if all are in the same
+ // namespace.
+ for (const auto *CurDecl : Declarations) {
+ if (CurDecl->hasDefinition() || CurDecl->isReferenced()) {
+ continue; // Skip forward declarations that are used/referenced.
+ }
+ if (FriendTypes.count(CurDecl->getTypeForDecl()) != 0) {
+ continue; // Skip forward declarations referenced as friend.
+ }
+ if (CurDecl->getLocation().isMacroID() ||
+ CurDecl->getLocation().isInvalid()) {
+ continue;
+ }
+ // Compare with all other declarations with the same name.
+ for (const auto *Decl : Declarations) {
+ if (Decl == CurDecl) {
+ continue; // Don't compare with self.
+ }
+ if (!CurDecl->hasDefinition() &&
+ !haveSameNamespaceOrTranslationUnit(CurDecl, Decl)) {
+ diag(CurDecl->getLocation(),
+ "declaration %0 is never referenced, but a declaration with "
+ "the same name found in another namespace '%1'")
+ << CurDecl << getNameOfNamespace(Decl);
+ diag(Decl->getLocation(), "a declaration of %0 is found here",
+ DiagnosticIDs::Note)
+ << Decl;
+ break; // FIXME: We only generate one warning for each declaration.
+ }
+ }
+ // Check if a definition in another namespace exists.
+ const auto DeclName = CurDecl->getName();
+ if (DeclNameToDefinitions.find(DeclName) == DeclNameToDefinitions.end()) {
+ continue; // No definition in this translation unit, we can skip it.
+ }
+ // Make a warning for each definition with the same name (in other
+ // namespaces).
+ const auto &Definitions = DeclNameToDefinitions[DeclName];
+ for (const auto *Def : Definitions) {
+ diag(CurDecl->getLocation(),
+ "no definition found for %0, but a definition with "
+ "the same name %1 found in another namespace '%2'")
+ << CurDecl << Def << getNameOfNamespace(Def);
+ diag(Def->getLocation(), "a definition of %0 is found here",
+ DiagnosticIDs::Note)
+ << Def;
+ }
+ }
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.h
new file mode 100644
index 0000000..c3d3018
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.h
@@ -0,0 +1,59 @@
+//===--- ForwardDeclarationNamespaceCheck.h - clang-tidy --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_FORWARDDECLARATIONNAMESPACECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_FORWARDDECLARATIONNAMESPACECHECK_H
+
+#include "../ClangTidy.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include <set>
+#include <vector>
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Checks if an unused forward declaration is in a wrong namespace.
+///
+/// The check inspects all unused forward declarations and checks if there is
+/// any declaration/definition with the same name, which could indicate
+/// that the forward declaration is potentially in a wrong namespace.
+///
+/// \code
+/// namespace na { struct A; }
+/// namespace nb { struct A {} };
+/// nb::A a;
+/// // warning : no definition found for 'A', but a definition with the same
+/// name 'A' found in another namespace 'nb::'
+/// \endcode
+///
+/// This check can only generate warnings, but it can't suggest fixes at this
+/// point.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-forward-declaration-namespace.html
+class ForwardDeclarationNamespaceCheck : public ClangTidyCheck {
+public:
+ ForwardDeclarationNamespaceCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void onEndOfTranslationUnit() override;
+
+private:
+ llvm::StringMap<std::vector<const CXXRecordDecl *>> DeclNameToDefinitions;
+ llvm::StringMap<std::vector<const CXXRecordDecl *>> DeclNameToDeclarations;
+ llvm::SmallPtrSet<const Type *, 16> FriendTypes;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_FORWARDDECLARATIONNAMESPACECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp
new file mode 100644
index 0000000..17bdc76
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp
@@ -0,0 +1,148 @@
+//===--- ForwardingReferenceOverloadCheck.cpp - clang-tidy-----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ForwardingReferenceOverloadCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <algorithm>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+// Check if the given type is related to std::enable_if.
+AST_MATCHER(QualType, isEnableIf) {
+ auto CheckTemplate = [](const TemplateSpecializationType *Spec) {
+ if (!Spec || !Spec->getTemplateName().getAsTemplateDecl()) {
+ return false;
+ }
+ const NamedDecl *TypeDecl =
+ Spec->getTemplateName().getAsTemplateDecl()->getTemplatedDecl();
+ return TypeDecl->isInStdNamespace() &&
+ (TypeDecl->getName().equals("enable_if") ||
+ TypeDecl->getName().equals("enable_if_t"));
+ };
+ const Type *BaseType = Node.getTypePtr();
+ // Case: pointer or reference to enable_if.
+ while (BaseType->isPointerType() || BaseType->isReferenceType()) {
+ BaseType = BaseType->getPointeeType().getTypePtr();
+ }
+ // Case: type parameter dependent (enable_if<is_integral<T>>).
+ if (const auto *Dependent = BaseType->getAs<DependentNameType>()) {
+ BaseType = Dependent->getQualifier()->getAsType();
+ }
+ if (!BaseType)
+ return false;
+ if (CheckTemplate(BaseType->getAs<TemplateSpecializationType>())) {
+ return true; // Case: enable_if_t< >.
+ } else if (const auto *Elaborated = BaseType->getAs<ElaboratedType>()) {
+ if (const auto *Qualifier = Elaborated->getQualifier()->getAsType()) {
+ if (CheckTemplate(Qualifier->getAs<TemplateSpecializationType>())) {
+ return true; // Case: enable_if< >::type.
+ }
+ }
+ }
+ return false;
+}
+AST_MATCHER_P(TemplateTypeParmDecl, hasDefaultArgument,
+ clang::ast_matchers::internal::Matcher<QualType>, TypeMatcher) {
+ return Node.hasDefaultArgument() &&
+ TypeMatcher.matches(Node.getDefaultArgument(), Finder, Builder);
+}
+} // namespace
+
+void ForwardingReferenceOverloadCheck::registerMatchers(MatchFinder *Finder) {
+ // Forwarding references require C++11 or later.
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ auto ForwardingRefParm =
+ parmVarDecl(
+ hasType(qualType(rValueReferenceType(),
+ references(templateTypeParmType(hasDeclaration(
+ templateTypeParmDecl().bind("type-parm-decl")))),
+ unless(references(isConstQualified())))))
+ .bind("parm-var");
+
+ DeclarationMatcher findOverload =
+ cxxConstructorDecl(
+ hasParameter(0, ForwardingRefParm),
+ unless(hasAnyParameter(
+ // No warning: enable_if as constructor parameter.
+ parmVarDecl(hasType(isEnableIf())))),
+ unless(hasParent(functionTemplateDecl(has(templateTypeParmDecl(
+ // No warning: enable_if as type parameter.
+ hasDefaultArgument(isEnableIf())))))))
+ .bind("ctor");
+ Finder->addMatcher(findOverload, this);
+}
+
+void ForwardingReferenceOverloadCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *ParmVar = Result.Nodes.getNodeAs<ParmVarDecl>("parm-var");
+ const auto *TypeParmDecl =
+ Result.Nodes.getNodeAs<TemplateTypeParmDecl>("type-parm-decl");
+
+ // Get the FunctionDecl and FunctionTemplateDecl containing the function
+ // parameter.
+ const auto *FuncForParam = dyn_cast<FunctionDecl>(ParmVar->getDeclContext());
+ if (!FuncForParam)
+ return;
+ const FunctionTemplateDecl *FuncTemplate =
+ FuncForParam->getDescribedFunctionTemplate();
+ if (!FuncTemplate)
+ return;
+
+ // Check that the template type parameter belongs to the same function
+ // template as the function parameter of that type. (This implies that type
+ // deduction will happen on the type.)
+ const TemplateParameterList *Params = FuncTemplate->getTemplateParameters();
+ if (std::find(Params->begin(), Params->end(), TypeParmDecl) == Params->end())
+ return;
+
+ // Every parameter after the first must have a default value.
+ const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
+ for (auto Iter = Ctor->param_begin() + 1; Iter != Ctor->param_end(); ++Iter) {
+ if (!(*Iter)->hasDefaultArg())
+ return;
+ }
+ bool EnabledCopy = false, DisabledCopy = false, EnabledMove = false,
+ DisabledMove = false;
+ for (const auto *OtherCtor : Ctor->getParent()->ctors()) {
+ if (OtherCtor->isCopyOrMoveConstructor()) {
+ if (OtherCtor->isDeleted() || OtherCtor->getAccess() == AS_private)
+ (OtherCtor->isCopyConstructor() ? DisabledCopy : DisabledMove) = true;
+ else
+ (OtherCtor->isCopyConstructor() ? EnabledCopy : EnabledMove) = true;
+ }
+ }
+ bool Copy = (!EnabledMove && !DisabledMove && !DisabledCopy) || EnabledCopy;
+ bool Move = !DisabledMove || EnabledMove;
+ if (!Copy && !Move)
+ return;
+ diag(Ctor->getLocation(),
+ "constructor accepting a forwarding reference can "
+ "hide the %select{copy|move|copy and move}0 constructor%s1")
+ << (Copy && Move ? 2 : (Copy ? 0 : 1)) << Copy + Move;
+ for (const auto *OtherCtor : Ctor->getParent()->ctors()) {
+ if (OtherCtor->isCopyOrMoveConstructor() && !OtherCtor->isDeleted() &&
+ OtherCtor->getAccess() != AS_private) {
+ diag(OtherCtor->getLocation(),
+ "%select{copy|move}0 constructor declared here", DiagnosticIDs::Note)
+ << OtherCtor->isMoveConstructor();
+ }
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.h
new file mode 100644
index 0000000..4b00ab2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.h
@@ -0,0 +1,42 @@
+//===--- ForwardingReferenceOverloadCheck.h - clang-tidy---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_FORWARDINGREFERENCEOVERLOADCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_FORWARDINGREFERENCEOVERLOADCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// The checker looks for constructors that can act as copy or move constructors
+/// through their forwarding reference parameters. If a non const lvalue
+/// reference is passed to the constructor, the forwarding reference parameter
+/// can be a perfect match while the const reference parameter of the copy
+/// constructor can't. The forwarding reference constructor will be called,
+/// which can lead to confusion.
+/// For detailed description of this problem see: Scott Meyers, Effective Modern
+/// C++ Design, item 26.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-forwarding-reference-overload.html
+class ForwardingReferenceOverloadCheck : public ClangTidyCheck {
+public:
+ ForwardingReferenceOverloadCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_FORWARDINGREFERENCEOVERLOADCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/InaccurateEraseCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/InaccurateEraseCheck.cpp
new file mode 100644
index 0000000..cf1be0e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/InaccurateEraseCheck.cpp
@@ -0,0 +1,81 @@
+//===--- InaccurateEraseCheck.cpp - clang-tidy-----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InaccurateEraseCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+AST_MATCHER(Decl, isInStdNamespace) { return Node.isInStdNamespace(); }
+}
+
+void InaccurateEraseCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ const auto EndCall =
+ callExpr(
+ callee(functionDecl(hasAnyName("remove", "remove_if", "unique"))),
+ hasArgument(
+ 1,
+ anyOf(cxxConstructExpr(has(ignoringImplicit(
+ cxxMemberCallExpr(callee(cxxMethodDecl(hasName("end"))))
+ .bind("end")))),
+ anything())))
+ .bind("alg");
+
+ const auto DeclInStd = type(hasUnqualifiedDesugaredType(
+ tagType(hasDeclaration(decl(isInStdNamespace())))));
+ Finder->addMatcher(
+ cxxMemberCallExpr(
+ on(anyOf(hasType(DeclInStd), hasType(pointsTo(DeclInStd)))),
+ callee(cxxMethodDecl(hasName("erase"))), argumentCountIs(1),
+ hasArgument(0, has(ignoringImplicit(
+ anyOf(EndCall, has(ignoringImplicit(EndCall)))))),
+ unless(isInTemplateInstantiation()))
+ .bind("erase"),
+ this);
+}
+
+void InaccurateEraseCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MemberCall =
+ Result.Nodes.getNodeAs<CXXMemberCallExpr>("erase");
+ const auto *EndExpr =
+ Result.Nodes.getNodeAs<CXXMemberCallExpr>("end");
+ const SourceLocation Loc = MemberCall->getLocStart();
+
+ FixItHint Hint;
+
+ if (!Loc.isMacroID() && EndExpr) {
+ const auto *AlgCall = Result.Nodes.getNodeAs<CallExpr>("alg");
+ std::string ReplacementText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(EndExpr->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ AlgCall->getLocEnd(), 0, *Result.SourceManager, getLangOpts());
+ Hint = FixItHint::CreateInsertion(EndLoc, ", " + ReplacementText);
+ }
+
+ diag(Loc, "this call will remove at most one item even when multiple items "
+ "should be removed")
+ << Hint;
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/InaccurateEraseCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/InaccurateEraseCheck.h
new file mode 100644
index 0000000..d6b3729
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/InaccurateEraseCheck.h
@@ -0,0 +1,38 @@
+//===--- InaccurateEraseCheck.h - clang-tidy---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INACCURATEERASECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INACCURATEERASECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Checks for inaccurate use of the `erase()` method.
+///
+/// Algorithms like `remove()` do not actually remove any element from the
+/// container but return an iterator to the first redundant element at the end
+/// of the container. These redundant elements must be removed using the
+/// `erase()` method. This check warns when not all of the elements will be
+/// removed due to using an inappropriate overload.
+class InaccurateEraseCheck : public ClangTidyCheck {
+public:
+ InaccurateEraseCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INACCURATEERASECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/IncorrectRoundingsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/IncorrectRoundingsCheck.cpp
new file mode 100644
index 0000000..ab7b28d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/IncorrectRoundingsCheck.cpp
@@ -0,0 +1,71 @@
+//===--- IncorrectRoundingsCheck.cpp - clang-tidy ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IncorrectRoundingsCheck.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/Type.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+AST_MATCHER(FloatingLiteral, floatHalf) {
+ const auto &literal = Node.getValue();
+ if ((&Node.getSemantics()) == &llvm::APFloat::IEEEsingle())
+ return literal.convertToFloat() == 0.5f;
+ if ((&Node.getSemantics()) == &llvm::APFloat::IEEEdouble())
+ return literal.convertToDouble() == 0.5;
+ return false;
+}
+} // namespace
+
+void IncorrectRoundingsCheck::registerMatchers(MatchFinder *MatchFinder) {
+ // Match a floating literal with value 0.5.
+ auto FloatHalf = floatLiteral(floatHalf());
+
+ // Match a floating point expression.
+ auto FloatType = expr(hasType(realFloatingPointType()));
+
+ // Match a floating literal of 0.5 or a floating literal of 0.5 implicitly.
+ // cast to floating type.
+ auto FloatOrCastHalf =
+ anyOf(FloatHalf,
+ implicitCastExpr(FloatType, has(ignoringParenImpCasts(FloatHalf))));
+
+ // Match if either the LHS or RHS is a floating literal of 0.5 or a floating
+ // literal of 0.5 and the other is of type double or vice versa.
+ auto OneSideHalf = anyOf(allOf(hasLHS(FloatOrCastHalf), hasRHS(FloatType)),
+ allOf(hasRHS(FloatOrCastHalf), hasLHS(FloatType)));
+
+ // Find expressions of cast to int of the sum of a floating point expression
+ // and 0.5.
+ MatchFinder->addMatcher(
+ implicitCastExpr(
+ hasImplicitDestinationType(isInteger()),
+ ignoringParenCasts(binaryOperator(hasOperatorName("+"), OneSideHalf)))
+ .bind("CastExpr"),
+ this);
+}
+
+void IncorrectRoundingsCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *CastExpr = Result.Nodes.getNodeAs<ImplicitCastExpr>("CastExpr");
+ diag(CastExpr->getLocStart(),
+ "casting (double + 0.5) to integer leads to incorrect rounding; "
+ "consider using lround (#include <cmath>) instead");
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/IncorrectRoundingsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/IncorrectRoundingsCheck.h
new file mode 100644
index 0000000..b1886fd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/IncorrectRoundingsCheck.h
@@ -0,0 +1,39 @@
+//===--- IncorrectRoundingsCheck.h - clang-tidy -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INCORRECTROUNDINGSCHECK_H_
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INCORRECTROUNDINGSCHECK_H_
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// \brief Checks the usage of patterns known to produce incorrect rounding.
+/// Programmers often use
+/// (int)(double_expression + 0.5)
+/// to round the double expression to an integer. The problem with this
+/// 1. It is unnecessarily slow.
+/// 2. It is incorrect. The number 0.499999975 (smallest representable float
+/// number below 0.5) rounds to 1.0. Even worse behavior for negative
+/// numbers where both -0.5f and -1.4f both round to 0.0.
+class IncorrectRoundingsCheck : public ClangTidyCheck {
+public:
+ IncorrectRoundingsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INCORRECTROUNDINGSCHECK_H_
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/IntegerDivisionCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/IntegerDivisionCheck.cpp
new file mode 100644
index 0000000..1b4eaea
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/IntegerDivisionCheck.cpp
@@ -0,0 +1,57 @@
+//===--- IntegerDivisionCheck.cpp - clang-tidy-----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IntegerDivisionCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void IntegerDivisionCheck::registerMatchers(MatchFinder *Finder) {
+ const auto IntType = hasType(isInteger());
+
+ const auto BinaryOperators = binaryOperator(anyOf(
+ hasOperatorName("%"), hasOperatorName("<<"), hasOperatorName(">>"),
+ hasOperatorName("<<"), hasOperatorName("^"), hasOperatorName("|"),
+ hasOperatorName("&"), hasOperatorName("||"), hasOperatorName("&&"),
+ hasOperatorName("<"), hasOperatorName(">"), hasOperatorName("<="),
+ hasOperatorName(">="), hasOperatorName("=="), hasOperatorName("!=")));
+
+ const auto UnaryOperators =
+ unaryOperator(anyOf(hasOperatorName("~"), hasOperatorName("!")));
+
+ const auto Exceptions =
+ anyOf(BinaryOperators, conditionalOperator(), binaryConditionalOperator(),
+ callExpr(IntType), explicitCastExpr(IntType), UnaryOperators);
+
+ Finder->addMatcher(
+ binaryOperator(
+ hasOperatorName("/"), hasLHS(expr(IntType)), hasRHS(expr(IntType)),
+ hasAncestor(
+ castExpr(hasCastKind(CK_IntegralToFloating)).bind("FloatCast")),
+ unless(hasAncestor(
+ expr(Exceptions,
+ hasAncestor(castExpr(equalsBoundNode("FloatCast")))))))
+ .bind("IntDiv"),
+ this);
+}
+
+void IntegerDivisionCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *IntDiv = Result.Nodes.getNodeAs<BinaryOperator>("IntDiv");
+ diag(IntDiv->getLocStart(), "result of integer division used in a floating "
+ "point context; possible loss of precision");
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/IntegerDivisionCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/IntegerDivisionCheck.h
new file mode 100644
index 0000000..307e493
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/IntegerDivisionCheck.h
@@ -0,0 +1,36 @@
+//===--- IntegerDivisionCheck.h - clang-tidy---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INTEGER_DIVISION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INTEGER_DIVISION_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds cases where integer division in a floating point context is likely to
+/// cause unintended loss of precision.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-integer-division.html
+class IntegerDivisionCheck : public ClangTidyCheck {
+public:
+ IntegerDivisionCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INTEGER_DIVISION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.cpp
new file mode 100644
index 0000000..55dbe8b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.cpp
@@ -0,0 +1,99 @@
+//===--- LambdaFunctionNameCheck.cpp - clang-tidy--------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LambdaFunctionNameCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+
+// Keep track of macro expansions that contain both __FILE__ and __LINE__. If
+// such a macro also uses __func__ or __FUNCTION__, we don't want to issue a
+// warning because __FILE__ and __LINE__ may be useful even if __func__ or
+// __FUNCTION__ is not, especially if the macro could be used in the context of
+// either a function body or a lambda body.
+class MacroExpansionsWithFileAndLine : public PPCallbacks {
+public:
+ explicit MacroExpansionsWithFileAndLine(
+ LambdaFunctionNameCheck::SourceRangeSet *SME)
+ : SuppressMacroExpansions(SME) {}
+
+ void MacroExpands(const Token &MacroNameTok,
+ const MacroDefinition &MD, SourceRange Range,
+ const MacroArgs *Args) override {
+ bool has_file = false;
+ bool has_line = false;
+ for (const auto& T : MD.getMacroInfo()->tokens()) {
+ if (T.is(tok::identifier)) {
+ StringRef IdentName = T.getIdentifierInfo()->getName();
+ if (IdentName == "__FILE__") {
+ has_file = true;
+ } else if (IdentName == "__LINE__") {
+ has_line = true;
+ }
+ }
+ }
+ if (has_file && has_line) {
+ SuppressMacroExpansions->insert(Range);
+ }
+ }
+
+private:
+ LambdaFunctionNameCheck::SourceRangeSet* SuppressMacroExpansions;
+};
+
+} // namespace
+
+void LambdaFunctionNameCheck::registerMatchers(MatchFinder *Finder) {
+ // Match on PredefinedExprs inside a lambda.
+ Finder->addMatcher(predefinedExpr(hasAncestor(lambdaExpr())).bind("E"),
+ this);
+}
+
+void LambdaFunctionNameCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+ Compiler.getPreprocessor().addPPCallbacks(
+ llvm::make_unique<MacroExpansionsWithFileAndLine>(
+ &SuppressMacroExpansions));
+}
+
+void LambdaFunctionNameCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *E = Result.Nodes.getNodeAs<PredefinedExpr>("E");
+ if (E->getIdentType() != PredefinedExpr::Func &&
+ E->getIdentType() != PredefinedExpr::Function) {
+ // We don't care about other PredefinedExprs.
+ return;
+ }
+ if (E->getLocation().isMacroID()) {
+ auto ER =
+ Result.SourceManager->getImmediateExpansionRange(E->getLocation());
+ if (SuppressMacroExpansions.find(ER.getAsRange()) !=
+ SuppressMacroExpansions.end()) {
+ // This is a macro expansion for which we should not warn.
+ return;
+ }
+ }
+ diag(E->getLocation(),
+ "inside a lambda, '%0' expands to the name of the function call "
+ "operator; consider capturing the name of the enclosing function "
+ "explicitly")
+ << PredefinedExpr::getIdentTypeName(E->getIdentType());
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.h
new file mode 100644
index 0000000..b7b1b44
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/LambdaFunctionNameCheck.h
@@ -0,0 +1,51 @@
+//===--- LambdaFunctionNameCheck.h - clang-tidy------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_LAMBDAFUNCTIONNAMECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_LAMBDAFUNCTIONNAMECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Detect when __func__ or __FUNCTION__ is being used from within a lambda. In
+/// that context, those expressions expand to the name of the call operator
+/// (i.e., `operator()`).
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-lambda-function-name.html
+class LambdaFunctionNameCheck : public ClangTidyCheck {
+public:
+ struct SourceRangeLessThan {
+ bool operator()(const SourceRange &L, const SourceRange &R) const {
+ if (L.getBegin() == R.getBegin()) {
+ return L.getEnd() < R.getEnd();
+ }
+ return L.getBegin() < R.getBegin();
+ }
+ };
+ using SourceRangeSet = std::set<SourceRange, SourceRangeLessThan>;
+
+ LambdaFunctionNameCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ SourceRangeSet SuppressMacroExpansions;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_LAMBDAFUNCTIONNAMECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp
new file mode 100644
index 0000000..6846bc2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.cpp
@@ -0,0 +1,260 @@
+//===--- MacroParenthesesCheck.cpp - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MacroParenthesesCheck.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+class MacroParenthesesPPCallbacks : public PPCallbacks {
+public:
+ MacroParenthesesPPCallbacks(Preprocessor *PP, MacroParenthesesCheck *Check)
+ : PP(PP), Check(Check) {}
+
+ void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
+ replacementList(MacroNameTok, MD->getMacroInfo());
+ argument(MacroNameTok, MD->getMacroInfo());
+ }
+
+private:
+ /// Replacement list with calculations should be enclosed in parentheses.
+ void replacementList(const Token &MacroNameTok, const MacroInfo *MI);
+
+ /// Arguments should be enclosed in parentheses.
+ void argument(const Token &MacroNameTok, const MacroInfo *MI);
+
+ Preprocessor *PP;
+ MacroParenthesesCheck *Check;
+};
+} // namespace
+
+/// Is argument surrounded properly with parentheses/braces/squares/commas?
+static bool isSurroundedLeft(const Token &T) {
+ return T.isOneOf(tok::l_paren, tok::l_brace, tok::l_square, tok::comma,
+ tok::semi);
+}
+
+/// Is argument surrounded properly with parentheses/braces/squares/commas?
+static bool isSurroundedRight(const Token &T) {
+ return T.isOneOf(tok::r_paren, tok::r_brace, tok::r_square, tok::comma,
+ tok::semi);
+}
+
+/// Is given TokenKind a keyword?
+static bool isKeyword(const Token &T) {
+ // FIXME: better matching of keywords to avoid false positives.
+ return T.isOneOf(tok::kw_case, tok::kw_const, tok::kw_struct);
+}
+
+/// Warning is written when one of these operators are not within parentheses.
+static bool isWarnOp(const Token &T) {
+ // FIXME: This is an initial list of operators. It can be tweaked later to
+ // get more positives or perhaps avoid some false positive.
+ return T.isOneOf(tok::plus, tok::minus, tok::star, tok::slash, tok::percent,
+ tok::amp, tok::pipe, tok::caret);
+}
+
+/// Is given Token a keyword that is used in variable declarations?
+static bool isVarDeclKeyword(const Token &T) {
+ return T.isOneOf(tok::kw_bool, tok::kw_char, tok::kw_short, tok::kw_int,
+ tok::kw_long, tok::kw_float, tok::kw_double, tok::kw_const,
+ tok::kw_enum, tok::kw_inline, tok::kw_static, tok::kw_struct,
+ tok::kw_signed, tok::kw_unsigned);
+}
+
+/// Is there a possible variable declaration at Tok?
+static bool possibleVarDecl(const MacroInfo *MI, const Token *Tok) {
+ if (Tok == MI->tokens_end())
+ return false;
+
+ // If we see int/short/struct/etc., just assume this is a variable
+ // declaration.
+ if (isVarDeclKeyword(*Tok))
+ return true;
+
+ // Variable declarations start with identifier or coloncolon.
+ if (!Tok->isOneOf(tok::identifier, tok::raw_identifier, tok::coloncolon))
+ return false;
+
+ // Skip possible types, etc
+ while (Tok != MI->tokens_end() &&
+ Tok->isOneOf(tok::identifier, tok::raw_identifier, tok::coloncolon,
+ tok::star, tok::amp, tok::ampamp, tok::less,
+ tok::greater))
+ Tok++;
+
+ // Return true for possible variable declarations.
+ return Tok == MI->tokens_end() ||
+ Tok->isOneOf(tok::equal, tok::semi, tok::l_square, tok::l_paren) ||
+ isVarDeclKeyword(*Tok);
+}
+
+void MacroParenthesesPPCallbacks::replacementList(const Token &MacroNameTok,
+ const MacroInfo *MI) {
+ // Make sure macro replacement isn't a variable declaration.
+ if (possibleVarDecl(MI, MI->tokens_begin()))
+ return;
+
+ // Count how deep we are in parentheses/braces/squares.
+ int Count = 0;
+
+ // SourceLocation for error
+ SourceLocation Loc;
+
+ for (auto TI = MI->tokens_begin(), TE = MI->tokens_end(); TI != TE; ++TI) {
+ const Token &Tok = *TI;
+ // Replacement list contains keywords, don't warn about it.
+ if (isKeyword(Tok))
+ return;
+ // When replacement list contains comma/semi don't warn about it.
+ if (Count == 0 && Tok.isOneOf(tok::comma, tok::semi))
+ return;
+ if (Tok.isOneOf(tok::l_paren, tok::l_brace, tok::l_square)) {
+ ++Count;
+ } else if (Tok.isOneOf(tok::r_paren, tok::r_brace, tok::r_square)) {
+ --Count;
+ // If there are unbalanced parentheses don't write any warning
+ if (Count < 0)
+ return;
+ } else if (Count == 0 && isWarnOp(Tok)) {
+ // Heuristic for macros that are clearly not intended to be enclosed in
+ // parentheses, macro starts with operator. For example:
+ // #define X *10
+ if (TI == MI->tokens_begin() && (TI + 1) != TE &&
+ !Tok.isOneOf(tok::plus, tok::minus))
+ return;
+ // Don't warn about this macro if the last token is a star. For example:
+ // #define X void *
+ if ((TE - 1)->is(tok::star))
+ return;
+
+ Loc = Tok.getLocation();
+ }
+ }
+ if (Loc.isValid()) {
+ const Token &Last = *(MI->tokens_end() - 1);
+ Check->diag(Loc, "macro replacement list should be enclosed in parentheses")
+ << FixItHint::CreateInsertion(MI->tokens_begin()->getLocation(), "(")
+ << FixItHint::CreateInsertion(Last.getLocation().getLocWithOffset(
+ PP->getSpelling(Last).length()),
+ ")");
+ }
+}
+
+void MacroParenthesesPPCallbacks::argument(const Token &MacroNameTok,
+ const MacroInfo *MI) {
+
+ // Skip variable declaration.
+ bool VarDecl = possibleVarDecl(MI, MI->tokens_begin());
+
+ for (auto TI = MI->tokens_begin(), TE = MI->tokens_end(); TI != TE; ++TI) {
+ // First token.
+ if (TI == MI->tokens_begin())
+ continue;
+
+ // Last token.
+ if ((TI + 1) == MI->tokens_end())
+ continue;
+
+ const Token &Prev = *(TI - 1);
+ const Token &Next = *(TI + 1);
+
+ const Token &Tok = *TI;
+
+ // There should not be extra parentheses in possible variable declaration.
+ if (VarDecl) {
+ if (Tok.isOneOf(tok::equal, tok::semi, tok::l_square, tok::l_paren))
+ VarDecl = false;
+ continue;
+ }
+
+ // Only interested in identifiers.
+ if (!Tok.isOneOf(tok::identifier, tok::raw_identifier))
+ continue;
+
+ // Only interested in macro arguments.
+ if (MI->getParameterNum(Tok.getIdentifierInfo()) < 0)
+ continue;
+
+ // Argument is surrounded with parentheses/squares/braces/commas.
+ if (isSurroundedLeft(Prev) && isSurroundedRight(Next))
+ continue;
+
+ // Don't warn after hash/hashhash or before hashhash.
+ if (Prev.isOneOf(tok::hash, tok::hashhash) || Next.is(tok::hashhash))
+ continue;
+
+ // Argument is a struct member.
+ if (Prev.isOneOf(tok::period, tok::arrow, tok::coloncolon, tok::arrowstar,
+ tok::periodstar))
+ continue;
+
+ // Argument is a namespace or class.
+ if (Next.is(tok::coloncolon))
+ continue;
+
+ // String concatenation.
+ if (isStringLiteral(Prev.getKind()) || isStringLiteral(Next.getKind()))
+ continue;
+
+ // Type/Var.
+ if (isAnyIdentifier(Prev.getKind()) || isKeyword(Prev) ||
+ isAnyIdentifier(Next.getKind()) || isKeyword(Next))
+ continue;
+
+ // Initialization.
+ if (Next.is(tok::l_paren))
+ continue;
+
+ // Cast.
+ if (Prev.is(tok::l_paren) && Next.is(tok::star) &&
+ TI + 2 != MI->tokens_end() && (TI + 2)->is(tok::r_paren))
+ continue;
+
+ // Assignment/return, i.e. '=x;' or 'return x;'.
+ if (Prev.isOneOf(tok::equal, tok::kw_return) && Next.is(tok::semi))
+ continue;
+
+ // C++ template parameters.
+ if (PP->getLangOpts().CPlusPlus && Prev.isOneOf(tok::comma, tok::less) &&
+ Next.isOneOf(tok::comma, tok::greater))
+ continue;
+
+ // Namespaces.
+ if (Prev.is(tok::kw_namespace))
+ continue;
+
+ // Variadic templates
+ if (MI->isVariadic())
+ continue;
+
+ Check->diag(Tok.getLocation(), "macro argument should be enclosed in "
+ "parentheses")
+ << FixItHint::CreateInsertion(Tok.getLocation(), "(")
+ << FixItHint::CreateInsertion(Tok.getLocation().getLocWithOffset(
+ PP->getSpelling(Tok).length()),
+ ")");
+ }
+}
+
+void MacroParenthesesCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+ Compiler.getPreprocessor().addPPCallbacks(
+ llvm::make_unique<MacroParenthesesPPCallbacks>(
+ &Compiler.getPreprocessor(), this));
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.h
new file mode 100644
index 0000000..383a6cc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MacroParenthesesCheck.h
@@ -0,0 +1,43 @@
+//===--- MacroParenthesesCheck.h - clang-tidy--------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MACROPARENTHESESCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MACROPARENTHESESCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds macros that can have unexpected behaviour due to missing parentheses.
+///
+/// Macros are expanded by the preprocessor as-is. As a result, there can be
+/// unexpected behaviour; operators may be evaluated in unexpected order and
+/// unary operators may become binary operators, etc.
+///
+/// When the replacement list has an expression, it is recommended to surround
+/// it with parentheses. This ensures that the macro result is evaluated
+/// completely before it is used.
+///
+/// It is also recommended to surround macro arguments in the replacement list
+/// with parentheses. This ensures that the argument value is calculated
+/// properly.
+class MacroParenthesesCheck : public ClangTidyCheck {
+public:
+ MacroParenthesesCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MACROPARENTHESESCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MacroRepeatedSideEffectsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MacroRepeatedSideEffectsCheck.cpp
new file mode 100644
index 0000000..30c770e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MacroRepeatedSideEffectsCheck.cpp
@@ -0,0 +1,184 @@
+//===--- MacroRepeatedSideEffectsCheck.cpp - clang-tidy--------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MacroRepeatedSideEffectsCheck.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/MacroArgs.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+class MacroRepeatedPPCallbacks : public PPCallbacks {
+public:
+ MacroRepeatedPPCallbacks(ClangTidyCheck &Check, Preprocessor &PP)
+ : Check(Check), PP(PP) {}
+
+ void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
+ SourceRange Range, const MacroArgs *Args) override;
+
+private:
+ ClangTidyCheck &Check;
+ Preprocessor &PP;
+
+ unsigned countArgumentExpansions(const MacroInfo *MI,
+ const IdentifierInfo *Arg) const;
+
+ bool hasSideEffects(const Token *ResultArgToks) const;
+};
+} // End of anonymous namespace.
+
+void MacroRepeatedPPCallbacks::MacroExpands(const Token &MacroNameTok,
+ const MacroDefinition &MD,
+ SourceRange Range,
+ const MacroArgs *Args) {
+ // Ignore macro argument expansions.
+ if (!Range.getBegin().isFileID())
+ return;
+
+ const MacroInfo *MI = MD.getMacroInfo();
+
+ // Bail out if the contents of the macro are containing keywords that are
+ // making the macro too complex.
+ if (std::find_if(
+ MI->tokens().begin(), MI->tokens().end(), [](const Token &T) {
+ return T.isOneOf(tok::kw_if, tok::kw_else, tok::kw_switch,
+ tok::kw_case, tok::kw_break, tok::kw_while,
+ tok::kw_do, tok::kw_for, tok::kw_continue,
+ tok::kw_goto, tok::kw_return);
+ }) != MI->tokens().end())
+ return;
+
+ for (unsigned ArgNo = 0U; ArgNo < MI->getNumParams(); ++ArgNo) {
+ const IdentifierInfo *Arg = *(MI->param_begin() + ArgNo);
+ const Token *ResultArgToks = Args->getUnexpArgument(ArgNo);
+
+ if (hasSideEffects(ResultArgToks) &&
+ countArgumentExpansions(MI, Arg) >= 2) {
+ Check.diag(ResultArgToks->getLocation(),
+ "side effects in the %ordinal0 macro argument %1 are "
+ "repeated in macro expansion")
+ << (ArgNo + 1) << Arg;
+ Check.diag(MI->getDefinitionLoc(), "macro %0 defined here",
+ DiagnosticIDs::Note)
+ << MacroNameTok.getIdentifierInfo();
+ }
+ }
+}
+
+unsigned MacroRepeatedPPCallbacks::countArgumentExpansions(
+ const MacroInfo *MI, const IdentifierInfo *Arg) const {
+ // Current argument count. When moving forward to a different control-flow
+ // path this can decrease.
+ unsigned Current = 0;
+ // Max argument count.
+ unsigned Max = 0;
+ bool SkipParen = false;
+ int SkipParenCount = 0;
+ // Has a __builtin_constant_p been found?
+ bool FoundBuiltin = false;
+ bool PrevTokenIsHash = false;
+ // Count when "?" is reached. The "Current" will get this value when the ":"
+ // is reached.
+ std::stack<unsigned, SmallVector<unsigned, 8>> CountAtQuestion;
+ for (const auto &T : MI->tokens()) {
+ // The result of __builtin_constant_p(x) is 0 if x is a macro argument
+ // with side effects. If we see a __builtin_constant_p(x) followed by a
+ // "?" "&&" or "||", then we need to reason about control flow to report
+ // warnings correctly. Until such reasoning is added, bail out when this
+ // happens.
+ if (FoundBuiltin && T.isOneOf(tok::question, tok::ampamp, tok::pipepipe))
+ return Max;
+
+ // Skip stringified tokens.
+ if (T.is(tok::hash)) {
+ PrevTokenIsHash = true;
+ continue;
+ }
+ if (PrevTokenIsHash) {
+ PrevTokenIsHash = false;
+ continue;
+ }
+
+ // Handling of ? and :.
+ if (T.is(tok::question)) {
+ CountAtQuestion.push(Current);
+ } else if (T.is(tok::colon)) {
+ if (CountAtQuestion.empty())
+ return 0;
+ Current = CountAtQuestion.top();
+ CountAtQuestion.pop();
+ }
+
+ // If current token is a parenthesis, skip it.
+ if (SkipParen) {
+ if (T.is(tok::l_paren))
+ SkipParenCount++;
+ else if (T.is(tok::r_paren))
+ SkipParenCount--;
+ SkipParen = (SkipParenCount != 0);
+ if (SkipParen)
+ continue;
+ }
+
+ IdentifierInfo *TII = T.getIdentifierInfo();
+ // If not existent, skip it.
+ if (TII == nullptr)
+ continue;
+
+ // If a __builtin_constant_p is found within the macro definition, don't
+ // count arguments inside the parentheses and remember that it has been
+ // seen in case there are "?", "&&" or "||" operators later.
+ if (TII->getBuiltinID() == Builtin::BI__builtin_constant_p) {
+ FoundBuiltin = true;
+ SkipParen = true;
+ continue;
+ }
+
+ // If another macro is found within the macro definition, skip the macro
+ // and the eventual arguments.
+ if (TII->hasMacroDefinition()) {
+ const MacroInfo *M = PP.getMacroDefinition(TII).getMacroInfo();
+ if (M != nullptr && M->isFunctionLike())
+ SkipParen = true;
+ continue;
+ }
+
+ // Count argument.
+ if (TII == Arg) {
+ Current++;
+ if (Current > Max)
+ Max = Current;
+ }
+ }
+ return Max;
+}
+
+bool MacroRepeatedPPCallbacks::hasSideEffects(
+ const Token *ResultArgToks) const {
+ for (; ResultArgToks->isNot(tok::eof); ++ResultArgToks) {
+ if (ResultArgToks->isOneOf(tok::plusplus, tok::minusminus))
+ return true;
+ }
+ return false;
+}
+
+void MacroRepeatedSideEffectsCheck::registerPPCallbacks(
+ CompilerInstance &Compiler) {
+ Compiler.getPreprocessor().addPPCallbacks(
+ ::llvm::make_unique<MacroRepeatedPPCallbacks>(
+ *this, Compiler.getPreprocessor()));
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MacroRepeatedSideEffectsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MacroRepeatedSideEffectsCheck.h
new file mode 100644
index 0000000..a2a3134
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MacroRepeatedSideEffectsCheck.h
@@ -0,0 +1,31 @@
+//===--- MacroRepeatedSideEffectsCheck.h - clang-tidy -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MACROREPEATEDSIDEEFFECTSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MACROREPEATEDSIDEEFFECTSCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Checks for repeated argument with side effects in macros.
+class MacroRepeatedSideEffectsCheck : public ClangTidyCheck {
+public:
+ MacroRepeatedSideEffectsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MACROREPEATEDSIDEEFFECTSCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.cpp
new file mode 100644
index 0000000..f8db0b3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.cpp
@@ -0,0 +1,112 @@
+//===--- MisplacedOperatorInStrlenInAllocCheck.cpp - clang-tidy------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MisplacedOperatorInStrlenInAllocCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void MisplacedOperatorInStrlenInAllocCheck::registerMatchers(
+ MatchFinder *Finder) {
+ const auto StrLenFunc = functionDecl(anyOf(
+ hasName("::strlen"), hasName("::std::strlen"), hasName("::strnlen"),
+ hasName("::std::strnlen"), hasName("::strnlen_s"),
+ hasName("::std::strnlen_s"), hasName("::wcslen"),
+ hasName("::std::wcslen"), hasName("::wcsnlen"), hasName("::std::wcsnlen"),
+ hasName("::wcsnlen_s"), hasName("std::wcsnlen_s")));
+
+ const auto BadUse =
+ callExpr(callee(StrLenFunc),
+ hasAnyArgument(ignoringImpCasts(
+ binaryOperator(allOf(hasOperatorName("+"),
+ hasRHS(ignoringParenImpCasts(
+ integerLiteral(equals(1))))))
+ .bind("BinOp"))))
+ .bind("StrLen");
+
+ const auto BadArg = anyOf(
+ allOf(hasDescendant(BadUse),
+ unless(binaryOperator(allOf(
+ hasOperatorName("+"), hasLHS(BadUse),
+ hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))))),
+ BadUse);
+
+ const auto Alloc0Func =
+ functionDecl(anyOf(hasName("::malloc"), hasName("std::malloc"),
+ hasName("::alloca"), hasName("std::alloca")));
+ const auto Alloc1Func =
+ functionDecl(anyOf(hasName("::calloc"), hasName("std::calloc"),
+ hasName("::realloc"), hasName("std::realloc")));
+
+ const auto Alloc0FuncPtr =
+ varDecl(hasType(isConstQualified()),
+ hasInitializer(ignoringParenImpCasts(
+ declRefExpr(hasDeclaration(Alloc0Func)))));
+ const auto Alloc1FuncPtr =
+ varDecl(hasType(isConstQualified()),
+ hasInitializer(ignoringParenImpCasts(
+ declRefExpr(hasDeclaration(Alloc1Func)))));
+
+ Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc0Func, Alloc0FuncPtr))),
+ hasArgument(0, BadArg))
+ .bind("Alloc"),
+ this);
+ Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc1Func, Alloc1FuncPtr))),
+ hasArgument(1, BadArg))
+ .bind("Alloc"),
+ this);
+ Finder->addMatcher(
+ cxxNewExpr(isArray(), hasArraySize(BadArg)).bind("Alloc"), this);
+}
+
+void MisplacedOperatorInStrlenInAllocCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const Expr *Alloc = Result.Nodes.getNodeAs<CallExpr>("Alloc");
+ if (!Alloc)
+ Alloc = Result.Nodes.getNodeAs<CXXNewExpr>("Alloc");
+ assert(Alloc && "Matched node bound by 'Alloc' shoud be either 'CallExpr'"
+ " or 'CXXNewExpr'");
+
+ const auto *StrLen = Result.Nodes.getNodeAs<CallExpr>("StrLen");
+ const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("BinOp");
+
+ const StringRef StrLenText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(StrLen->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ const StringRef Arg0Text = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(StrLen->getArg(0)->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ const StringRef StrLenBegin = StrLenText.substr(0, StrLenText.find(Arg0Text));
+ const StringRef StrLenEnd = StrLenText.substr(
+ StrLenText.find(Arg0Text) + Arg0Text.size(), StrLenText.size());
+
+ const StringRef LHSText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(BinOp->getLHS()->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ const StringRef RHSText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(BinOp->getRHS()->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+
+ auto Hint = FixItHint::CreateReplacement(
+ StrLen->getSourceRange(),
+ (StrLenBegin + LHSText + StrLenEnd + " + " + RHSText).str());
+
+ diag(Alloc->getLocStart(),
+ "addition operator is applied to the argument of %0 instead of its "
+ "result") << StrLen->getDirectCallee()->getName() << Hint;
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.h
new file mode 100644
index 0000000..99cfcfb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.h
@@ -0,0 +1,37 @@
+//===--- MisplacedOperatorInStrlenInAllocCheck.h - clang-tidy----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MISPLACED_OPERATOR_IN_STRLEN_IN_ALLOC_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MISPLACED_OPERATOR_IN_STRLEN_IN_ALLOC_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds cases where ``1`` is added to the string in the argument to a function
+/// in the ``strlen()`` family instead of the result and value is used as an
+/// argument to a memory allocation function.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-misplaced-operator-in-strlen-in-alloc.html
+class MisplacedOperatorInStrlenInAllocCheck : public ClangTidyCheck {
+public:
+ MisplacedOperatorInStrlenInAllocCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MISPLACED_OPERATOR_IN_STRLEN_IN_ALLOC_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedWideningCastCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedWideningCastCheck.cpp
new file mode 100644
index 0000000..e263366
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedWideningCastCheck.cpp
@@ -0,0 +1,233 @@
+//===--- MisplacedWideningCastCheck.cpp - clang-tidy-----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MisplacedWideningCastCheck.h"
+#include "../utils/Matchers.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+MisplacedWideningCastCheck::MisplacedWideningCastCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ CheckImplicitCasts(Options.get("CheckImplicitCasts", false)) {}
+
+void MisplacedWideningCastCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "CheckImplicitCasts", CheckImplicitCasts);
+}
+
+void MisplacedWideningCastCheck::registerMatchers(MatchFinder *Finder) {
+ const auto Calc =
+ expr(anyOf(binaryOperator(
+ anyOf(hasOperatorName("+"), hasOperatorName("-"),
+ hasOperatorName("*"), hasOperatorName("<<"))),
+ unaryOperator(hasOperatorName("~"))),
+ hasType(isInteger()))
+ .bind("Calc");
+
+ const auto ExplicitCast = explicitCastExpr(hasDestinationType(isInteger()),
+ has(ignoringParenImpCasts(Calc)));
+ const auto ImplicitCast =
+ implicitCastExpr(hasImplicitDestinationType(isInteger()),
+ has(ignoringParenImpCasts(Calc)));
+ const auto Cast = expr(anyOf(ExplicitCast, ImplicitCast)).bind("Cast");
+
+ Finder->addMatcher(varDecl(hasInitializer(Cast)), this);
+ Finder->addMatcher(returnStmt(hasReturnValue(Cast)), this);
+ Finder->addMatcher(callExpr(hasAnyArgument(Cast)), this);
+ Finder->addMatcher(binaryOperator(hasOperatorName("="), hasRHS(Cast)), this);
+ Finder->addMatcher(
+ binaryOperator(matchers::isComparisonOperator(), hasEitherOperand(Cast)),
+ this);
+}
+
+static unsigned getMaxCalculationWidth(const ASTContext &Context,
+ const Expr *E) {
+ E = E->IgnoreParenImpCasts();
+
+ if (const auto *Bop = dyn_cast<BinaryOperator>(E)) {
+ unsigned LHSWidth = getMaxCalculationWidth(Context, Bop->getLHS());
+ unsigned RHSWidth = getMaxCalculationWidth(Context, Bop->getRHS());
+ if (Bop->getOpcode() == BO_Mul)
+ return LHSWidth + RHSWidth;
+ if (Bop->getOpcode() == BO_Add)
+ return std::max(LHSWidth, RHSWidth) + 1;
+ if (Bop->getOpcode() == BO_Rem) {
+ llvm::APSInt Val;
+ if (Bop->getRHS()->EvaluateAsInt(Val, Context))
+ return Val.getActiveBits();
+ } else if (Bop->getOpcode() == BO_Shl) {
+ llvm::APSInt Bits;
+ if (Bop->getRHS()->EvaluateAsInt(Bits, Context)) {
+ // We don't handle negative values and large values well. It is assumed
+ // that compiler warnings are written for such values so the user will
+ // fix that.
+ return LHSWidth + Bits.getExtValue();
+ }
+
+ // Unknown bitcount, assume there is truncation.
+ return 1024U;
+ }
+ } else if (const auto *Uop = dyn_cast<UnaryOperator>(E)) {
+ // There is truncation when ~ is used.
+ if (Uop->getOpcode() == UO_Not)
+ return 1024U;
+
+ QualType T = Uop->getType();
+ return T->isIntegerType() ? Context.getIntWidth(T) : 1024U;
+ } else if (const auto *I = dyn_cast<IntegerLiteral>(E)) {
+ return I->getValue().getActiveBits();
+ }
+
+ return Context.getIntWidth(E->getType());
+}
+
+static int relativeIntSizes(BuiltinType::Kind Kind) {
+ switch (Kind) {
+ case BuiltinType::UChar:
+ return 1;
+ case BuiltinType::SChar:
+ return 1;
+ case BuiltinType::Char_U:
+ return 1;
+ case BuiltinType::Char_S:
+ return 1;
+ case BuiltinType::UShort:
+ return 2;
+ case BuiltinType::Short:
+ return 2;
+ case BuiltinType::UInt:
+ return 3;
+ case BuiltinType::Int:
+ return 3;
+ case BuiltinType::ULong:
+ return 4;
+ case BuiltinType::Long:
+ return 4;
+ case BuiltinType::ULongLong:
+ return 5;
+ case BuiltinType::LongLong:
+ return 5;
+ case BuiltinType::UInt128:
+ return 6;
+ case BuiltinType::Int128:
+ return 6;
+ default:
+ return 0;
+ }
+}
+
+static int relativeCharSizes(BuiltinType::Kind Kind) {
+ switch (Kind) {
+ case BuiltinType::UChar:
+ return 1;
+ case BuiltinType::SChar:
+ return 1;
+ case BuiltinType::Char_U:
+ return 1;
+ case BuiltinType::Char_S:
+ return 1;
+ case BuiltinType::Char16:
+ return 2;
+ case BuiltinType::Char32:
+ return 3;
+ default:
+ return 0;
+ }
+}
+
+static int relativeCharSizesW(BuiltinType::Kind Kind) {
+ switch (Kind) {
+ case BuiltinType::UChar:
+ return 1;
+ case BuiltinType::SChar:
+ return 1;
+ case BuiltinType::Char_U:
+ return 1;
+ case BuiltinType::Char_S:
+ return 1;
+ case BuiltinType::WChar_U:
+ return 2;
+ case BuiltinType::WChar_S:
+ return 2;
+ default:
+ return 0;
+ }
+}
+
+static bool isFirstWider(BuiltinType::Kind First, BuiltinType::Kind Second) {
+ int FirstSize, SecondSize;
+ if ((FirstSize = relativeIntSizes(First)) != 0 &&
+ (SecondSize = relativeIntSizes(Second)) != 0)
+ return FirstSize > SecondSize;
+ if ((FirstSize = relativeCharSizes(First)) != 0 &&
+ (SecondSize = relativeCharSizes(Second)) != 0)
+ return FirstSize > SecondSize;
+ if ((FirstSize = relativeCharSizesW(First)) != 0 &&
+ (SecondSize = relativeCharSizesW(Second)) != 0)
+ return FirstSize > SecondSize;
+ return false;
+}
+
+void MisplacedWideningCastCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Cast = Result.Nodes.getNodeAs<CastExpr>("Cast");
+ if (!CheckImplicitCasts && isa<ImplicitCastExpr>(Cast))
+ return;
+ if (Cast->getLocStart().isMacroID())
+ return;
+
+ const auto *Calc = Result.Nodes.getNodeAs<Expr>("Calc");
+ if (Calc->getLocStart().isMacroID())
+ return;
+
+ if (Cast->isTypeDependent() || Cast->isValueDependent() ||
+ Calc->isTypeDependent() || Calc->isValueDependent())
+ return;
+
+ ASTContext &Context = *Result.Context;
+
+ QualType CastType = Cast->getType();
+ QualType CalcType = Calc->getType();
+
+ // Explicit truncation using cast.
+ if (Context.getIntWidth(CastType) < Context.getIntWidth(CalcType))
+ return;
+
+ // If CalcType and CastType have same size then there is no real danger, but
+ // there can be a portability problem.
+
+ if (Context.getIntWidth(CastType) == Context.getIntWidth(CalcType)) {
+ const auto *CastBuiltinType =
+ dyn_cast<BuiltinType>(CastType->getUnqualifiedDesugaredType());
+ const auto *CalcBuiltinType =
+ dyn_cast<BuiltinType>(CalcType->getUnqualifiedDesugaredType());
+ if (CastBuiltinType && CalcBuiltinType &&
+ !isFirstWider(CastBuiltinType->getKind(), CalcBuiltinType->getKind()))
+ return;
+ }
+
+ // Don't write a warning if we can easily see that the result is not
+ // truncated.
+ if (Context.getIntWidth(CalcType) >= getMaxCalculationWidth(Context, Calc))
+ return;
+
+ diag(Cast->getLocStart(), "either cast from %0 to %1 is ineffective, or "
+ "there is loss of precision before the conversion")
+ << CalcType << CastType;
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedWideningCastCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedWideningCastCheck.h
new file mode 100644
index 0000000..b61556f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MisplacedWideningCastCheck.h
@@ -0,0 +1,46 @@
+//===--- MisplacedWideningCastCheck.h - clang-tidy---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MISPLACEDWIDENINGCASTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MISPLACEDWIDENINGCASTCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Find casts of calculation results to bigger type. Typically from int to
+/// long. If the intention of the cast is to avoid loss of precision then
+/// the cast is misplaced, and there can be loss of precision. Otherwise
+/// such cast is ineffective.
+///
+/// There is one option:
+///
+/// - `CheckImplicitCasts`: Whether to check implicit casts as well which may
+// be the most common case. Enabled by default.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-misplaced-widening-cast.html
+class MisplacedWideningCastCheck : public ClangTidyCheck {
+public:
+ MisplacedWideningCastCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const bool CheckImplicitCasts;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp
new file mode 100644
index 0000000..516ee19
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp
@@ -0,0 +1,133 @@
+//===--- MoveForwardingReferenceCheck.cpp - clang-tidy --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MoveForwardingReferenceCheck.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <algorithm>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+static void replaceMoveWithForward(const UnresolvedLookupExpr *Callee,
+ const ParmVarDecl *ParmVar,
+ const TemplateTypeParmDecl *TypeParmDecl,
+ DiagnosticBuilder &Diag,
+ const ASTContext &Context) {
+ const SourceManager &SM = Context.getSourceManager();
+ const LangOptions &LangOpts = Context.getLangOpts();
+
+ CharSourceRange CallRange =
+ Lexer::makeFileCharRange(CharSourceRange::getTokenRange(
+ Callee->getLocStart(), Callee->getLocEnd()),
+ SM, LangOpts);
+
+ if (CallRange.isValid()) {
+ const std::string TypeName =
+ TypeParmDecl->getIdentifier()
+ ? TypeParmDecl->getName().str()
+ : (llvm::Twine("decltype(") + ParmVar->getName() + ")").str();
+
+ const std::string ForwardName =
+ (llvm::Twine("forward<") + TypeName + ">").str();
+
+ // Create a replacement only if we see a "standard" way of calling
+ // std::move(). This will hopefully prevent erroneous replacements if the
+ // code does unusual things (e.g. create an alias for std::move() in
+ // another namespace).
+ NestedNameSpecifier *NNS = Callee->getQualifier();
+ if (!NNS) {
+ // Called as "move" (i.e. presumably the code had a "using std::move;").
+ // We still conservatively put a "std::" in front of the forward because
+ // we don't know whether the code also had a "using std::forward;".
+ Diag << FixItHint::CreateReplacement(CallRange, "std::" + ForwardName);
+ } else if (const NamespaceDecl *Namespace = NNS->getAsNamespace()) {
+ if (Namespace->getName() == "std") {
+ if (!NNS->getPrefix()) {
+ // Called as "std::move".
+ Diag << FixItHint::CreateReplacement(CallRange,
+ "std::" + ForwardName);
+ } else if (NNS->getPrefix()->getKind() == NestedNameSpecifier::Global) {
+ // Called as "::std::move".
+ Diag << FixItHint::CreateReplacement(CallRange,
+ "::std::" + ForwardName);
+ }
+ }
+ }
+ }
+}
+
+void MoveForwardingReferenceCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ // Matches a ParmVarDecl for a forwarding reference, i.e. a non-const rvalue
+ // reference of a function template parameter type.
+ auto ForwardingReferenceParmMatcher =
+ parmVarDecl(
+ hasType(qualType(rValueReferenceType(),
+ references(templateTypeParmType(hasDeclaration(
+ templateTypeParmDecl().bind("type-parm-decl")))),
+ unless(references(qualType(isConstQualified()))))))
+ .bind("parm-var");
+
+ Finder->addMatcher(
+ callExpr(callee(unresolvedLookupExpr(
+ hasAnyDeclaration(namedDecl(
+ hasUnderlyingDecl(hasName("::std::move")))))
+ .bind("lookup")),
+ argumentCountIs(1),
+ hasArgument(0, ignoringParenImpCasts(declRefExpr(
+ to(ForwardingReferenceParmMatcher)))))
+ .bind("call-move"),
+ this);
+}
+
+void MoveForwardingReferenceCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *CallMove = Result.Nodes.getNodeAs<CallExpr>("call-move");
+ const auto *UnresolvedLookup =
+ Result.Nodes.getNodeAs<UnresolvedLookupExpr>("lookup");
+ const auto *ParmVar = Result.Nodes.getNodeAs<ParmVarDecl>("parm-var");
+ const auto *TypeParmDecl =
+ Result.Nodes.getNodeAs<TemplateTypeParmDecl>("type-parm-decl");
+
+ // Get the FunctionDecl and FunctionTemplateDecl containing the function
+ // parameter.
+ const auto *FuncForParam = dyn_cast<FunctionDecl>(ParmVar->getDeclContext());
+ if (!FuncForParam)
+ return;
+ const FunctionTemplateDecl *FuncTemplate =
+ FuncForParam->getDescribedFunctionTemplate();
+ if (!FuncTemplate)
+ return;
+
+ // Check that the template type parameter belongs to the same function
+ // template as the function parameter of that type. (This implies that type
+ // deduction will happen on the type.)
+ const TemplateParameterList *Params = FuncTemplate->getTemplateParameters();
+ if (!std::count(Params->begin(), Params->end(), TypeParmDecl))
+ return;
+
+ auto Diag = diag(CallMove->getExprLoc(),
+ "forwarding reference passed to std::move(), which may "
+ "unexpectedly cause lvalues to be moved; use "
+ "std::forward() instead");
+
+ replaceMoveWithForward(UnresolvedLookup, ParmVar, TypeParmDecl, Diag,
+ *Result.Context);
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.h
new file mode 100644
index 0000000..c61de75
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.h
@@ -0,0 +1,49 @@
+//===--- MoveForwardingReferenceCheck.h - clang-tidy ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MOVEFORWARDINGREFERENCECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MOVEFORWARDINGREFERENCECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// The check warns if std::move is applied to a forwarding reference (i.e. an
+/// rvalue reference of a function template argument type).
+///
+/// If a developer is unaware of the special rules for template argument
+/// deduction on forwarding references, it will seem reasonable to apply
+/// std::move to the forwarding reference, in the same way that this would be
+/// done for a "normal" rvalue reference.
+///
+/// This has a consequence that is usually unwanted and possibly surprising: if
+/// the function that takes the forwarding reference as its parameter is called
+/// with an lvalue, that lvalue will be moved from (and hence placed into an
+/// indeterminate state) even though no std::move was applied to the lvalue at
+/// the call site.
+//
+/// The check suggests replacing the std::move with a std::forward.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-move-forwarding-reference.html
+class MoveForwardingReferenceCheck : public ClangTidyCheck {
+public:
+ MoveForwardingReferenceCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MOVEFORWARDINGREFERENCECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MultipleStatementMacroCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MultipleStatementMacroCheck.cpp
new file mode 100644
index 0000000..942c875
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MultipleStatementMacroCheck.cpp
@@ -0,0 +1,107 @@
+//===--- MultipleStatementMacroCheck.cpp - clang-tidy----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MultipleStatementMacroCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+
+AST_MATCHER(Expr, isInMacro) { return Node.getLocStart().isMacroID(); }
+
+/// \brief Find the next statement after `S`.
+const Stmt *nextStmt(const MatchFinder::MatchResult &Result, const Stmt *S) {
+ auto Parents = Result.Context->getParents(*S);
+ if (Parents.empty())
+ return nullptr;
+ const auto *Parent = Parents[0].get<Stmt>();
+ if (!Parent)
+ return nullptr;
+ const Stmt *Prev = nullptr;
+ for (const Stmt *Child : Parent->children()) {
+ if (Prev == S)
+ return Child;
+ Prev = Child;
+ }
+ return nextStmt(Result, Parent);
+}
+
+using ExpansionRanges = std::vector<SourceRange>;
+
+/// \bried Get all the macro expansion ranges related to `Loc`.
+///
+/// The result is ordered from most inner to most outer.
+ExpansionRanges getExpansionRanges(SourceLocation Loc,
+ const MatchFinder::MatchResult &Result) {
+ ExpansionRanges Locs;
+ while (Loc.isMacroID()) {
+ Locs.push_back(
+ Result.SourceManager->getImmediateExpansionRange(Loc).getAsRange());
+ Loc = Locs.back().getBegin();
+ }
+ return Locs;
+}
+
+} // namespace
+
+void MultipleStatementMacroCheck::registerMatchers(MatchFinder *Finder) {
+ const auto Inner = expr(isInMacro(), unless(compoundStmt())).bind("inner");
+ Finder->addMatcher(
+ stmt(anyOf(ifStmt(hasThen(Inner)), ifStmt(hasElse(Inner)).bind("else"),
+ whileStmt(hasBody(Inner)), forStmt(hasBody(Inner))))
+ .bind("outer"),
+ this);
+}
+
+void MultipleStatementMacroCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *Inner = Result.Nodes.getNodeAs<Expr>("inner");
+ const auto *Outer = Result.Nodes.getNodeAs<Stmt>("outer");
+ const auto *Next = nextStmt(Result, Outer);
+ if (!Next)
+ return;
+
+ SourceLocation OuterLoc = Outer->getLocStart();
+ if (Result.Nodes.getNodeAs<Stmt>("else"))
+ OuterLoc = cast<IfStmt>(Outer)->getElseLoc();
+
+ auto InnerRanges = getExpansionRanges(Inner->getLocStart(), Result);
+ auto OuterRanges = getExpansionRanges(OuterLoc, Result);
+ auto NextRanges = getExpansionRanges(Next->getLocStart(), Result);
+
+ // Remove all the common ranges, starting from the top (the last ones in the
+ // list).
+ while (!InnerRanges.empty() && !OuterRanges.empty() && !NextRanges.empty() &&
+ InnerRanges.back() == OuterRanges.back() &&
+ InnerRanges.back() == NextRanges.back()) {
+ InnerRanges.pop_back();
+ OuterRanges.pop_back();
+ NextRanges.pop_back();
+ }
+
+ // Inner and Next must have at least one more macro that Outer doesn't have,
+ // and that range must be common to both.
+ if (InnerRanges.empty() || NextRanges.empty() ||
+ InnerRanges.back() != NextRanges.back())
+ return;
+
+ diag(InnerRanges.back().getBegin(), "multiple statement macro used without "
+ "braces; some statements will be "
+ "unconditionally executed");
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MultipleStatementMacroCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MultipleStatementMacroCheck.h
new file mode 100644
index 0000000..efc6599
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/MultipleStatementMacroCheck.h
@@ -0,0 +1,37 @@
+//===--- MultipleStatementMacroCheck.h - clang-tidy--------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MULTIPLE_STATEMENT_MACRO_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MULTIPLE_STATEMENT_MACRO_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Detect multiple statement macros that are used in unbraced conditionals.
+/// Only the first statement of the macro will be inside the conditional and the
+/// other ones will be executed unconditionally.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-multiple-statement-macro.html
+class MultipleStatementMacroCheck : public ClangTidyCheck {
+public:
+ MultipleStatementMacroCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MULTIPLE_STATEMENT_MACRO_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.cpp
new file mode 100755
index 0000000..919a691
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.cpp
@@ -0,0 +1,156 @@
+//===--- ParentVirtualCallCheck.cpp - clang-tidy---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ParentVirtualCallCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/FixIt.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include <algorithm>
+#include <cctype>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+using BasesVector = llvm::SmallVector<const CXXRecordDecl *, 5>;
+
+static bool isParentOf(const CXXRecordDecl &Parent,
+ const CXXRecordDecl &ThisClass) {
+ if (Parent.getCanonicalDecl() == ThisClass.getCanonicalDecl())
+ return true;
+ const CXXRecordDecl *ParentCanonicalDecl = Parent.getCanonicalDecl();
+ return ThisClass.bases_end() !=
+ llvm::find_if(ThisClass.bases(), [=](const CXXBaseSpecifier &Base) {
+ auto *BaseDecl = Base.getType()->getAsCXXRecordDecl();
+ assert(BaseDecl);
+ return ParentCanonicalDecl == BaseDecl->getCanonicalDecl();
+ });
+}
+
+static BasesVector getParentsByGrandParent(const CXXRecordDecl &GrandParent,
+ const CXXRecordDecl &ThisClass,
+ const CXXMethodDecl &MemberDecl) {
+ BasesVector Result;
+ for (const auto &Base : ThisClass.bases()) {
+ const auto *BaseDecl = Base.getType()->getAsCXXRecordDecl();
+ const CXXMethodDecl *ActualMemberDecl =
+ MemberDecl.getCorrespondingMethodInClass(BaseDecl);
+ if (!ActualMemberDecl)
+ continue;
+ // TypePtr is the nearest base class to ThisClass between ThisClass and
+ // GrandParent, where MemberDecl is overridden. TypePtr is the class the
+ // check proposes to fix to.
+ const Type *TypePtr =
+ ActualMemberDecl->getThisType(ActualMemberDecl->getASTContext())
+ .getTypePtr();
+ const CXXRecordDecl *RecordDeclType = TypePtr->getPointeeCXXRecordDecl();
+ assert(RecordDeclType && "TypePtr is not a pointer to CXXRecordDecl!");
+ if (RecordDeclType->getCanonicalDecl()->isDerivedFrom(&GrandParent))
+ Result.emplace_back(RecordDeclType);
+ }
+
+ return Result;
+}
+
+static std::string getNameAsString(const NamedDecl *Decl) {
+ std::string QualName;
+ llvm::raw_string_ostream OS(QualName);
+ PrintingPolicy PP(Decl->getASTContext().getPrintingPolicy());
+ PP.SuppressUnwrittenScope = true;
+ Decl->printQualifiedName(OS, PP);
+ return OS.str();
+}
+
+// Returns E as written in the source code. Used to handle 'using' and
+// 'typedef'ed names of grand-parent classes.
+static std::string getExprAsString(const clang::Expr &E,
+ clang::ASTContext &AC) {
+ std::string Text = tooling::fixit::getText(E, AC).str();
+ Text.erase(
+ llvm::remove_if(
+ Text,
+ [](char C) { return std::isspace(static_cast<unsigned char>(C)); }),
+ Text.end());
+ return Text;
+}
+
+void ParentVirtualCallCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ cxxMemberCallExpr(
+ callee(memberExpr(hasDescendant(implicitCastExpr(
+ hasImplicitDestinationType(pointsTo(
+ type(anything()).bind("castToType"))),
+ hasSourceExpression(cxxThisExpr(hasType(
+ type(anything()).bind("thisType")))))))
+ .bind("member")),
+ callee(cxxMethodDecl(isVirtual()))),
+ this);
+}
+
+void ParentVirtualCallCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Member = Result.Nodes.getNodeAs<MemberExpr>("member");
+ assert(Member);
+
+ if (!Member->getQualifier())
+ return;
+
+ const auto *MemberDecl = cast<CXXMethodDecl>(Member->getMemberDecl());
+
+ const auto *ThisTypePtr = Result.Nodes.getNodeAs<PointerType>("thisType");
+ assert(ThisTypePtr);
+
+ const auto *ThisType = ThisTypePtr->getPointeeCXXRecordDecl();
+ assert(ThisType);
+
+ const auto *CastToTypePtr = Result.Nodes.getNodeAs<Type>("castToType");
+ assert(CastToTypePtr);
+
+ const auto *CastToType = CastToTypePtr->getAsCXXRecordDecl();
+ assert(CastToType);
+
+ if (isParentOf(*CastToType, *ThisType))
+ return;
+
+ const BasesVector Parents =
+ getParentsByGrandParent(*CastToType, *ThisType, *MemberDecl);
+
+ if (Parents.empty())
+ return;
+
+ std::string ParentsStr;
+ ParentsStr.reserve(30 * Parents.size());
+ for (const CXXRecordDecl *Parent : Parents) {
+ if (!ParentsStr.empty())
+ ParentsStr.append(" or ");
+ ParentsStr.append("'").append(getNameAsString(Parent)).append("'");
+ }
+
+ assert(Member->getQualifierLoc().getSourceRange().getBegin().isValid());
+ auto Diag = diag(Member->getQualifierLoc().getSourceRange().getBegin(),
+ "qualified name '%0' refers to a member overridden "
+ "in subclass%1; did you mean %2?")
+ << getExprAsString(*Member, *Result.Context)
+ << (Parents.size() > 1 ? "es" : "") << ParentsStr;
+
+ // Propose a fix if there's only one parent class...
+ if (Parents.size() == 1 &&
+ // ...unless parent class is templated
+ !isa<ClassTemplateSpecializationDecl>(Parents.front()))
+ Diag << FixItHint::CreateReplacement(
+ Member->getQualifierLoc().getSourceRange(),
+ getNameAsString(Parents.front()) + "::");
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.h
new file mode 100755
index 0000000..08c3aef
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.h
@@ -0,0 +1,35 @@
+//===--- ParentVirtualCallCheck.h - clang-tidy-------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_PARENTVIRTUALCALLCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_PARENTVIRTUALCALLCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds calls to grand..-parent virtual methods instead of parent's.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-parent-virtual-call.html
+class ParentVirtualCallCheck : public ClangTidyCheck {
+public:
+ ParentVirtualCallCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_PARENTVIRTUALCALLCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SizeofContainerCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SizeofContainerCheck.cpp
new file mode 100644
index 0000000..b4a019e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SizeofContainerCheck.cpp
@@ -0,0 +1,49 @@
+//===--- SizeofContainerCheck.cpp - clang-tidy-----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SizeofContainerCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void SizeofContainerCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ expr(unless(isInTemplateInstantiation()),
+ expr(sizeOfExpr(has(ignoringParenImpCasts(
+ expr(hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(
+ matchesName("^(::std::|::string)"),
+ unless(matchesName("^::std::(bitset|array)$")),
+ hasMethod(cxxMethodDecl(hasName("size"), isPublic(),
+ isConst())))))))))))
+ .bind("sizeof"),
+ // Ignore ARRAYSIZE(<array of containers>) pattern.
+ unless(hasAncestor(binaryOperator(
+ anyOf(hasOperatorName("/"), hasOperatorName("%")),
+ hasLHS(ignoringParenCasts(sizeOfExpr(expr()))),
+ hasRHS(ignoringParenCasts(equalsBoundNode("sizeof"))))))),
+ this);
+}
+
+void SizeofContainerCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *SizeOf =
+ Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeof");
+
+ auto Diag =
+ diag(SizeOf->getLocStart(), "sizeof() doesn't return the size of the "
+ "container; did you mean .size()?");
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SizeofContainerCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SizeofContainerCheck.h
new file mode 100644
index 0000000..76b82b0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SizeofContainerCheck.h
@@ -0,0 +1,36 @@
+//===--- SizeofContainerCheck.h - clang-tidy---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIZEOFCONTAINERCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIZEOFCONTAINERCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Find usages of sizeof on expressions of STL container types. Most likely the
+/// user wanted to use `.size()` instead.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-sizeof-container.html
+class SizeofContainerCheck : public ClangTidyCheck {
+public:
+ SizeofContainerCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIZEOFCONTAINERCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
new file mode 100644
index 0000000..f05a900
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
@@ -0,0 +1,284 @@
+//===--- SizeofExpressionCheck.cpp - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SizeofExpressionCheck.h"
+#include "../utils/Matchers.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+
+AST_MATCHER_P(IntegerLiteral, isBiggerThan, unsigned, N) {
+ return Node.getValue().getZExtValue() > N;
+}
+
+AST_MATCHER_P2(Expr, hasSizeOfDescendant, int, Depth,
+ ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
+ if (Depth < 0)
+ return false;
+
+ const Expr *E = Node.IgnoreParenImpCasts();
+ if (InnerMatcher.matches(*E, Finder, Builder))
+ return true;
+
+ if (const auto *CE = dyn_cast<CastExpr>(E)) {
+ const auto M = hasSizeOfDescendant(Depth - 1, InnerMatcher);
+ return M.matches(*CE->getSubExpr(), Finder, Builder);
+ } else if (const auto *UE = dyn_cast<UnaryOperator>(E)) {
+ const auto M = hasSizeOfDescendant(Depth - 1, InnerMatcher);
+ return M.matches(*UE->getSubExpr(), Finder, Builder);
+ } else if (const auto *BE = dyn_cast<BinaryOperator>(E)) {
+ const auto LHS = hasSizeOfDescendant(Depth - 1, InnerMatcher);
+ const auto RHS = hasSizeOfDescendant(Depth - 1, InnerMatcher);
+ return LHS.matches(*BE->getLHS(), Finder, Builder) ||
+ RHS.matches(*BE->getRHS(), Finder, Builder);
+ }
+
+ return false;
+}
+
+CharUnits getSizeOfType(const ASTContext &Ctx, const Type *Ty) {
+ if (!Ty || Ty->isIncompleteType() || Ty->isDependentType() ||
+ isa<DependentSizedArrayType>(Ty) || !Ty->isConstantSizeType())
+ return CharUnits::Zero();
+ return Ctx.getTypeSizeInChars(Ty);
+}
+
+} // namespace
+
+SizeofExpressionCheck::SizeofExpressionCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ WarnOnSizeOfConstant(Options.get("WarnOnSizeOfConstant", 1) != 0),
+ WarnOnSizeOfIntegerExpression(
+ Options.get("WarnOnSizeOfIntegerExpression", 0) != 0),
+ WarnOnSizeOfThis(Options.get("WarnOnSizeOfThis", 1) != 0),
+ WarnOnSizeOfCompareToConstant(
+ Options.get("WarnOnSizeOfCompareToConstant", 1) != 0) {}
+
+void SizeofExpressionCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "WarnOnSizeOfConstant", WarnOnSizeOfConstant);
+ Options.store(Opts, "WarnOnSizeOfIntegerExpression",
+ WarnOnSizeOfIntegerExpression);
+ Options.store(Opts, "WarnOnSizeOfThis", WarnOnSizeOfThis);
+ Options.store(Opts, "WarnOnSizeOfCompareToConstant",
+ WarnOnSizeOfCompareToConstant);
+}
+
+void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {
+ const auto IntegerExpr = ignoringParenImpCasts(integerLiteral());
+ const auto ConstantExpr = expr(ignoringParenImpCasts(
+ anyOf(integerLiteral(), unaryOperator(hasUnaryOperand(IntegerExpr)),
+ binaryOperator(hasLHS(IntegerExpr), hasRHS(IntegerExpr)))));
+ const auto IntegerCallExpr = expr(ignoringParenImpCasts(
+ callExpr(anyOf(hasType(isInteger()), hasType(enumType())),
+ unless(isInTemplateInstantiation()))));
+ const auto SizeOfExpr =
+ expr(anyOf(sizeOfExpr(has(type())), sizeOfExpr(has(expr()))));
+ const auto SizeOfZero = expr(
+ sizeOfExpr(has(ignoringParenImpCasts(expr(integerLiteral(equals(0)))))));
+
+ // Detect expression like: sizeof(ARRAYLEN);
+ // Note: The expression 'sizeof(sizeof(0))' is a portable trick used to know
+ // the sizeof size_t.
+ if (WarnOnSizeOfConstant) {
+ Finder->addMatcher(
+ expr(sizeOfExpr(has(ignoringParenImpCasts(ConstantExpr))),
+ unless(SizeOfZero))
+ .bind("sizeof-constant"),
+ this);
+ }
+
+ // Detect sizeof(f())
+ if (WarnOnSizeOfIntegerExpression) {
+ Finder->addMatcher(
+ expr(sizeOfExpr(ignoringParenImpCasts(has(IntegerCallExpr))))
+ .bind("sizeof-integer-call"),
+ this);
+ }
+
+ // Detect expression like: sizeof(this);
+ if (WarnOnSizeOfThis) {
+ Finder->addMatcher(
+ expr(sizeOfExpr(has(ignoringParenImpCasts(expr(cxxThisExpr())))))
+ .bind("sizeof-this"),
+ this);
+ }
+
+ // Detect sizeof(kPtr) where kPtr is 'const char* kPtr = "abc"';
+ const auto CharPtrType = pointerType(pointee(isAnyCharacter()));
+ const auto ConstStrLiteralDecl =
+ varDecl(isDefinition(), hasType(qualType(hasCanonicalType(CharPtrType))),
+ hasInitializer(ignoringParenImpCasts(stringLiteral())));
+ Finder->addMatcher(expr(sizeOfExpr(has(ignoringParenImpCasts(expr(
+ hasType(qualType(hasCanonicalType(CharPtrType))),
+ ignoringParenImpCasts(declRefExpr(
+ hasDeclaration(ConstStrLiteralDecl))))))))
+ .bind("sizeof-charp"),
+ this);
+
+ // Detect sizeof(ptr) where ptr points to an aggregate (i.e. sizeof(&S)).
+ const auto ArrayExpr = expr(ignoringParenImpCasts(
+ expr(hasType(qualType(hasCanonicalType(arrayType()))))));
+ const auto ArrayCastExpr = expr(anyOf(
+ unaryOperator(hasUnaryOperand(ArrayExpr), unless(hasOperatorName("*"))),
+ binaryOperator(hasEitherOperand(ArrayExpr)),
+ castExpr(hasSourceExpression(ArrayExpr))));
+ const auto PointerToArrayExpr = expr(ignoringParenImpCasts(expr(
+ hasType(qualType(hasCanonicalType(pointerType(pointee(arrayType()))))))));
+
+ const auto StructAddrOfExpr =
+ unaryOperator(hasOperatorName("&"),
+ hasUnaryOperand(ignoringParenImpCasts(expr(
+ hasType(qualType(hasCanonicalType(recordType())))))));
+
+ Finder->addMatcher(
+ expr(sizeOfExpr(has(expr(ignoringParenImpCasts(
+ anyOf(ArrayCastExpr, PointerToArrayExpr, StructAddrOfExpr))))))
+ .bind("sizeof-pointer-to-aggregate"),
+ this);
+
+ // Detect expression like: sizeof(epxr) <= k for a suspicious constant 'k'.
+ if (WarnOnSizeOfCompareToConstant) {
+ Finder->addMatcher(
+ binaryOperator(matchers::isRelationalOperator(),
+ hasEitherOperand(ignoringParenImpCasts(SizeOfExpr)),
+ hasEitherOperand(ignoringParenImpCasts(
+ anyOf(integerLiteral(equals(0)),
+ integerLiteral(isBiggerThan(0x80000))))))
+ .bind("sizeof-compare-constant"),
+ this);
+ }
+
+ // Detect expression like: sizeof(expr, expr); most likely an error.
+ Finder->addMatcher(expr(sizeOfExpr(has(expr(ignoringParenImpCasts(
+ binaryOperator(hasOperatorName(",")))))))
+ .bind("sizeof-comma-expr"),
+ this);
+
+ // Detect sizeof(...) /sizeof(...));
+ const auto ElemType =
+ arrayType(hasElementType(recordType().bind("elem-type")));
+ const auto ElemPtrType = pointerType(pointee(type().bind("elem-ptr-type")));
+ const auto NumType = qualType(hasCanonicalType(
+ type(anyOf(ElemType, ElemPtrType, type())).bind("num-type")));
+ const auto DenomType = qualType(hasCanonicalType(type().bind("denom-type")));
+
+ Finder->addMatcher(
+ binaryOperator(hasOperatorName("/"),
+ hasLHS(expr(ignoringParenImpCasts(
+ anyOf(sizeOfExpr(has(NumType)),
+ sizeOfExpr(has(expr(hasType(NumType)))))))),
+ hasRHS(expr(ignoringParenImpCasts(
+ anyOf(sizeOfExpr(has(DenomType)),
+ sizeOfExpr(has(expr(hasType(DenomType)))))))))
+ .bind("sizeof-divide-expr"),
+ this);
+
+ // Detect expression like: sizeof(...) * sizeof(...)); most likely an error.
+ Finder->addMatcher(binaryOperator(hasOperatorName("*"),
+ hasLHS(ignoringParenImpCasts(SizeOfExpr)),
+ hasRHS(ignoringParenImpCasts(SizeOfExpr)))
+ .bind("sizeof-multiply-sizeof"),
+ this);
+
+ Finder->addMatcher(
+ binaryOperator(hasOperatorName("*"),
+ hasEitherOperand(ignoringParenImpCasts(SizeOfExpr)),
+ hasEitherOperand(ignoringParenImpCasts(binaryOperator(
+ hasOperatorName("*"),
+ hasEitherOperand(ignoringParenImpCasts(SizeOfExpr))))))
+ .bind("sizeof-multiply-sizeof"),
+ this);
+
+ // Detect strange double-sizeof expression like: sizeof(sizeof(...));
+ // Note: The expression 'sizeof(sizeof(0))' is accepted.
+ Finder->addMatcher(
+ expr(sizeOfExpr(has(ignoringParenImpCasts(expr(
+ hasSizeOfDescendant(8, expr(SizeOfExpr, unless(SizeOfZero))))))))
+ .bind("sizeof-sizeof-expr"),
+ this);
+}
+
+void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) {
+ const ASTContext &Ctx = *Result.Context;
+
+ if (const auto *E = Result.Nodes.getNodeAs<Expr>("sizeof-constant")) {
+ diag(E->getLocStart(),
+ "suspicious usage of 'sizeof(K)'; did you mean 'K'?");
+ } else if (const auto *E =
+ Result.Nodes.getNodeAs<Expr>("sizeof-integer-call")) {
+ diag(E->getLocStart(), "suspicious usage of 'sizeof()' on an expression "
+ "that results in an integer");
+ } else if (const auto *E = Result.Nodes.getNodeAs<Expr>("sizeof-this")) {
+ diag(E->getLocStart(),
+ "suspicious usage of 'sizeof(this)'; did you mean 'sizeof(*this)'");
+ } else if (const auto *E = Result.Nodes.getNodeAs<Expr>("sizeof-charp")) {
+ diag(E->getLocStart(),
+ "suspicious usage of 'sizeof(char*)'; do you mean 'strlen'?");
+ } else if (const auto *E =
+ Result.Nodes.getNodeAs<Expr>("sizeof-pointer-to-aggregate")) {
+ diag(E->getLocStart(),
+ "suspicious usage of 'sizeof(A*)'; pointer to aggregate");
+ } else if (const auto *E =
+ Result.Nodes.getNodeAs<Expr>("sizeof-compare-constant")) {
+ diag(E->getLocStart(),
+ "suspicious comparison of 'sizeof(expr)' to a constant");
+ } else if (const auto *E =
+ Result.Nodes.getNodeAs<Expr>("sizeof-comma-expr")) {
+ diag(E->getLocStart(), "suspicious usage of 'sizeof(..., ...)'");
+ } else if (const auto *E =
+ Result.Nodes.getNodeAs<Expr>("sizeof-divide-expr")) {
+ const auto *NumTy = Result.Nodes.getNodeAs<Type>("num-type");
+ const auto *DenomTy = Result.Nodes.getNodeAs<Type>("denom-type");
+ const auto *ElementTy = Result.Nodes.getNodeAs<Type>("elem-type");
+ const auto *PointedTy = Result.Nodes.getNodeAs<Type>("elem-ptr-type");
+
+ CharUnits NumeratorSize = getSizeOfType(Ctx, NumTy);
+ CharUnits DenominatorSize = getSizeOfType(Ctx, DenomTy);
+ CharUnits ElementSize = getSizeOfType(Ctx, ElementTy);
+
+ if (DenominatorSize > CharUnits::Zero() &&
+ !NumeratorSize.isMultipleOf(DenominatorSize)) {
+ diag(E->getLocStart(), "suspicious usage of 'sizeof(...)/sizeof(...)';"
+ " numerator is not a multiple of denominator");
+ } else if (ElementSize > CharUnits::Zero() &&
+ DenominatorSize > CharUnits::Zero() &&
+ ElementSize != DenominatorSize) {
+ diag(E->getLocStart(), "suspicious usage of 'sizeof(...)/sizeof(...)';"
+ " numerator is not a multiple of denominator");
+ } else if (NumTy && DenomTy && NumTy == DenomTy) {
+ diag(E->getLocStart(),
+ "suspicious usage of sizeof pointer 'sizeof(T)/sizeof(T)'");
+ } else if (PointedTy && DenomTy && PointedTy == DenomTy) {
+ diag(E->getLocStart(),
+ "suspicious usage of sizeof pointer 'sizeof(T*)/sizeof(T)'");
+ } else if (NumTy && DenomTy && NumTy->isPointerType() &&
+ DenomTy->isPointerType()) {
+ diag(E->getLocStart(),
+ "suspicious usage of sizeof pointer 'sizeof(P*)/sizeof(Q*)'");
+ }
+ } else if (const auto *E =
+ Result.Nodes.getNodeAs<Expr>("sizeof-sizeof-expr")) {
+ diag(E->getLocStart(), "suspicious usage of 'sizeof(sizeof(...))'");
+ } else if (const auto *E =
+ Result.Nodes.getNodeAs<Expr>("sizeof-multiply-sizeof")) {
+ diag(E->getLocStart(), "suspicious 'sizeof' by 'sizeof' multiplication");
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.h
new file mode 100644
index 0000000..8e14c31
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.h
@@ -0,0 +1,41 @@
+//===--- SizeofExpressionCheck.h - clang-tidy--------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIZEOFEXPRESSIONCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIZEOFEXPRESSIONCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Find suspicious usages of sizeof expression.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-sizeof-expression.html
+class SizeofExpressionCheck : public ClangTidyCheck {
+public:
+ SizeofExpressionCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const bool WarnOnSizeOfConstant;
+ const bool WarnOnSizeOfIntegerExpression;
+ const bool WarnOnSizeOfThis;
+ const bool WarnOnSizeOfCompareToConstant;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIZEOFEXPRESSIONCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.cpp
new file mode 100644
index 0000000..420428f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.cpp
@@ -0,0 +1,136 @@
+//===--- StringConstructorCheck.cpp - clang-tidy---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StringConstructorCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+AST_MATCHER_P(IntegerLiteral, isBiggerThan, unsigned, N) {
+ return Node.getValue().getZExtValue() > N;
+}
+} // namespace
+
+StringConstructorCheck::StringConstructorCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ WarnOnLargeLength(Options.get("WarnOnLargeLength", 1) != 0),
+ LargeLengthThreshold(Options.get("LargeLengthThreshold", 0x800000)) {}
+
+void StringConstructorCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "WarnOnLargeLength", WarnOnLargeLength);
+ Options.store(Opts, "LargeLengthThreshold", LargeLengthThreshold);
+}
+
+void StringConstructorCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ const auto ZeroExpr = expr(ignoringParenImpCasts(integerLiteral(equals(0))));
+ const auto CharExpr = expr(ignoringParenImpCasts(characterLiteral()));
+ const auto NegativeExpr = expr(ignoringParenImpCasts(
+ unaryOperator(hasOperatorName("-"),
+ hasUnaryOperand(integerLiteral(unless(equals(0)))))));
+ const auto LargeLengthExpr = expr(ignoringParenImpCasts(
+ integerLiteral(isBiggerThan(LargeLengthThreshold))));
+ const auto CharPtrType = type(anyOf(pointerType(), arrayType()));
+
+ // Match a string-literal; even through a declaration with initializer.
+ const auto BoundStringLiteral = stringLiteral().bind("str");
+ const auto ConstStrLiteralDecl = varDecl(
+ isDefinition(), hasType(constantArrayType()), hasType(isConstQualified()),
+ hasInitializer(ignoringParenImpCasts(BoundStringLiteral)));
+ const auto ConstPtrStrLiteralDecl = varDecl(
+ isDefinition(),
+ hasType(pointerType(pointee(isAnyCharacter(), isConstQualified()))),
+ hasInitializer(ignoringParenImpCasts(BoundStringLiteral)));
+ const auto ConstStrLiteral = expr(ignoringParenImpCasts(anyOf(
+ BoundStringLiteral, declRefExpr(hasDeclaration(anyOf(
+ ConstPtrStrLiteralDecl, ConstStrLiteralDecl))))));
+
+ // Check the fill constructor. Fills the string with n consecutive copies of
+ // character c. [i.e string(size_t n, char c);].
+ Finder->addMatcher(
+ cxxConstructExpr(
+ hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+ hasArgument(0, hasType(qualType(isInteger()))),
+ hasArgument(1, hasType(qualType(isInteger()))),
+ anyOf(
+ // Detect the expression: string('x', 40);
+ hasArgument(0, CharExpr.bind("swapped-parameter")),
+ // Detect the expression: string(0, ...);
+ hasArgument(0, ZeroExpr.bind("empty-string")),
+ // Detect the expression: string(-4, ...);
+ hasArgument(0, NegativeExpr.bind("negative-length")),
+ // Detect the expression: string(0x1234567, ...);
+ hasArgument(0, LargeLengthExpr.bind("large-length"))))
+ .bind("constructor"),
+ this);
+
+ // Check the literal string constructor with char pointer and length
+ // parameters. [i.e. string (const char* s, size_t n);]
+ Finder->addMatcher(
+ cxxConstructExpr(
+ hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+ hasArgument(0, hasType(CharPtrType)),
+ hasArgument(1, hasType(isInteger())),
+ anyOf(
+ // Detect the expression: string("...", 0);
+ hasArgument(1, ZeroExpr.bind("empty-string")),
+ // Detect the expression: string("...", -4);
+ hasArgument(1, NegativeExpr.bind("negative-length")),
+ // Detect the expression: string("lit", 0x1234567);
+ hasArgument(1, LargeLengthExpr.bind("large-length")),
+ // Detect the expression: string("lit", 5)
+ allOf(hasArgument(0, ConstStrLiteral.bind("literal-with-length")),
+ hasArgument(1, ignoringParenImpCasts(
+ integerLiteral().bind("int"))))))
+ .bind("constructor"),
+ this);
+}
+
+void StringConstructorCheck::check(const MatchFinder::MatchResult &Result) {
+ const ASTContext &Ctx = *Result.Context;
+ const auto *E = Result.Nodes.getNodeAs<CXXConstructExpr>("constructor");
+ assert(E && "missing constructor expression");
+ SourceLocation Loc = E->getLocStart();
+
+ if (Result.Nodes.getNodeAs<Expr>("swapped-parameter")) {
+ const Expr *P0 = E->getArg(0);
+ const Expr *P1 = E->getArg(1);
+ diag(Loc, "string constructor parameters are probably swapped;"
+ " expecting string(count, character)")
+ << tooling::fixit::createReplacement(*P0, *P1, Ctx)
+ << tooling::fixit::createReplacement(*P1, *P0, Ctx);
+ } else if (Result.Nodes.getNodeAs<Expr>("empty-string")) {
+ diag(Loc, "constructor creating an empty string");
+ } else if (Result.Nodes.getNodeAs<Expr>("negative-length")) {
+ diag(Loc, "negative value used as length parameter");
+ } else if (Result.Nodes.getNodeAs<Expr>("large-length")) {
+ if (WarnOnLargeLength)
+ diag(Loc, "suspicious large length parameter");
+ } else if (Result.Nodes.getNodeAs<Expr>("literal-with-length")) {
+ const auto *Str = Result.Nodes.getNodeAs<StringLiteral>("str");
+ const auto *Lit = Result.Nodes.getNodeAs<IntegerLiteral>("int");
+ if (Lit->getValue().ugt(Str->getLength())) {
+ diag(Loc, "length is bigger then string literal size");
+ }
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.h
new file mode 100644
index 0000000..52e9791
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.h
@@ -0,0 +1,39 @@
+//===--- StringConstructorCheck.h - clang-tidy-------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STRING_CONSTRUCTOR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STRING_CONSTRUCTOR_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds suspicious string constructor and check their parameters.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-string-constructor.html
+class StringConstructorCheck : public ClangTidyCheck {
+public:
+ StringConstructorCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const bool WarnOnLargeLength;
+ const unsigned int LargeLengthThreshold;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STRING_CONSTRUCTOR_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
new file mode 100644
index 0000000..f373648
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -0,0 +1,86 @@
+//===--- StringIntegerAssignmentCheck.cpp - clang-tidy---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StringIntegerAssignmentCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void StringIntegerAssignmentCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+ Finder->addMatcher(
+ cxxOperatorCallExpr(
+ anyOf(hasOverloadedOperatorName("="),
+ hasOverloadedOperatorName("+=")),
+ callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
+ hasName("::std::basic_string"),
+ hasTemplateArgument(0, refersToType(qualType().bind("type"))))))),
+ hasArgument(1,
+ ignoringImpCasts(expr(hasType(isInteger()),
+ unless(hasType(isAnyCharacter())))
+ .bind("expr"))),
+ unless(isInTemplateInstantiation())),
+ this);
+}
+
+void StringIntegerAssignmentCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *Argument = Result.Nodes.getNodeAs<Expr>("expr");
+ SourceLocation Loc = Argument->getLocStart();
+
+ auto Diag =
+ diag(Loc, "an integer is interpreted as a character code when assigning "
+ "it to a string; if this is intended, cast the integer to the "
+ "appropriate character type; if you want a string "
+ "representation, use the appropriate conversion facility");
+
+ if (Loc.isMacroID())
+ return;
+
+ auto CharType = *Result.Nodes.getNodeAs<QualType>("type");
+ bool IsWideCharType = CharType->isWideCharType();
+ if (!CharType->isCharType() && !IsWideCharType)
+ return;
+ bool IsOneDigit = false;
+ bool IsLiteral = false;
+ if (const auto *Literal = dyn_cast<IntegerLiteral>(Argument)) {
+ IsOneDigit = Literal->getValue().getLimitedValue() < 10;
+ IsLiteral = true;
+ }
+
+ SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ Argument->getLocEnd(), 0, *Result.SourceManager, getLangOpts());
+ if (IsOneDigit) {
+ Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "L'" : "'")
+ << FixItHint::CreateInsertion(EndLoc, "'");
+ return;
+ }
+ if (IsLiteral) {
+ Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "L\"" : "\"")
+ << FixItHint::CreateInsertion(EndLoc, "\"");
+ return;
+ }
+
+ if (getLangOpts().CPlusPlus11) {
+ Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "std::to_wstring("
+ : "std::to_string(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.h
new file mode 100644
index 0000000..42fa53e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.h
@@ -0,0 +1,35 @@
+//===--- StringIntegerAssignmentCheck.h - clang-tidy-------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STRINGINTEGERASSIGNMENTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STRINGINTEGERASSIGNMENTCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds instances where an integer is assigned to a string.
+///
+/// For more details see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-string-assignment.html
+class StringIntegerAssignmentCheck : public ClangTidyCheck {
+public:
+ StringIntegerAssignmentCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STRINGINTEGERASSIGNMENTCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringLiteralWithEmbeddedNulCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringLiteralWithEmbeddedNulCheck.cpp
new file mode 100644
index 0000000..eaa610f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringLiteralWithEmbeddedNulCheck.cpp
@@ -0,0 +1,85 @@
+//===--- StringLiteralWithEmbeddedNulCheck.cpp - clang-tidy----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StringLiteralWithEmbeddedNulCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+AST_MATCHER(StringLiteral, containsNul) {
+ for (size_t i = 0; i < Node.getLength(); ++i)
+ if (Node.getCodeUnit(i) == '\0')
+ return true;
+ return false;
+}
+} // namespace
+
+void StringLiteralWithEmbeddedNulCheck::registerMatchers(MatchFinder *Finder) {
+ // Match a string that contains embedded NUL character. Extra-checks are
+ // applied in |check| to find incorectly escaped characters.
+ Finder->addMatcher(stringLiteral(containsNul()).bind("strlit"), this);
+
+ // The remaining checks only apply to C++.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ const auto StrLitWithNul =
+ ignoringParenImpCasts(stringLiteral(containsNul()).bind("truncated"));
+
+ // Match string constructor.
+ const auto StringConstructorExpr = expr(anyOf(
+ cxxConstructExpr(argumentCountIs(1),
+ hasDeclaration(cxxMethodDecl(hasName("basic_string")))),
+ // If present, the second argument is the alloc object which must not
+ // be present explicitly.
+ cxxConstructExpr(argumentCountIs(2),
+ hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+ hasArgument(1, cxxDefaultArgExpr()))));
+
+ // Detect passing a suspicious string literal to a string constructor.
+ // example: std::string str = "abc\0def";
+ Finder->addMatcher(
+ cxxConstructExpr(StringConstructorExpr, hasArgument(0, StrLitWithNul)),
+ this);
+
+ // Detect passing a suspicious string literal through an overloaded operator.
+ Finder->addMatcher(cxxOperatorCallExpr(hasAnyArgument(StrLitWithNul)), this);
+}
+
+void StringLiteralWithEmbeddedNulCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ if (const auto *SL = Result.Nodes.getNodeAs<StringLiteral>("strlit")) {
+ for (size_t Offset = 0, Length = SL->getLength(); Offset < Length;
+ ++Offset) {
+ // Find a sequence of character like "\0x12".
+ if (Offset + 3 < Length && SL->getCodeUnit(Offset) == '\0' &&
+ SL->getCodeUnit(Offset + 1) == 'x' &&
+ isDigit(SL->getCodeUnit(Offset + 2)) &&
+ isDigit(SL->getCodeUnit(Offset + 3))) {
+ diag(SL->getLocStart(), "suspicious embedded NUL character");
+ return;
+ }
+ }
+ }
+
+ if (const auto *SL = Result.Nodes.getNodeAs<StringLiteral>("truncated")) {
+ diag(SL->getLocStart(),
+ "truncated string literal with embedded NUL character");
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringLiteralWithEmbeddedNulCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringLiteralWithEmbeddedNulCheck.h
new file mode 100644
index 0000000..f5341c3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/StringLiteralWithEmbeddedNulCheck.h
@@ -0,0 +1,35 @@
+//===--- StringLiteralWithEmbeddedNulCheck.h - clang-tidy--------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STRINGLITERALWITHEMBEDDEDNULCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STRINGLITERALWITHEMBEDDEDNULCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Find suspicious string literals with embedded NUL characters.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-string-literal-with-embedded-nul.html
+class StringLiteralWithEmbeddedNulCheck : public ClangTidyCheck {
+public:
+ StringLiteralWithEmbeddedNulCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STRINGLITERALWITHEMBEDDEDNULCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousEnumUsageCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousEnumUsageCheck.cpp
new file mode 100644
index 0000000..1abad4e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousEnumUsageCheck.cpp
@@ -0,0 +1,219 @@
+//===--- SuspiciousEnumUsageCheck.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SuspiciousEnumUsageCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <algorithm>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+static const char DifferentEnumErrorMessage[] =
+ "enum values are from different enum types";
+
+static const char BitmaskErrorMessage[] =
+ "enum type seems like a bitmask (contains mostly "
+ "power-of-2 literals), but this literal is not a "
+ "power-of-2";
+
+static const char BitmaskVarErrorMessage[] =
+ "enum type seems like a bitmask (contains mostly "
+ "power-of-2 literals) but %plural{1:a literal is|:some literals are}0 not "
+ "power-of-2";
+
+static const char BitmaskNoteMessage[] = "used here as a bitmask";
+
+/// Stores a min and a max value which describe an interval.
+struct ValueRange {
+ llvm::APSInt MinVal;
+ llvm::APSInt MaxVal;
+
+ ValueRange(const EnumDecl *EnumDec) {
+ const auto MinMaxVal = std::minmax_element(
+ EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
+ [](const EnumConstantDecl *E1, const EnumConstantDecl *E2) {
+ return llvm::APSInt::compareValues(E1->getInitVal(),
+ E2->getInitVal()) < 0;
+ });
+ MinVal = MinMaxVal.first->getInitVal();
+ MaxVal = MinMaxVal.second->getInitVal();
+ }
+};
+
+/// Return the number of EnumConstantDecls in an EnumDecl.
+static int enumLength(const EnumDecl *EnumDec) {
+ return std::distance(EnumDec->enumerator_begin(), EnumDec->enumerator_end());
+}
+
+static bool hasDisjointValueRange(const EnumDecl *Enum1,
+ const EnumDecl *Enum2) {
+ ValueRange Range1(Enum1), Range2(Enum2);
+ return llvm::APSInt::compareValues(Range1.MaxVal, Range2.MinVal) < 0 ||
+ llvm::APSInt::compareValues(Range2.MaxVal, Range1.MinVal) < 0;
+}
+
+static bool isNonPowerOf2NorNullLiteral(const EnumConstantDecl *EnumConst) {
+ llvm::APSInt Val = EnumConst->getInitVal();
+ if (Val.isPowerOf2() || !Val.getBoolValue())
+ return false;
+ const Expr *InitExpr = EnumConst->getInitExpr();
+ if (!InitExpr)
+ return true;
+ return isa<IntegerLiteral>(InitExpr->IgnoreImpCasts());
+}
+
+static bool isMaxValAllBitSetLiteral(const EnumDecl *EnumDec) {
+ auto EnumConst = std::max_element(
+ EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
+ [](const EnumConstantDecl *E1, const EnumConstantDecl *E2) {
+ return E1->getInitVal() < E2->getInitVal();
+ });
+
+ if (const Expr *InitExpr = EnumConst->getInitExpr()) {
+ return EnumConst->getInitVal().countTrailingOnes() ==
+ EnumConst->getInitVal().getActiveBits() &&
+ isa<IntegerLiteral>(InitExpr->IgnoreImpCasts());
+ }
+ return false;
+}
+
+static int countNonPowOfTwoLiteralNum(const EnumDecl *EnumDec) {
+ return std::count_if(
+ EnumDec->enumerator_begin(), EnumDec->enumerator_end(),
+ [](const EnumConstantDecl *E) { return isNonPowerOf2NorNullLiteral(E); });
+}
+
+/// Check if there is one or two enumerators that are not a power of 2 and are
+/// initialized by a literal in the enum type, and that the enumeration contains
+/// enough elements to reasonably act as a bitmask. Exclude the case where the
+/// last enumerator is the sum of the lesser values (and initialized by a
+/// literal) or when it could contain consecutive values.
+static bool isPossiblyBitMask(const EnumDecl *EnumDec) {
+ ValueRange VR(EnumDec);
+ int EnumLen = enumLength(EnumDec);
+ int NonPowOfTwoCounter = countNonPowOfTwoLiteralNum(EnumDec);
+ return NonPowOfTwoCounter >= 1 && NonPowOfTwoCounter <= 2 &&
+ NonPowOfTwoCounter < EnumLen / 2 &&
+ (VR.MaxVal - VR.MinVal != EnumLen - 1) &&
+ !(NonPowOfTwoCounter == 1 && isMaxValAllBitSetLiteral(EnumDec));
+}
+
+SuspiciousEnumUsageCheck::SuspiciousEnumUsageCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ StrictMode(Options.getLocalOrGlobal("StrictMode", 0)) {}
+
+void SuspiciousEnumUsageCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "StrictMode", StrictMode);
+}
+
+void SuspiciousEnumUsageCheck::registerMatchers(MatchFinder *Finder) {
+ const auto enumExpr = [](StringRef RefName, StringRef DeclName) {
+ return allOf(ignoringImpCasts(expr().bind(RefName)),
+ ignoringImpCasts(hasType(enumDecl().bind(DeclName))));
+ };
+
+ Finder->addMatcher(
+ binaryOperator(hasOperatorName("|"), hasLHS(enumExpr("", "enumDecl")),
+ hasRHS(allOf(enumExpr("", "otherEnumDecl"),
+ ignoringImpCasts(hasType(enumDecl(
+ unless(equalsBoundNode("enumDecl"))))))))
+ .bind("diffEnumOp"),
+ this);
+
+ Finder->addMatcher(
+ binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("|")),
+ hasLHS(enumExpr("lhsExpr", "enumDecl")),
+ hasRHS(allOf(enumExpr("rhsExpr", ""),
+ ignoringImpCasts(hasType(enumDecl(
+ equalsBoundNode("enumDecl"))))))),
+ this);
+
+ Finder->addMatcher(
+ binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("|")),
+ hasEitherOperand(
+ allOf(hasType(isInteger()), unless(enumExpr("", "")))),
+ hasEitherOperand(enumExpr("enumExpr", "enumDecl"))),
+ this);
+
+ Finder->addMatcher(
+ binaryOperator(anyOf(hasOperatorName("|="), hasOperatorName("+=")),
+ hasRHS(enumExpr("enumExpr", "enumDecl"))),
+ this);
+}
+
+void SuspiciousEnumUsageCheck::checkSuspiciousBitmaskUsage(
+ const Expr *NodeExpr, const EnumDecl *EnumDec) {
+ const auto *EnumExpr = dyn_cast<DeclRefExpr>(NodeExpr);
+ const auto *EnumConst =
+ EnumExpr ? dyn_cast<EnumConstantDecl>(EnumExpr->getDecl()) : nullptr;
+
+ // Report the parameter if neccessary.
+ if (!EnumConst) {
+ diag(EnumDec->getInnerLocStart(), BitmaskVarErrorMessage)
+ << countNonPowOfTwoLiteralNum(EnumDec);
+ diag(EnumExpr->getExprLoc(), BitmaskNoteMessage, DiagnosticIDs::Note);
+ } else if (isNonPowerOf2NorNullLiteral(EnumConst)) {
+ diag(EnumConst->getSourceRange().getBegin(), BitmaskErrorMessage);
+ diag(EnumExpr->getExprLoc(), BitmaskNoteMessage, DiagnosticIDs::Note);
+ }
+}
+
+void SuspiciousEnumUsageCheck::check(const MatchFinder::MatchResult &Result) {
+ // Case 1: The two enum values come from different types.
+ if (const auto *DiffEnumOp =
+ Result.Nodes.getNodeAs<BinaryOperator>("diffEnumOp")) {
+ const auto *EnumDec = Result.Nodes.getNodeAs<EnumDecl>("enumDecl");
+ const auto *OtherEnumDec =
+ Result.Nodes.getNodeAs<EnumDecl>("otherEnumDecl");
+ // Skip when one of the parameters is an empty enum. The
+ // hasDisjointValueRange function could not decide the values properly in
+ // case of an empty enum.
+ if (EnumDec->enumerator_begin() == EnumDec->enumerator_end() ||
+ OtherEnumDec->enumerator_begin() == OtherEnumDec->enumerator_end())
+ return;
+
+ if (!hasDisjointValueRange(EnumDec, OtherEnumDec))
+ diag(DiffEnumOp->getOperatorLoc(), DifferentEnumErrorMessage);
+ return;
+ }
+
+ // Case 2 and 3 only checked in strict mode. The checker tries to detect
+ // suspicious bitmasks which contains values initialized by non power-of-2
+ // literals.
+ if (!StrictMode)
+ return;
+ const auto *EnumDec = Result.Nodes.getNodeAs<EnumDecl>("enumDecl");
+ if (!isPossiblyBitMask(EnumDec))
+ return;
+
+ // Case 2:
+ // a. Investigating the right hand side of `+=` or `|=` operator.
+ // b. When the operator is `|` or `+` but only one of them is an EnumExpr
+ if (const auto *EnumExpr = Result.Nodes.getNodeAs<Expr>("enumExpr")) {
+ checkSuspiciousBitmaskUsage(EnumExpr, EnumDec);
+ return;
+ }
+
+ // Case 3:
+ // '|' or '+' operator where both argument comes from the same enum type
+ const auto *LhsExpr = Result.Nodes.getNodeAs<Expr>("lhsExpr");
+ checkSuspiciousBitmaskUsage(LhsExpr, EnumDec);
+
+ const auto *RhsExpr = Result.Nodes.getNodeAs<Expr>("rhsExpr");
+ checkSuspiciousBitmaskUsage(RhsExpr, EnumDec);
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousEnumUsageCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousEnumUsageCheck.h
new file mode 100644
index 0000000..9c1b53d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousEnumUsageCheck.h
@@ -0,0 +1,39 @@
+//===--- SuspiciousEnumUsageCheck.h - clang-tidy--------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSENUMUSAGECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSENUMUSAGECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// The checker detects various cases when an enum is probably misused (as a
+/// bitmask).
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-enum-usage.html
+class SuspiciousEnumUsageCheck : public ClangTidyCheck {
+public:
+ SuspiciousEnumUsageCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ void checkSuspiciousBitmaskUsage(const Expr*, const EnumDecl*);
+ const bool StrictMode;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSENUMUSAGECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemsetUsageCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemsetUsageCheck.cpp
new file mode 100644
index 0000000..8e11a43
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemsetUsageCheck.cpp
@@ -0,0 +1,127 @@
+//===--- SuspiciousMemsetUsageCheck.cpp - clang-tidy-----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SuspiciousMemsetUsageCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void SuspiciousMemsetUsageCheck::registerMatchers(MatchFinder *Finder) {
+ // Note: void *memset(void *buffer, int fill_char, size_t byte_count);
+ // Look for memset(x, '0', z). Probably memset(x, 0, z) was intended.
+ Finder->addMatcher(
+ callExpr(
+ callee(functionDecl(hasName("::memset"))),
+ hasArgument(1, characterLiteral(equals(static_cast<unsigned>('0')))
+ .bind("char-zero-fill")),
+ unless(
+ eachOf(hasArgument(0, anyOf(hasType(pointsTo(isAnyCharacter())),
+ hasType(arrayType(hasElementType(
+ isAnyCharacter()))))),
+ isInTemplateInstantiation()))),
+ this);
+
+ // Look for memset with an integer literal in its fill_char argument.
+ // Will check if it gets truncated.
+ Finder->addMatcher(callExpr(callee(functionDecl(hasName("::memset"))),
+ hasArgument(1, integerLiteral().bind("num-fill")),
+ unless(isInTemplateInstantiation())),
+ this);
+
+ // Look for memset(x, y, 0) as that is most likely an argument swap.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasName("::memset"))),
+ unless(hasArgument(1, anyOf(characterLiteral(equals(
+ static_cast<unsigned>('0'))),
+ integerLiteral()))),
+ unless(isInTemplateInstantiation()))
+ .bind("call"),
+ this);
+}
+
+void SuspiciousMemsetUsageCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *CharZeroFill =
+ Result.Nodes.getNodeAs<CharacterLiteral>("char-zero-fill")) {
+ // Case 1: fill_char of memset() is a character '0'. Probably an
+ // integer zero was intended.
+
+ SourceRange CharRange = CharZeroFill->getSourceRange();
+ auto Diag =
+ diag(CharZeroFill->getLocStart(), "memset fill value is char '0', "
+ "potentially mistaken for int 0");
+
+ // Only suggest a fix if no macros are involved.
+ if (CharRange.getBegin().isMacroID())
+ return;
+ Diag << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(CharRange), "0");
+ }
+
+ else if (const auto *NumFill =
+ Result.Nodes.getNodeAs<IntegerLiteral>("num-fill")) {
+ // Case 2: fill_char of memset() is larger in size than an unsigned char
+ // so it gets truncated during conversion.
+
+ llvm::APSInt NumValue;
+ const auto UCharMax = (1 << Result.Context->getCharWidth()) - 1;
+ if (!NumFill->EvaluateAsInt(NumValue, *Result.Context) ||
+ (NumValue >= 0 && NumValue <= UCharMax))
+ return;
+
+ diag(NumFill->getLocStart(), "memset fill value is out of unsigned "
+ "character range, gets truncated");
+ }
+
+ else if (const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call")) {
+ // Case 3: byte_count of memset() is zero. This is most likely an
+ // argument swap.
+
+ const Expr *FillChar = Call->getArg(1);
+ const Expr *ByteCount = Call->getArg(2);
+
+ // Return if `byte_count` is not zero at compile time.
+ llvm::APSInt Value1, Value2;
+ if (ByteCount->isValueDependent() ||
+ !ByteCount->EvaluateAsInt(Value2, *Result.Context) || Value2 != 0)
+ return;
+
+ // Return if `fill_char` is known to be zero or negative at compile
+ // time. In these cases, swapping the args would be a nop, or
+ // introduce a definite bug. The code is likely correct.
+ if (!FillChar->isValueDependent() &&
+ FillChar->EvaluateAsInt(Value1, *Result.Context) &&
+ (Value1 == 0 || Value1.isNegative()))
+ return;
+
+ // `byte_count` is known to be zero at compile time, and `fill_char` is
+ // either not known or known to be a positive integer. Emit a warning
+ // and fix-its to swap the arguments.
+ auto D = diag(Call->getLocStart(),
+ "memset of size zero, potentially swapped arguments");
+ StringRef RHSString = tooling::fixit::getText(*ByteCount, *Result.Context);
+ StringRef LHSString = tooling::fixit::getText(*FillChar, *Result.Context);
+ if (LHSString.empty() || RHSString.empty())
+ return;
+
+ D << tooling::fixit::createReplacement(*FillChar, RHSString)
+ << tooling::fixit::createReplacement(*ByteCount, LHSString);
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemsetUsageCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemsetUsageCheck.h
new file mode 100644
index 0000000..1c0d1bc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousMemsetUsageCheck.h
@@ -0,0 +1,35 @@
+//===--- SuspiciousMemsetUsageCheck.h - clang-tidy---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUS_MEMSET_USAGE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUS_MEMSET_USAGE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds memset calls with potential mistakes in their arguments.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-memset-usage.html
+class SuspiciousMemsetUsageCheck : public ClangTidyCheck {
+public:
+ SuspiciousMemsetUsageCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUS_MEMSET_USAGE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp
new file mode 100644
index 0000000..3831dc3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp
@@ -0,0 +1,129 @@
+//===--- SuspiciousMissingCommaCheck.cpp - clang-tidy----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SuspiciousMissingCommaCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+
+bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx,
+ const StringLiteral *Lit) {
+ // String literals surrounded by parentheses are assumed to be on purpose.
+ // i.e.: const char* Array[] = { ("a" "b" "c"), "d", [...] };
+ auto Parents = Ctx->getParents(*Lit);
+ if (Parents.size() == 1 && Parents[0].get<ParenExpr>() != nullptr)
+ return true;
+
+ // Appropriately indented string literals are assumed to be on purpose.
+ // The following frequent indentation is accepted:
+ // const char* Array[] = {
+ // "first literal"
+ // "indented literal"
+ // "indented literal",
+ // "second literal",
+ // [...]
+ // };
+ const SourceManager &SM = Ctx->getSourceManager();
+ bool IndentedCorrectly = true;
+ SourceLocation FirstToken = Lit->getStrTokenLoc(0);
+ FileID BaseFID = SM.getFileID(FirstToken);
+ unsigned int BaseIndent = SM.getSpellingColumnNumber(FirstToken);
+ unsigned int BaseLine = SM.getSpellingLineNumber(FirstToken);
+ for (unsigned int TokNum = 1; TokNum < Lit->getNumConcatenated(); ++TokNum) {
+ SourceLocation Token = Lit->getStrTokenLoc(TokNum);
+ FileID FID = SM.getFileID(Token);
+ unsigned int Indent = SM.getSpellingColumnNumber(Token);
+ unsigned int Line = SM.getSpellingLineNumber(Token);
+ if (FID != BaseFID || Line != BaseLine + TokNum || Indent <= BaseIndent) {
+ IndentedCorrectly = false;
+ break;
+ }
+ }
+ if (IndentedCorrectly)
+ return true;
+
+ // There is no pattern recognized by the checker, assume it's not on purpose.
+ return false;
+}
+
+AST_MATCHER_P(StringLiteral, isConcatenatedLiteral, unsigned,
+ MaxConcatenatedTokens) {
+ return Node.getNumConcatenated() > 1 &&
+ Node.getNumConcatenated() < MaxConcatenatedTokens &&
+ !isConcatenatedLiteralsOnPurpose(&Finder->getASTContext(), &Node);
+}
+
+} // namespace
+
+SuspiciousMissingCommaCheck::SuspiciousMissingCommaCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ SizeThreshold(Options.get("SizeThreshold", 5U)),
+ RatioThreshold(std::stod(Options.get("RatioThreshold", ".2"))),
+ MaxConcatenatedTokens(Options.get("MaxConcatenatedTokens", 5U)) {}
+
+void SuspiciousMissingCommaCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "SizeThreshold", SizeThreshold);
+ Options.store(Opts, "RatioThreshold", std::to_string(RatioThreshold));
+ Options.store(Opts, "MaxConcatenatedTokens", MaxConcatenatedTokens);
+}
+
+void SuspiciousMissingCommaCheck::registerMatchers(MatchFinder *Finder) {
+ const auto ConcatenatedStringLiteral =
+ stringLiteral(isConcatenatedLiteral(MaxConcatenatedTokens)).bind("str");
+
+ const auto StringsInitializerList =
+ initListExpr(hasType(constantArrayType()),
+ has(ignoringParenImpCasts(expr(ConcatenatedStringLiteral))));
+
+ Finder->addMatcher(StringsInitializerList.bind("list"), this);
+}
+
+void SuspiciousMissingCommaCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *InitializerList = Result.Nodes.getNodeAs<InitListExpr>("list");
+ const auto *ConcatenatedLiteral =
+ Result.Nodes.getNodeAs<StringLiteral>("str");
+ assert(InitializerList && ConcatenatedLiteral);
+
+ // Skip small arrays as they often generate false-positive.
+ unsigned int Size = InitializerList->getNumInits();
+ if (Size < SizeThreshold)
+ return;
+
+ // Count the number of occurence of concatenated string literal.
+ unsigned int Count = 0;
+ for (unsigned int i = 0; i < Size; ++i) {
+ const Expr *Child = InitializerList->getInit(i)->IgnoreImpCasts();
+ if (const auto *Literal = dyn_cast<StringLiteral>(Child)) {
+ if (Literal->getNumConcatenated() > 1)
+ ++Count;
+ }
+ }
+
+ // Warn only when concatenation is not common in this initializer list.
+ // The current threshold is set to less than 1/5 of the string literals.
+ if (double(Count) / Size > RatioThreshold)
+ return;
+
+ diag(ConcatenatedLiteral->getLocStart(),
+ "suspicious string literal, probably missing a comma");
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.h
new file mode 100644
index 0000000..4ae3ecf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.h
@@ -0,0 +1,44 @@
+//===--- SuspiciousMissingCommaCheck.h - clang-tidy--------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSMISSINGCOMMACHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSMISSINGCOMMACHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// This check finds string literals which are probably concatenated
+/// accidentally.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-missing-comma.html
+class SuspiciousMissingCommaCheck : public ClangTidyCheck {
+public:
+ SuspiciousMissingCommaCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ // Minimal size of a string literals array to be considered by the checker.
+ const unsigned SizeThreshold;
+ // Maximal threshold ratio of suspicious string literals to be considered.
+ const double RatioThreshold;
+ // Maximal number of concatenated tokens.
+ const unsigned MaxConcatenatedTokens;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSMISSINGCOMMACHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousSemicolonCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousSemicolonCheck.cpp
new file mode 100644
index 0000000..d7f51d0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousSemicolonCheck.cpp
@@ -0,0 +1,77 @@
+//===--- SuspiciousSemicolonCheck.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SuspiciousSemicolonCheck.h"
+#include "../utils/LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void SuspiciousSemicolonCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ stmt(anyOf(ifStmt(hasThen(nullStmt().bind("semi")),
+ unless(hasElse(stmt()))),
+ forStmt(hasBody(nullStmt().bind("semi"))),
+ cxxForRangeStmt(hasBody(nullStmt().bind("semi"))),
+ whileStmt(hasBody(nullStmt().bind("semi")))))
+ .bind("stmt"),
+ this);
+}
+
+void SuspiciousSemicolonCheck::check(const MatchFinder::MatchResult &Result) {
+ if (Result.Context->getDiagnostics().hasUncompilableErrorOccurred())
+ return;
+
+ const auto *Semicolon = Result.Nodes.getNodeAs<NullStmt>("semi");
+ SourceLocation LocStart = Semicolon->getLocStart();
+
+ if (LocStart.isMacroID())
+ return;
+
+ ASTContext &Ctxt = *Result.Context;
+ auto Token = utils::lexer::getPreviousToken(Ctxt, LocStart);
+ auto &SM = *Result.SourceManager;
+ unsigned SemicolonLine = SM.getSpellingLineNumber(LocStart);
+
+ const auto *Statement = Result.Nodes.getNodeAs<Stmt>("stmt");
+ const bool IsIfStmt = isa<IfStmt>(Statement);
+
+ if (!IsIfStmt &&
+ SM.getSpellingLineNumber(Token.getLocation()) != SemicolonLine)
+ return;
+
+ SourceLocation LocEnd = Semicolon->getLocEnd();
+ FileID FID = SM.getFileID(LocEnd);
+ llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, LocEnd);
+ Lexer Lexer(SM.getLocForStartOfFile(FID), Ctxt.getLangOpts(),
+ Buffer->getBufferStart(), SM.getCharacterData(LocEnd) + 1,
+ Buffer->getBufferEnd());
+ if (Lexer.LexFromRawLexer(Token))
+ return;
+
+ unsigned BaseIndent = SM.getSpellingColumnNumber(Statement->getLocStart());
+ unsigned NewTokenIndent = SM.getSpellingColumnNumber(Token.getLocation());
+ unsigned NewTokenLine = SM.getSpellingLineNumber(Token.getLocation());
+
+ if (!IsIfStmt && NewTokenIndent <= BaseIndent &&
+ Token.getKind() != tok::l_brace && NewTokenLine != SemicolonLine)
+ return;
+
+ diag(LocStart, "potentially unintended semicolon")
+ << FixItHint::CreateRemoval(SourceRange(LocStart, LocEnd));
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousSemicolonCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousSemicolonCheck.h
new file mode 100644
index 0000000..adfced1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousSemicolonCheck.h
@@ -0,0 +1,36 @@
+//===--- SuspiciousSemicolonCheck.h - clang-tidy-----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSSEMICOLONCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSSEMICOLONCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// This check finds semicolon that modifies the meaning of the program
+/// unintendedly.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-semicolon.html
+class SuspiciousSemicolonCheck : public ClangTidyCheck {
+public:
+ SuspiciousSemicolonCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSSEMICOLONCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp
new file mode 100644
index 0000000..0cc6215
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp
@@ -0,0 +1,218 @@
+//===--- SuspiciousStringCompareCheck.cpp - clang-tidy---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SuspiciousStringCompareCheck.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+// Semicolon separated list of known string compare-like functions. The list
+// must ends with a semicolon.
+static const char KnownStringCompareFunctions[] = "__builtin_memcmp;"
+ "__builtin_strcasecmp;"
+ "__builtin_strcmp;"
+ "__builtin_strncasecmp;"
+ "__builtin_strncmp;"
+ "_mbscmp;"
+ "_mbscmp_l;"
+ "_mbsicmp;"
+ "_mbsicmp_l;"
+ "_mbsnbcmp;"
+ "_mbsnbcmp_l;"
+ "_mbsnbicmp;"
+ "_mbsnbicmp_l;"
+ "_mbsncmp;"
+ "_mbsncmp_l;"
+ "_mbsnicmp;"
+ "_mbsnicmp_l;"
+ "_memicmp;"
+ "_memicmp_l;"
+ "_stricmp;"
+ "_stricmp_l;"
+ "_strnicmp;"
+ "_strnicmp_l;"
+ "_wcsicmp;"
+ "_wcsicmp_l;"
+ "_wcsnicmp;"
+ "_wcsnicmp_l;"
+ "lstrcmp;"
+ "lstrcmpi;"
+ "memcmp;"
+ "memicmp;"
+ "strcasecmp;"
+ "strcmp;"
+ "strcmpi;"
+ "stricmp;"
+ "strncasecmp;"
+ "strncmp;"
+ "strnicmp;"
+ "wcscasecmp;"
+ "wcscmp;"
+ "wcsicmp;"
+ "wcsncmp;"
+ "wcsnicmp;"
+ "wmemcmp;";
+
+SuspiciousStringCompareCheck::SuspiciousStringCompareCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ WarnOnImplicitComparison(Options.get("WarnOnImplicitComparison", 1)),
+ WarnOnLogicalNotComparison(Options.get("WarnOnLogicalNotComparison", 0)),
+ StringCompareLikeFunctions(
+ Options.get("StringCompareLikeFunctions", "")) {}
+
+void SuspiciousStringCompareCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "WarnOnImplicitComparison", WarnOnImplicitComparison);
+ Options.store(Opts, "WarnOnLogicalNotComparison", WarnOnLogicalNotComparison);
+ Options.store(Opts, "StringCompareLikeFunctions", StringCompareLikeFunctions);
+}
+
+void SuspiciousStringCompareCheck::registerMatchers(MatchFinder *Finder) {
+ // Match relational operators.
+ const auto ComparisonUnaryOperator = unaryOperator(hasOperatorName("!"));
+ const auto ComparisonBinaryOperator =
+ binaryOperator(matchers::isComparisonOperator());
+ const auto ComparisonOperator =
+ expr(anyOf(ComparisonUnaryOperator, ComparisonBinaryOperator));
+
+ // Add the list of known string compare-like functions and add user-defined
+ // functions.
+ std::vector<std::string> FunctionNames = utils::options::parseStringList(
+ (llvm::Twine(KnownStringCompareFunctions) + StringCompareLikeFunctions)
+ .str());
+
+ // Match a call to a string compare functions.
+ const auto FunctionCompareDecl =
+ functionDecl(hasAnyName(std::vector<StringRef>(FunctionNames.begin(),
+ FunctionNames.end())))
+ .bind("decl");
+ const auto DirectStringCompareCallExpr =
+ callExpr(hasDeclaration(FunctionCompareDecl)).bind("call");
+ const auto MacroStringCompareCallExpr = conditionalOperator(anyOf(
+ hasTrueExpression(ignoringParenImpCasts(DirectStringCompareCallExpr)),
+ hasFalseExpression(ignoringParenImpCasts(DirectStringCompareCallExpr))));
+ // The implicit cast is not present in C.
+ const auto StringCompareCallExpr = ignoringParenImpCasts(
+ anyOf(DirectStringCompareCallExpr, MacroStringCompareCallExpr));
+
+ if (WarnOnImplicitComparison) {
+ // Detect suspicious calls to string compare:
+ // 'if (strcmp())' -> 'if (strcmp() != 0)'
+ Finder->addMatcher(
+ stmt(anyOf(ifStmt(hasCondition(StringCompareCallExpr)),
+ whileStmt(hasCondition(StringCompareCallExpr)),
+ doStmt(hasCondition(StringCompareCallExpr)),
+ forStmt(hasCondition(StringCompareCallExpr)),
+ binaryOperator(
+ anyOf(hasOperatorName("&&"), hasOperatorName("||")),
+ hasEitherOperand(StringCompareCallExpr))))
+ .bind("missing-comparison"),
+ this);
+ }
+
+ if (WarnOnLogicalNotComparison) {
+ // Detect suspicious calls to string compared with '!' operator:
+ // 'if (!strcmp())' -> 'if (strcmp() == 0)'
+ Finder->addMatcher(unaryOperator(hasOperatorName("!"),
+ hasUnaryOperand(ignoringParenImpCasts(
+ StringCompareCallExpr)))
+ .bind("logical-not-comparison"),
+ this);
+ }
+
+ // Detect suspicious cast to an inconsistant type (i.e. not integer type).
+ Finder->addMatcher(
+ implicitCastExpr(unless(hasType(isInteger())),
+ hasSourceExpression(StringCompareCallExpr))
+ .bind("invalid-conversion"),
+ this);
+
+ // Detect suspicious operator with string compare function as operand.
+ Finder->addMatcher(
+ binaryOperator(
+ unless(anyOf(matchers::isComparisonOperator(), hasOperatorName("&&"),
+ hasOperatorName("||"), hasOperatorName("="))),
+ hasEitherOperand(StringCompareCallExpr))
+ .bind("suspicious-operator"),
+ this);
+
+ // Detect comparison to invalid constant: 'strcmp() == -1'.
+ const auto InvalidLiteral = ignoringParenImpCasts(
+ anyOf(integerLiteral(unless(equals(0))),
+ unaryOperator(
+ hasOperatorName("-"),
+ has(ignoringParenImpCasts(integerLiteral(unless(equals(0)))))),
+ characterLiteral(), cxxBoolLiteral()));
+
+ Finder->addMatcher(binaryOperator(matchers::isComparisonOperator(),
+ hasEitherOperand(StringCompareCallExpr),
+ hasEitherOperand(InvalidLiteral))
+ .bind("invalid-comparison"),
+ this);
+}
+
+void SuspiciousStringCompareCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *Decl = Result.Nodes.getNodeAs<FunctionDecl>("decl");
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+ assert(Decl != nullptr && Call != nullptr);
+
+ if (Result.Nodes.getNodeAs<Stmt>("missing-comparison")) {
+ SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ Call->getRParenLoc(), 0, Result.Context->getSourceManager(),
+ getLangOpts());
+
+ diag(Call->getLocStart(),
+ "function %0 is called without explicitly comparing result")
+ << Decl << FixItHint::CreateInsertion(EndLoc, " != 0");
+ }
+
+ if (const auto *E = Result.Nodes.getNodeAs<Expr>("logical-not-comparison")) {
+ SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ Call->getRParenLoc(), 0, Result.Context->getSourceManager(),
+ getLangOpts());
+ SourceLocation NotLoc = E->getLocStart();
+
+ diag(Call->getLocStart(),
+ "function %0 is compared using logical not operator")
+ << Decl << FixItHint::CreateRemoval(
+ CharSourceRange::getTokenRange(NotLoc, NotLoc))
+ << FixItHint::CreateInsertion(EndLoc, " == 0");
+ }
+
+ if (Result.Nodes.getNodeAs<Stmt>("invalid-comparison")) {
+ diag(Call->getLocStart(),
+ "function %0 is compared to a suspicious constant")
+ << Decl;
+ }
+
+ if (const auto *BinOp =
+ Result.Nodes.getNodeAs<BinaryOperator>("suspicious-operator")) {
+ diag(Call->getLocStart(), "results of function %0 used by operator '%1'")
+ << Decl << BinOp->getOpcodeStr();
+ }
+
+ if (Result.Nodes.getNodeAs<Stmt>("invalid-conversion")) {
+ diag(Call->getLocStart(), "function %0 has suspicious implicit cast")
+ << Decl;
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.h
new file mode 100644
index 0000000..38a9d9c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.h
@@ -0,0 +1,40 @@
+//===--- SuspiciousStringCompareCheck.h - clang-tidy-------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSSTRINGCOMPARECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSSTRINGCOMPARECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Find suspicious calls to string compare functions.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-string-compare.html
+class SuspiciousStringCompareCheck : public ClangTidyCheck {
+public:
+ SuspiciousStringCompareCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const bool WarnOnImplicitComparison;
+ const bool WarnOnLogicalNotComparison;
+ const std::string StringCompareLikeFunctions;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSSTRINGCOMPARECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp
new file mode 100644
index 0000000..64d3eaf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp
@@ -0,0 +1,102 @@
+//===--- SwappedArgumentsCheck.cpp - clang-tidy ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SwappedArgumentsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/FixIt.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void SwappedArgumentsCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(callExpr().bind("call"), this);
+}
+
+/// \brief Look through lvalue to rvalue and nop casts. This filters out
+/// implicit conversions that have no effect on the input but block our view for
+/// other implicit casts.
+static const Expr *ignoreNoOpCasts(const Expr *E) {
+ if (auto *Cast = dyn_cast<CastExpr>(E))
+ if (Cast->getCastKind() == CK_LValueToRValue ||
+ Cast->getCastKind() == CK_NoOp)
+ return ignoreNoOpCasts(Cast->getSubExpr());
+ return E;
+}
+
+/// \brief Restrict the warning to implicit casts that are most likely
+/// accidental. User defined or integral conversions fit in this category,
+/// lvalue to rvalue or derived to base does not.
+static bool isImplicitCastCandidate(const CastExpr *Cast) {
+ return Cast->getCastKind() == CK_UserDefinedConversion ||
+ Cast->getCastKind() == CK_FloatingToBoolean ||
+ Cast->getCastKind() == CK_FloatingToIntegral ||
+ Cast->getCastKind() == CK_IntegralToBoolean ||
+ Cast->getCastKind() == CK_IntegralToFloating ||
+ Cast->getCastKind() == CK_MemberPointerToBoolean ||
+ Cast->getCastKind() == CK_PointerToBoolean;
+}
+
+void SwappedArgumentsCheck::check(const MatchFinder::MatchResult &Result) {
+ const ASTContext &Ctx = *Result.Context;
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+
+ llvm::SmallPtrSet<const Expr *, 4> UsedArgs;
+ for (unsigned I = 1, E = Call->getNumArgs(); I < E; ++I) {
+ const Expr *LHS = Call->getArg(I - 1);
+ const Expr *RHS = Call->getArg(I);
+
+ // Only need to check RHS, as LHS has already been covered. We don't want to
+ // emit two warnings for a single argument.
+ if (UsedArgs.count(RHS))
+ continue;
+
+ const auto *LHSCast = dyn_cast<ImplicitCastExpr>(ignoreNoOpCasts(LHS));
+ const auto *RHSCast = dyn_cast<ImplicitCastExpr>(ignoreNoOpCasts(RHS));
+
+ // Look if this is a potentially swapped argument pair. First look for
+ // implicit casts.
+ if (!LHSCast || !RHSCast || !isImplicitCastCandidate(LHSCast) ||
+ !isImplicitCastCandidate(RHSCast))
+ continue;
+
+ // If the types that go into the implicit casts match the types of the other
+ // argument in the declaration there is a high probability that the
+ // arguments were swapped.
+ // TODO: We could make use of the edit distance between the argument name
+ // and the name of the passed variable in addition to this type based
+ // heuristic.
+ const Expr *LHSFrom = ignoreNoOpCasts(LHSCast->getSubExpr());
+ const Expr *RHSFrom = ignoreNoOpCasts(RHSCast->getSubExpr());
+ if (LHS->getType() == RHS->getType() ||
+ LHS->getType() != RHSFrom->getType() ||
+ RHS->getType() != LHSFrom->getType())
+ continue;
+
+ // Emit a warning and fix-its that swap the arguments.
+ diag(Call->getLocStart(), "argument with implicit conversion from %0 "
+ "to %1 followed by argument converted from "
+ "%2 to %3, potentially swapped arguments.")
+ << LHS->getType() << LHSFrom->getType() << RHS->getType()
+ << RHSFrom->getType()
+ << tooling::fixit::createReplacement(*LHS, *RHS, Ctx)
+ << tooling::fixit::createReplacement(*RHS, *LHS, Ctx);
+
+ // Remember that we emitted a warning for this argument.
+ UsedArgs.insert(RHSCast);
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.h
new file mode 100644
index 0000000..59ec3ad
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.h
@@ -0,0 +1,32 @@
+//===--- SwappedArgumentsCheck.h - clang-tidy -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SWAPPEDARGUMENTSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SWAPPEDARGUMENTSCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds potentially swapped arguments by looking at implicit conversions.
+class SwappedArgumentsCheck : public ClangTidyCheck {
+public:
+ SwappedArgumentsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SWAPPEDARGUMENTSCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/TerminatingContinueCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/TerminatingContinueCheck.cpp
new file mode 100644
index 0000000..3e11e06
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/TerminatingContinueCheck.cpp
@@ -0,0 +1,49 @@
+//===--- TerminatingContinueCheck.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TerminatingContinueCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void TerminatingContinueCheck::registerMatchers(MatchFinder *Finder) {
+ const auto doWithFalse =
+ doStmt(hasCondition(ignoringImpCasts(
+ anyOf(cxxBoolLiteral(equals(false)), integerLiteral(equals(0)),
+ cxxNullPtrLiteralExpr(), gnuNullExpr()))),
+ equalsBoundNode("closestLoop"));
+
+ Finder->addMatcher(
+ continueStmt(hasAncestor(stmt(anyOf(forStmt(), whileStmt(),
+ cxxForRangeStmt(), doStmt()))
+ .bind("closestLoop")),
+ hasAncestor(doWithFalse))
+ .bind("continue"),
+ this);
+}
+
+void TerminatingContinueCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *ContStmt = Result.Nodes.getNodeAs<ContinueStmt>("continue");
+
+ auto Diag =
+ diag(ContStmt->getLocStart(),
+ "'continue' in loop with false condition is equivalent to 'break'")
+ << tooling::fixit::createReplacement(*ContStmt, "break");
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/TerminatingContinueCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/TerminatingContinueCheck.h
new file mode 100644
index 0000000..5985693
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/TerminatingContinueCheck.h
@@ -0,0 +1,36 @@
+//===--- TerminatingContinueCheck.h - clang-tidy-----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_TERMINATINGCONTINUECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_TERMINATINGCONTINUECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Checks if a 'continue' statement terminates the loop (i.e. the loop has
+/// a condition which always evaluates to false).
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-terminating-continue.html
+class TerminatingContinueCheck : public ClangTidyCheck {
+public:
+ TerminatingContinueCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_TERMINATINGCONTINUECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
new file mode 100644
index 0000000..350cf3b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.cpp
@@ -0,0 +1,52 @@
+//===--- ThrowKeywordMissingCheck.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ThrowKeywordMissingCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void ThrowKeywordMissingCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ auto CtorInitializerList =
+ cxxConstructorDecl(hasAnyConstructorInitializer(anything()));
+
+ Finder->addMatcher(
+ expr(anyOf(cxxFunctionalCastExpr(), cxxBindTemporaryExpr(),
+ cxxTemporaryObjectExpr()),
+ hasType(cxxRecordDecl(
+ isSameOrDerivedFrom(matchesName("[Ee]xception|EXCEPTION")))),
+ unless(anyOf(hasAncestor(stmt(
+ anyOf(cxxThrowExpr(), callExpr(), returnStmt()))),
+ hasAncestor(varDecl()),
+ allOf(hasAncestor(CtorInitializerList),
+ unless(hasAncestor(cxxCatchStmt()))))))
+ .bind("temporary-exception-not-thrown"),
+ this);
+}
+
+void ThrowKeywordMissingCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *TemporaryExpr =
+ Result.Nodes.getNodeAs<Expr>("temporary-exception-not-thrown");
+
+ diag(TemporaryExpr->getLocStart(), "suspicious exception object created but "
+ "not thrown; did you mean 'throw %0'?")
+ << TemporaryExpr->getType().getBaseTypeIdentifier()->getName();
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.h
new file mode 100644
index 0000000..cc57083
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/ThrowKeywordMissingCheck.h
@@ -0,0 +1,36 @@
+//===--- ThrowKeywordMissingCheck.h - clang-tidy-----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_THROWKEYWORDMISSINGCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_THROWKEYWORDMISSINGCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Emits a warning about temporary objects whose type is (or is derived from) a
+/// class that has 'EXCEPTION', 'Exception' or 'exception' in its name.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-throw-keyword-missing.html
+class ThrowKeywordMissingCheck : public ClangTidyCheck {
+public:
+ ThrowKeywordMissingCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_THROWKEYWORDMISSINGCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp
new file mode 100644
index 0000000..ebfe517
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.cpp
@@ -0,0 +1,71 @@
+//===--- UndefinedMemoryManipulationCheck.cpp - clang-tidy-----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UndefinedMemoryManipulationCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+AST_MATCHER(CXXRecordDecl, isNotTriviallyCopyable) {
+ // For incomplete types, assume they are TriviallyCopyable.
+ return Node.hasDefinition() ? !Node.isTriviallyCopyable() : false;
+}
+} // namespace
+
+void UndefinedMemoryManipulationCheck::registerMatchers(MatchFinder *Finder) {
+ const auto NotTriviallyCopyableObject =
+ hasType(ast_matchers::hasCanonicalType(
+ pointsTo(cxxRecordDecl(isNotTriviallyCopyable()))));
+
+ // Check whether destination object is not TriviallyCopyable.
+ // Applicable to all three memory manipulation functions.
+ Finder->addMatcher(callExpr(callee(functionDecl(hasAnyName(
+ "::memset", "::memcpy", "::memmove"))),
+ hasArgument(0, NotTriviallyCopyableObject))
+ .bind("dest"),
+ this);
+
+ // Check whether source object is not TriviallyCopyable.
+ // Only applicable to memcpy() and memmove().
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasAnyName("::memcpy", "::memmove"))),
+ hasArgument(1, NotTriviallyCopyableObject))
+ .bind("src"),
+ this);
+}
+
+void UndefinedMemoryManipulationCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ if (const auto *Call = Result.Nodes.getNodeAs<CallExpr>("dest")) {
+ QualType DestType = Call->getArg(0)->IgnoreImplicit()->getType();
+ if (!DestType->getPointeeType().isNull())
+ DestType = DestType->getPointeeType();
+ diag(Call->getLocStart(), "undefined behavior, destination object type %0 "
+ "is not TriviallyCopyable")
+ << DestType;
+ }
+ if (const auto *Call = Result.Nodes.getNodeAs<CallExpr>("src")) {
+ QualType SourceType = Call->getArg(1)->IgnoreImplicit()->getType();
+ if (!SourceType->getPointeeType().isNull())
+ SourceType = SourceType->getPointeeType();
+ diag(Call->getLocStart(),
+ "undefined behavior, source object type %0 is not TriviallyCopyable")
+ << SourceType;
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.h
new file mode 100644
index 0000000..64d6c56
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UndefinedMemoryManipulationCheck.h
@@ -0,0 +1,37 @@
+//===--- UndefinedMemoryManipulationCheck.h - clang-tidy---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNDEFINED_MEMORY_MANIPULATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNDEFINED_MEMORY_MANIPULATION_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds calls of memory manipulation functions ``memset()``, ``memcpy()`` and
+/// ``memmove()`` on not TriviallyCopyable objects resulting in undefined
+/// behavior.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-undefined-memory-manipulation.html
+class UndefinedMemoryManipulationCheck : public ClangTidyCheck {
+public:
+ UndefinedMemoryManipulationCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNDEFINED_MEMORY_MANIPULATION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UndelegatedConstructorCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UndelegatedConstructorCheck.cpp
new file mode 100644
index 0000000..f47ad7e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UndelegatedConstructorCheck.cpp
@@ -0,0 +1,84 @@
+//===--- UndelegatedConstructorCheck.cpp - clang-tidy --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UndelegatedConstructorCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+AST_MATCHER_P(Stmt, ignoringTemporaryExpr,
+ ast_matchers::internal::Matcher<Stmt>, InnerMatcher) {
+ const Stmt *E = &Node;
+ for (;;) {
+ // Temporaries with non-trivial dtors.
+ if (const auto *EWC = dyn_cast<ExprWithCleanups>(E))
+ E = EWC->getSubExpr();
+ // Temporaries with zero or more than two ctor arguments.
+ else if (const auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
+ E = BTE->getSubExpr();
+ // Temporaries with exactly one ctor argument.
+ else if (const auto *FCE = dyn_cast<CXXFunctionalCastExpr>(E))
+ E = FCE->getSubExpr();
+ else
+ break;
+ }
+
+ return InnerMatcher.matches(*E, Finder, Builder);
+}
+
+// Finds a node if it's a base of an already bound node.
+AST_MATCHER_P(CXXRecordDecl, baseOfBoundNode, std::string, ID) {
+ return Builder->removeBindings(
+ [&](const ast_matchers::internal::BoundNodesMap &Nodes) {
+ const auto *Derived = Nodes.getNodeAs<CXXRecordDecl>(ID);
+ return Derived != &Node && !Derived->isDerivedFrom(&Node);
+ });
+}
+} // namespace
+
+void UndelegatedConstructorCheck::registerMatchers(MatchFinder *Finder) {
+ // We look for calls to constructors of the same type in constructors. To do
+ // this we have to look through a variety of nodes that occur in the path,
+ // depending on the type's destructor and the number of arguments on the
+ // constructor call, this is handled by ignoringTemporaryExpr. Ignore template
+ // instantiations to reduce the number of duplicated warnings.
+ //
+ // Only register the matchers for C++11; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ Finder->addMatcher(
+ compoundStmt(
+ hasParent(
+ cxxConstructorDecl(ofClass(cxxRecordDecl().bind("parent")))),
+ forEach(ignoringTemporaryExpr(
+ cxxConstructExpr(hasDeclaration(cxxConstructorDecl(ofClass(
+ cxxRecordDecl(baseOfBoundNode("parent"))))))
+ .bind("construct"))),
+ unless(isInTemplateInstantiation())),
+ this);
+}
+
+void UndelegatedConstructorCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *E = Result.Nodes.getNodeAs<CXXConstructExpr>("construct");
+ diag(E->getLocStart(), "did you intend to call a delegated constructor? "
+ "A temporary object is created here instead");
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UndelegatedConstructorCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UndelegatedConstructorCheck.h
new file mode 100644
index 0000000..ed881e1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UndelegatedConstructorCheck.h
@@ -0,0 +1,36 @@
+//===--- UndelegatedConstructorCheck.h - clang-tidy -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNDELEGATEDCONSTRUCTOR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNDELEGATEDCONSTRUCTOR_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds creation of temporary objects in constructors that look like a
+/// function call to another constructor of the same class.
+///
+/// The user most likely meant to use a delegating constructor or base class
+/// initializer.
+class UndelegatedConstructorCheck : public ClangTidyCheck {
+public:
+ UndelegatedConstructorCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNDELEGATEDCONSTRUCTOR_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
new file mode 100644
index 0000000..e2882f3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp
@@ -0,0 +1,94 @@
+//===--- UnusedRaiiCheck.cpp - clang-tidy ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnusedRaiiCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+AST_MATCHER(CXXRecordDecl, hasNonTrivialDestructor) {
+ // TODO: If the dtor is there but empty we don't want to warn either.
+ return Node.hasDefinition() && Node.hasNonTrivialDestructor();
+}
+} // namespace
+
+void UnusedRaiiCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // Look for temporaries that are constructed in-place and immediately
+ // destroyed. Look for temporaries created by a functional cast but not for
+ // those returned from a call.
+ auto BindTemp =
+ cxxBindTemporaryExpr(unless(has(ignoringParenImpCasts(callExpr()))))
+ .bind("temp");
+ Finder->addMatcher(
+ exprWithCleanups(unless(isInTemplateInstantiation()),
+ hasParent(compoundStmt().bind("compound")),
+ hasType(cxxRecordDecl(hasNonTrivialDestructor())),
+ anyOf(has(ignoringParenImpCasts(BindTemp)),
+ has(ignoringParenImpCasts(cxxFunctionalCastExpr(
+ has(ignoringParenImpCasts(BindTemp)))))))
+ .bind("expr"),
+ this);
+}
+
+void UnusedRaiiCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *E = Result.Nodes.getNodeAs<Expr>("expr");
+
+ // We ignore code expanded from macros to reduce the number of false
+ // positives.
+ if (E->getLocStart().isMacroID())
+ return;
+
+ // Don't emit a warning for the last statement in the surrounding compund
+ // statement.
+ const auto *CS = Result.Nodes.getNodeAs<CompoundStmt>("compound");
+ if (E == CS->body_back())
+ return;
+
+ // Emit a warning.
+ auto D = diag(E->getLocStart(), "object destroyed immediately after "
+ "creation; did you mean to name the object?");
+ const char *Replacement = " give_me_a_name";
+
+ // If this is a default ctor we have to remove the parens or we'll introduce a
+ // most vexing parse.
+ const auto *BTE = Result.Nodes.getNodeAs<CXXBindTemporaryExpr>("temp");
+ if (const auto *TOE = dyn_cast<CXXTemporaryObjectExpr>(BTE->getSubExpr()))
+ if (TOE->getNumArgs() == 0) {
+ D << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(TOE->getParenOrBraceRange()),
+ Replacement);
+ return;
+ }
+
+ // Otherwise just suggest adding a name. To find the place to insert the name
+ // find the first TypeLoc in the children of E, which always points to the
+ // written type.
+ auto Matches =
+ match(expr(hasDescendant(typeLoc().bind("t"))), *E, *Result.Context);
+ const auto *TL = selectFirst<TypeLoc>("t", Matches);
+ D << FixItHint::CreateInsertion(
+ Lexer::getLocForEndOfToken(TL->getLocEnd(), 0, *Result.SourceManager,
+ getLangOpts()),
+ Replacement);
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.h
new file mode 100644
index 0000000..34190ec
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.h
@@ -0,0 +1,35 @@
+//===--- UnusedRaiiCheck.h - clang-tidy -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDRAIICHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDRAIICHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds temporaries that look like RAII objects.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-unused-raii.html
+class UnusedRaiiCheck : public ClangTidyCheck {
+public:
+ UnusedRaiiCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDRAIICHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.cpp
new file mode 100644
index 0000000..d0c5885
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.cpp
@@ -0,0 +1,100 @@
+//===--- UnusedReturnValueCheck.cpp - clang-tidy---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnusedReturnValueCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::ast_matchers::internal;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+
+// Matches functions that are instantiated from a class template member function
+// matching InnerMatcher. Functions not instantiated from a class template
+// member function are matched directly with InnerMatcher.
+AST_MATCHER_P(FunctionDecl, isInstantiatedFrom, Matcher<FunctionDecl>,
+ InnerMatcher) {
+ FunctionDecl *InstantiatedFrom = Node.getInstantiatedFromMemberFunction();
+ return InnerMatcher.matches(InstantiatedFrom ? *InstantiatedFrom : Node,
+ Finder, Builder);
+}
+
+} // namespace
+
+UnusedReturnValueCheck::UnusedReturnValueCheck(llvm::StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ CheckedFunctions(Options.get("CheckedFunctions",
+ "::std::async;"
+ "::std::launder;"
+ "::std::remove;"
+ "::std::remove_if;"
+ "::std::unique;"
+ "::std::unique_ptr::release;"
+ "::std::basic_string::empty;"
+ "::std::vector::empty")) {}
+
+void UnusedReturnValueCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "CheckedFunctions", CheckedFunctions);
+}
+
+void UnusedReturnValueCheck::registerMatchers(MatchFinder *Finder) {
+ auto FunVec = utils::options::parseStringList(CheckedFunctions);
+ auto MatchedCallExpr = expr(ignoringImplicit(ignoringParenImpCasts(
+ callExpr(callee(functionDecl(
+ // Don't match void overloads of checked functions.
+ unless(returns(voidType())),
+ isInstantiatedFrom(hasAnyName(
+ std::vector<StringRef>(FunVec.begin(), FunVec.end()))))))
+ .bind("match"))));
+
+ auto UnusedInCompoundStmt =
+ compoundStmt(forEach(MatchedCallExpr),
+ // The checker can't currently differentiate between the
+ // return statement and other statements inside GNU statement
+ // expressions, so disable the checker inside them to avoid
+ // false positives.
+ unless(hasParent(stmtExpr())));
+ auto UnusedInIfStmt =
+ ifStmt(eachOf(hasThen(MatchedCallExpr), hasElse(MatchedCallExpr)));
+ auto UnusedInWhileStmt = whileStmt(hasBody(MatchedCallExpr));
+ auto UnusedInDoStmt = doStmt(hasBody(MatchedCallExpr));
+ auto UnusedInForStmt =
+ forStmt(eachOf(hasLoopInit(MatchedCallExpr),
+ hasIncrement(MatchedCallExpr), hasBody(MatchedCallExpr)));
+ auto UnusedInRangeForStmt = cxxForRangeStmt(hasBody(MatchedCallExpr));
+ auto UnusedInCaseStmt = switchCase(forEach(MatchedCallExpr));
+
+ Finder->addMatcher(
+ stmt(anyOf(UnusedInCompoundStmt, UnusedInIfStmt, UnusedInWhileStmt,
+ UnusedInDoStmt, UnusedInForStmt, UnusedInRangeForStmt,
+ UnusedInCaseStmt)),
+ this);
+}
+
+void UnusedReturnValueCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *Matched = Result.Nodes.getNodeAs<CallExpr>("match")) {
+ diag(Matched->getLocStart(),
+ "the value returned by this function should be used")
+ << Matched->getSourceRange();
+ diag(Matched->getLocStart(),
+ "cast the expression to void to silence this warning",
+ DiagnosticIDs::Note);
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.h
new file mode 100644
index 0000000..9475f56
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.h
@@ -0,0 +1,39 @@
+//===--- UnusedReturnValueCheck.h - clang-tidy-------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDRETURNVALUECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDRETURNVALUECHECK_H
+
+#include "../ClangTidy.h"
+#include <string>
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Detects function calls where the return value is unused.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-unused-return-value.html
+class UnusedReturnValueCheck : public ClangTidyCheck {
+public:
+ UnusedReturnValueCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ std::string CheckedFunctions;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDRETURNVALUECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
new file mode 100644
index 0000000..6fa4cab
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -0,0 +1,434 @@
+//===--- UseAfterMoveCheck.cpp - clang-tidy -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseAfterMoveCheck.h"
+
+#include "clang/Analysis/CFG.h"
+#include "clang/Lex/Lexer.h"
+
+#include "../utils/ExprSequence.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::tidy::utils;
+
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+
+/// Contains information about a use-after-move.
+struct UseAfterMove {
+ // The DeclRefExpr that constituted the use of the object.
+ const DeclRefExpr *DeclRef;
+
+ // Is the order in which the move and the use are evaluated undefined?
+ bool EvaluationOrderUndefined;
+};
+
+/// Finds uses of a variable after a move (and maintains state required by the
+/// various internal helper functions).
+class UseAfterMoveFinder {
+public:
+ UseAfterMoveFinder(ASTContext *TheContext);
+
+ // Within the given function body, finds the first use of 'MovedVariable' that
+ // occurs after 'MovingCall' (the expression that performs the move). If a
+ // use-after-move is found, writes information about it to 'TheUseAfterMove'.
+ // Returns whether a use-after-move was found.
+ bool find(Stmt *FunctionBody, const Expr *MovingCall,
+ const ValueDecl *MovedVariable, UseAfterMove *TheUseAfterMove);
+
+private:
+ bool findInternal(const CFGBlock *Block, const Expr *MovingCall,
+ const ValueDecl *MovedVariable,
+ UseAfterMove *TheUseAfterMove);
+ void getUsesAndReinits(const CFGBlock *Block, const ValueDecl *MovedVariable,
+ llvm::SmallVectorImpl<const DeclRefExpr *> *Uses,
+ llvm::SmallPtrSetImpl<const Stmt *> *Reinits);
+ void getDeclRefs(const CFGBlock *Block, const Decl *MovedVariable,
+ llvm::SmallPtrSetImpl<const DeclRefExpr *> *DeclRefs);
+ void getReinits(const CFGBlock *Block, const ValueDecl *MovedVariable,
+ llvm::SmallPtrSetImpl<const Stmt *> *Stmts,
+ llvm::SmallPtrSetImpl<const DeclRefExpr *> *DeclRefs);
+
+ ASTContext *Context;
+ std::unique_ptr<ExprSequence> Sequence;
+ std::unique_ptr<StmtToBlockMap> BlockMap;
+ llvm::SmallPtrSet<const CFGBlock *, 8> Visited;
+};
+
+} // namespace
+
+
+// Matches nodes that are
+// - Part of a decltype argument or class template argument (we check this by
+// seeing if they are children of a TypeLoc), or
+// - Part of a function template argument (we check this by seeing if they are
+// children of a DeclRefExpr that references a function template).
+// DeclRefExprs that fulfill these conditions should not be counted as a use or
+// move.
+static StatementMatcher inDecltypeOrTemplateArg() {
+ return anyOf(hasAncestor(typeLoc()),
+ hasAncestor(declRefExpr(
+ to(functionDecl(ast_matchers::isTemplateInstantiation())))));
+}
+
+UseAfterMoveFinder::UseAfterMoveFinder(ASTContext *TheContext)
+ : Context(TheContext) {}
+
+bool UseAfterMoveFinder::find(Stmt *FunctionBody, const Expr *MovingCall,
+ const ValueDecl *MovedVariable,
+ UseAfterMove *TheUseAfterMove) {
+ // Generate the CFG manually instead of through an AnalysisDeclContext because
+ // it seems the latter can't be used to generate a CFG for the body of a
+ // labmda.
+ //
+ // We include implicit and temporary destructors in the CFG so that
+ // destructors marked [[noreturn]] are handled correctly in the control flow
+ // analysis. (These are used in some styles of assertion macros.)
+ CFG::BuildOptions Options;
+ Options.AddImplicitDtors = true;
+ Options.AddTemporaryDtors = true;
+ std::unique_ptr<CFG> TheCFG =
+ CFG::buildCFG(nullptr, FunctionBody, Context, Options);
+ if (!TheCFG)
+ return false;
+
+ Sequence.reset(new ExprSequence(TheCFG.get(), Context));
+ BlockMap.reset(new StmtToBlockMap(TheCFG.get(), Context));
+ Visited.clear();
+
+ const CFGBlock *Block = BlockMap->blockContainingStmt(MovingCall);
+ if (!Block)
+ return false;
+
+ return findInternal(Block, MovingCall, MovedVariable, TheUseAfterMove);
+}
+
+bool UseAfterMoveFinder::findInternal(const CFGBlock *Block,
+ const Expr *MovingCall,
+ const ValueDecl *MovedVariable,
+ UseAfterMove *TheUseAfterMove) {
+ if (Visited.count(Block))
+ return false;
+
+ // Mark the block as visited (except if this is the block containing the
+ // std::move() and it's being visited the first time).
+ if (!MovingCall)
+ Visited.insert(Block);
+
+ // Get all uses and reinits in the block.
+ llvm::SmallVector<const DeclRefExpr *, 1> Uses;
+ llvm::SmallPtrSet<const Stmt *, 1> Reinits;
+ getUsesAndReinits(Block, MovedVariable, &Uses, &Reinits);
+
+ // Ignore all reinitializations where the move potentially comes after the
+ // reinit.
+ llvm::SmallVector<const Stmt *, 1> ReinitsToDelete;
+ for (const Stmt *Reinit : Reinits) {
+ if (MovingCall && Sequence->potentiallyAfter(MovingCall, Reinit))
+ ReinitsToDelete.push_back(Reinit);
+ }
+ for (const Stmt *Reinit : ReinitsToDelete) {
+ Reinits.erase(Reinit);
+ }
+
+ // Find all uses that potentially come after the move.
+ for (const DeclRefExpr *Use : Uses) {
+ if (!MovingCall || Sequence->potentiallyAfter(Use, MovingCall)) {
+ // Does the use have a saving reinit? A reinit is saving if it definitely
+ // comes before the use, i.e. if there's no potential that the reinit is
+ // after the use.
+ bool HaveSavingReinit = false;
+ for (const Stmt *Reinit : Reinits) {
+ if (!Sequence->potentiallyAfter(Reinit, Use))
+ HaveSavingReinit = true;
+ }
+
+ if (!HaveSavingReinit) {
+ TheUseAfterMove->DeclRef = Use;
+
+ // Is this a use-after-move that depends on order of evaluation?
+ // This is the case if the move potentially comes after the use (and we
+ // already know that use potentially comes after the move, which taken
+ // together tells us that the ordering is unclear).
+ TheUseAfterMove->EvaluationOrderUndefined =
+ MovingCall != nullptr &&
+ Sequence->potentiallyAfter(MovingCall, Use);
+
+ return true;
+ }
+ }
+ }
+
+ // If the object wasn't reinitialized, call ourselves recursively on all
+ // successors.
+ if (Reinits.empty()) {
+ for (const auto &Succ : Block->succs()) {
+ if (Succ && findInternal(Succ, nullptr, MovedVariable, TheUseAfterMove))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void UseAfterMoveFinder::getUsesAndReinits(
+ const CFGBlock *Block, const ValueDecl *MovedVariable,
+ llvm::SmallVectorImpl<const DeclRefExpr *> *Uses,
+ llvm::SmallPtrSetImpl<const Stmt *> *Reinits) {
+ llvm::SmallPtrSet<const DeclRefExpr *, 1> DeclRefs;
+ llvm::SmallPtrSet<const DeclRefExpr *, 1> ReinitDeclRefs;
+
+ getDeclRefs(Block, MovedVariable, &DeclRefs);
+ getReinits(Block, MovedVariable, Reinits, &ReinitDeclRefs);
+
+ // All references to the variable that aren't reinitializations are uses.
+ Uses->clear();
+ for (const DeclRefExpr *DeclRef : DeclRefs) {
+ if (!ReinitDeclRefs.count(DeclRef))
+ Uses->push_back(DeclRef);
+ }
+
+ // Sort the uses by their occurrence in the source code.
+ std::sort(Uses->begin(), Uses->end(),
+ [](const DeclRefExpr *D1, const DeclRefExpr *D2) {
+ return D1->getExprLoc() < D2->getExprLoc();
+ });
+}
+
+bool isStandardSmartPointer(const ValueDecl *VD) {
+ const Type *TheType = VD->getType().getTypePtrOrNull();
+ if (!TheType)
+ return false;
+
+ const CXXRecordDecl *RecordDecl = TheType->getAsCXXRecordDecl();
+ if (!RecordDecl)
+ return false;
+
+ const IdentifierInfo *ID = RecordDecl->getIdentifier();
+ if (!ID)
+ return false;
+
+ StringRef Name = ID->getName();
+ if (Name != "unique_ptr" && Name != "shared_ptr" && Name != "weak_ptr")
+ return false;
+
+ return RecordDecl->getDeclContext()->isStdNamespace();
+}
+
+void UseAfterMoveFinder::getDeclRefs(
+ const CFGBlock *Block, const Decl *MovedVariable,
+ llvm::SmallPtrSetImpl<const DeclRefExpr *> *DeclRefs) {
+ DeclRefs->clear();
+ for (const auto &Elem : *Block) {
+ Optional<CFGStmt> S = Elem.getAs<CFGStmt>();
+ if (!S)
+ continue;
+
+ auto addDeclRefs = [this, Block,
+ DeclRefs](const ArrayRef<BoundNodes> Matches) {
+ for (const auto &Match : Matches) {
+ const auto *DeclRef = Match.getNodeAs<DeclRefExpr>("declref");
+ const auto *Operator = Match.getNodeAs<CXXOperatorCallExpr>("operator");
+ if (DeclRef && BlockMap->blockContainingStmt(DeclRef) == Block) {
+ // Ignore uses of a standard smart pointer that don't dereference the
+ // pointer.
+ if (Operator || !isStandardSmartPointer(DeclRef->getDecl())) {
+ DeclRefs->insert(DeclRef);
+ }
+ }
+ }
+ };
+
+ auto DeclRefMatcher = declRefExpr(hasDeclaration(equalsNode(MovedVariable)),
+ unless(inDecltypeOrTemplateArg()))
+ .bind("declref");
+
+ addDeclRefs(match(findAll(DeclRefMatcher), *S->getStmt(), *Context));
+ addDeclRefs(match(
+ findAll(cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("*"),
+ hasOverloadedOperatorName("->"),
+ hasOverloadedOperatorName("[]")),
+ hasArgument(0, DeclRefMatcher))
+ .bind("operator")),
+ *S->getStmt(), *Context));
+ }
+}
+
+void UseAfterMoveFinder::getReinits(
+ const CFGBlock *Block, const ValueDecl *MovedVariable,
+ llvm::SmallPtrSetImpl<const Stmt *> *Stmts,
+ llvm::SmallPtrSetImpl<const DeclRefExpr *> *DeclRefs) {
+ auto DeclRefMatcher =
+ declRefExpr(hasDeclaration(equalsNode(MovedVariable))).bind("declref");
+
+ auto StandardContainerTypeMatcher = hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(cxxRecordDecl(hasAnyName(
+ "::std::basic_string", "::std::vector", "::std::deque",
+ "::std::forward_list", "::std::list", "::std::set", "::std::map",
+ "::std::multiset", "::std::multimap", "::std::unordered_set",
+ "::std::unordered_map", "::std::unordered_multiset",
+ "::std::unordered_multimap"))))));
+
+ auto StandardSmartPointerTypeMatcher = hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(cxxRecordDecl(hasAnyName(
+ "::std::unique_ptr", "::std::shared_ptr", "::std::weak_ptr"))))));
+
+ // Matches different types of reinitialization.
+ auto ReinitMatcher =
+ stmt(anyOf(
+ // Assignment. In addition to the overloaded assignment operator,
+ // test for built-in assignment as well, since template functions
+ // may be instantiated to use std::move() on built-in types.
+ binaryOperator(hasOperatorName("="), hasLHS(DeclRefMatcher)),
+ cxxOperatorCallExpr(hasOverloadedOperatorName("="),
+ hasArgument(0, DeclRefMatcher)),
+ // Declaration. We treat this as a type of reinitialization too,
+ // so we don't need to treat it separately.
+ declStmt(hasDescendant(equalsNode(MovedVariable))),
+ // clear() and assign() on standard containers.
+ cxxMemberCallExpr(
+ on(allOf(DeclRefMatcher, StandardContainerTypeMatcher)),
+ // To keep the matcher simple, we check for assign() calls
+ // on all standard containers, even though only vector,
+ // deque, forward_list and list have assign(). If assign()
+ // is called on any of the other containers, this will be
+ // flagged by a compile error anyway.
+ callee(cxxMethodDecl(hasAnyName("clear", "assign")))),
+ // reset() on standard smart pointers.
+ cxxMemberCallExpr(
+ on(allOf(DeclRefMatcher, StandardSmartPointerTypeMatcher)),
+ callee(cxxMethodDecl(hasName("reset")))),
+ // Passing variable to a function as a non-const pointer.
+ callExpr(forEachArgumentWithParam(
+ unaryOperator(hasOperatorName("&"),
+ hasUnaryOperand(DeclRefMatcher)),
+ unless(parmVarDecl(hasType(pointsTo(isConstQualified())))))),
+ // Passing variable to a function as a non-const lvalue reference
+ // (unless that function is std::move()).
+ callExpr(forEachArgumentWithParam(
+ DeclRefMatcher,
+ unless(parmVarDecl(hasType(
+ references(qualType(isConstQualified())))))),
+ unless(callee(functionDecl(hasName("::std::move")))))))
+ .bind("reinit");
+
+ Stmts->clear();
+ DeclRefs->clear();
+ for (const auto &Elem : *Block) {
+ Optional<CFGStmt> S = Elem.getAs<CFGStmt>();
+ if (!S)
+ continue;
+
+ SmallVector<BoundNodes, 1> Matches =
+ match(findAll(ReinitMatcher), *S->getStmt(), *Context);
+
+ for (const auto &Match : Matches) {
+ const auto *TheStmt = Match.getNodeAs<Stmt>("reinit");
+ const auto *TheDeclRef = Match.getNodeAs<DeclRefExpr>("declref");
+ if (TheStmt && BlockMap->blockContainingStmt(TheStmt) == Block) {
+ Stmts->insert(TheStmt);
+
+ // We count DeclStmts as reinitializations, but they don't have a
+ // DeclRefExpr associated with them -- so we need to check 'TheDeclRef'
+ // before adding it to the set.
+ if (TheDeclRef)
+ DeclRefs->insert(TheDeclRef);
+ }
+ }
+ }
+}
+
+static void emitDiagnostic(const Expr *MovingCall, const DeclRefExpr *MoveArg,
+ const UseAfterMove &Use, ClangTidyCheck *Check,
+ ASTContext *Context) {
+ SourceLocation UseLoc = Use.DeclRef->getExprLoc();
+ SourceLocation MoveLoc = MovingCall->getExprLoc();
+
+ Check->diag(UseLoc, "'%0' used after it was moved")
+ << MoveArg->getDecl()->getName();
+ Check->diag(MoveLoc, "move occurred here", DiagnosticIDs::Note);
+ if (Use.EvaluationOrderUndefined) {
+ Check->diag(UseLoc,
+ "the use and move are unsequenced, i.e. there is no guarantee "
+ "about the order in which they are evaluated",
+ DiagnosticIDs::Note);
+ } else if (UseLoc < MoveLoc || Use.DeclRef == MoveArg) {
+ Check->diag(UseLoc,
+ "the use happens in a later loop iteration than the move",
+ DiagnosticIDs::Note);
+ }
+}
+
+void UseAfterMoveCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ auto CallMoveMatcher =
+ callExpr(callee(functionDecl(hasName("::std::move"))), argumentCountIs(1),
+ hasArgument(0, declRefExpr().bind("arg")),
+ anyOf(hasAncestor(lambdaExpr().bind("containing-lambda")),
+ hasAncestor(functionDecl().bind("containing-func"))),
+ unless(inDecltypeOrTemplateArg()))
+ .bind("call-move");
+
+ Finder->addMatcher(
+ // To find the Stmt that we assume performs the actual move, we look for
+ // the direct ancestor of the std::move() that isn't one of the node
+ // types ignored by ignoringParenImpCasts().
+ stmt(forEach(expr(ignoringParenImpCasts(CallMoveMatcher))),
+ // Don't allow an InitListExpr to be the moving call. An InitListExpr
+ // has both a syntactic and a semantic form, and the parent-child
+ // relationships are different between the two. This could cause an
+ // InitListExpr to be analyzed as the moving call in addition to the
+ // Expr that we actually want, resulting in two diagnostics with
+ // different code locations for the same move.
+ unless(initListExpr()),
+ unless(expr(ignoringParenImpCasts(equalsBoundNode("call-move")))))
+ .bind("moving-call"),
+ this);
+}
+
+void UseAfterMoveCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *ContainingLambda =
+ Result.Nodes.getNodeAs<LambdaExpr>("containing-lambda");
+ const auto *ContainingFunc =
+ Result.Nodes.getNodeAs<FunctionDecl>("containing-func");
+ const auto *CallMove = Result.Nodes.getNodeAs<CallExpr>("call-move");
+ const auto *MovingCall = Result.Nodes.getNodeAs<Expr>("moving-call");
+ const auto *Arg = Result.Nodes.getNodeAs<DeclRefExpr>("arg");
+
+ if (!MovingCall || !MovingCall->getExprLoc().isValid())
+ MovingCall = CallMove;
+
+ Stmt *FunctionBody = nullptr;
+ if (ContainingLambda)
+ FunctionBody = ContainingLambda->getBody();
+ else if (ContainingFunc)
+ FunctionBody = ContainingFunc->getBody();
+ else
+ return;
+
+ // Ignore the std::move if the variable that was passed to it isn't a local
+ // variable.
+ if (!Arg->getDecl()->getDeclContext()->isFunctionOrMethod())
+ return;
+
+ UseAfterMoveFinder finder(Result.Context);
+ UseAfterMove Use;
+ if (finder.find(FunctionBody, MovingCall, Arg->getDecl(), &Use))
+ emitDiagnostic(MovingCall, Arg, Use, this, Result.Context);
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.h
new file mode 100644
index 0000000..f6dea68
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.h
@@ -0,0 +1,36 @@
+//===--- UseAfterMoveCheck.h - clang-tidy ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_USEAFTERMOVECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_USEAFTERMOVECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// The check warns if an object is used after it has been moved, without an
+/// intervening reinitialization.
+///
+/// For details, see the user-facing documentation:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-use-after-move.html
+class UseAfterMoveCheck : public ClangTidyCheck {
+public:
+ UseAfterMoveCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_USEAFTERMOVECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp
new file mode 100644
index 0000000..bb9c9b6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp
@@ -0,0 +1,276 @@
+//===--- VirtualNearMissCheck.cpp - clang-tidy-----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "VirtualNearMissCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+namespace {
+AST_MATCHER(CXXMethodDecl, isStatic) { return Node.isStatic(); }
+
+AST_MATCHER(CXXMethodDecl, isOverloadedOperator) {
+ return Node.isOverloadedOperator();
+}
+} // namespace
+
+/// Finds out if the given method overrides some method.
+static bool isOverrideMethod(const CXXMethodDecl *MD) {
+ return MD->size_overridden_methods() > 0 || MD->hasAttr<OverrideAttr>();
+}
+
+/// Checks whether the return types are covariant, according to
+/// C++[class.virtual]p7.
+///
+/// Similar with clang::Sema::CheckOverridingFunctionReturnType.
+/// \returns true if the return types of BaseMD and DerivedMD are covariant.
+static bool checkOverridingFunctionReturnType(const ASTContext *Context,
+ const CXXMethodDecl *BaseMD,
+ const CXXMethodDecl *DerivedMD) {
+ QualType BaseReturnTy = BaseMD->getType()
+ ->getAs<FunctionType>()
+ ->getReturnType()
+ .getCanonicalType();
+ QualType DerivedReturnTy = DerivedMD->getType()
+ ->getAs<FunctionType>()
+ ->getReturnType()
+ .getCanonicalType();
+
+ if (DerivedReturnTy->isDependentType() || BaseReturnTy->isDependentType())
+ return false;
+
+ // Check if return types are identical.
+ if (Context->hasSameType(DerivedReturnTy, BaseReturnTy))
+ return true;
+
+ /// Check if the return types are covariant.
+
+ // Both types must be pointers or references to classes.
+ if (!(BaseReturnTy->isPointerType() && DerivedReturnTy->isPointerType()) &&
+ !(BaseReturnTy->isReferenceType() && DerivedReturnTy->isReferenceType()))
+ return false;
+
+ /// BTy is the class type in return type of BaseMD. For example,
+ /// B* Base::md()
+ /// While BRD is the declaration of B.
+ QualType DTy = DerivedReturnTy->getPointeeType().getCanonicalType();
+ QualType BTy = BaseReturnTy->getPointeeType().getCanonicalType();
+
+ const CXXRecordDecl *DRD = DTy->getAsCXXRecordDecl();
+ const CXXRecordDecl *BRD = BTy->getAsCXXRecordDecl();
+ if (DRD == nullptr || BRD == nullptr)
+ return false;
+
+ if (!DRD->hasDefinition() || !BRD->hasDefinition())
+ return false;
+
+ if (DRD == BRD)
+ return true;
+
+ if (!Context->hasSameUnqualifiedType(DTy, BTy)) {
+ // Begin checking whether the conversion from D to B is valid.
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+
+ // Check whether D is derived from B, and fill in a CXXBasePaths object.
+ if (!DRD->isDerivedFrom(BRD, Paths))
+ return false;
+
+ // Check ambiguity.
+ if (Paths.isAmbiguous(Context->getCanonicalType(BTy).getUnqualifiedType()))
+ return false;
+
+ // Check accessibility.
+ // FIXME: We currently only support checking if B is accessible base class
+ // of D, or D is the same class which DerivedMD is in.
+ bool IsItself =
+ DRD->getCanonicalDecl() == DerivedMD->getParent()->getCanonicalDecl();
+ bool HasPublicAccess = false;
+ for (const auto &Path : Paths) {
+ if (Path.Access == AS_public)
+ HasPublicAccess = true;
+ }
+ if (!HasPublicAccess && !IsItself)
+ return false;
+ // End checking conversion from D to B.
+ }
+
+ // Both pointers or references should have the same cv-qualification.
+ if (DerivedReturnTy.getLocalCVRQualifiers() !=
+ BaseReturnTy.getLocalCVRQualifiers())
+ return false;
+
+ // The class type D should have the same cv-qualification as or less
+ // cv-qualification than the class type B.
+ if (DTy.isMoreQualifiedThan(BTy))
+ return false;
+
+ return true;
+}
+
+/// \returns decayed type for arrays and functions.
+static QualType getDecayedType(QualType Type) {
+ if (const auto *Decayed = Type->getAs<DecayedType>())
+ return Decayed->getDecayedType();
+ return Type;
+}
+
+/// \returns true if the param types are the same.
+static bool checkParamTypes(const CXXMethodDecl *BaseMD,
+ const CXXMethodDecl *DerivedMD) {
+ unsigned NumParamA = BaseMD->getNumParams();
+ unsigned NumParamB = DerivedMD->getNumParams();
+ if (NumParamA != NumParamB)
+ return false;
+
+ for (unsigned I = 0; I < NumParamA; I++) {
+ if (getDecayedType(BaseMD->getParamDecl(I)->getType().getCanonicalType()) !=
+ getDecayedType(
+ DerivedMD->getParamDecl(I)->getType().getCanonicalType()))
+ return false;
+ }
+ return true;
+}
+
+/// \returns true if derived method can override base method except for the
+/// name.
+static bool checkOverrideWithoutName(const ASTContext *Context,
+ const CXXMethodDecl *BaseMD,
+ const CXXMethodDecl *DerivedMD) {
+ if (BaseMD->isStatic() != DerivedMD->isStatic())
+ return false;
+
+ if (BaseMD->getType() == DerivedMD->getType())
+ return true;
+
+ // Now the function types are not identical. Then check if the return types
+ // are covariant and if the param types are the same.
+ if (!checkOverridingFunctionReturnType(Context, BaseMD, DerivedMD))
+ return false;
+ return checkParamTypes(BaseMD, DerivedMD);
+}
+
+/// Check whether BaseMD overrides DerivedMD.
+///
+/// Prerequisite: the class which BaseMD is in should be a base class of that
+/// DerivedMD is in.
+static bool checkOverrideByDerivedMethod(const CXXMethodDecl *BaseMD,
+ const CXXMethodDecl *DerivedMD) {
+ for (CXXMethodDecl::method_iterator I = DerivedMD->begin_overridden_methods(),
+ E = DerivedMD->end_overridden_methods();
+ I != E; ++I) {
+ const CXXMethodDecl *OverriddenMD = *I;
+ if (BaseMD->getCanonicalDecl() == OverriddenMD->getCanonicalDecl())
+ return true;
+ }
+
+ return false;
+}
+
+bool VirtualNearMissCheck::isPossibleToBeOverridden(
+ const CXXMethodDecl *BaseMD) {
+ auto Iter = PossibleMap.find(BaseMD);
+ if (Iter != PossibleMap.end())
+ return Iter->second;
+
+ bool IsPossible = !BaseMD->isImplicit() && !isa<CXXConstructorDecl>(BaseMD) &&
+ !isa<CXXDestructorDecl>(BaseMD) && BaseMD->isVirtual() &&
+ !BaseMD->isOverloadedOperator() &&
+ !isa<CXXConversionDecl>(BaseMD);
+ PossibleMap[BaseMD] = IsPossible;
+ return IsPossible;
+}
+
+bool VirtualNearMissCheck::isOverriddenByDerivedClass(
+ const CXXMethodDecl *BaseMD, const CXXRecordDecl *DerivedRD) {
+ auto Key = std::make_pair(BaseMD, DerivedRD);
+ auto Iter = OverriddenMap.find(Key);
+ if (Iter != OverriddenMap.end())
+ return Iter->second;
+
+ bool IsOverridden = false;
+ for (const CXXMethodDecl *DerivedMD : DerivedRD->methods()) {
+ if (!isOverrideMethod(DerivedMD))
+ continue;
+
+ if (checkOverrideByDerivedMethod(BaseMD, DerivedMD)) {
+ IsOverridden = true;
+ break;
+ }
+ }
+ OverriddenMap[Key] = IsOverridden;
+ return IsOverridden;
+}
+
+void VirtualNearMissCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(
+ cxxMethodDecl(
+ unless(anyOf(isOverride(), isImplicit(), cxxConstructorDecl(),
+ cxxDestructorDecl(), cxxConversionDecl(), isStatic(),
+ isOverloadedOperator())))
+ .bind("method"),
+ this);
+}
+
+void VirtualNearMissCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *DerivedMD = Result.Nodes.getNodeAs<CXXMethodDecl>("method");
+ assert(DerivedMD);
+
+ const ASTContext *Context = Result.Context;
+
+ const auto *DerivedRD = DerivedMD->getParent()->getDefinition();
+ assert(DerivedRD);
+
+ for (const auto &BaseSpec : DerivedRD->bases()) {
+ if (const auto *BaseRD = BaseSpec.getType()->getAsCXXRecordDecl()) {
+ for (const auto *BaseMD : BaseRD->methods()) {
+ if (!isPossibleToBeOverridden(BaseMD))
+ continue;
+
+ if (isOverriddenByDerivedClass(BaseMD, DerivedRD))
+ continue;
+
+ unsigned EditDistance = BaseMD->getName().edit_distance(
+ DerivedMD->getName(), EditDistanceThreshold);
+ if (EditDistance > 0 && EditDistance <= EditDistanceThreshold) {
+ if (checkOverrideWithoutName(Context, BaseMD, DerivedMD)) {
+ // A "virtual near miss" is found.
+ auto Range = CharSourceRange::getTokenRange(
+ SourceRange(DerivedMD->getLocation()));
+
+ bool ApplyFix = !BaseMD->isTemplateInstantiation() &&
+ !DerivedMD->isTemplateInstantiation();
+ auto Diag =
+ diag(DerivedMD->getLocStart(),
+ "method '%0' has a similar name and the same signature as "
+ "virtual method '%1'; did you mean to override it?")
+ << DerivedMD->getQualifiedNameAsString()
+ << BaseMD->getQualifiedNameAsString();
+ if (ApplyFix)
+ Diag << FixItHint::CreateReplacement(Range, BaseMD->getName());
+ }
+ }
+ }
+ }
+ }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.h
new file mode 100644
index 0000000..ea1e256
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.h
@@ -0,0 +1,65 @@
+//===--- VirtualNearMissCheck.h - clang-tidy---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_VIRTUAL_NEAR_MISS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_VIRTUAL_NEAR_MISS_H
+
+#include "../ClangTidy.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// \brief Checks for near miss of virtual methods.
+///
+/// For a method in a derived class, this check looks for virtual method with a
+/// very similar name and an identical signature defined in a base class.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-virtual-near-miss.html
+class VirtualNearMissCheck : public ClangTidyCheck {
+public:
+ VirtualNearMissCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ /// Check if the given method is possible to be overridden by some other
+ /// method. Operators and destructors are excluded.
+ ///
+ /// Results are memoized in PossibleMap.
+ bool isPossibleToBeOverridden(const CXXMethodDecl *BaseMD);
+
+ /// Check if the given base method is overridden by some methods in the given
+ /// derived class.
+ ///
+ /// Results are memoized in OverriddenMap.
+ bool isOverriddenByDerivedClass(const CXXMethodDecl *BaseMD,
+ const CXXRecordDecl *DerivedRD);
+
+ /// Key: the unique ID of a method.
+ /// Value: whether the method is possible to be overridden.
+ llvm::DenseMap<const CXXMethodDecl *, bool> PossibleMap;
+
+ /// Key: <unique ID of base method, name of derived class>
+ /// Value: whether the base method is overridden by some method in the derived
+ /// class.
+ llvm::DenseMap<std::pair<const CXXMethodDecl *, const CXXRecordDecl *>, bool>
+ OverriddenMap;
+
+ const unsigned EditDistanceThreshold = 1;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_VIRTUAL_NEAR_MISS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
new file mode 100644
index 0000000..da09932
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
@@ -0,0 +1,95 @@
+//===--- CERTTidyModule.cpp - clang-tidy ----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "../google/UnnamedNamespaceInHeaderCheck.h"
+#include "../misc/NewDeleteOverloadsCheck.h"
+#include "../misc/NonCopyableObjects.h"
+#include "../misc/StaticAssertCheck.h"
+#include "../misc/ThrowByValueCatchByReferenceCheck.h"
+#include "../performance/MoveConstructorInitCheck.h"
+#include "CommandProcessorCheck.h"
+#include "DontModifyStdNamespaceCheck.h"
+#include "FloatLoopCounter.h"
+#include "LimitedRandomnessCheck.h"
+#include "PostfixOperatorCheck.h"
+#include "ProperlySeededRandomGeneratorCheck.h"
+#include "SetLongJmpCheck.h"
+#include "StaticObjectExceptionCheck.h"
+#include "StrToNumCheck.h"
+#include "ThrownExceptionTypeCheck.h"
+#include "VariadicFunctionDefCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+class CERTModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ // C++ checkers
+ // DCL
+ CheckFactories.registerCheck<PostfixOperatorCheck>(
+ "cert-dcl21-cpp");
+ CheckFactories.registerCheck<VariadicFunctionDefCheck>("cert-dcl50-cpp");
+ CheckFactories.registerCheck<misc::NewDeleteOverloadsCheck>(
+ "cert-dcl54-cpp");
+ CheckFactories.registerCheck<DontModifyStdNamespaceCheck>(
+ "cert-dcl58-cpp");
+ CheckFactories.registerCheck<google::build::UnnamedNamespaceInHeaderCheck>(
+ "cert-dcl59-cpp");
+ // OOP
+ CheckFactories.registerCheck<performance::MoveConstructorInitCheck>(
+ "cert-oop11-cpp");
+ // ERR
+ CheckFactories.registerCheck<misc::ThrowByValueCatchByReferenceCheck>(
+ "cert-err09-cpp");
+ CheckFactories.registerCheck<SetLongJmpCheck>("cert-err52-cpp");
+ CheckFactories.registerCheck<StaticObjectExceptionCheck>("cert-err58-cpp");
+ CheckFactories.registerCheck<ThrownExceptionTypeCheck>("cert-err60-cpp");
+ CheckFactories.registerCheck<misc::ThrowByValueCatchByReferenceCheck>(
+ "cert-err61-cpp");
+ // MSC
+ CheckFactories.registerCheck<LimitedRandomnessCheck>("cert-msc50-cpp");
+ CheckFactories.registerCheck<ProperlySeededRandomGeneratorCheck>(
+ "cert-msc51-cpp");
+
+ // C checkers
+ // DCL
+ CheckFactories.registerCheck<misc::StaticAssertCheck>("cert-dcl03-c");
+ // ENV
+ CheckFactories.registerCheck<CommandProcessorCheck>("cert-env33-c");
+ // FLP
+ CheckFactories.registerCheck<FloatLoopCounter>("cert-flp30-c");
+ // FIO
+ CheckFactories.registerCheck<misc::NonCopyableObjectsCheck>("cert-fio38-c");
+ // ERR
+ CheckFactories.registerCheck<StrToNumCheck>("cert-err34-c");
+ // MSC
+ CheckFactories.registerCheck<LimitedRandomnessCheck>("cert-msc30-c");
+ CheckFactories.registerCheck<ProperlySeededRandomGeneratorCheck>(
+ "cert-msc32-c");
+ }
+};
+
+} // namespace cert
+
+// Register the MiscTidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<cert::CERTModule>
+ X("cert-module",
+ "Adds lint checks corresponding to CERT secure coding guidelines.");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the CERTModule.
+volatile int CERTModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/CMakeLists.txt
new file mode 100644
index 0000000..edc93c8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/CMakeLists.txt
@@ -0,0 +1,28 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyCERTModule
+ CERTTidyModule.cpp
+ CommandProcessorCheck.cpp
+ DontModifyStdNamespaceCheck.cpp
+ FloatLoopCounter.cpp
+ LimitedRandomnessCheck.cpp
+ PostfixOperatorCheck.cpp
+ ProperlySeededRandomGeneratorCheck.cpp
+ SetLongJmpCheck.cpp
+ StaticObjectExceptionCheck.cpp
+ StrToNumCheck.cpp
+ ThrownExceptionTypeCheck.cpp
+ VariadicFunctionDefCheck.cpp
+
+ LINK_LIBS
+ clangAnalysis
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyGoogleModule
+ clangTidyMiscModule
+ clangTidyPerformanceModule
+ clangTidyUtils
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/CommandProcessorCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/CommandProcessorCheck.cpp
new file mode 100644
index 0000000..e2dbeca
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/CommandProcessorCheck.cpp
@@ -0,0 +1,45 @@
+//===--- Env33CCheck.cpp - clang-tidy--------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandProcessorCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+void CommandProcessorCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ callExpr(
+ callee(functionDecl(anyOf(hasName("::system"), hasName("::popen"),
+ hasName("::_popen")))
+ .bind("func")),
+ // Do not diagnose when the call expression passes a null pointer
+ // constant to system(); that only checks for the presence of a
+ // command processor, which is not a security risk by itself.
+ unless(callExpr(callee(functionDecl(hasName("::system"))),
+ argumentCountIs(1),
+ hasArgument(0, nullPointerConstant()))))
+ .bind("expr"),
+ this);
+}
+
+void CommandProcessorCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Fn = Result.Nodes.getNodeAs<FunctionDecl>("func");
+ const auto *E = Result.Nodes.getNodeAs<CallExpr>("expr");
+
+ diag(E->getExprLoc(), "calling %0 uses a command processor") << Fn;
+}
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/CommandProcessorCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/CommandProcessorCheck.h
new file mode 100644
index 0000000..a85a7ed
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/CommandProcessorCheck.h
@@ -0,0 +1,38 @@
+//===--- CommandInterpreterCheck.h - clang-tidy------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_COMMAND_PROCESSOR_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_COMMAND_PROCESSOR_CHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+/// Execution of a command processor can lead to security vulnerabilities,
+/// and is generally not required. Instead, prefer to launch executables
+/// directly via mechanisms that give you more control over what executable is
+/// actually launched.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-env33-c.html
+class CommandProcessorCheck : public ClangTidyCheck {
+public:
+ CommandProcessorCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_COMMAND_PROCESSOR_CHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/DontModifyStdNamespaceCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/DontModifyStdNamespaceCheck.cpp
new file mode 100644
index 0000000..e5759a5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/DontModifyStdNamespaceCheck.cpp
@@ -0,0 +1,49 @@
+//===--- DontModifyStdNamespaceCheck.cpp - clang-tidy----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DontModifyStdNamespaceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+void DontModifyStdNamespaceCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(
+ namespaceDecl(unless(isExpansionInSystemHeader()),
+ anyOf(hasName("std"), hasName("posix")),
+ has(decl(unless(anyOf(
+ functionDecl(isExplicitTemplateSpecialization()),
+ cxxRecordDecl(isExplicitTemplateSpecialization()))))))
+ .bind("nmspc"),
+ this);
+}
+
+void DontModifyStdNamespaceCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *N = Result.Nodes.getNodeAs<NamespaceDecl>("nmspc");
+
+ // Only consider top level namespaces.
+ if (N->getParent() != Result.Context->getTranslationUnitDecl())
+ return;
+
+ diag(N->getLocation(),
+ "modification of %0 namespace can result in undefined behavior")
+ << N;
+}
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/DontModifyStdNamespaceCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/DontModifyStdNamespaceCheck.h
new file mode 100644
index 0000000..0cc23f7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/DontModifyStdNamespaceCheck.h
@@ -0,0 +1,36 @@
+//===--- DontModifyStdNamespaceCheck.h - clang-tidy--------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_DONT_MODIFY_STD_NAMESPACE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_DONT_MODIFY_STD_NAMESPACE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+/// Modification of the std or posix namespace can result in undefined behavior.
+/// This check warns for such modifications.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-msc53-cpp.html
+class DontModifyStdNamespaceCheck : public ClangTidyCheck {
+public:
+ DontModifyStdNamespaceCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_DONT_MODIFY_STD_NAMESPACE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/FloatLoopCounter.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/FloatLoopCounter.cpp
new file mode 100644
index 0000000..e92552e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/FloatLoopCounter.cpp
@@ -0,0 +1,35 @@
+//===--- FloatLoopCounter.cpp - clang-tidy---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FloatLoopCounter.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+void FloatLoopCounter::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ forStmt(hasIncrement(expr(hasType(realFloatingPointType())))).bind("for"),
+ this);
+}
+
+void FloatLoopCounter::check(const MatchFinder::MatchResult &Result) {
+ const auto *FS = Result.Nodes.getNodeAs<ForStmt>("for");
+
+ diag(FS->getInc()->getExprLoc(), "loop induction expression should not have "
+ "floating-point type");
+}
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/FloatLoopCounter.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/FloatLoopCounter.h
new file mode 100644
index 0000000..c66e44a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/FloatLoopCounter.h
@@ -0,0 +1,37 @@
+//===--- FloatLoopCounter.h - clang-tidy-------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_FLOAT_LOOP_COUNTER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_FLOAT_LOOP_COUNTER_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+/// This check diagnoses when the loop induction expression of a for loop has
+/// floating-point type. The check corresponds to:
+/// https://www.securecoding.cert.org/confluence/display/c/FLP30-C.+Do+not+use+floating-point+variables+as+loop+counters
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-flp30-c.html
+class FloatLoopCounter : public ClangTidyCheck {
+public:
+ FloatLoopCounter(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_FLOAT_LOOP_COUNTER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/LICENSE.TXT b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/LICENSE.TXT
new file mode 100644
index 0000000..d8395cc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/LICENSE.TXT
@@ -0,0 +1,22 @@
+------------------------------------------------------------------------------
+clang-tidy CERT Files
+------------------------------------------------------------------------------
+All clang-tidy files are licensed under the LLVM license with the following
+additions:
+
+Any file referencing a CERT Secure Coding guideline:
+Please allow this letter to serve as confirmation that open source projects on
+http://llvm.org are permitted to link via hypertext to the CERT(R) secure coding
+guidelines available at https://www.securecoding.cert.org.
+
+The foregoing is permitted by the Terms of Use as follows:
+"Linking to the Service
+Because we update many of our Web documents regularly, we would prefer that you
+link to our Web pages whenever possible rather than reproduce them. It is not
+necessary to request permission to make referential hypertext links to The
+Service."
+http://www.sei.cmu.edu/legal/ip/index.cfm.
+
+Please allow this letter to also confirm that no formal permission is required
+to reproduce the title of the content being linked to, nor to reproduce any
+de Minimis description of such content.
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/LimitedRandomnessCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/LimitedRandomnessCheck.cpp
new file mode 100644
index 0000000..f319f9f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/LimitedRandomnessCheck.cpp
@@ -0,0 +1,38 @@
+//===--- LimitedRandomnessCheck.cpp - clang-tidy---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LimitedRandomnessCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+void LimitedRandomnessCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(callExpr(callee(functionDecl(namedDecl(hasName("::rand")),
+ parameterCountIs(0))))
+ .bind("randomGenerator"),
+ this);
+}
+
+void LimitedRandomnessCheck::check(const MatchFinder::MatchResult &Result) {
+ std::string msg = "";
+ if (getLangOpts().CPlusPlus)
+ msg = "; use C++11 random library instead";
+
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<CallExpr>("randomGenerator");
+ diag(MatchedDecl->getLocStart(), "rand() has limited randomness" + msg);
+}
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/LimitedRandomnessCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/LimitedRandomnessCheck.h
new file mode 100644
index 0000000..59d511c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/LimitedRandomnessCheck.h
@@ -0,0 +1,38 @@
+//===--- LimitedRandomnessCheck.h - clang-tidy-------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_LIMITED_RANDOMNESS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_LIMITED_RANDOMNESS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+/// Pseudorandom number generators are not genuinely random. The result of the
+/// std::rand() function makes no guarantees as to the quality of the random
+/// sequence produced.
+/// This check warns for the usage of std::rand() function.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-msc50-cpp.html
+class LimitedRandomnessCheck : public ClangTidyCheck {
+public:
+ LimitedRandomnessCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_LIMITED_RANDOMNESS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/PostfixOperatorCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/PostfixOperatorCheck.cpp
new file mode 100644
index 0000000..2b8dbbe
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/PostfixOperatorCheck.cpp
@@ -0,0 +1,88 @@
+//===--- PostfixOperatorCheck.cpp - clang-tidy-----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PostfixOperatorCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+void PostfixOperatorCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(functionDecl(anyOf(hasOverloadedOperatorName("++"),
+ hasOverloadedOperatorName("--")))
+ .bind("decl"),
+ this);
+}
+
+void PostfixOperatorCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("decl");
+
+ bool HasThis = false;
+ if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FuncDecl))
+ HasThis = MethodDecl->isInstance();
+
+ // Check if the operator is a postfix one.
+ if (FuncDecl->getNumParams() != (HasThis ? 1 : 2))
+ return;
+
+ SourceRange ReturnRange = FuncDecl->getReturnTypeSourceRange();
+ SourceLocation Location = ReturnRange.getBegin();
+ if (!Location.isValid())
+ return;
+
+ QualType ReturnType = FuncDecl->getReturnType();
+
+ // Warn when the operators return a reference.
+ if (const auto *RefType = ReturnType->getAs<ReferenceType>()) {
+ auto Diag = diag(Location, "overloaded %0 returns a reference instead of a "
+ "constant object type")
+ << FuncDecl;
+
+ if (Location.isMacroID() || ReturnType->getAs<TypedefType>() ||
+ RefType->getPointeeTypeAsWritten()->getAs<TypedefType>())
+ return;
+
+ QualType ReplaceType =
+ ReturnType.getNonReferenceType().getLocalUnqualifiedType();
+ // The getReturnTypeSourceRange omits the qualifiers. We do not want to
+ // duplicate the const.
+ if (!ReturnType->getPointeeType().isConstQualified())
+ ReplaceType.addConst();
+
+ Diag << FixItHint::CreateReplacement(
+ ReturnRange,
+ ReplaceType.getAsString(Result.Context->getPrintingPolicy()) + " ");
+
+ return;
+ }
+
+ if (ReturnType.isConstQualified() || ReturnType->isBuiltinType() ||
+ ReturnType->isPointerType())
+ return;
+
+ auto Diag =
+ diag(Location, "overloaded %0 returns a non-constant object instead of a "
+ "constant object type")
+ << FuncDecl;
+
+ if (!Location.isMacroID() && !ReturnType->getAs<TypedefType>())
+ Diag << FixItHint::CreateInsertion(Location, "const ");
+}
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/PostfixOperatorCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/PostfixOperatorCheck.h
new file mode 100644
index 0000000..29c2306
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/PostfixOperatorCheck.h
@@ -0,0 +1,36 @@
+//===--- PostfixOperatorCheck.h - clang-tidy---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_POSTFIX_OPERATOR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_POSTFIX_OPERATOR_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+/// Checks if the overloaded postfix ++ and -- operator return a constant
+/// object.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-postfix-operator.html
+class PostfixOperatorCheck : public ClangTidyCheck {
+public:
+ PostfixOperatorCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_POSTFIX_OPERATOR_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/ProperlySeededRandomGeneratorCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/ProperlySeededRandomGeneratorCheck.cpp
new file mode 100644
index 0000000..256525e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/ProperlySeededRandomGeneratorCheck.cpp
@@ -0,0 +1,124 @@
+//===--- ProperlySeededRandomGeneratorCheck.cpp - clang-tidy---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProperlySeededRandomGeneratorCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+ProperlySeededRandomGeneratorCheck::ProperlySeededRandomGeneratorCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ RawDisallowedSeedTypes(
+ Options.get("DisallowedSeedTypes", "time_t,std::time_t")) {
+ StringRef(RawDisallowedSeedTypes).split(DisallowedSeedTypes, ',');
+}
+
+void ProperlySeededRandomGeneratorCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "DisallowedSeedTypes", RawDisallowedSeedTypes);
+}
+
+void ProperlySeededRandomGeneratorCheck::registerMatchers(MatchFinder *Finder) {
+ auto RandomGeneratorEngineDecl = cxxRecordDecl(hasAnyName(
+ "::std::linear_congruential_engine", "::std::mersenne_twister_engine",
+ "::std::subtract_with_carry_engine", "::std::discard_block_engine",
+ "::std::independent_bits_engine", "::std::shuffle_order_engine"));
+ auto RandomGeneratorEngineTypeMatcher = hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(RandomGeneratorEngineDecl))));
+
+ // std::mt19937 engine;
+ // engine.seed();
+ // ^
+ // engine.seed(1);
+ // ^
+ // const int x = 1;
+ // engine.seed(x);
+ // ^
+ Finder->addMatcher(
+ cxxMemberCallExpr(
+ has(memberExpr(has(declRefExpr(RandomGeneratorEngineTypeMatcher)),
+ member(hasName("seed")),
+ unless(hasDescendant(cxxThisExpr())))))
+ .bind("seed"),
+ this);
+
+ // std::mt19937 engine;
+ // ^
+ // std::mt19937 engine(1);
+ // ^
+ // const int x = 1;
+ // std::mt19937 engine(x);
+ // ^
+ Finder->addMatcher(
+ cxxConstructExpr(RandomGeneratorEngineTypeMatcher).bind("ctor"), this);
+
+ // srand();
+ // ^
+ // const int x = 1;
+ // srand(x);
+ // ^
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasAnyName("::srand", "::std::srand"))))
+ .bind("srand"),
+ this);
+}
+
+void ProperlySeededRandomGeneratorCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructExpr>("ctor");
+ if (Ctor)
+ checkSeed(Result, Ctor);
+
+ const auto *Func = Result.Nodes.getNodeAs<CXXMemberCallExpr>("seed");
+ if (Func)
+ checkSeed(Result, Func);
+
+ const auto *Srand = Result.Nodes.getNodeAs<CallExpr>("srand");
+ if (Srand)
+ checkSeed(Result, Srand);
+}
+
+template <class T>
+void ProperlySeededRandomGeneratorCheck::checkSeed(
+ const MatchFinder::MatchResult &Result, const T *Func) {
+ if (Func->getNumArgs() == 0 || Func->getArg(0)->isDefaultArgument()) {
+ diag(Func->getExprLoc(),
+ "random number generator seeded with a default argument will generate "
+ "a predictable sequence of values");
+ return;
+ }
+
+ llvm::APSInt Value;
+ if (Func->getArg(0)->EvaluateAsInt(Value, *Result.Context)) {
+ diag(Func->getExprLoc(),
+ "random number generator seeded with a constant value will generate a "
+ "predictable sequence of values");
+ return;
+ }
+
+ const std::string SeedType(
+ Func->getArg(0)->IgnoreCasts()->getType().getAsString());
+ if (llvm::find(DisallowedSeedTypes, SeedType) != DisallowedSeedTypes.end()) {
+ diag(Func->getExprLoc(),
+ "random number generator seeded with a disallowed source of seed "
+ "value will generate a predictable sequence of values");
+ return;
+ }
+}
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/ProperlySeededRandomGeneratorCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/ProperlySeededRandomGeneratorCheck.h
new file mode 100644
index 0000000..ac5507c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/ProperlySeededRandomGeneratorCheck.h
@@ -0,0 +1,47 @@
+//===--- ProperlySeededRandomGeneratorCheck.h - clang-tidy-------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_PROPERLY_SEEDED_RANDOM_GENERATOR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_PROPERLY_SEEDED_RANDOM_GENERATOR_H
+
+#include "../ClangTidy.h"
+#include <string>
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+/// Random number generator must be seeded properly.
+///
+/// A random number generator initialized with default value or a
+/// constant expression is a security vulnerability.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-properly-seeded-random-generator.html
+class ProperlySeededRandomGeneratorCheck : public ClangTidyCheck {
+public:
+ ProperlySeededRandomGeneratorCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ template <class T>
+ void checkSeed(const ast_matchers::MatchFinder::MatchResult &Result,
+ const T *Func);
+
+ std::string RawDisallowedSeedTypes;
+ SmallVector<StringRef, 5> DisallowedSeedTypes;
+};
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_PROPERLY_SEEDED_RANDOM_GENERATOR_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.cpp
new file mode 100644
index 0000000..89ba5e7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.cpp
@@ -0,0 +1,79 @@
+//===--- SetLongJmpCheck.cpp - clang-tidy----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SetLongJmpCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+const char SetLongJmpCheck::DiagWording[] =
+ "do not call %0; consider using exception handling instead";
+
+namespace {
+class SetJmpMacroCallbacks : public PPCallbacks {
+ SetLongJmpCheck &Check;
+
+public:
+ explicit SetJmpMacroCallbacks(SetLongJmpCheck &Check) : Check(Check) {}
+
+ void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
+ SourceRange Range, const MacroArgs *Args) override {
+ const auto *II = MacroNameTok.getIdentifierInfo();
+ if (!II)
+ return;
+
+ if (II->getName() == "setjmp")
+ Check.diag(Range.getBegin(), Check.DiagWording) << II;
+ }
+};
+} // namespace
+
+void SetLongJmpCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+ // This checker only applies to C++, where exception handling is a superior
+ // solution to setjmp/longjmp calls.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // Per [headers]p5, setjmp must be exposed as a macro instead of a function,
+ // despite the allowance in C for setjmp to also be an extern function.
+ Compiler.getPreprocessor().addPPCallbacks(
+ llvm::make_unique<SetJmpMacroCallbacks>(*this));
+}
+
+void SetLongJmpCheck::registerMatchers(MatchFinder *Finder) {
+ // This checker only applies to C++, where exception handling is a superior
+ // solution to setjmp/longjmp calls.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // In case there is an implementation that happens to define setjmp as a
+ // function instead of a macro, this will also catch use of it. However, we
+ // are primarily searching for uses of longjmp.
+ Finder->addMatcher(callExpr(callee(functionDecl(anyOf(hasName("setjmp"),
+ hasName("longjmp")))))
+ .bind("expr"),
+ this);
+}
+
+void SetLongJmpCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *E = Result.Nodes.getNodeAs<CallExpr>("expr");
+ diag(E->getExprLoc(), DiagWording) << cast<NamedDecl>(E->getCalleeDecl());
+}
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.h
new file mode 100644
index 0000000..1d6c098
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/SetLongJmpCheck.h
@@ -0,0 +1,38 @@
+//===--- SetLongJmpCheck.h - clang-tidy--------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SETLONGJMPCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SETLONGJMPCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+/// Guards against use of setjmp/longjmp in C++ code
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-err52-cpp.html
+class SetLongJmpCheck : public ClangTidyCheck {
+public:
+ SetLongJmpCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+
+ static const char DiagWording[];
+};
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SETLONGJMPCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/StaticObjectExceptionCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/StaticObjectExceptionCheck.cpp
new file mode 100644
index 0000000..45f9433
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/StaticObjectExceptionCheck.cpp
@@ -0,0 +1,60 @@
+//===--- StaticObjectExceptionCheck.cpp - clang-tidy-----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StaticObjectExceptionCheck.h"
+#include "../utils/Matchers.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+void StaticObjectExceptionCheck::registerMatchers(MatchFinder *Finder) {
+ if ((!getLangOpts().CPlusPlus) || (!getLangOpts().CXXExceptions))
+ return;
+
+ // Match any static or thread_local variable declaration that has an
+ // initializer that can throw.
+ Finder->addMatcher(
+ varDecl(anyOf(hasThreadStorageDuration(), hasStaticStorageDuration()),
+ unless(hasAncestor(functionDecl())),
+ anyOf(hasDescendant(cxxConstructExpr(hasDeclaration(
+ cxxConstructorDecl(unless(isNoThrow())).bind("func")))),
+ hasDescendant(cxxNewExpr(hasDeclaration(
+ functionDecl(unless(isNoThrow())).bind("func")))),
+ hasDescendant(callExpr(hasDeclaration(
+ functionDecl(unless(isNoThrow())).bind("func"))))))
+ .bind("var"),
+ this);
+}
+
+void StaticObjectExceptionCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *VD = Result.Nodes.getNodeAs<VarDecl>("var");
+ const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
+
+ diag(VD->getLocation(),
+ "initialization of %0 with %select{static|thread_local}1 storage "
+ "duration may throw an exception that cannot be caught")
+ << VD << (VD->getStorageDuration() == SD_Static ? 0 : 1);
+
+ SourceLocation FuncLocation = Func->getLocation();
+ if (FuncLocation.isValid()) {
+ diag(FuncLocation,
+ "possibly throwing %select{constructor|function}0 declared here",
+ DiagnosticIDs::Note)
+ << (isa<CXXConstructorDecl>(Func) ? 0 : 1);
+ }
+}
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/StaticObjectExceptionCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/StaticObjectExceptionCheck.h
new file mode 100644
index 0000000..463f433
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/StaticObjectExceptionCheck.h
@@ -0,0 +1,36 @@
+//===--- StaticObjectExceptionCheck.h - clang-tidy---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_ERR58_CPP_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_ERR58_CPP_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+/// Checks whether the constructor for a static or thread_local object will
+/// throw.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-err58-cpp.html
+class StaticObjectExceptionCheck : public ClangTidyCheck {
+public:
+ StaticObjectExceptionCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_ERR58_CPP_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/StrToNumCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/StrToNumCheck.cpp
new file mode 100644
index 0000000..bd84cf2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/StrToNumCheck.cpp
@@ -0,0 +1,235 @@
+//===--- Err34CCheck.cpp - clang-tidy--------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StrToNumCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Analysis/Analyses/FormatString.h"
+#include "llvm/ADT/StringSwitch.h"
+#include <cassert>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+void StrToNumCheck::registerMatchers(MatchFinder *Finder) {
+ // Match any function call to the C standard library string conversion
+ // functions that do no error checking.
+ Finder->addMatcher(
+ callExpr(
+ callee(functionDecl(anyOf(
+ functionDecl(hasAnyName("::atoi", "::atof", "::atol", "::atoll"))
+ .bind("converter"),
+ functionDecl(hasAnyName("::scanf", "::sscanf", "::fscanf",
+ "::vfscanf", "::vscanf", "::vsscanf"))
+ .bind("formatted")))))
+ .bind("expr"),
+ this);
+}
+
+namespace {
+enum class ConversionKind {
+ None,
+ ToInt,
+ ToUInt,
+ ToLongInt,
+ ToLongUInt,
+ ToIntMax,
+ ToUIntMax,
+ ToFloat,
+ ToDouble,
+ ToLongDouble
+};
+
+ConversionKind ClassifyConversionFunc(const FunctionDecl *FD) {
+ return llvm::StringSwitch<ConversionKind>(FD->getName())
+ .Cases("atoi", "atol", ConversionKind::ToInt)
+ .Case("atoll", ConversionKind::ToLongInt)
+ .Case("atof", ConversionKind::ToDouble)
+ .Default(ConversionKind::None);
+}
+
+ConversionKind ClassifyFormatString(StringRef Fmt, const LangOptions &LO,
+ const TargetInfo &TI) {
+ // Scan the format string for the first problematic format specifier, then
+ // report that as the conversion type. This will miss additional conversion
+ // specifiers, but that is acceptable behavior.
+
+ class Handler : public analyze_format_string::FormatStringHandler {
+ ConversionKind CK;
+
+ bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
+ const char *startSpecifier,
+ unsigned specifierLen) override {
+ // If we just consume the argument without assignment, we don't care
+ // about it having conversion errors.
+ if (!FS.consumesDataArgument())
+ return true;
+
+ // Get the conversion specifier and use it to determine the conversion
+ // kind.
+ analyze_scanf::ScanfConversionSpecifier SCS = FS.getConversionSpecifier();
+ if (SCS.isIntArg()) {
+ switch (FS.getLengthModifier().getKind()) {
+ case analyze_scanf::LengthModifier::AsLongLong:
+ CK = ConversionKind::ToLongInt;
+ break;
+ case analyze_scanf::LengthModifier::AsIntMax:
+ CK = ConversionKind::ToIntMax;
+ break;
+ default:
+ CK = ConversionKind::ToInt;
+ break;
+ }
+ } else if (SCS.isUIntArg()) {
+ switch (FS.getLengthModifier().getKind()) {
+ case analyze_scanf::LengthModifier::AsLongLong:
+ CK = ConversionKind::ToLongUInt;
+ break;
+ case analyze_scanf::LengthModifier::AsIntMax:
+ CK = ConversionKind::ToUIntMax;
+ break;
+ default:
+ CK = ConversionKind::ToUInt;
+ break;
+ }
+ } else if (SCS.isDoubleArg()) {
+ switch (FS.getLengthModifier().getKind()) {
+ case analyze_scanf::LengthModifier::AsLongDouble:
+ CK = ConversionKind::ToLongDouble;
+ break;
+ case analyze_scanf::LengthModifier::AsLong:
+ CK = ConversionKind::ToDouble;
+ break;
+ default:
+ CK = ConversionKind::ToFloat;
+ break;
+ }
+ }
+
+ // Continue if we have yet to find a conversion kind that we care about.
+ return CK == ConversionKind::None;
+ }
+
+ public:
+ Handler() : CK(ConversionKind::None) {}
+
+ ConversionKind get() const { return CK; }
+ };
+
+ Handler H;
+ analyze_format_string::ParseScanfString(H, Fmt.begin(), Fmt.end(), LO, TI);
+
+ return H.get();
+}
+
+StringRef ClassifyConversionType(ConversionKind K) {
+ switch (K) {
+ case ConversionKind::None:
+ assert(false && "Unexpected conversion kind");
+ case ConversionKind::ToInt:
+ case ConversionKind::ToLongInt:
+ case ConversionKind::ToIntMax:
+ return "an integer value";
+ case ConversionKind::ToUInt:
+ case ConversionKind::ToLongUInt:
+ case ConversionKind::ToUIntMax:
+ return "an unsigned integer value";
+ case ConversionKind::ToFloat:
+ case ConversionKind::ToDouble:
+ case ConversionKind::ToLongDouble:
+ return "a floating-point value";
+ }
+ llvm_unreachable("Unknown conversion kind");
+}
+
+StringRef ClassifyReplacement(ConversionKind K) {
+ switch (K) {
+ case ConversionKind::None:
+ assert(false && "Unexpected conversion kind");
+ case ConversionKind::ToInt:
+ return "strtol";
+ case ConversionKind::ToUInt:
+ return "strtoul";
+ case ConversionKind::ToIntMax:
+ return "strtoimax";
+ case ConversionKind::ToLongInt:
+ return "strtoll";
+ case ConversionKind::ToLongUInt:
+ return "strtoull";
+ case ConversionKind::ToUIntMax:
+ return "strtoumax";
+ case ConversionKind::ToFloat:
+ return "strtof";
+ case ConversionKind::ToDouble:
+ return "strtod";
+ case ConversionKind::ToLongDouble:
+ return "strtold";
+ }
+ llvm_unreachable("Unknown conversion kind");
+}
+} // unnamed namespace
+
+void StrToNumCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("expr");
+ const FunctionDecl *FuncDecl = nullptr;
+ ConversionKind Conversion;
+
+ if (const auto *ConverterFunc =
+ Result.Nodes.getNodeAs<FunctionDecl>("converter")) {
+ // Converter functions are always incorrect to use.
+ FuncDecl = ConverterFunc;
+ Conversion = ClassifyConversionFunc(ConverterFunc);
+ } else if (const auto *FFD =
+ Result.Nodes.getNodeAs<FunctionDecl>("formatted")) {
+ StringRef FmtStr;
+ // The format string comes from the call expression and depends on which
+ // flavor of scanf is called.
+ // Index 0: scanf, vscanf, Index 1: fscanf, sscanf, vfscanf, vsscanf.
+ unsigned Idx =
+ (FFD->getName() == "scanf" || FFD->getName() == "vscanf") ? 0 : 1;
+
+ // Given the index, see if the call expression argument at that index is
+ // a string literal.
+ if (Call->getNumArgs() < Idx)
+ return;
+
+ if (const Expr *Arg = Call->getArg(Idx)->IgnoreParenImpCasts()) {
+ if (const auto *SL = dyn_cast<StringLiteral>(Arg)) {
+ FmtStr = SL->getString();
+ }
+ }
+
+ // If we could not get the format string, bail out.
+ if (FmtStr.empty())
+ return;
+
+ // Formatted input functions need further checking of the format string to
+ // determine whether a problematic conversion may be happening.
+ Conversion = ClassifyFormatString(FmtStr, getLangOpts(),
+ Result.Context->getTargetInfo());
+ if (Conversion != ConversionKind::None)
+ FuncDecl = FFD;
+ }
+
+ if (!FuncDecl)
+ return;
+
+ diag(Call->getExprLoc(),
+ "%0 used to convert a string to %1, but function will not report "
+ "conversion errors; consider using '%2' instead")
+ << FuncDecl << ClassifyConversionType(Conversion)
+ << ClassifyReplacement(Conversion);
+}
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/StrToNumCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/StrToNumCheck.h
new file mode 100644
index 0000000..55f13be
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/StrToNumCheck.h
@@ -0,0 +1,36 @@
+//===--- StrToNumCheck.h - clang-tidy----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_STRTONUMCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_STRTONUMCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+/// Guards against use of string conversion functions that do not have
+/// reasonable error handling for conversion errors.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-err34-c.html
+class StrToNumCheck : public ClangTidyCheck {
+public:
+ StrToNumCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_STRTONUMCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/ThrownExceptionTypeCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/ThrownExceptionTypeCheck.cpp
new file mode 100644
index 0000000..37fb355
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/ThrownExceptionTypeCheck.cpp
@@ -0,0 +1,41 @@
+//===--- ThrownExceptionTypeCheck.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ThrownExceptionTypeCheck.h"
+#include "../utils/Matchers.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+void ThrownExceptionTypeCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(
+ cxxThrowExpr(has(ignoringParenImpCasts(
+ cxxConstructExpr(hasDeclaration(cxxConstructorDecl(
+ isCopyConstructor(), unless(isNoThrow()))))
+ .bind("expr")))),
+ this);
+}
+
+void ThrownExceptionTypeCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *E = Result.Nodes.getNodeAs<Expr>("expr");
+ diag(E->getExprLoc(),
+ "thrown exception type is not nothrow copy constructible");
+}
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/ThrownExceptionTypeCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/ThrownExceptionTypeCheck.h
new file mode 100644
index 0000000..2f9d887
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/ThrownExceptionTypeCheck.h
@@ -0,0 +1,35 @@
+//===--- ThrownExceptionTypeCheck.h - clang-tidy-----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_THROWNEXCEPTIONTYPECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_THROWNEXCEPTIONTYPECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+/// Checks whether a thrown object is nothrow copy constructible.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-err60-cpp.html
+class ThrownExceptionTypeCheck : public ClangTidyCheck {
+public:
+ ThrownExceptionTypeCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_THROWNEXCEPTIONTYPECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/VariadicFunctionDefCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/VariadicFunctionDefCheck.cpp
new file mode 100644
index 0000000..ea6112a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/VariadicFunctionDefCheck.cpp
@@ -0,0 +1,42 @@
+//===--- VariadicfunctiondefCheck.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "VariadicFunctionDefCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+void VariadicFunctionDefCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // We only care about function *definitions* that are variadic, and do not
+ // have extern "C" language linkage.
+ Finder->addMatcher(
+ functionDecl(isDefinition(), isVariadic(), unless(isExternC()))
+ .bind("func"),
+ this);
+}
+
+void VariadicFunctionDefCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("func");
+
+ diag(FD->getLocation(),
+ "do not define a C-style variadic function; consider using a function "
+ "parameter pack or currying instead");
+}
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/VariadicFunctionDefCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/VariadicFunctionDefCheck.h
new file mode 100644
index 0000000..e215e8d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cert/VariadicFunctionDefCheck.h
@@ -0,0 +1,35 @@
+//===--- VariadicFunctionDefCheck.h - clang-tidy-----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_VARIADICFUNCTIONDEF_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_VARIADICFUNCTIONDEF_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+/// Guards against any C-style variadic function definitions (not declarations).
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-dcl50-cpp.html
+class VariadicFunctionDefCheck : public ClangTidyCheck {
+public:
+ VariadicFunctionDefCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_VARIADICFUNCTIONDEF_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.cpp
new file mode 100644
index 0000000..3e800cd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.cpp
@@ -0,0 +1,57 @@
+//===--- AvoidGotoCheck.cpp - clang-tidy-----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AvoidGotoCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+namespace {
+AST_MATCHER(GotoStmt, isForwardJumping) {
+ return Node.getLocStart() < Node.getLabel()->getLocStart();
+}
+} // namespace
+
+void AvoidGotoCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // TODO: This check does not recognize `IndirectGotoStmt` which is a
+ // GNU extension. These must be matched separately and an AST matcher
+ // is currently missing for them.
+
+ // Check if the 'goto' is used for control flow other than jumping
+ // out of a nested loop.
+ auto Loop = stmt(anyOf(forStmt(), cxxForRangeStmt(), whileStmt(), doStmt()));
+ auto NestedLoop =
+ stmt(anyOf(forStmt(hasAncestor(Loop)), cxxForRangeStmt(hasAncestor(Loop)),
+ whileStmt(hasAncestor(Loop)), doStmt(hasAncestor(Loop))));
+
+ Finder->addMatcher(gotoStmt(anyOf(unless(hasAncestor(NestedLoop)),
+ unless(isForwardJumping())))
+ .bind("goto"),
+ this);
+}
+
+void AvoidGotoCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Goto = Result.Nodes.getNodeAs<GotoStmt>("goto");
+
+ diag(Goto->getGotoLoc(), "avoid using 'goto' for flow control")
+ << Goto->getSourceRange();
+ diag(Goto->getLabel()->getLocStart(), "label defined here",
+ DiagnosticIDs::Note);
+}
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.h
new file mode 100644
index 0000000..cf7dd76
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.h
@@ -0,0 +1,36 @@
+//===--- AvoidGotoCheck.h - clang-tidy---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDGOTOCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDGOTOCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// The usage of ``goto`` for control flow is error prone and should be replaced
+/// with looping constructs. Only forward jumps in nested loops are accepted.
+//
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-avoid-goto.html
+class AvoidGotoCheck : public ClangTidyCheck {
+public:
+ AvoidGotoCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDGOTOCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
new file mode 100644
index 0000000..49fedd6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
@@ -0,0 +1,32 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyCppCoreGuidelinesModule
+ AvoidGotoCheck.cpp
+ CppCoreGuidelinesTidyModule.cpp
+ InterfacesGlobalInitCheck.cpp
+ NarrowingConversionsCheck.cpp
+ NoMallocCheck.cpp
+ OwningMemoryCheck.cpp
+ ProBoundsArrayToPointerDecayCheck.cpp
+ ProBoundsConstantArrayIndexCheck.cpp
+ ProBoundsPointerArithmeticCheck.cpp
+ ProTypeConstCastCheck.cpp
+ ProTypeCstyleCastCheck.cpp
+ ProTypeMemberInitCheck.cpp
+ ProTypeReinterpretCastCheck.cpp
+ ProTypeStaticCastDowncastCheck.cpp
+ ProTypeUnionAccessCheck.cpp
+ ProTypeVarargCheck.cpp
+ SpecialMemberFunctionsCheck.cpp
+ SlicingCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyMiscModule
+ clangTidyUtils
+ clangTooling
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
new file mode 100644
index 0000000..a039259
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
@@ -0,0 +1,88 @@
+//===--- CppCoreGuidelinesModule.cpp - clang-tidy -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "../misc/UnconventionalAssignOperatorCheck.h"
+#include "AvoidGotoCheck.h"
+#include "InterfacesGlobalInitCheck.h"
+#include "NarrowingConversionsCheck.h"
+#include "NoMallocCheck.h"
+#include "OwningMemoryCheck.h"
+#include "ProBoundsArrayToPointerDecayCheck.h"
+#include "ProBoundsConstantArrayIndexCheck.h"
+#include "ProBoundsPointerArithmeticCheck.h"
+#include "ProTypeConstCastCheck.h"
+#include "ProTypeCstyleCastCheck.h"
+#include "ProTypeMemberInitCheck.h"
+#include "ProTypeReinterpretCastCheck.h"
+#include "ProTypeStaticCastDowncastCheck.h"
+#include "ProTypeUnionAccessCheck.h"
+#include "ProTypeVarargCheck.h"
+#include "SlicingCheck.h"
+#include "SpecialMemberFunctionsCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// A module containing checks of the C++ Core Guidelines
+class CppCoreGuidelinesModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<AvoidGotoCheck>(
+ "cppcoreguidelines-avoid-goto");
+ CheckFactories.registerCheck<InterfacesGlobalInitCheck>(
+ "cppcoreguidelines-interfaces-global-init");
+ CheckFactories.registerCheck<NarrowingConversionsCheck>(
+ "cppcoreguidelines-narrowing-conversions");
+ CheckFactories.registerCheck<NoMallocCheck>("cppcoreguidelines-no-malloc");
+ CheckFactories.registerCheck<OwningMemoryCheck>(
+ "cppcoreguidelines-owning-memory");
+ CheckFactories.registerCheck<ProBoundsArrayToPointerDecayCheck>(
+ "cppcoreguidelines-pro-bounds-array-to-pointer-decay");
+ CheckFactories.registerCheck<ProBoundsConstantArrayIndexCheck>(
+ "cppcoreguidelines-pro-bounds-constant-array-index");
+ CheckFactories.registerCheck<ProBoundsPointerArithmeticCheck>(
+ "cppcoreguidelines-pro-bounds-pointer-arithmetic");
+ CheckFactories.registerCheck<ProTypeConstCastCheck>(
+ "cppcoreguidelines-pro-type-const-cast");
+ CheckFactories.registerCheck<ProTypeCstyleCastCheck>(
+ "cppcoreguidelines-pro-type-cstyle-cast");
+ CheckFactories.registerCheck<ProTypeMemberInitCheck>(
+ "cppcoreguidelines-pro-type-member-init");
+ CheckFactories.registerCheck<ProTypeReinterpretCastCheck>(
+ "cppcoreguidelines-pro-type-reinterpret-cast");
+ CheckFactories.registerCheck<ProTypeStaticCastDowncastCheck>(
+ "cppcoreguidelines-pro-type-static-cast-downcast");
+ CheckFactories.registerCheck<ProTypeUnionAccessCheck>(
+ "cppcoreguidelines-pro-type-union-access");
+ CheckFactories.registerCheck<ProTypeVarargCheck>(
+ "cppcoreguidelines-pro-type-vararg");
+ CheckFactories.registerCheck<SpecialMemberFunctionsCheck>(
+ "cppcoreguidelines-special-member-functions");
+ CheckFactories.registerCheck<SlicingCheck>("cppcoreguidelines-slicing");
+ CheckFactories.registerCheck<misc::UnconventionalAssignOperatorCheck>(
+ "cppcoreguidelines-c-copy-assignment-signature");
+ }
+};
+
+// Register the LLVMTidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<CppCoreGuidelinesModule>
+ X("cppcoreguidelines-module", "Adds checks for the C++ Core Guidelines.");
+
+} // namespace cppcoreguidelines
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the CppCoreGuidelinesModule.
+volatile int CppCoreGuidelinesModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.cpp
new file mode 100644
index 0000000..f601b24
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.cpp
@@ -0,0 +1,59 @@
+//===--- InterfacesGlobalInitCheck.cpp - clang-tidy------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InterfacesGlobalInitCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+void InterfacesGlobalInitCheck::registerMatchers(MatchFinder *Finder) {
+ const auto IsGlobal =
+ allOf(hasGlobalStorage(),
+ hasDeclContext(anyOf(translationUnitDecl(), // Global scope.
+ namespaceDecl(), // Namespace scope.
+ recordDecl())), // Class scope.
+ unless(isConstexpr()));
+
+ const auto ReferencesUndefinedGlobalVar = declRefExpr(hasDeclaration(
+ varDecl(IsGlobal, unless(isDefinition())).bind("referencee")));
+
+ Finder->addMatcher(
+ varDecl(IsGlobal, isDefinition(),
+ hasInitializer(expr(hasDescendant(ReferencesUndefinedGlobalVar))))
+ .bind("var"),
+ this);
+}
+
+void InterfacesGlobalInitCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *const Var = Result.Nodes.getNodeAs<VarDecl>("var");
+ // For now assume that people who write macros know what they're doing.
+ if (Var->getLocation().isMacroID())
+ return;
+ const auto *const Referencee = Result.Nodes.getNodeAs<VarDecl>("referencee");
+ // If the variable has been defined, we're good.
+ const auto *const ReferenceeDef = Referencee->getDefinition();
+ if (ReferenceeDef != nullptr &&
+ Result.SourceManager->isBeforeInTranslationUnit(
+ ReferenceeDef->getLocation(), Var->getLocation())) {
+ return;
+ }
+ diag(Var->getLocation(),
+ "initializing non-local variable with non-const expression depending on "
+ "uninitialized non-local variable %0")
+ << Referencee;
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.h
new file mode 100644
index 0000000..13712d1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.h
@@ -0,0 +1,35 @@
+//===--- InterfacesGlobalInitCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_INTERFACES_GLOBAL_INIT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_INTERFACES_GLOBAL_INIT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// Flags possible initialization order issues of static variables.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-interfaces-global-init.html
+class InterfacesGlobalInitCheck : public ClangTidyCheck {
+public:
+ InterfacesGlobalInitCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_INTERFACES_GLOBAL_INIT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp
new file mode 100644
index 0000000..2c5676e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp
@@ -0,0 +1,70 @@
+//===--- NarrowingConversionsCheck.cpp - clang-tidy------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NarrowingConversionsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+// FIXME: Check double -> float truncation. Pay attention to casts:
+void NarrowingConversionsCheck::registerMatchers(MatchFinder *Finder) {
+ // ceil() and floor() are guaranteed to return integers, even though the type
+ // is not integral.
+ const auto IsCeilFloorCall = callExpr(callee(functionDecl(
+ hasAnyName("::ceil", "::std::ceil", "::floor", "::std::floor"))));
+
+ const auto IsFloatExpr =
+ expr(hasType(realFloatingPointType()), unless(IsCeilFloorCall));
+
+ // casts:
+ // i = 0.5;
+ // void f(int); f(0.5);
+ Finder->addMatcher(implicitCastExpr(hasImplicitDestinationType(isInteger()),
+ hasSourceExpression(IsFloatExpr),
+ unless(hasParent(castExpr())),
+ unless(isInTemplateInstantiation()))
+ .bind("cast"),
+ this);
+
+ // Binary operators:
+ // i += 0.5;
+ Finder->addMatcher(
+ binaryOperator(isAssignmentOperator(),
+ // The `=` case generates an implicit cast which is covered
+ // by the previous matcher.
+ unless(hasOperatorName("=")),
+ hasLHS(hasType(isInteger())), hasRHS(IsFloatExpr),
+ unless(isInTemplateInstantiation()))
+ .bind("op"),
+ this);
+}
+
+void NarrowingConversionsCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *Op = Result.Nodes.getNodeAs<BinaryOperator>("op")) {
+ if (Op->getLocStart().isMacroID())
+ return;
+ diag(Op->getOperatorLoc(), "narrowing conversion from %0 to %1")
+ << Op->getRHS()->getType() << Op->getLHS()->getType();
+ return;
+ }
+ const auto *Cast = Result.Nodes.getNodeAs<ImplicitCastExpr>("cast");
+ if (Cast->getLocStart().isMacroID())
+ return;
+ diag(Cast->getExprLoc(), "narrowing conversion from %0 to %1")
+ << Cast->getSubExpr()->getType() << Cast->getType();
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.h
new file mode 100644
index 0000000..35f58bc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.h
@@ -0,0 +1,37 @@
+//===--- NarrowingConversionsCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_NARROWING_CONVERSIONS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_NARROWING_CONVERSIONS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// Checks for narrowing conversions, e.g:
+/// int i = 0;
+/// i += 0.1;
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.html
+class NarrowingConversionsCheck : public ClangTidyCheck {
+public:
+ NarrowingConversionsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_NARROWING_CONVERSIONS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/NoMallocCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/NoMallocCheck.cpp
new file mode 100644
index 0000000..5a2b882
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/NoMallocCheck.cpp
@@ -0,0 +1,82 @@
+//===--- NoMallocCheck.cpp - clang-tidy------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NoMallocCheck.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <algorithm>
+#include <string>
+#include <vector>
+
+using namespace clang::ast_matchers;
+using namespace clang::ast_matchers::internal;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+namespace {
+Matcher<FunctionDecl> hasAnyListedName(const std::string &FunctionNames) {
+ const std::vector<std::string> NameList =
+ utils::options::parseStringList(FunctionNames);
+ return hasAnyName(std::vector<StringRef>(NameList.begin(), NameList.end()));
+}
+} // namespace
+
+void NoMallocCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "Allocations", AllocList);
+ Options.store(Opts, "Reallocations", ReallocList);
+ Options.store(Opts, "Deallocations", DeallocList);
+}
+
+void NoMallocCheck::registerMatchers(MatchFinder *Finder) {
+ // C-style memory management is only problematic in C++.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // Registering malloc, will suggest RAII.
+ Finder->addMatcher(callExpr(callee(functionDecl(hasAnyListedName(AllocList))))
+ .bind("allocation"),
+ this);
+
+ // Registering realloc calls, suggest std::vector or std::string.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasAnyListedName(ReallocList))))
+ .bind("realloc"),
+ this);
+
+ // Registering free calls, will suggest RAII instead.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasAnyListedName(DeallocList))))
+ .bind("free"),
+ this);
+}
+
+void NoMallocCheck::check(const MatchFinder::MatchResult &Result) {
+ const CallExpr *Call = nullptr;
+ StringRef Recommendation;
+
+ if ((Call = Result.Nodes.getNodeAs<CallExpr>("allocation")))
+ Recommendation = "consider a container or a smart pointer";
+ else if ((Call = Result.Nodes.getNodeAs<CallExpr>("realloc")))
+ Recommendation = "consider std::vector or std::string";
+ else if ((Call = Result.Nodes.getNodeAs<CallExpr>("free")))
+ Recommendation = "use RAII";
+
+ assert(Call && "Unhandled binding in the Matcher");
+
+ diag(Call->getLocStart(), "do not manage memory manually; %0")
+ << Recommendation << SourceRange(Call->getLocStart(), Call->getLocEnd());
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/NoMallocCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/NoMallocCheck.h
new file mode 100644
index 0000000..4cec8a8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/NoMallocCheck.h
@@ -0,0 +1,62 @@
+//===--- NoMallocCheck.h - clang-tidy----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_NO_MALLOC_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_NO_MALLOC_H
+
+#include "../ClangTidy.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// This checker is concerned with C-style memory management and suggest modern
+/// alternatives to it.
+/// The check is only enabled in C++. For analyzing malloc calls see Clang
+/// Static Analyzer - unix.Malloc.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-no-malloc.html
+class NoMallocCheck : public ClangTidyCheck {
+public:
+ /// Construct Checker and read in configuration for function names.
+ NoMallocCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ AllocList(Options.get("Allocations", "::malloc;::calloc")),
+ ReallocList(Options.get("Reallocations", "::realloc")),
+ DeallocList(Options.get("Deallocations", "::free")) {}
+
+ /// Make configuration of checker discoverable.
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+ /// Registering for malloc, calloc, realloc and free calls.
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+
+ /// Checks matched function calls and gives suggestion to modernize the code.
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ /// Semicolon-separated list of fully qualified names of memory allocation
+ /// functions the check warns about. Defaults to `::malloc;::calloc`.
+ const std::string AllocList;
+ /// Semicolon-separated list of fully qualified names of memory reallocation
+ /// functions the check warns about. Defaults to `::realloc`.
+ const std::string ReallocList;
+ /// Semicolon-separated list of fully qualified names of memory deallocation
+ /// functions the check warns about. Defaults to `::free`.
+ const std::string DeallocList;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_NO_MALLOC_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
new file mode 100644
index 0000000..6c86e05
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp
@@ -0,0 +1,394 @@
+//===--- OwningMemoryCheck.cpp - clang-tidy--------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OwningMemoryCheck.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <string>
+#include <vector>
+
+using namespace clang::ast_matchers;
+using namespace clang::ast_matchers::internal;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+// FIXME: Copied from 'NoMallocCheck.cpp'. Has to be refactored into 'util' or
+// something like that.
+namespace {
+Matcher<FunctionDecl> hasAnyListedName(const std::string &FunctionNames) {
+ const std::vector<std::string> NameList =
+ utils::options::parseStringList(FunctionNames);
+ return hasAnyName(std::vector<StringRef>(NameList.begin(), NameList.end()));
+}
+} // namespace
+
+void OwningMemoryCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "LegacyResourceProducers", LegacyResourceProducers);
+ Options.store(Opts, "LegacyResourceConsumers", LegacyResourceConsumers);
+}
+
+/// Match common cases, where the owner semantic is relevant, like function
+/// calls, delete expressions and others.
+void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ const auto OwnerDecl = typeAliasTemplateDecl(hasName("::gsl::owner"));
+ const auto IsOwnerType = hasType(OwnerDecl);
+
+ const auto LegacyCreatorFunctions = hasAnyListedName(LegacyResourceProducers);
+ const auto LegacyConsumerFunctions =
+ hasAnyListedName(LegacyResourceConsumers);
+
+ // Legacy functions that are use for resource management but cannot be
+ // updated to use `gsl::owner<>`, like standard C memory management.
+ const auto CreatesLegacyOwner =
+ callExpr(callee(functionDecl(LegacyCreatorFunctions)));
+ // C-style functions like `::malloc()` sometimes create owners as void*
+ // which is expected to be cast to the correct type in C++. This case
+ // must be catched explicitly.
+ const auto LegacyOwnerCast =
+ castExpr(hasSourceExpression(CreatesLegacyOwner));
+ // Functions that do manual resource management but cannot be updated to use
+ // owner. Best example is `::free()`.
+ const auto LegacyOwnerConsumers = functionDecl(LegacyConsumerFunctions);
+
+ const auto CreatesOwner =
+ anyOf(cxxNewExpr(),
+ callExpr(callee(
+ functionDecl(returns(qualType(hasDeclaration(OwnerDecl)))))),
+ CreatesLegacyOwner, LegacyOwnerCast);
+
+ const auto ConsideredOwner = eachOf(IsOwnerType, CreatesOwner);
+
+ // Find delete expressions that delete non-owners.
+ Finder->addMatcher(
+ cxxDeleteExpr(
+ hasDescendant(
+ declRefExpr(unless(ConsideredOwner)).bind("deleted_variable")))
+ .bind("delete_expr"),
+ this);
+
+ // Ignoring the implicit casts is vital because the legacy owners do not work
+ // with the 'owner<>' annotation and therefore always implicitly cast to the
+ // legacy type (even 'void *').
+ //
+ // Furthermore, legacy owner functions are assumed to use raw pointers for
+ // resources. This check assumes that all pointer arguments of a legacy
+ // functions shall be 'gsl::owner<>'.
+ Finder->addMatcher(
+ callExpr(
+ allOf(callee(LegacyOwnerConsumers),
+ hasAnyArgument(allOf(unless(ignoringImpCasts(ConsideredOwner)),
+ hasType(pointerType())))))
+ .bind("legacy_consumer"),
+ this);
+
+ // Matching assignment to owners, with the rhs not being an owner nor creating
+ // one.
+ Finder->addMatcher(binaryOperator(allOf(matchers::isAssignmentOperator(),
+ hasLHS(IsOwnerType),
+ hasRHS(unless(ConsideredOwner))))
+ .bind("owner_assignment"),
+ this);
+
+ // Matching initialization of owners with non-owners, nor creating owners.
+ Finder->addMatcher(
+ namedDecl(
+ varDecl(allOf(hasInitializer(unless(ConsideredOwner)), IsOwnerType))
+ .bind("owner_initialization")),
+ this);
+
+ const auto HasConstructorInitializerForOwner =
+ has(cxxConstructorDecl(forEachConstructorInitializer(
+ cxxCtorInitializer(allOf(isMemberInitializer(), forField(IsOwnerType),
+ withInitializer(
+ // Avoid templatesdeclaration with
+ // excluding parenListExpr.
+ allOf(unless(ConsideredOwner),
+ unless(parenListExpr())))))
+ .bind("owner_member_initializer"))));
+
+ // Match class member initialization that expects owners, but does not get
+ // them.
+ Finder->addMatcher(cxxRecordDecl(HasConstructorInitializerForOwner), this);
+
+ // Matching on assignment operations where the RHS is a newly created owner,
+ // but the LHS is not an owner.
+ Finder->addMatcher(
+ binaryOperator(allOf(matchers::isAssignmentOperator(),
+ hasLHS(unless(IsOwnerType)), hasRHS(CreatesOwner)))
+ .bind("bad_owner_creation_assignment"),
+ this);
+
+ // Matching on initialization operations where the initial value is a newly
+ // created owner, but the LHS is not an owner.
+ Finder->addMatcher(
+ namedDecl(varDecl(eachOf(allOf(hasInitializer(CreatesOwner),
+ unless(IsOwnerType)),
+ allOf(hasInitializer(ConsideredOwner),
+ hasType(autoType().bind("deduced_type")))))
+ .bind("bad_owner_creation_variable")),
+ this);
+
+ // Match on all function calls that expect owners as arguments, but didn't
+ // get them.
+ Finder->addMatcher(
+ callExpr(forEachArgumentWithParam(
+ expr(unless(ConsideredOwner)).bind("expected_owner_argument"),
+ parmVarDecl(IsOwnerType))),
+ this);
+
+ // Matching for function calls where one argument is a created owner, but the
+ // parameter type is not an owner.
+ Finder->addMatcher(callExpr(forEachArgumentWithParam(
+ expr(CreatesOwner).bind("bad_owner_creation_argument"),
+ parmVarDecl(unless(IsOwnerType))
+ .bind("bad_owner_creation_parameter"))),
+ this);
+
+ // Matching on functions, that return an owner/resource, but don't declare
+ // their return type as owner.
+ Finder->addMatcher(
+ functionDecl(
+ allOf(hasDescendant(returnStmt(hasReturnValue(ConsideredOwner))
+ .bind("bad_owner_return")),
+ unless(returns(qualType(hasDeclaration(OwnerDecl))))))
+ .bind("function_decl"),
+ this);
+
+ // Match on classes that have an owner as member, but don't declare a
+ // destructor to properly release the owner.
+ Finder->addMatcher(
+ cxxRecordDecl(
+ allOf(
+ has(fieldDecl(IsOwnerType).bind("undestructed_owner_member")),
+ anyOf(unless(has(cxxDestructorDecl())),
+ has(cxxDestructorDecl(anyOf(isDefaulted(), isDeleted()))))))
+ .bind("non_destructor_class"),
+ this);
+}
+
+void OwningMemoryCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto &Nodes = Result.Nodes;
+
+ bool CheckExecuted = false;
+ CheckExecuted |= handleDeletion(Nodes);
+ CheckExecuted |= handleLegacyConsumers(Nodes);
+ CheckExecuted |= handleExpectedOwner(Nodes);
+ CheckExecuted |= handleAssignmentAndInit(Nodes);
+ CheckExecuted |= handleAssignmentFromNewOwner(Nodes);
+ CheckExecuted |= handleReturnValues(Nodes);
+ CheckExecuted |= handleOwnerMembers(Nodes);
+
+ assert(CheckExecuted &&
+ "None of the subroutines executed, logic error in matcher!");
+}
+
+bool OwningMemoryCheck::handleDeletion(const BoundNodes &Nodes) {
+ // Result of delete matchers.
+ const auto *DeleteStmt = Nodes.getNodeAs<CXXDeleteExpr>("delete_expr");
+ const auto *DeletedVariable =
+ Nodes.getNodeAs<DeclRefExpr>("deleted_variable");
+
+ // Deletion of non-owners, with `delete variable;`
+ if (DeleteStmt) {
+ diag(DeleteStmt->getLocStart(),
+ "deleting a pointer through a type that is "
+ "not marked 'gsl::owner<>'; consider using a "
+ "smart pointer instead")
+ << DeletedVariable->getSourceRange();
+
+ // FIXME: The declaration of the variable that was deleted can be
+ // rewritten.
+ const ValueDecl *Decl = DeletedVariable->getDecl();
+ diag(Decl->getLocStart(), "variable declared here", DiagnosticIDs::Note)
+ << Decl->getSourceRange();
+
+ return true;
+ }
+ return false;
+}
+
+bool OwningMemoryCheck::handleLegacyConsumers(const BoundNodes &Nodes) {
+ // Result of matching for legacy consumer-functions like `::free()`.
+ const auto *LegacyConsumer = Nodes.getNodeAs<CallExpr>("legacy_consumer");
+
+ // FIXME: `freopen` should be handled seperately because it takes the filename
+ // as a pointer, which should not be an owner. The argument that is an owner
+ // is known and the false positive coming from the filename can be avoided.
+ if (LegacyConsumer) {
+ diag(LegacyConsumer->getLocStart(),
+ "calling legacy resource function without passing a 'gsl::owner<>'")
+ << LegacyConsumer->getSourceRange();
+ return true;
+ }
+ return false;
+}
+
+bool OwningMemoryCheck::handleExpectedOwner(const BoundNodes &Nodes) {
+ // Result of function call matchers.
+ const auto *ExpectedOwner = Nodes.getNodeAs<Expr>("expected_owner_argument");
+
+ // Expected function argument to be owner.
+ if (ExpectedOwner) {
+ diag(ExpectedOwner->getLocStart(),
+ "expected argument of type 'gsl::owner<>'; got %0")
+ << ExpectedOwner->getType() << ExpectedOwner->getSourceRange();
+ return true;
+ }
+ return false;
+}
+
+/// Assignment and initialization of owner variables.
+bool OwningMemoryCheck::handleAssignmentAndInit(const BoundNodes &Nodes) {
+ const auto *OwnerAssignment =
+ Nodes.getNodeAs<BinaryOperator>("owner_assignment");
+ const auto *OwnerInitialization =
+ Nodes.getNodeAs<VarDecl>("owner_initialization");
+ const auto *OwnerInitializer =
+ Nodes.getNodeAs<CXXCtorInitializer>("owner_member_initializer");
+
+ // Assignments to owners.
+ if (OwnerAssignment) {
+ diag(OwnerAssignment->getLocStart(),
+ "expected assignment source to be of type 'gsl::owner<>'; got %0")
+ << OwnerAssignment->getRHS()->getType()
+ << OwnerAssignment->getSourceRange();
+ return true;
+ }
+
+ // Initialization of owners.
+ if (OwnerInitialization) {
+ diag(OwnerInitialization->getLocStart(),
+ "expected initialization with value of type 'gsl::owner<>'; got %0")
+ << OwnerInitialization->getAnyInitializer()->getType()
+ << OwnerInitialization->getSourceRange();
+ return true;
+ }
+
+ // Initializer of class constructors that initialize owners.
+ if (OwnerInitializer) {
+ diag(OwnerInitializer->getSourceLocation(),
+ "expected initialization of owner member variable with value of type "
+ "'gsl::owner<>'; got %0")
+ // FIXME: the expression from getInit has type 'void', but the type
+ // of the supplied argument would be of interest.
+ << OwnerInitializer->getInit()->getType()
+ << OwnerInitializer->getSourceRange();
+ return true;
+ }
+ return false;
+}
+
+/// Problematic assignment and initializations, since the assigned value is a
+/// newly created owner.
+bool OwningMemoryCheck::handleAssignmentFromNewOwner(const BoundNodes &Nodes) {
+ const auto *BadOwnerAssignment =
+ Nodes.getNodeAs<BinaryOperator>("bad_owner_creation_assignment");
+ const auto *BadOwnerInitialization =
+ Nodes.getNodeAs<VarDecl>("bad_owner_creation_variable");
+
+ const auto *BadOwnerArgument =
+ Nodes.getNodeAs<Expr>("bad_owner_creation_argument");
+ const auto *BadOwnerParameter =
+ Nodes.getNodeAs<ParmVarDecl>("bad_owner_creation_parameter");
+
+ // Bad assignments to non-owners, where the RHS is a newly created owner.
+ if (BadOwnerAssignment) {
+ diag(BadOwnerAssignment->getLocStart(),
+ "assigning newly created 'gsl::owner<>' to non-owner %0")
+ << BadOwnerAssignment->getLHS()->getType()
+ << BadOwnerAssignment->getSourceRange();
+ return true;
+ }
+
+ // Bad initialization of non-owners, where the RHS is a newly created owner.
+ if (BadOwnerInitialization) {
+ diag(BadOwnerInitialization->getLocStart(),
+ "initializing non-owner %0 with a newly created 'gsl::owner<>'")
+ << BadOwnerInitialization->getType()
+ << BadOwnerInitialization->getSourceRange();
+
+ // FIXME: FixitHint to rewrite the type of the initialized variable
+ // as 'gsl::owner<OriginalType>'
+
+ // If the type of the variable was deduced, the wrapping owner typedef is
+ // eliminated, therefore the check emits a special note for that case.
+ if (Nodes.getNodeAs<AutoType>("deduced_type")) {
+ diag(BadOwnerInitialization->getLocStart(),
+ "type deduction did not result in an owner", DiagnosticIDs::Note);
+ }
+ return true;
+ }
+
+ // Function call, where one arguments is a newly created owner, but the
+ // parameter type is not.
+ if (BadOwnerArgument) {
+ assert(BadOwnerParameter &&
+ "parameter for the problematic argument not found");
+ diag(BadOwnerArgument->getLocStart(), "initializing non-owner argument of "
+ "type %0 with a newly created "
+ "'gsl::owner<>'")
+ << BadOwnerParameter->getType() << BadOwnerArgument->getSourceRange();
+ return true;
+ }
+ return false;
+}
+
+bool OwningMemoryCheck::handleReturnValues(const BoundNodes &Nodes) {
+ // Function return statements, that are owners/resources, but the function
+ // declaration does not declare its return value as owner.
+ const auto *BadReturnType = Nodes.getNodeAs<ReturnStmt>("bad_owner_return");
+ const auto *Function = Nodes.getNodeAs<FunctionDecl>("function_decl");
+
+ // Function return values, that should be owners but aren't.
+ if (BadReturnType) {
+ // The returned value is a resource or variable that was not annotated with
+ // owner<> and the function return type is not owner<>.
+ diag(BadReturnType->getLocStart(),
+ "returning a newly created resource of "
+ "type %0 or 'gsl::owner<>' from a "
+ "function whose return type is not 'gsl::owner<>'")
+ << Function->getReturnType() << BadReturnType->getSourceRange();
+
+ // FIXME: Rewrite the return type as 'gsl::owner<OriginalType>'
+ return true;
+ }
+ return false;
+}
+
+bool OwningMemoryCheck::handleOwnerMembers(const BoundNodes &Nodes) {
+ // Classes, that have owners as member, but do not declare destructors
+ // accordingly.
+ const auto *BadClass = Nodes.getNodeAs<CXXRecordDecl>("non_destructor_class");
+
+ // Classes, that contains owners, but do not declare destructors.
+ if (BadClass) {
+ const auto *DeclaredOwnerMember =
+ Nodes.getNodeAs<FieldDecl>("undestructed_owner_member");
+ assert(DeclaredOwnerMember &&
+ "match on class with bad destructor but without a declared owner");
+
+ diag(DeclaredOwnerMember->getLocStart(),
+ "member variable of type 'gsl::owner<>' requires the class %0 to "
+ "implement a destructor to release the owned resource")
+ << BadClass;
+ return true;
+ }
+ return false;
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.h
new file mode 100644
index 0000000..e68e4c0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.h
@@ -0,0 +1,63 @@
+//===--- OwningMemoryCheck.h - clang-tidy------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_OWNING_MEMORY_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_OWNING_MEMORY_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// Checks for common use cases for gsl::owner and enforces the unique owner
+/// nature of it whenever possible.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-owning-memory.html
+class OwningMemoryCheck : public ClangTidyCheck {
+public:
+ OwningMemoryCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ LegacyResourceProducers(Options.get(
+ "LegacyResourceProducers", "::malloc;::aligned_alloc;::realloc;"
+ "::calloc;::fopen;::freopen;::tmpfile")),
+ LegacyResourceConsumers(Options.get(
+ "LegacyResourceConsumers", "::free;::realloc;::freopen;::fclose")) {
+ }
+
+ /// Make configuration of checker discoverable.
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ bool handleDeletion(const ast_matchers::BoundNodes &Nodes);
+ bool handleLegacyConsumers(const ast_matchers::BoundNodes &Nodes);
+ bool handleExpectedOwner(const ast_matchers::BoundNodes &Nodes);
+ bool handleAssignmentAndInit(const ast_matchers::BoundNodes &Nodes);
+ bool handleAssignmentFromNewOwner(const ast_matchers::BoundNodes &Nodes);
+ bool handleReturnValues(const ast_matchers::BoundNodes &Nodes);
+ bool handleOwnerMembers(const ast_matchers::BoundNodes &Nodes);
+
+ /// List of old C-style functions that create resources.
+ /// Defaults to
+ /// `::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile`.
+ const std::string LegacyResourceProducers;
+ /// List of old C-style functions that consume or release resources.
+ /// Defaults to `::free;::realloc;::freopen;::fclose`.
+ const std::string LegacyResourceConsumers;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_OWNING_MEMORY_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp
new file mode 100644
index 0000000..8b0f7ce
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp
@@ -0,0 +1,82 @@
+//===--- ProBoundsArrayToPointerDecayCheck.cpp - clang-tidy----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProBoundsArrayToPointerDecayCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+namespace {
+AST_MATCHER_P(CXXForRangeStmt, hasRangeBeginEndStmt,
+ ast_matchers::internal::Matcher<DeclStmt>, InnerMatcher) {
+ for (const DeclStmt *Stmt : {Node.getBeginStmt(), Node.getEndStmt()})
+ if (Stmt != nullptr && InnerMatcher.matches(*Stmt, Finder, Builder))
+ return true;
+ return false;
+}
+
+AST_MATCHER(Stmt, isInsideOfRangeBeginEndStmt) {
+ return stmt(hasAncestor(cxxForRangeStmt(
+ hasRangeBeginEndStmt(hasDescendant(equalsNode(&Node))))))
+ .matches(Node, Finder, Builder);
+}
+
+AST_MATCHER_P(Expr, hasParentIgnoringImpCasts,
+ ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
+ const Expr *E = &Node;
+ do {
+ ASTContext::DynTypedNodeList Parents =
+ Finder->getASTContext().getParents(*E);
+ if (Parents.size() != 1)
+ return false;
+ E = Parents[0].get<Expr>();
+ if (!E)
+ return false;
+ } while (isa<ImplicitCastExpr>(E));
+
+ return InnerMatcher.matches(*E, Finder, Builder);
+}
+} // namespace
+
+void ProBoundsArrayToPointerDecayCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // The only allowed array to pointer decay
+ // 1) just before array subscription
+ // 2) inside a range-for over an array
+ // 3) if it converts a string literal to a pointer
+ Finder->addMatcher(
+ implicitCastExpr(unless(hasParent(arraySubscriptExpr())),
+ unless(hasParentIgnoringImpCasts(explicitCastExpr())),
+ unless(isInsideOfRangeBeginEndStmt()),
+ unless(hasSourceExpression(stringLiteral())))
+ .bind("cast"),
+ this);
+}
+
+void ProBoundsArrayToPointerDecayCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *MatchedCast = Result.Nodes.getNodeAs<ImplicitCastExpr>("cast");
+ if (MatchedCast->getCastKind() != CK_ArrayToPointerDecay)
+ return;
+
+ diag(MatchedCast->getExprLoc(), "do not implicitly decay an array into a "
+ "pointer; consider using gsl::array_view or "
+ "an explicit cast instead");
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.h
new file mode 100644
index 0000000..0afffb6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.h
@@ -0,0 +1,35 @@
+//===--- ProBoundsArrayToPointerDecayCheck.h - clang-tidy--------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_ARRAY_TO_POINTER_DECAY_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_ARRAY_TO_POINTER_DECAY_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// This check flags all array to pointer decays
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-bounds-array-to-pointer-decay.html
+class ProBoundsArrayToPointerDecayCheck : public ClangTidyCheck {
+public:
+ ProBoundsArrayToPointerDecayCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_ARRAY_TO_POINTER_DECAY_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsConstantArrayIndexCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsConstantArrayIndexCheck.cpp
new file mode 100644
index 0000000..a81496e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsConstantArrayIndexCheck.cpp
@@ -0,0 +1,141 @@
+//===--- ProBoundsConstantArrayIndexCheck.cpp - clang-tidy-----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProBoundsConstantArrayIndexCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+ProBoundsConstantArrayIndexCheck::ProBoundsConstantArrayIndexCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context), GslHeader(Options.get("GslHeader", "")),
+ IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
+ Options.getLocalOrGlobal("IncludeStyle", "llvm"))) {}
+
+void ProBoundsConstantArrayIndexCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "GslHeader", GslHeader);
+ Options.store(Opts, "IncludeStyle", IncludeStyle);
+}
+
+void ProBoundsConstantArrayIndexCheck::registerPPCallbacks(
+ CompilerInstance &Compiler) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Inserter.reset(new utils::IncludeInserter(
+ Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle));
+ Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
+}
+
+void ProBoundsConstantArrayIndexCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // Note: if a struct contains an array member, the compiler-generated
+ // constructor has an arraySubscriptExpr.
+ Finder->addMatcher(
+ arraySubscriptExpr(
+ hasBase(ignoringImpCasts(hasType(constantArrayType().bind("type")))),
+ hasIndex(expr().bind("index")), unless(hasAncestor(isImplicit())))
+ .bind("expr"),
+ this);
+
+ Finder->addMatcher(
+ cxxOperatorCallExpr(
+ hasOverloadedOperatorName("[]"),
+ hasArgument(
+ 0, hasType(cxxRecordDecl(hasName("::std::array")).bind("type"))),
+ hasArgument(1, expr().bind("index")))
+ .bind("expr"),
+ this);
+}
+
+void ProBoundsConstantArrayIndexCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *Matched = Result.Nodes.getNodeAs<Expr>("expr");
+ const auto *IndexExpr = Result.Nodes.getNodeAs<Expr>("index");
+
+ if (IndexExpr->isValueDependent())
+ return; // We check in the specialization.
+
+ llvm::APSInt Index;
+ if (!IndexExpr->isIntegerConstantExpr(Index, *Result.Context, nullptr,
+ /*isEvaluated=*/true)) {
+ SourceRange BaseRange;
+ if (const auto *ArraySubscriptE = dyn_cast<ArraySubscriptExpr>(Matched))
+ BaseRange = ArraySubscriptE->getBase()->getSourceRange();
+ else
+ BaseRange =
+ dyn_cast<CXXOperatorCallExpr>(Matched)->getArg(0)->getSourceRange();
+ SourceRange IndexRange = IndexExpr->getSourceRange();
+
+ auto Diag = diag(Matched->getExprLoc(),
+ "do not use array subscript when the index is "
+ "not an integer constant expression; use gsl::at() "
+ "instead");
+ if (!GslHeader.empty()) {
+ Diag << FixItHint::CreateInsertion(BaseRange.getBegin(), "gsl::at(")
+ << FixItHint::CreateReplacement(
+ SourceRange(BaseRange.getEnd().getLocWithOffset(1),
+ IndexRange.getBegin().getLocWithOffset(-1)),
+ ", ")
+ << FixItHint::CreateReplacement(Matched->getLocEnd(), ")");
+
+ Optional<FixItHint> Insertion = Inserter->CreateIncludeInsertion(
+ Result.SourceManager->getMainFileID(), GslHeader,
+ /*IsAngled=*/false);
+ if (Insertion)
+ Diag << Insertion.getValue();
+ }
+ return;
+ }
+
+ const auto *StdArrayDecl =
+ Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("type");
+
+ // For static arrays, this is handled in clang-diagnostic-array-bounds.
+ if (!StdArrayDecl)
+ return;
+
+ if (Index.isSigned() && Index.isNegative()) {
+ diag(Matched->getExprLoc(), "std::array<> index %0 is negative")
+ << Index.toString(10);
+ return;
+ }
+
+ const TemplateArgumentList &TemplateArgs = StdArrayDecl->getTemplateArgs();
+ if (TemplateArgs.size() < 2)
+ return;
+ // First template arg of std::array is the type, second arg is the size.
+ const auto &SizeArg = TemplateArgs[1];
+ if (SizeArg.getKind() != TemplateArgument::Integral)
+ return;
+ llvm::APInt ArraySize = SizeArg.getAsIntegral();
+
+ // Get uint64_t values, because different bitwidths would lead to an assertion
+ // in APInt::uge.
+ if (Index.getZExtValue() >= ArraySize.getZExtValue()) {
+ diag(Matched->getExprLoc(),
+ "std::array<> index %0 is past the end of the array "
+ "(which contains %1 elements)")
+ << Index.toString(10) << ArraySize.toString(10, false);
+ }
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsConstantArrayIndexCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsConstantArrayIndexCheck.h
new file mode 100644
index 0000000..28b24a6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsConstantArrayIndexCheck.h
@@ -0,0 +1,42 @@
+//===--- ProBoundsConstantArrayIndexCheck.h - clang-tidy---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_CONSTANT_ARRAY_INDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_CONSTANT_ARRAY_INDEX_H
+
+#include "../ClangTidy.h"
+#include "../utils/IncludeInserter.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// This checks that all array subscriptions on static arrays and std::arrays
+/// have a constant index and are within bounds
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-bounds-constant-array-index.html
+class ProBoundsConstantArrayIndexCheck : public ClangTidyCheck {
+ const std::string GslHeader;
+ const utils::IncludeSorter::IncludeStyle IncludeStyle;
+ std::unique_ptr<utils::IncludeInserter> Inserter;
+
+public:
+ ProBoundsConstantArrayIndexCheck(StringRef Name, ClangTidyContext *Context);
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_CONSTANT_ARRAY_INDEX_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp
new file mode 100644
index 0000000..dfbb51b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp
@@ -0,0 +1,63 @@
+//===--- ProBoundsPointerArithmeticCheck.cpp - clang-tidy------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProBoundsPointerArithmeticCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+void ProBoundsPointerArithmeticCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ const auto AllPointerTypes = anyOf(
+ hasType(pointerType()), hasType(autoType(hasDeducedType(pointerType()))),
+ hasType(decltypeType(hasUnderlyingType(pointerType()))));
+
+ // Flag all operators +, -, +=, -=, ++, -- that result in a pointer
+ Finder->addMatcher(
+ binaryOperator(
+ anyOf(hasOperatorName("+"), hasOperatorName("-"),
+ hasOperatorName("+="), hasOperatorName("-=")),
+ AllPointerTypes,
+ unless(hasLHS(ignoringImpCasts(declRefExpr(to(isImplicit()))))))
+ .bind("expr"),
+ this);
+
+ Finder->addMatcher(
+ unaryOperator(anyOf(hasOperatorName("++"), hasOperatorName("--")),
+ hasType(pointerType()))
+ .bind("expr"),
+ this);
+
+ // Array subscript on a pointer (not an array) is also pointer arithmetic
+ Finder->addMatcher(
+ arraySubscriptExpr(
+ hasBase(ignoringImpCasts(
+ anyOf(AllPointerTypes,
+ hasType(decayedType(hasDecayedType(pointerType())))))))
+ .bind("expr"),
+ this);
+}
+
+void ProBoundsPointerArithmeticCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *MatchedExpr = Result.Nodes.getNodeAs<Expr>("expr");
+
+ diag(MatchedExpr->getExprLoc(), "do not use pointer arithmetic");
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.h
new file mode 100644
index 0000000..5ecf93c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.h
@@ -0,0 +1,37 @@
+//===--- ProBoundsPointerArithmeticCheck.h - clang-tidy----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_POINTER_ARITHMETIC_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_POINTER_ARITHMETIC_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// Flags all kinds of pointer arithmetic that have result of pointer type, i.e.
+/// +, -, +=, -=, ++, --. In addition, the [] operator on pointers (not on
+/// arrays) is flagged.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-bounds-pointer-arithmetic.html
+class ProBoundsPointerArithmeticCheck : public ClangTidyCheck {
+public:
+ ProBoundsPointerArithmeticCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_POINTER_ARITHMETIC_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeConstCastCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeConstCastCheck.cpp
new file mode 100644
index 0000000..4b6fb42
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeConstCastCheck.cpp
@@ -0,0 +1,34 @@
+//===--- ProTypeConstCastCheck.cpp - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProTypeConstCastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+void ProTypeConstCastCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(cxxConstCastExpr().bind("cast"), this);
+}
+
+void ProTypeConstCastCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedCast = Result.Nodes.getNodeAs<CXXConstCastExpr>("cast");
+ diag(MatchedCast->getOperatorLoc(), "do not use const_cast");
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeConstCastCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeConstCastCheck.h
new file mode 100644
index 0000000..92a3a1b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeConstCastCheck.h
@@ -0,0 +1,35 @@
+//===--- ProTypeConstCastCheck.h - clang-tidy--------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_CONST_CAST_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_CONST_CAST_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// This check flags all instances of const_cast
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-type-const-cast.html
+class ProTypeConstCastCheck : public ClangTidyCheck {
+public:
+ ProTypeConstCastCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_CONST_CAST_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp
new file mode 100644
index 0000000..52156ad
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp
@@ -0,0 +1,108 @@
+//===--- ProTypeCstyleCastCheck.cpp - clang-tidy---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProTypeCstyleCastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+static bool needsConstCast(QualType SourceType, QualType DestType) {
+ SourceType = SourceType.getNonReferenceType();
+ DestType = DestType.getNonReferenceType();
+ while (SourceType->isPointerType() && DestType->isPointerType()) {
+ SourceType = SourceType->getPointeeType();
+ DestType = DestType->getPointeeType();
+ if (SourceType.isConstQualified() && !DestType.isConstQualified())
+ return true;
+ }
+ return false;
+}
+
+void ProTypeCstyleCastCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(
+ cStyleCastExpr(unless(isInTemplateInstantiation())).bind("cast"), this);
+}
+
+void ProTypeCstyleCastCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedCast = Result.Nodes.getNodeAs<CStyleCastExpr>("cast");
+
+ if (MatchedCast->getCastKind() == CK_BitCast ||
+ MatchedCast->getCastKind() == CK_LValueBitCast ||
+ MatchedCast->getCastKind() == CK_IntegralToPointer ||
+ MatchedCast->getCastKind() == CK_PointerToIntegral ||
+ MatchedCast->getCastKind() == CK_ReinterpretMemberPointer) {
+ diag(MatchedCast->getLocStart(),
+ "do not use C-style cast to convert between unrelated types");
+ return;
+ }
+
+ QualType SourceType = MatchedCast->getSubExpr()->getType();
+
+ if (MatchedCast->getCastKind() == CK_BaseToDerived) {
+ const auto *SourceDecl = SourceType->getPointeeCXXRecordDecl();
+ if (!SourceDecl) // The cast is from object to reference.
+ SourceDecl = SourceType->getAsCXXRecordDecl();
+ if (!SourceDecl)
+ return;
+
+ if (SourceDecl->isPolymorphic()) {
+ // Leave type spelling exactly as it was (unlike
+ // getTypeAsWritten().getAsString() which would spell enum types 'enum
+ // X').
+ StringRef DestTypeString = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(
+ MatchedCast->getLParenLoc().getLocWithOffset(1),
+ MatchedCast->getRParenLoc().getLocWithOffset(-1)),
+ *Result.SourceManager, getLangOpts());
+
+ auto diag_builder = diag(
+ MatchedCast->getLocStart(),
+ "do not use C-style cast to downcast from a base to a derived class; "
+ "use dynamic_cast instead");
+
+ const Expr *SubExpr =
+ MatchedCast->getSubExprAsWritten()->IgnoreImpCasts();
+ std::string CastText = ("dynamic_cast<" + DestTypeString + ">").str();
+ if (!isa<ParenExpr>(SubExpr)) {
+ CastText.push_back('(');
+ diag_builder << FixItHint::CreateInsertion(
+ Lexer::getLocForEndOfToken(SubExpr->getLocEnd(), 0,
+ *Result.SourceManager, getLangOpts()),
+ ")");
+ }
+ auto ParenRange = CharSourceRange::getTokenRange(
+ MatchedCast->getLParenLoc(), MatchedCast->getRParenLoc());
+ diag_builder << FixItHint::CreateReplacement(ParenRange, CastText);
+ } else {
+ diag(
+ MatchedCast->getLocStart(),
+ "do not use C-style cast to downcast from a base to a derived class");
+ }
+ return;
+ }
+
+ if (MatchedCast->getCastKind() == CK_NoOp &&
+ needsConstCast(SourceType, MatchedCast->getType())) {
+ diag(MatchedCast->getLocStart(),
+ "do not use C-style cast to cast away constness");
+ }
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.h
new file mode 100644
index 0000000..c08b883
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.h
@@ -0,0 +1,36 @@
+//===--- ProTypeCstyleCastCheck.h - clang-tidy-------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_CSTYLE_CAST_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_CSTYLE_CAST_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// This check flags all use of C-style casts that perform a static_cast
+/// downcast, const_cast, or reinterpret_cast.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-type-cstyle-cast.html
+class ProTypeCstyleCastCheck : public ClangTidyCheck {
+public:
+ ProTypeCstyleCastCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_CSTYLE_CAST_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
new file mode 100644
index 0000000..4d9be81
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
@@ -0,0 +1,485 @@
+//===--- ProTypeMemberInitCheck.cpp - clang-tidy---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProTypeMemberInitCheck.h"
+#include "../utils/LexerUtils.h"
+#include "../utils/Matchers.h"
+#include "../utils/TypeTraits.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::tidy::matchers;
+using llvm::SmallPtrSet;
+using llvm::SmallPtrSetImpl;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+namespace {
+
+AST_MATCHER(CXXRecordDecl, hasDefaultConstructor) {
+ return Node.hasDefaultConstructor();
+}
+
+// Iterate over all the fields in a record type, both direct and indirect (e.g.
+// if the record contains an anonmyous struct).
+template <typename T, typename Func>
+void forEachField(const RecordDecl &Record, const T &Fields, Func &&Fn) {
+ for (const FieldDecl *F : Fields) {
+ if (F->isAnonymousStructOrUnion()) {
+ if (const CXXRecordDecl *R = F->getType()->getAsCXXRecordDecl())
+ forEachField(*R, R->fields(), Fn);
+ } else {
+ Fn(F);
+ }
+ }
+}
+
+void removeFieldsInitializedInBody(
+ const Stmt &Stmt, ASTContext &Context,
+ SmallPtrSetImpl<const FieldDecl *> &FieldDecls) {
+ auto Matches =
+ match(findAll(binaryOperator(
+ hasOperatorName("="),
+ hasLHS(memberExpr(member(fieldDecl().bind("fieldDecl")))))),
+ Stmt, Context);
+ for (const auto &Match : Matches)
+ FieldDecls.erase(Match.getNodeAs<FieldDecl>("fieldDecl"));
+}
+
+StringRef getName(const FieldDecl *Field) { return Field->getName(); }
+
+StringRef getName(const RecordDecl *Record) {
+ // Get the typedef name if this is a C-style anonymous struct and typedef.
+ if (const TypedefNameDecl *Typedef = Record->getTypedefNameForAnonDecl())
+ return Typedef->getName();
+ return Record->getName();
+}
+
+// Creates comma separated list of decls requiring initialization in order of
+// declaration.
+template <typename R, typename T>
+std::string
+toCommaSeparatedString(const R &OrderedDecls,
+ const SmallPtrSetImpl<const T *> &DeclsToInit) {
+ SmallVector<StringRef, 16> Names;
+ for (const T *Decl : OrderedDecls) {
+ if (DeclsToInit.count(Decl))
+ Names.emplace_back(getName(Decl));
+ }
+ return llvm::join(Names.begin(), Names.end(), ", ");
+}
+
+SourceLocation getLocationForEndOfToken(const ASTContext &Context,
+ SourceLocation Location) {
+ return Lexer::getLocForEndOfToken(Location, 0, Context.getSourceManager(),
+ Context.getLangOpts());
+}
+
+// There are 3 kinds of insertion placements:
+enum class InitializerPlacement {
+ // 1. The fields are inserted after an existing CXXCtorInitializer stored in
+ // Where. This will be the case whenever there is a written initializer before
+ // the fields available.
+ After,
+
+ // 2. The fields are inserted before the first existing initializer stored in
+ // Where.
+ Before,
+
+ // 3. There are no written initializers and the fields will be inserted before
+ // the constructor's body creating a new initializer list including the ':'.
+ New
+};
+
+// An InitializerInsertion contains a list of fields and/or base classes to
+// insert into the initializer list of a constructor. We use this to ensure
+// proper absolute ordering according to the class declaration relative to the
+// (perhaps improper) ordering in the existing initializer list, if any.
+struct IntializerInsertion {
+ IntializerInsertion(InitializerPlacement Placement,
+ const CXXCtorInitializer *Where)
+ : Placement(Placement), Where(Where) {}
+
+ SourceLocation getLocation(const ASTContext &Context,
+ const CXXConstructorDecl &Constructor) const {
+ assert((Where != nullptr || Placement == InitializerPlacement::New) &&
+ "Location should be relative to an existing initializer or this "
+ "insertion represents a new initializer list.");
+ SourceLocation Location;
+ switch (Placement) {
+ case InitializerPlacement::New:
+ Location = utils::lexer::getPreviousToken(
+ Context, Constructor.getBody()->getLocStart())
+ .getLocation();
+ break;
+ case InitializerPlacement::Before:
+ Location = utils::lexer::getPreviousToken(
+ Context, Where->getSourceRange().getBegin())
+ .getLocation();
+ break;
+ case InitializerPlacement::After:
+ Location = Where->getRParenLoc();
+ break;
+ }
+ return getLocationForEndOfToken(Context, Location);
+ }
+
+ std::string codeToInsert() const {
+ assert(!Initializers.empty() && "No initializers to insert");
+ std::string Code;
+ llvm::raw_string_ostream Stream(Code);
+ std::string joined =
+ llvm::join(Initializers.begin(), Initializers.end(), "(), ");
+ switch (Placement) {
+ case InitializerPlacement::New:
+ Stream << " : " << joined << "()";
+ break;
+ case InitializerPlacement::Before:
+ Stream << " " << joined << "(),";
+ break;
+ case InitializerPlacement::After:
+ Stream << ", " << joined << "()";
+ break;
+ }
+ return Stream.str();
+ }
+
+ InitializerPlacement Placement;
+ const CXXCtorInitializer *Where;
+ SmallVector<std::string, 4> Initializers;
+};
+
+// Convenience utility to get a RecordDecl from a QualType.
+const RecordDecl *getCanonicalRecordDecl(const QualType &Type) {
+ if (const auto *RT = Type.getCanonicalType()->getAs<RecordType>())
+ return RT->getDecl();
+ return nullptr;
+}
+
+template <typename R, typename T>
+SmallVector<IntializerInsertion, 16>
+computeInsertions(const CXXConstructorDecl::init_const_range &Inits,
+ const R &OrderedDecls,
+ const SmallPtrSetImpl<const T *> &DeclsToInit) {
+ SmallVector<IntializerInsertion, 16> Insertions;
+ Insertions.emplace_back(InitializerPlacement::New, nullptr);
+
+ typename R::const_iterator Decl = std::begin(OrderedDecls);
+ for (const CXXCtorInitializer *Init : Inits) {
+ if (Init->isWritten()) {
+ if (Insertions.size() == 1)
+ Insertions.emplace_back(InitializerPlacement::Before, Init);
+
+ // Gets either the field or base class being initialized by the provided
+ // initializer.
+ const auto *InitDecl =
+ Init->isAnyMemberInitializer()
+ ? static_cast<const NamedDecl *>(Init->getAnyMember())
+ : Init->getBaseClass()->getAsCXXRecordDecl();
+
+ // Add all fields between current field up until the next intializer.
+ for (; Decl != std::end(OrderedDecls) && *Decl != InitDecl; ++Decl) {
+ if (const auto *D = dyn_cast<T>(*Decl)) {
+ if (DeclsToInit.count(D) > 0)
+ Insertions.back().Initializers.emplace_back(getName(D));
+ }
+ }
+
+ Insertions.emplace_back(InitializerPlacement::After, Init);
+ }
+ }
+
+ // Add remaining decls that require initialization.
+ for (; Decl != std::end(OrderedDecls); ++Decl) {
+ if (const auto *D = dyn_cast<T>(*Decl)) {
+ if (DeclsToInit.count(D) > 0)
+ Insertions.back().Initializers.emplace_back(getName(D));
+ }
+ }
+ return Insertions;
+}
+
+// Gets the list of bases and members that could possibly be initialized, in
+// order as they appear in the class declaration.
+void getInitializationsInOrder(const CXXRecordDecl &ClassDecl,
+ SmallVectorImpl<const NamedDecl *> &Decls) {
+ Decls.clear();
+ for (const auto &Base : ClassDecl.bases()) {
+ // Decl may be null if the base class is a template parameter.
+ if (const NamedDecl *Decl = getCanonicalRecordDecl(Base.getType())) {
+ Decls.emplace_back(Decl);
+ }
+ }
+ forEachField(ClassDecl, ClassDecl.fields(),
+ [&](const FieldDecl *F) { Decls.push_back(F); });
+}
+
+template <typename T>
+void fixInitializerList(const ASTContext &Context, DiagnosticBuilder &Diag,
+ const CXXConstructorDecl *Ctor,
+ const SmallPtrSetImpl<const T *> &DeclsToInit) {
+ // Do not propose fixes in macros since we cannot place them correctly.
+ if (Ctor->getLocStart().isMacroID())
+ return;
+
+ SmallVector<const NamedDecl *, 16> OrderedDecls;
+ getInitializationsInOrder(*Ctor->getParent(), OrderedDecls);
+
+ for (const auto &Insertion :
+ computeInsertions(Ctor->inits(), OrderedDecls, DeclsToInit)) {
+ if (!Insertion.Initializers.empty())
+ Diag << FixItHint::CreateInsertion(Insertion.getLocation(Context, *Ctor),
+ Insertion.codeToInsert());
+ }
+}
+
+} // anonymous namespace
+
+ProTypeMemberInitCheck::ProTypeMemberInitCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IgnoreArrays(Options.get("IgnoreArrays", false)) {}
+
+void ProTypeMemberInitCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ auto IsUserProvidedNonDelegatingConstructor =
+ allOf(isUserProvided(),
+ unless(anyOf(isInstantiated(), isDelegatingConstructor())));
+ auto IsNonTrivialDefaultConstructor = allOf(
+ isDefaultConstructor(), unless(isUserProvided()),
+ hasParent(cxxRecordDecl(unless(isTriviallyDefaultConstructible()))));
+ Finder->addMatcher(
+ cxxConstructorDecl(isDefinition(),
+ anyOf(IsUserProvidedNonDelegatingConstructor,
+ IsNonTrivialDefaultConstructor))
+ .bind("ctor"),
+ this);
+
+ // Match classes with a default constructor that is defaulted or is not in the
+ // AST.
+ Finder->addMatcher(
+ cxxRecordDecl(
+ isDefinition(), unless(isInstantiated()), hasDefaultConstructor(),
+ anyOf(has(cxxConstructorDecl(isDefaultConstructor(), isDefaulted(),
+ unless(isImplicit()))),
+ unless(has(cxxConstructorDecl()))),
+ unless(isTriviallyDefaultConstructible()))
+ .bind("record"),
+ this);
+
+ auto HasDefaultConstructor = hasInitializer(
+ cxxConstructExpr(unless(requiresZeroInitialization()),
+ hasDeclaration(cxxConstructorDecl(
+ isDefaultConstructor(), unless(isUserProvided())))));
+ Finder->addMatcher(
+ varDecl(isDefinition(), HasDefaultConstructor,
+ hasAutomaticStorageDuration(),
+ hasType(recordDecl(has(fieldDecl()),
+ isTriviallyDefaultConstructible())))
+ .bind("var"),
+ this);
+}
+
+void ProTypeMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor")) {
+ // Skip declarations delayed by late template parsing without a body.
+ if (!Ctor->getBody())
+ return;
+ checkMissingMemberInitializer(*Result.Context, *Ctor->getParent(), Ctor);
+ checkMissingBaseClassInitializer(*Result.Context, *Ctor->getParent(), Ctor);
+ } else if (const auto *Record =
+ Result.Nodes.getNodeAs<CXXRecordDecl>("record")) {
+ assert(Record->hasDefaultConstructor() &&
+ "Matched record should have a default constructor");
+ checkMissingMemberInitializer(*Result.Context, *Record, nullptr);
+ checkMissingBaseClassInitializer(*Result.Context, *Record, nullptr);
+ } else if (const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var")) {
+ checkUninitializedTrivialType(*Result.Context, Var);
+ }
+}
+
+void ProTypeMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IgnoreArrays", IgnoreArrays);
+}
+
+// FIXME: Copied from clang/lib/Sema/SemaDeclCXX.cpp.
+static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) {
+ if (T->isIncompleteArrayType())
+ return true;
+
+ while (const ConstantArrayType *ArrayT = Context.getAsConstantArrayType(T)) {
+ if (!ArrayT->getSize())
+ return true;
+
+ T = ArrayT->getElementType();
+ }
+
+ return false;
+}
+
+static bool isEmpty(ASTContext &Context, const QualType &Type) {
+ if (const CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl()) {
+ return ClassDecl->isEmpty();
+ }
+ return isIncompleteOrZeroLengthArrayType(Context, Type);
+}
+
+void ProTypeMemberInitCheck::checkMissingMemberInitializer(
+ ASTContext &Context, const CXXRecordDecl &ClassDecl,
+ const CXXConstructorDecl *Ctor) {
+ bool IsUnion = ClassDecl.isUnion();
+
+ if (IsUnion && ClassDecl.hasInClassInitializer())
+ return;
+
+ // Gather all fields (direct and indirect) that need to be initialized.
+ SmallPtrSet<const FieldDecl *, 16> FieldsToInit;
+ forEachField(ClassDecl, ClassDecl.fields(), [&](const FieldDecl *F) {
+ if (!F->hasInClassInitializer() &&
+ utils::type_traits::isTriviallyDefaultConstructible(F->getType(),
+ Context) &&
+ !isEmpty(Context, F->getType()) && !F->isUnnamedBitfield())
+ FieldsToInit.insert(F);
+ });
+ if (FieldsToInit.empty())
+ return;
+
+ if (Ctor) {
+ for (const CXXCtorInitializer *Init : Ctor->inits()) {
+ // Remove any fields that were explicitly written in the initializer list
+ // or in-class.
+ if (Init->isAnyMemberInitializer() && Init->isWritten()) {
+ if (IsUnion)
+ return; // We can only initialize one member of a union.
+ FieldsToInit.erase(Init->getAnyMember());
+ }
+ }
+ removeFieldsInitializedInBody(*Ctor->getBody(), Context, FieldsToInit);
+ }
+
+ // Collect all fields in order, both direct fields and indirect fields from
+ // anonmyous record types.
+ SmallVector<const FieldDecl *, 16> OrderedFields;
+ forEachField(ClassDecl, ClassDecl.fields(),
+ [&](const FieldDecl *F) { OrderedFields.push_back(F); });
+
+ // Collect all the fields we need to initialize, including indirect fields.
+ SmallPtrSet<const FieldDecl *, 16> AllFieldsToInit;
+ forEachField(ClassDecl, FieldsToInit,
+ [&](const FieldDecl *F) { AllFieldsToInit.insert(F); });
+ if (AllFieldsToInit.empty())
+ return;
+
+ DiagnosticBuilder Diag =
+ diag(Ctor ? Ctor->getLocStart() : ClassDecl.getLocation(),
+ IsUnion
+ ? "union constructor should initialize one of these fields: %0"
+ : "constructor does not initialize these fields: %0")
+ << toCommaSeparatedString(OrderedFields, AllFieldsToInit);
+
+ // Do not propose fixes for constructors in macros since we cannot place them
+ // correctly.
+ if (Ctor && Ctor->getLocStart().isMacroID())
+ return;
+
+ // Collect all fields but only suggest a fix for the first member of unions,
+ // as initializing more than one union member is an error.
+ SmallPtrSet<const FieldDecl *, 16> FieldsToFix;
+ SmallPtrSet<const RecordDecl *, 4> UnionsSeen;
+ forEachField(ClassDecl, OrderedFields, [&](const FieldDecl *F) {
+ if (!FieldsToInit.count(F))
+ return;
+ // Don't suggest fixes for enums because we don't know a good default.
+ // Don't suggest fixes for bitfields because in-class initialization is not
+ // possible until C++2a.
+ if (F->getType()->isEnumeralType() ||
+ (!getLangOpts().CPlusPlus2a && F->isBitField()))
+ return;
+ if (!F->getParent()->isUnion() || UnionsSeen.insert(F->getParent()).second)
+ FieldsToFix.insert(F);
+ });
+ if (FieldsToFix.empty())
+ return;
+
+ // Use in-class initialization if possible.
+ if (Context.getLangOpts().CPlusPlus11) {
+ for (const FieldDecl *Field : FieldsToFix) {
+ Diag << FixItHint::CreateInsertion(
+ getLocationForEndOfToken(Context, Field->getSourceRange().getEnd()),
+ "{}");
+ }
+ } else if (Ctor) {
+ // Otherwise, rewrite the constructor's initializer list.
+ fixInitializerList(Context, Diag, Ctor, FieldsToFix);
+ }
+}
+
+void ProTypeMemberInitCheck::checkMissingBaseClassInitializer(
+ const ASTContext &Context, const CXXRecordDecl &ClassDecl,
+ const CXXConstructorDecl *Ctor) {
+
+ // Gather any base classes that need to be initialized.
+ SmallVector<const RecordDecl *, 4> AllBases;
+ SmallPtrSet<const RecordDecl *, 4> BasesToInit;
+ for (const CXXBaseSpecifier &Base : ClassDecl.bases()) {
+ if (const auto *BaseClassDecl = getCanonicalRecordDecl(Base.getType())) {
+ AllBases.emplace_back(BaseClassDecl);
+ if (!BaseClassDecl->field_empty() &&
+ utils::type_traits::isTriviallyDefaultConstructible(Base.getType(),
+ Context))
+ BasesToInit.insert(BaseClassDecl);
+ }
+ }
+
+ if (BasesToInit.empty())
+ return;
+
+ // Remove any bases that were explicitly written in the initializer list.
+ if (Ctor) {
+ if (Ctor->isImplicit())
+ return;
+
+ for (const CXXCtorInitializer *Init : Ctor->inits()) {
+ if (Init->isBaseInitializer() && Init->isWritten())
+ BasesToInit.erase(Init->getBaseClass()->getAsCXXRecordDecl());
+ }
+ }
+
+ if (BasesToInit.empty())
+ return;
+
+ DiagnosticBuilder Diag =
+ diag(Ctor ? Ctor->getLocStart() : ClassDecl.getLocation(),
+ "constructor does not initialize these bases: %0")
+ << toCommaSeparatedString(AllBases, BasesToInit);
+
+ if (Ctor)
+ fixInitializerList(Context, Diag, Ctor, BasesToInit);
+}
+
+void ProTypeMemberInitCheck::checkUninitializedTrivialType(
+ const ASTContext &Context, const VarDecl *Var) {
+ DiagnosticBuilder Diag =
+ diag(Var->getLocStart(), "uninitialized record type: %0") << Var;
+
+ Diag << FixItHint::CreateInsertion(
+ getLocationForEndOfToken(Context, Var->getSourceRange().getEnd()),
+ Context.getLangOpts().CPlusPlus11 ? "{}" : " = {}");
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
new file mode 100644
index 0000000..20d3f60
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
@@ -0,0 +1,74 @@
+//===--- ProTypeMemberInitCheck.h - clang-tidy-------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_MEMBER_INIT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_MEMBER_INIT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// \brief Implements C++ Core Guidelines Type.6.
+///
+/// Checks that every user-provided constructor value-initializes all class
+/// members and base classes that would have undefined behavior otherwise. Also
+/// check that any record types without user-provided default constructors are
+/// value-initialized where used.
+///
+/// Members initialized through function calls in the body of the constructor
+/// will result in false positives.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.html
+/// TODO: See if 'fixes' for false positives are optimized away by the compiler.
+/// TODO: For classes with multiple constructors, make sure that we don't offer
+/// multiple in-class initializer fixits for the same member.
+class ProTypeMemberInitCheck : public ClangTidyCheck {
+public:
+ ProTypeMemberInitCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ // Checks Type.6 part 1:
+ // Issue a diagnostic for any constructor of a non-trivially-constructible
+ // type that does not initialize all member variables.
+ //
+ // To fix: Write a data member initializer, or mention it in the member
+ // initializer list.
+ void checkMissingMemberInitializer(ASTContext &Context,
+ const CXXRecordDecl &ClassDecl,
+ const CXXConstructorDecl *Ctor);
+
+ // A subtle side effect of Type.6 part 2:
+ // Make sure to initialize trivially constructible base classes.
+ void checkMissingBaseClassInitializer(const ASTContext &Context,
+ const CXXRecordDecl &ClassDecl,
+ const CXXConstructorDecl *Ctor);
+
+ // Checks Type.6 part 2:
+ // Issue a diagnostic when constructing an object of a trivially constructible
+ // type without () or {} to initialize its members.
+ //
+ // To fix: Add () or {}.
+ void checkUninitializedTrivialType(const ASTContext &Context,
+ const VarDecl *Var);
+
+ // Whether arrays need to be initialized or not. Default is false.
+ bool IgnoreArrays;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_MEMBER_INIT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeReinterpretCastCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeReinterpretCastCheck.cpp
new file mode 100644
index 0000000..e56e638
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeReinterpretCastCheck.cpp
@@ -0,0 +1,36 @@
+//===--- ProTypeReinterpretCastCheck.cpp - clang-tidy----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProTypeReinterpretCastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+void ProTypeReinterpretCastCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(cxxReinterpretCastExpr().bind("cast"), this);
+}
+
+void ProTypeReinterpretCastCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *MatchedCast =
+ Result.Nodes.getNodeAs<CXXReinterpretCastExpr>("cast");
+ diag(MatchedCast->getOperatorLoc(), "do not use reinterpret_cast");
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeReinterpretCastCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeReinterpretCastCheck.h
new file mode 100644
index 0000000..9610546
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeReinterpretCastCheck.h
@@ -0,0 +1,35 @@
+//===--- ProTypeReinterpretCast.h - clang-tidy------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_REINTERPRETCAST_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_REINTERPRETCAST_CHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// Flags all occurrences of reinterpret_cast
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-type-reinterpret-cast.html
+class ProTypeReinterpretCastCheck : public ClangTidyCheck {
+public:
+ ProTypeReinterpretCastCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_REINTERPRETCAST_CHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.cpp
new file mode 100644
index 0000000..f43e4fa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.cpp
@@ -0,0 +1,55 @@
+//===--- ProTypeStaticCastDowncastCheck.cpp - clang-tidy-------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProTypeStaticCastDowncastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+void ProTypeStaticCastDowncastCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(
+ cxxStaticCastExpr(unless(isInTemplateInstantiation())).bind("cast"),
+ this);
+}
+
+void ProTypeStaticCastDowncastCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *MatchedCast = Result.Nodes.getNodeAs<CXXStaticCastExpr>("cast");
+ if (MatchedCast->getCastKind() != CK_BaseToDerived)
+ return;
+
+ QualType SourceType = MatchedCast->getSubExpr()->getType();
+ const auto *SourceDecl = SourceType->getPointeeCXXRecordDecl();
+ if (!SourceDecl) // The cast is from object to reference
+ SourceDecl = SourceType->getAsCXXRecordDecl();
+ if (!SourceDecl)
+ return;
+
+ if (SourceDecl->isPolymorphic())
+ diag(MatchedCast->getOperatorLoc(),
+ "do not use static_cast to downcast from a base to a derived class; "
+ "use dynamic_cast instead")
+ << FixItHint::CreateReplacement(MatchedCast->getOperatorLoc(),
+ "dynamic_cast");
+ else
+ diag(MatchedCast->getOperatorLoc(),
+ "do not use static_cast to downcast from a base to a derived class");
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.h
new file mode 100644
index 0000000..b6d76a6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeStaticCastDowncastCheck.h
@@ -0,0 +1,36 @@
+//===--- ProTypeStaticCastDowncastCheck.h - clang-tidy-----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_STATIC_CAST_DOWNCAST_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_STATIC_CAST_DOWNCAST_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// Checks for usages of static_cast, where a base class is downcasted to a
+/// derived class.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-type-static-cast-downcast.html
+class ProTypeStaticCastDowncastCheck : public ClangTidyCheck {
+public:
+ ProTypeStaticCastDowncastCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_STATIC_CAST_DOWNCAST_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeUnionAccessCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeUnionAccessCheck.cpp
new file mode 100644
index 0000000..09752f6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeUnionAccessCheck.cpp
@@ -0,0 +1,38 @@
+//===--- ProTypeUnionAccessCheck.cpp - clang-tidy--------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProTypeUnionAccessCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+void ProTypeUnionAccessCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(
+ memberExpr(hasObjectExpression(hasType(recordDecl(isUnion()))))
+ .bind("expr"),
+ this);
+}
+
+void ProTypeUnionAccessCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Matched = Result.Nodes.getNodeAs<MemberExpr>("expr");
+ diag(Matched->getMemberLoc(),
+ "do not access members of unions; use (boost::)variant instead");
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeUnionAccessCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeUnionAccessCheck.h
new file mode 100644
index 0000000..fc7dd67
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeUnionAccessCheck.h
@@ -0,0 +1,36 @@
+//===--- ProTypeUnionAccessCheck.h - clang-tidy------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_UNION_ACCESS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_UNION_ACCESS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// This check flags all access to members of unions.
+/// Access to a union as a whole (e.g. passing to a function) is not flagged.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-type-union-access.html
+class ProTypeUnionAccessCheck : public ClangTidyCheck {
+public:
+ ProTypeUnionAccessCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_UNION_ACCESS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp
new file mode 100644
index 0000000..56227b2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp
@@ -0,0 +1,76 @@
+//===--- ProTypeVarargCheck.cpp - clang-tidy-------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProTypeVarargCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+const internal::VariadicDynCastAllOfMatcher<Stmt, VAArgExpr> vAArgExpr;
+
+void ProTypeVarargCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(vAArgExpr().bind("va_use"), this);
+
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(isVariadic()))).bind("callvararg"), this);
+}
+
+static bool hasSingleVariadicArgumentWithValue(const CallExpr *C, uint64_t I) {
+ const auto *FDecl = dyn_cast<FunctionDecl>(C->getCalleeDecl());
+ if (!FDecl)
+ return false;
+
+ auto N = FDecl->getNumParams(); // Number of parameters without '...'
+ if (C->getNumArgs() != N + 1)
+ return false; // more/less than one argument passed to '...'
+
+ const auto *IntLit =
+ dyn_cast<IntegerLiteral>(C->getArg(N)->IgnoreParenImpCasts());
+ if (!IntLit)
+ return false;
+
+ if (IntLit->getValue() != I)
+ return false;
+
+ return true;
+}
+
+void ProTypeVarargCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *Matched = Result.Nodes.getNodeAs<CallExpr>("callvararg")) {
+ if (hasSingleVariadicArgumentWithValue(Matched, 0))
+ return;
+ diag(Matched->getExprLoc(), "do not call c-style vararg functions");
+ }
+
+ if (const auto *Matched = Result.Nodes.getNodeAs<Expr>("va_use")) {
+ diag(Matched->getExprLoc(),
+ "do not use va_start/va_arg to define c-style vararg functions; "
+ "use variadic templates instead");
+ }
+
+ if (const auto *Matched = Result.Nodes.getNodeAs<VarDecl>("va_list")) {
+ auto SR = Matched->getSourceRange();
+ if (SR.isInvalid())
+ return; // some implicitly generated builtins take va_list
+ diag(SR.getBegin(), "do not declare variables of type va_list; "
+ "use variadic templates instead");
+ }
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.h
new file mode 100644
index 0000000..558c856
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.h
@@ -0,0 +1,36 @@
+//===--- ProTypeVarargCheck.h - clang-tidy--------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_VARARG_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_VARARG_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// This check flags all calls to c-style variadic functions and all use
+/// of va_arg.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-type-vararg.html
+class ProTypeVarargCheck : public ClangTidyCheck {
+public:
+ ProTypeVarargCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_VARARG_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp
new file mode 100644
index 0000000..53b2f72
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp
@@ -0,0 +1,136 @@
+//===--- SlicingCheck.cpp - clang-tidy-------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SlicingCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+void SlicingCheck::registerMatchers(MatchFinder *Finder) {
+ // When we see:
+ // class B : public A { ... };
+ // A a;
+ // B b;
+ // a = b;
+ // The assignment is OK if:
+ // - the assignment operator is defined as taking a B as second parameter,
+ // or
+ // - B does not define any additional members (either variables or
+ // overrides) wrt A.
+ //
+ // The same holds for copy ctor calls. This also captures stuff like:
+ // void f(A a);
+ // f(b);
+
+ // Helpers.
+ const auto OfBaseClass = ofClass(cxxRecordDecl().bind("BaseDecl"));
+ const auto IsDerivedFromBaseDecl =
+ cxxRecordDecl(isDerivedFrom(equalsBoundNode("BaseDecl")))
+ .bind("DerivedDecl");
+ const auto HasTypeDerivedFromBaseDecl =
+ anyOf(hasType(IsDerivedFromBaseDecl),
+ hasType(references(IsDerivedFromBaseDecl)));
+ const auto IsWithinDerivedCtor =
+ hasParent(cxxConstructorDecl(ofClass(equalsBoundNode("DerivedDecl"))));
+
+ // Assignement slicing: "a = b;" and "a = std::move(b);" variants.
+ const auto SlicesObjectInAssignment =
+ callExpr(callee(cxxMethodDecl(anyOf(isCopyAssignmentOperator(),
+ isMoveAssignmentOperator()),
+ OfBaseClass)),
+ hasArgument(1, HasTypeDerivedFromBaseDecl));
+
+ // Construction slicing: "A a{b};" and "f(b);" variants. Note that in case of
+ // slicing the letter will create a temporary and therefore call a ctor.
+ const auto SlicesObjectInCtor = cxxConstructExpr(
+ hasDeclaration(cxxConstructorDecl(
+ anyOf(isCopyConstructor(), isMoveConstructor()), OfBaseClass)),
+ hasArgument(0, HasTypeDerivedFromBaseDecl),
+ // We need to disable matching on the call to the base copy/move
+ // constructor in DerivedDecl's constructors.
+ unless(IsWithinDerivedCtor));
+
+ Finder->addMatcher(
+ expr(anyOf(SlicesObjectInAssignment, SlicesObjectInCtor)).bind("Call"),
+ this);
+}
+
+/// Warns on methods overridden in DerivedDecl with respect to BaseDecl.
+/// FIXME: this warns on all overrides outside of the sliced path in case of
+/// multiple inheritance.
+void SlicingCheck::DiagnoseSlicedOverriddenMethods(
+ const Expr &Call, const CXXRecordDecl &DerivedDecl,
+ const CXXRecordDecl &BaseDecl) {
+ if (DerivedDecl.getCanonicalDecl() == BaseDecl.getCanonicalDecl())
+ return;
+ for (const auto &Method : DerivedDecl.methods()) {
+ // Virtual destructors are OK. We're ignoring constructors since they are
+ // tagged as overrides.
+ if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
+ continue;
+ if (Method->size_overridden_methods() > 0) {
+ diag(Call.getExprLoc(),
+ "slicing object from type %0 to %1 discards override %2")
+ << &DerivedDecl << &BaseDecl << Method;
+ }
+ }
+ // Recursively process bases.
+ for (const auto &Base : DerivedDecl.bases()) {
+ if (const auto *BaseRecordType = Base.getType()->getAs<RecordType>()) {
+ if (const auto *BaseRecord = cast_or_null<CXXRecordDecl>(
+ BaseRecordType->getDecl()->getDefinition()))
+ DiagnoseSlicedOverriddenMethods(Call, *BaseRecord, BaseDecl);
+ }
+ }
+}
+
+void SlicingCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *BaseDecl = Result.Nodes.getNodeAs<CXXRecordDecl>("BaseDecl");
+ const auto *DerivedDecl =
+ Result.Nodes.getNodeAs<CXXRecordDecl>("DerivedDecl");
+ const auto *Call = Result.Nodes.getNodeAs<Expr>("Call");
+ assert(BaseDecl != nullptr);
+ assert(DerivedDecl != nullptr);
+ assert(Call != nullptr);
+
+ // Warn when slicing the vtable.
+ // We're looking through all the methods in the derived class and see if they
+ // override some methods in the base class.
+ // It's not enough to just test whether the class is polymorphic because we
+ // would be fine slicing B to A if no method in B (or its bases) overrides
+ // anything in A:
+ // class A { virtual void f(); };
+ // class B : public A {};
+ // because in that case calling A::f is the same as calling B::f.
+ DiagnoseSlicedOverriddenMethods(*Call, *DerivedDecl, *BaseDecl);
+
+ // Warn when slicing member variables.
+ const auto &BaseLayout =
+ BaseDecl->getASTContext().getASTRecordLayout(BaseDecl);
+ const auto &DerivedLayout =
+ DerivedDecl->getASTContext().getASTRecordLayout(DerivedDecl);
+ const CharUnits StateSize =
+ DerivedLayout.getDataSize() - BaseLayout.getDataSize();
+ if (StateSize.isPositive()) {
+ diag(Call->getExprLoc(), "slicing object from type %0 to %1 discards "
+ "%2 bytes of state")
+ << DerivedDecl << BaseDecl << static_cast<int>(StateSize.getQuantity());
+ }
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.h
new file mode 100644
index 0000000..9ee91bc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.h
@@ -0,0 +1,45 @@
+//===--- SlicingCheck.h - clang-tidy-----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_SLICING_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_SLICING_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// Flags slicing (incomplete copying of an object's state) of member variables
+/// or vtable. See:
+/// - https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es63-dont-slice
+/// for the former, and
+/// - https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c145-access-polymorphic-objects-through-pointers-and-references
+/// for the latter
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-slicing.html
+class SlicingCheck : public ClangTidyCheck {
+public:
+ SlicingCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void DiagnoseSlicedOverriddenMethods(const Expr &call,
+ const CXXRecordDecl &DerivedDecl,
+ const CXXRecordDecl &BaseDecl);
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_SLICING_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp
new file mode 100644
index 0000000..df3c279
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp
@@ -0,0 +1,191 @@
+//===--- SpecialMemberFunctionsCheck.cpp - clang-tidy----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SpecialMemberFunctionsCheck.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/StringExtras.h"
+
+#define DEBUG_TYPE "clang-tidy"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+SpecialMemberFunctionsCheck::SpecialMemberFunctionsCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ AllowMissingMoveFunctions(Options.get("AllowMissingMoveFunctions", 0)),
+ AllowSoleDefaultDtor(Options.get("AllowSoleDefaultDtor", 0)) {}
+
+void SpecialMemberFunctionsCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "AllowMissingMoveFunctions", AllowMissingMoveFunctions);
+ Options.store(Opts, "AllowSoleDefaultDtor", AllowSoleDefaultDtor);
+}
+
+void SpecialMemberFunctionsCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+ Finder->addMatcher(
+ cxxRecordDecl(
+ eachOf(
+ has(cxxDestructorDecl(unless(isImplicit())).bind("dtor")),
+ has(cxxConstructorDecl(isCopyConstructor(), unless(isImplicit()))
+ .bind("copy-ctor")),
+ has(cxxMethodDecl(isCopyAssignmentOperator(),
+ unless(isImplicit()))
+ .bind("copy-assign")),
+ has(cxxConstructorDecl(isMoveConstructor(), unless(isImplicit()))
+ .bind("move-ctor")),
+ has(cxxMethodDecl(isMoveAssignmentOperator(),
+ unless(isImplicit()))
+ .bind("move-assign"))))
+ .bind("class-def"),
+ this);
+}
+
+static llvm::StringRef
+toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K) {
+ switch (K) {
+ case SpecialMemberFunctionsCheck::SpecialMemberFunctionKind::Destructor:
+ return "a destructor";
+ case SpecialMemberFunctionsCheck::SpecialMemberFunctionKind::
+ DefaultDestructor:
+ return "a default destructor";
+ case SpecialMemberFunctionsCheck::SpecialMemberFunctionKind::
+ NonDefaultDestructor:
+ return "a non-default destructor";
+ case SpecialMemberFunctionsCheck::SpecialMemberFunctionKind::CopyConstructor:
+ return "a copy constructor";
+ case SpecialMemberFunctionsCheck::SpecialMemberFunctionKind::CopyAssignment:
+ return "a copy assignment operator";
+ case SpecialMemberFunctionsCheck::SpecialMemberFunctionKind::MoveConstructor:
+ return "a move constructor";
+ case SpecialMemberFunctionsCheck::SpecialMemberFunctionKind::MoveAssignment:
+ return "a move assignment operator";
+ }
+ llvm_unreachable("Unhandled SpecialMemberFunctionKind");
+}
+
+static std::string
+join(ArrayRef<SpecialMemberFunctionsCheck::SpecialMemberFunctionKind> SMFS,
+ llvm::StringRef AndOr) {
+
+ assert(!SMFS.empty() &&
+ "List of defined or undefined members should never be empty.");
+ std::string Buffer;
+ llvm::raw_string_ostream Stream(Buffer);
+
+ Stream << toString(SMFS[0]);
+ size_t LastIndex = SMFS.size() - 1;
+ for (size_t i = 1; i < LastIndex; ++i) {
+ Stream << ", " << toString(SMFS[i]);
+ }
+ if (LastIndex != 0) {
+ Stream << AndOr << toString(SMFS[LastIndex]);
+ }
+ return Stream.str();
+}
+
+void SpecialMemberFunctionsCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<CXXRecordDecl>("class-def");
+ if (!MatchedDecl)
+ return;
+
+ ClassDefId ID(MatchedDecl->getLocation(), MatchedDecl->getName());
+
+ auto StoreMember = [this, &ID](SpecialMemberFunctionKind Kind) {
+ llvm::SmallVectorImpl<SpecialMemberFunctionKind> &Members =
+ ClassWithSpecialMembers[ID];
+ if (!llvm::is_contained(Members, Kind))
+ Members.push_back(Kind);
+ };
+
+ if (const auto *Dtor = Result.Nodes.getNodeAs<CXXMethodDecl>("dtor")) {
+ StoreMember(Dtor->isDefaulted()
+ ? SpecialMemberFunctionKind::DefaultDestructor
+ : SpecialMemberFunctionKind::NonDefaultDestructor);
+ }
+
+ std::initializer_list<std::pair<std::string, SpecialMemberFunctionKind>>
+ Matchers = {{"copy-ctor", SpecialMemberFunctionKind::CopyConstructor},
+ {"copy-assign", SpecialMemberFunctionKind::CopyAssignment},
+ {"move-ctor", SpecialMemberFunctionKind::MoveConstructor},
+ {"move-assign", SpecialMemberFunctionKind::MoveAssignment}};
+
+ for (const auto &KV : Matchers)
+ if (Result.Nodes.getNodeAs<CXXMethodDecl>(KV.first)) {
+ StoreMember(KV.second);
+ }
+}
+
+void SpecialMemberFunctionsCheck::onEndOfTranslationUnit() {
+ for (const auto &C : ClassWithSpecialMembers) {
+ checkForMissingMembers(C.first, C.second);
+ }
+}
+
+void SpecialMemberFunctionsCheck::checkForMissingMembers(
+ const ClassDefId &ID,
+ llvm::ArrayRef<SpecialMemberFunctionKind> DefinedMembers) {
+ llvm::SmallVector<SpecialMemberFunctionKind, 5> MissingMembers;
+
+ auto HasMember = [&](SpecialMemberFunctionKind Kind) {
+ return llvm::is_contained(DefinedMembers, Kind);
+ };
+
+ auto RequireMember = [&](SpecialMemberFunctionKind Kind) {
+ if (!HasMember(Kind))
+ MissingMembers.push_back(Kind);
+ };
+
+ bool RequireThree =
+ HasMember(SpecialMemberFunctionKind::NonDefaultDestructor) ||
+ (!AllowSoleDefaultDtor &&
+ HasMember(SpecialMemberFunctionKind::DefaultDestructor)) ||
+ HasMember(SpecialMemberFunctionKind::CopyConstructor) ||
+ HasMember(SpecialMemberFunctionKind::CopyAssignment) ||
+ HasMember(SpecialMemberFunctionKind::MoveConstructor) ||
+ HasMember(SpecialMemberFunctionKind::MoveAssignment);
+
+ bool RequireFive = (!AllowMissingMoveFunctions && RequireThree &&
+ getLangOpts().CPlusPlus11) ||
+ HasMember(SpecialMemberFunctionKind::MoveConstructor) ||
+ HasMember(SpecialMemberFunctionKind::MoveAssignment);
+
+ if (RequireThree) {
+ if (!HasMember(SpecialMemberFunctionKind::DefaultDestructor) &&
+ !HasMember(SpecialMemberFunctionKind::NonDefaultDestructor))
+ MissingMembers.push_back(SpecialMemberFunctionKind::Destructor);
+
+ RequireMember(SpecialMemberFunctionKind::CopyConstructor);
+ RequireMember(SpecialMemberFunctionKind::CopyAssignment);
+ }
+
+ if (RequireFive) {
+ assert(RequireThree);
+ RequireMember(SpecialMemberFunctionKind::MoveConstructor);
+ RequireMember(SpecialMemberFunctionKind::MoveAssignment);
+ }
+
+ if (!MissingMembers.empty())
+ diag(ID.first, "class '%0' defines %1 but does not define %2")
+ << ID.second << cppcoreguidelines::join(DefinedMembers, " and ")
+ << cppcoreguidelines::join(MissingMembers, " or ");
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.h
new file mode 100644
index 0000000..8ab0c92
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.h
@@ -0,0 +1,105 @@
+//===--- SpecialMemberFunctionsCheck.h - clang-tidy--------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_SPECIAL_MEMBER_FUNCTIONS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_SPECIAL_MEMBER_FUNCTIONS_H
+
+#include "../ClangTidy.h"
+
+#include "llvm/ADT/DenseMapInfo.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// Checks for classes where some, but not all, of the special member functions
+/// are defined.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-special-member-functions.html
+class SpecialMemberFunctionsCheck : public ClangTidyCheck {
+public:
+ SpecialMemberFunctionsCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void onEndOfTranslationUnit() override;
+
+ enum class SpecialMemberFunctionKind : uint8_t {
+ Destructor,
+ DefaultDestructor,
+ NonDefaultDestructor,
+ CopyConstructor,
+ CopyAssignment,
+ MoveConstructor,
+ MoveAssignment
+ };
+
+ using ClassDefId = std::pair<SourceLocation, std::string>;
+
+ using ClassDefiningSpecialMembersMap =
+ llvm::DenseMap<ClassDefId,
+ llvm::SmallVector<SpecialMemberFunctionKind, 5>>;
+
+private:
+ void checkForMissingMembers(
+ const ClassDefId &ID,
+ llvm::ArrayRef<SpecialMemberFunctionKind> DefinedSpecialMembers);
+
+ const bool AllowMissingMoveFunctions;
+ const bool AllowSoleDefaultDtor;
+ ClassDefiningSpecialMembersMap ClassWithSpecialMembers;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+namespace llvm {
+/// Specialisation of DenseMapInfo to allow ClassDefId objects in DenseMaps
+/// FIXME: Move this to the corresponding cpp file as is done for
+/// clang-tidy/readability/IdentifierNamingCheck.cpp.
+template <>
+struct DenseMapInfo<
+ clang::tidy::cppcoreguidelines::SpecialMemberFunctionsCheck::ClassDefId> {
+ using ClassDefId =
+ clang::tidy::cppcoreguidelines::SpecialMemberFunctionsCheck::ClassDefId;
+
+ static inline ClassDefId getEmptyKey() {
+ return ClassDefId(
+ clang::SourceLocation::getFromRawEncoding(static_cast<unsigned>(-1)),
+ "EMPTY");
+ }
+
+ static inline ClassDefId getTombstoneKey() {
+ return ClassDefId(
+ clang::SourceLocation::getFromRawEncoding(static_cast<unsigned>(-2)),
+ "TOMBSTONE");
+ }
+
+ static unsigned getHashValue(ClassDefId Val) {
+ assert(Val != getEmptyKey() && "Cannot hash the empty key!");
+ assert(Val != getTombstoneKey() && "Cannot hash the tombstone key!");
+
+ std::hash<ClassDefId::second_type> SecondHash;
+ return Val.first.getRawEncoding() + SecondHash(Val.second);
+ }
+
+ static bool isEqual(const ClassDefId &LHS, const ClassDefId &RHS) {
+ if (RHS == getEmptyKey())
+ return LHS == getEmptyKey();
+ if (RHS == getTombstoneKey())
+ return LHS == getTombstoneKey();
+ return LHS == RHS;
+ }
+};
+
+} // namespace llvm
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_SPECIAL_MEMBER_FUNCTIONS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/CMakeLists.txt
new file mode 100644
index 0000000..b69a5c0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyFuchsiaModule
+ DefaultArgumentsCheck.cpp
+ FuchsiaTidyModule.cpp
+ MultipleInheritanceCheck.cpp
+ OverloadedOperatorCheck.cpp
+ RestrictSystemIncludesCheck.cpp
+ StaticallyConstructedObjectsCheck.cpp
+ TrailingReturnCheck.cpp
+ VirtualInheritanceCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyGoogleModule
+ clangTidyUtils
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsCheck.cpp
new file mode 100644
index 0000000..493ce9a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsCheck.cpp
@@ -0,0 +1,64 @@
+//===--- DefaultArgumentsCheck.cpp - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DefaultArgumentsCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+void DefaultArgumentsCheck::registerMatchers(MatchFinder *Finder) {
+ // Calling a function which uses default arguments is disallowed.
+ Finder->addMatcher(cxxDefaultArgExpr().bind("stmt"), this);
+ // Declaring default parameters is disallowed.
+ Finder->addMatcher(parmVarDecl(hasDefaultArgument()).bind("decl"), this);
+}
+
+void DefaultArgumentsCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *S =
+ Result.Nodes.getNodeAs<CXXDefaultArgExpr>("stmt")) {
+ diag(S->getUsedLocation(),
+ "calling a function that uses a default argument is disallowed");
+ diag(S->getParam()->getLocStart(),
+ "default parameter was declared here",
+ DiagnosticIDs::Note);
+ } else if (const ParmVarDecl *D =
+ Result.Nodes.getNodeAs<ParmVarDecl>("decl")) {
+ SourceRange DefaultArgRange = D->getDefaultArgRange();
+
+ if (DefaultArgRange.getEnd() != D->getLocEnd()) {
+ return;
+ } else if (DefaultArgRange.getBegin().isMacroID()) {
+ diag(D->getLocStart(),
+ "declaring a parameter with a default argument is disallowed");
+ } else {
+ SourceLocation StartLocation = D->getName().empty() ?
+ D->getLocStart() : D->getLocation();
+
+ SourceRange RemovalRange(Lexer::getLocForEndOfToken(
+ StartLocation, 0,
+ *Result.SourceManager,
+ Result.Context->getLangOpts()
+ ),
+ DefaultArgRange.getEnd()
+ );
+
+ diag(D->getLocStart(),
+ "declaring a parameter with a default argument is disallowed")
+ << D
+ << FixItHint::CreateRemoval(RemovalRange);
+ }
+ }
+}
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsCheck.h
new file mode 100644
index 0000000..f54fd96
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/DefaultArgumentsCheck.h
@@ -0,0 +1,35 @@
+//===--- DefaultArgumentsCheck.h - clang-tidy--------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_DEFAULT_ARGUMENTS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_DEFAULT_ARGUMENTS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+/// Default arguments are not allowed in declared or called functions.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-default-arguments.html
+class DefaultArgumentsCheck : public ClangTidyCheck {
+public:
+ DefaultArgumentsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_DEFAULT_ARGUMENTS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/FuchsiaTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/FuchsiaTidyModule.cpp
new file mode 100644
index 0000000..0d3bbfe
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/FuchsiaTidyModule.cpp
@@ -0,0 +1,60 @@
+//===--- FuchsiaTidyModule.cpp - clang-tidy--------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "../google/UnnamedNamespaceInHeaderCheck.h"
+#include "DefaultArgumentsCheck.h"
+#include "MultipleInheritanceCheck.h"
+#include "OverloadedOperatorCheck.h"
+#include "RestrictSystemIncludesCheck.h"
+#include "StaticallyConstructedObjectsCheck.h"
+#include "TrailingReturnCheck.h"
+#include "VirtualInheritanceCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+/// This module is for Fuchsia-specific checks.
+class FuchsiaModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<DefaultArgumentsCheck>(
+ "fuchsia-default-arguments");
+ CheckFactories.registerCheck<google::build::UnnamedNamespaceInHeaderCheck>(
+ "fuchsia-header-anon-namespaces");
+ CheckFactories.registerCheck<MultipleInheritanceCheck>(
+ "fuchsia-multiple-inheritance");
+ CheckFactories.registerCheck<OverloadedOperatorCheck>(
+ "fuchsia-overloaded-operator");
+ CheckFactories.registerCheck<RestrictSystemIncludesCheck>(
+ "fuchsia-restrict-system-includes");
+ CheckFactories.registerCheck<StaticallyConstructedObjectsCheck>(
+ "fuchsia-statically-constructed-objects");
+ CheckFactories.registerCheck<TrailingReturnCheck>(
+ "fuchsia-trailing-return");
+ CheckFactories.registerCheck<VirtualInheritanceCheck>(
+ "fuchsia-virtual-inheritance");
+ }
+};
+// Register the FuchsiaTidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<FuchsiaModule>
+ X("fuchsia-module", "Adds Fuchsia platform checks.");
+} // namespace fuchsia
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the FuchsiaModule.
+volatile int FuchsiaModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
new file mode 100644
index 0000000..35504c9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.cpp
@@ -0,0 +1,132 @@
+//===--- MultipleInheritanceCheck.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MultipleInheritanceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang;
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+namespace {
+AST_MATCHER(CXXRecordDecl, hasBases) {
+ if (Node.hasDefinition())
+ return Node.getNumBases() > 0;
+ return false;
+}
+} // namespace
+
+// Adds a node (by name) to the interface map, if it was not present in the map
+// previously.
+void MultipleInheritanceCheck::addNodeToInterfaceMap(const CXXRecordDecl *Node,
+ bool isInterface) {
+ assert(Node->getIdentifier());
+ StringRef Name = Node->getIdentifier()->getName();
+ InterfaceMap.insert(std::make_pair(Name, isInterface));
+}
+
+// Returns "true" if the boolean "isInterface" has been set to the
+// interface status of the current Node. Return "false" if the
+// interface status for the current node is not yet known.
+bool MultipleInheritanceCheck::getInterfaceStatus(const CXXRecordDecl *Node,
+ bool &isInterface) const {
+ assert(Node->getIdentifier());
+ StringRef Name = Node->getIdentifier()->getName();
+ llvm::StringMapConstIterator<bool> Pair = InterfaceMap.find(Name);
+ if (Pair == InterfaceMap.end())
+ return false;
+ isInterface = Pair->second;
+ return true;
+}
+
+bool MultipleInheritanceCheck::isCurrentClassInterface(
+ const CXXRecordDecl *Node) const {
+ // Interfaces should have no fields.
+ if (!Node->field_empty()) return false;
+
+ // Interfaces should have exclusively pure methods.
+ return llvm::none_of(Node->methods(), [](const CXXMethodDecl *M) {
+ return M->isUserProvided() && !M->isPure() && !M->isStatic();
+ });
+}
+
+bool MultipleInheritanceCheck::isInterface(const CXXRecordDecl *Node) {
+ if (!Node->getIdentifier())
+ return false;
+
+ // Short circuit the lookup if we have analyzed this record before.
+ bool PreviousIsInterfaceResult;
+ if (getInterfaceStatus(Node, PreviousIsInterfaceResult))
+ return PreviousIsInterfaceResult;
+
+ // To be an interface, all base classes must be interfaces as well.
+ for (const auto &I : Node->bases()) {
+ if (I.isVirtual()) continue;
+ const auto *Ty = I.getType()->getAs<RecordType>();
+ if (!Ty) continue;
+ const RecordDecl *D = Ty->getDecl()->getDefinition();
+ if (!D) continue;
+ const auto *Base = cast<CXXRecordDecl>(D);
+ if (!isInterface(Base)) {
+ addNodeToInterfaceMap(Node, false);
+ return false;
+ }
+ }
+
+ bool CurrentClassIsInterface = isCurrentClassInterface(Node);
+ addNodeToInterfaceMap(Node, CurrentClassIsInterface);
+ return CurrentClassIsInterface;
+}
+
+void MultipleInheritanceCheck::registerMatchers(MatchFinder *Finder) {
+ // Requires C++.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // Match declarations which have bases.
+ Finder->addMatcher(cxxRecordDecl(hasBases()).bind("decl"), this);
+}
+
+void MultipleInheritanceCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *D = Result.Nodes.getNodeAs<CXXRecordDecl>("decl")) {
+ // Check against map to see if if the class inherits from multiple
+ // concrete classes
+ unsigned NumConcrete = 0;
+ for (const auto &I : D->bases()) {
+ if (I.isVirtual()) continue;
+ const auto *Ty = I.getType()->getAs<RecordType>();
+ if (!Ty) continue;
+ const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
+ if (!isInterface(Base)) NumConcrete++;
+ }
+
+ // Check virtual bases to see if there is more than one concrete
+ // non-virtual base.
+ for (const auto &V : D->vbases()) {
+ const auto *Ty = V.getType()->getAs<RecordType>();
+ if (!Ty) continue;
+ const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
+ if (!isInterface(Base)) NumConcrete++;
+ }
+
+ if (NumConcrete > 1) {
+ diag(D->getLocStart(),
+ "inheriting mulitple classes that aren't "
+ "pure virtual is discouraged");
+ }
+ }
+}
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.h
new file mode 100644
index 0000000..6250e3e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/MultipleInheritanceCheck.h
@@ -0,0 +1,48 @@
+//===--- MultipleInheritanceCheck.h - clang-tidy-----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_MULTIPLE_INHERITANCE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_MULTIPLE_INHERITANCE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+/// Mulitple implementation inheritance is discouraged.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-multiple-inheritance.html
+class MultipleInheritanceCheck : public ClangTidyCheck {
+public:
+ MultipleInheritanceCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+ void onEndOfTranslationUnit() override { InterfaceMap.clear(); }
+
+private:
+ void addNodeToInterfaceMap(const CXXRecordDecl *Node, bool isInterface);
+ bool getInterfaceStatus(const CXXRecordDecl *Node, bool &isInterface) const;
+ bool isCurrentClassInterface(const CXXRecordDecl *Node) const;
+ bool isInterface(const CXXRecordDecl *Node);
+
+ // Contains the identity of each named CXXRecord as an interface. This is
+ // used to memoize lookup speeds and improve performance from O(N^2) to O(N),
+ // where N is the number of classes.
+ llvm::StringMap<bool> InterfaceMap;
+};
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_MULTIPLE_INHERITANCE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/OverloadedOperatorCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/OverloadedOperatorCheck.cpp
new file mode 100644
index 0000000..847f763
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/OverloadedOperatorCheck.cpp
@@ -0,0 +1,45 @@
+//===--- OverloadedOperatorCheck.cpp - clang-tidy--------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OverloadedOperatorCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+namespace {
+AST_MATCHER(FunctionDecl, isFuchsiaOverloadedOperator) {
+ if (const auto *CXXMethodNode = dyn_cast<CXXMethodDecl>(&Node)) {
+ if (CXXMethodNode->isCopyAssignmentOperator() ||
+ CXXMethodNode->isMoveAssignmentOperator())
+ return false;
+ }
+ return Node.isOverloadedOperator();
+}
+} // namespace
+
+void OverloadedOperatorCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(functionDecl(isFuchsiaOverloadedOperator()).bind("decl"),
+ this);
+}
+
+void OverloadedOperatorCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *D = Result.Nodes.getNodeAs<FunctionDecl>("decl");
+ assert(D && "No FunctionDecl captured!");
+
+ SourceLocation Loc = D->getLocStart();
+ if (Loc.isValid())
+ diag(Loc, "overloading %0 is disallowed") << D;
+}
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/OverloadedOperatorCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/OverloadedOperatorCheck.h
new file mode 100644
index 0000000..a22e5ae
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/OverloadedOperatorCheck.h
@@ -0,0 +1,35 @@
+//===--- OverloadedOperatorCheck.h - clang-tidy------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_OVERLOADED_OPERATOR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_OVERLOADED_OPERATOR_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+/// Overloading operators is disallowed by the Fuchsia coding standard.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-overloaded-operator.html
+class OverloadedOperatorCheck : public ClangTidyCheck {
+public:
+ OverloadedOperatorCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_OVERLOADED_OPERATOR_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/RestrictSystemIncludesCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/RestrictSystemIncludesCheck.cpp
new file mode 100644
index 0000000..4817e90
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/RestrictSystemIncludesCheck.cpp
@@ -0,0 +1,118 @@
+//===--- RestrictSystemIncludesCheck.cpp - clang-tidy----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RestrictSystemIncludesCheck.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Path.h"
+#include <cstring>
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+class RestrictedIncludesPPCallbacks : public PPCallbacks {
+public:
+ explicit RestrictedIncludesPPCallbacks(RestrictSystemIncludesCheck &Check,
+ SourceManager &SM)
+ : Check(Check), SM(SM) {}
+
+ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath,
+ const Module *Imported,
+ SrcMgr::CharacteristicKind FileType) override;
+ void EndOfMainFile() override;
+
+private:
+ struct IncludeDirective {
+ IncludeDirective() = default;
+ IncludeDirective(SourceLocation Loc, CharSourceRange Range,
+ StringRef Filename, StringRef FullPath, bool IsInMainFile)
+ : Loc(Loc), Range(Range), IncludeFile(Filename), IncludePath(FullPath),
+ IsInMainFile(IsInMainFile) {}
+
+ SourceLocation Loc; // '#' location in the include directive
+ CharSourceRange Range; // SourceRange for the file name
+ std::string IncludeFile; // Filename as a string
+ std::string IncludePath; // Full file path as a string
+ bool IsInMainFile; // Whether or not the include is in the main file
+ };
+
+ using FileIncludes = llvm::SmallVector<IncludeDirective, 8>;
+ llvm::SmallDenseMap<FileID, FileIncludes> IncludeDirectives;
+
+ RestrictSystemIncludesCheck &Check;
+ SourceManager &SM;
+};
+
+void RestrictedIncludesPPCallbacks::InclusionDirective(
+ SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
+ bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath, const Module *Imported,
+ SrcMgr::CharacteristicKind FileType) {
+ if (!Check.contains(FileName) && SrcMgr::isSystem(FileType)) {
+ SmallString<256> FullPath;
+ llvm::sys::path::append(FullPath, SearchPath);
+ llvm::sys::path::append(FullPath, RelativePath);
+ // Bucket the allowed include directives by the id of the file they were
+ // declared in.
+ IncludeDirectives[SM.getFileID(HashLoc)].emplace_back(
+ HashLoc, FilenameRange, FileName, FullPath.str(),
+ SM.isInMainFile(HashLoc));
+ }
+}
+
+void RestrictedIncludesPPCallbacks::EndOfMainFile() {
+ for (const auto &Bucket : IncludeDirectives) {
+ const FileIncludes &FileDirectives = Bucket.second;
+
+ // Emit fixits for all restricted includes.
+ for (const auto &Include : FileDirectives) {
+ // Fetch the length of the include statement from the start to just after
+ // the newline, for finding the end (including the newline).
+ unsigned ToLen = std::strcspn(SM.getCharacterData(Include.Loc), "\n") + 1;
+ CharSourceRange ToRange = CharSourceRange::getCharRange(
+ Include.Loc, Include.Loc.getLocWithOffset(ToLen));
+
+ if (!Include.IsInMainFile) {
+ auto D = Check.diag(
+ Include.Loc,
+ "system include %0 not allowed, transitively included from %1");
+ D << Include.IncludeFile << SM.getFilename(Include.Loc);
+ D << FixItHint::CreateRemoval(ToRange);
+ continue;
+ }
+ auto D = Check.diag(Include.Loc, "system include %0 not allowed");
+ D << Include.IncludeFile;
+ D << FixItHint::CreateRemoval(ToRange);
+ }
+ }
+}
+
+void RestrictSystemIncludesCheck::registerPPCallbacks(
+ CompilerInstance &Compiler) {
+ Compiler.getPreprocessor().addPPCallbacks(
+ llvm::make_unique<RestrictedIncludesPPCallbacks>(
+ *this, Compiler.getSourceManager()));
+}
+
+void RestrictSystemIncludesCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "Includes", AllowedIncludes);
+}
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/RestrictSystemIncludesCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/RestrictSystemIncludesCheck.h
new file mode 100644
index 0000000..d4e5ac1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/RestrictSystemIncludesCheck.h
@@ -0,0 +1,48 @@
+//===--- RestrictSystemIncludesCheck.h - clang-tidy---------- ----*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_RESTRICTINCLUDESSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_RESTRICTINCLUDESSCHECK_H
+
+#include "../ClangTidy.h"
+#include "../ClangTidyDiagnosticConsumer.h"
+#include "../utils/OptionsUtils.h"
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+/// Checks for allowed includes and suggests removal of any others. If no
+/// includes are specified, the check will exit without issuing any warnings.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-restrict-system-includes.html
+class RestrictSystemIncludesCheck : public ClangTidyCheck {
+public:
+ RestrictSystemIncludesCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ AllowedIncludes(Options.get("Includes", "*")),
+ AllowedIncludesGlobList(AllowedIncludes) {}
+
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ bool contains(StringRef FileName) {
+ return AllowedIncludesGlobList.contains(FileName);
+ }
+
+private:
+ std::string AllowedIncludes;
+ GlobList AllowedIncludesGlobList;
+};
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_RESTRICTINCLUDESSCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/StaticallyConstructedObjectsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/StaticallyConstructedObjectsCheck.cpp
new file mode 100644
index 0000000..16a534b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/StaticallyConstructedObjectsCheck.cpp
@@ -0,0 +1,60 @@
+//===--- StaticallyConstructedObjectsCheck.cpp - clang-tidy----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StaticallyConstructedObjectsCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+namespace {
+AST_MATCHER(Expr, isConstantInitializer) {
+ return Node.isConstantInitializer(Finder->getASTContext(), false);
+}
+
+AST_MATCHER(VarDecl, isGlobalStatic) {
+ return Node.getStorageDuration() == SD_Static && !Node.isLocalVarDecl();
+}
+} // namespace
+
+void StaticallyConstructedObjectsCheck::registerMatchers(MatchFinder *Finder) {
+ // Constructing global, non-trivial objects with static storage is
+ // disallowed, unless the object is statically initialized with a constexpr
+ // constructor or has no explicit constructor.
+
+ // Constexpr requires C++11 or later.
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ Finder->addMatcher(
+ varDecl(allOf(
+ // Match global, statically stored objects...
+ isGlobalStatic(),
+ // ... that have C++ constructors...
+ hasDescendant(cxxConstructExpr(unless(allOf(
+ // ... unless it is constexpr ...
+ hasDeclaration(cxxConstructorDecl(isConstexpr())),
+ // ... and is statically initialized.
+ isConstantInitializer()))))))
+ .bind("decl"),
+ this);
+}
+
+void StaticallyConstructedObjectsCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ if (const auto *D = Result.Nodes.getNodeAs<VarDecl>("decl"))
+ diag(D->getLocStart(), "static objects are disallowed; if possible, use a "
+ "constexpr constructor instead");
+}
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/StaticallyConstructedObjectsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/StaticallyConstructedObjectsCheck.h
new file mode 100644
index 0000000..6df9b1c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/StaticallyConstructedObjectsCheck.h
@@ -0,0 +1,37 @@
+//===--- StaticallyConstructedObjectsCheck.h - clang-tidy--------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_STATICALLY_CONSTRUCTED_OBJECTS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_STATICALLY_CONSTRUCTED_OBJECTS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+/// Constructing global, non-trivial objects with static storage is
+/// disallowed, unless the object is statically initialized with a constexpr
+/// constructor or has no explicit constructor.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-statically-constructed-objects.html
+class StaticallyConstructedObjectsCheck : public ClangTidyCheck {
+public:
+ StaticallyConstructedObjectsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_STATICALLY_CONSTRUCTED_OBJECTS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/TrailingReturnCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/TrailingReturnCheck.cpp
new file mode 100644
index 0000000..7af0c9c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/TrailingReturnCheck.cpp
@@ -0,0 +1,52 @@
+//===--- TrailingReturnCheck.cpp - clang-tidy------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TrailingReturnCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+namespace {
+AST_MATCHER(FunctionDecl, hasTrailingReturn) {
+ return Node.getType()->castAs<FunctionProtoType>()->hasTrailingReturn();
+}
+} // namespace
+
+void TrailingReturnCheck::registerMatchers(MatchFinder *Finder) {
+
+ // Requires C++11 or later.
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ // Functions that have trailing returns are disallowed, except for those
+ // using decltype specifiers and lambda with otherwise unutterable
+ // return types.
+ Finder->addMatcher(
+ functionDecl(allOf(hasTrailingReturn(),
+ unless(anyOf(returns(decltypeType()),
+ hasParent(cxxRecordDecl(isLambda()))))))
+ .bind("decl"),
+ this);
+}
+
+void TrailingReturnCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *D = Result.Nodes.getNodeAs<Decl>("decl"))
+ diag(D->getLocStart(),
+ "a trailing return type is disallowed for this type of declaration");
+}
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/TrailingReturnCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/TrailingReturnCheck.h
new file mode 100644
index 0000000..4a16c4e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/TrailingReturnCheck.h
@@ -0,0 +1,37 @@
+//===--- TrailingReturnCheck.h - clang-tidy----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_TRAILING_RETURN_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_TRAILING_RETURN_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+/// Functions that have trailing returns are disallowed, except for those
+/// using decltype specifiers and lambda with otherwise unutterable
+/// return types.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-trailing-return.html
+class TrailingReturnCheck : public ClangTidyCheck {
+public:
+ TrailingReturnCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_TRAILING_RETURN_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/VirtualInheritanceCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/VirtualInheritanceCheck.cpp
new file mode 100644
index 0000000..f3da2b6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/VirtualInheritanceCheck.cpp
@@ -0,0 +1,43 @@
+//===--- VirtualInheritanceCheck.cpp - clang-tidy--------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "VirtualInheritanceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+namespace {
+AST_MATCHER(CXXRecordDecl, hasDirectVirtualBaseClass) {
+ if (!Node.hasDefinition()) return false;
+ if (!Node.getNumVBases()) return false;
+ for (const CXXBaseSpecifier &Base : Node.bases())
+ if (Base.isVirtual()) return true;
+ return false;
+}
+} // namespace
+
+void VirtualInheritanceCheck::registerMatchers(MatchFinder *Finder) {
+ // Defining classes using direct virtual inheritance is disallowed.
+ Finder->addMatcher(cxxRecordDecl(hasDirectVirtualBaseClass()).bind("decl"),
+ this);
+}
+
+void VirtualInheritanceCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *D = Result.Nodes.getNodeAs<CXXRecordDecl>("decl"))
+ diag(D->getLocStart(), "direct virtual inheritance is disallowed");
+}
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/VirtualInheritanceCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/VirtualInheritanceCheck.h
new file mode 100644
index 0000000..b2c84c4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/fuchsia/VirtualInheritanceCheck.h
@@ -0,0 +1,35 @@
+//===--- VirtualInheritanceCheck.h - clang-tidy------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_VIRTUAL_INHERITANCE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_VIRTUAL_INHERITANCE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace fuchsia {
+
+/// Defining classes with virtual inheritance is disallowed.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-virtual-inheritance.html
+class VirtualInheritanceCheck : public ClangTidyCheck {
+ public:
+ VirtualInheritanceCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace fuchsia
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_FUCHSIA_VIRTUAL_INHERITANCE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp
new file mode 100644
index 0000000..4c7c164
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp
@@ -0,0 +1,221 @@
+//===--- AvoidCStyleCastsCheck.cpp - clang-tidy -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AvoidCStyleCastsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace readability {
+
+void AvoidCStyleCastsCheck::registerMatchers(
+ ast_matchers::MatchFinder *Finder) {
+ Finder->addMatcher(
+ cStyleCastExpr(
+ // Filter out (EnumType)IntegerLiteral construct, which is generated
+ // for non-type template arguments of enum types.
+ // FIXME: Remove this once this is fixed in the AST.
+ unless(hasParent(substNonTypeTemplateParmExpr())),
+ // Avoid matches in template instantiations.
+ unless(isInTemplateInstantiation()))
+ .bind("cast"),
+ this);
+}
+
+static bool needsConstCast(QualType SourceType, QualType DestType) {
+ while ((SourceType->isPointerType() && DestType->isPointerType()) ||
+ (SourceType->isReferenceType() && DestType->isReferenceType())) {
+ SourceType = SourceType->getPointeeType();
+ DestType = DestType->getPointeeType();
+ if (SourceType.isConstQualified() && !DestType.isConstQualified()) {
+ return (SourceType->isPointerType() == DestType->isPointerType()) &&
+ (SourceType->isReferenceType() == DestType->isReferenceType());
+ }
+ }
+ return false;
+}
+
+static bool pointedUnqualifiedTypesAreEqual(QualType T1, QualType T2) {
+ while ((T1->isPointerType() && T2->isPointerType()) ||
+ (T1->isReferenceType() && T2->isReferenceType())) {
+ T1 = T1->getPointeeType();
+ T2 = T2->getPointeeType();
+ }
+ return T1.getUnqualifiedType() == T2.getUnqualifiedType();
+}
+
+void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *CastExpr = Result.Nodes.getNodeAs<CStyleCastExpr>("cast");
+
+ // Ignore casts in macros.
+ if (CastExpr->getExprLoc().isMacroID())
+ return;
+
+ // Casting to void is an idiomatic way to mute "unused variable" and similar
+ // warnings.
+ if (CastExpr->getCastKind() == CK_ToVoid)
+ return;
+
+ auto isFunction = [](QualType T) {
+ T = T.getCanonicalType().getNonReferenceType();
+ return T->isFunctionType() || T->isFunctionPointerType() ||
+ T->isMemberFunctionPointerType();
+ };
+
+ const QualType DestTypeAsWritten =
+ CastExpr->getTypeAsWritten().getUnqualifiedType();
+ const QualType SourceTypeAsWritten =
+ CastExpr->getSubExprAsWritten()->getType().getUnqualifiedType();
+ const QualType SourceType = SourceTypeAsWritten.getCanonicalType();
+ const QualType DestType = DestTypeAsWritten.getCanonicalType();
+
+ auto ReplaceRange = CharSourceRange::getCharRange(
+ CastExpr->getLParenLoc(), CastExpr->getSubExprAsWritten()->getLocStart());
+
+ bool FnToFnCast =
+ isFunction(SourceTypeAsWritten) && isFunction(DestTypeAsWritten);
+
+ if (CastExpr->getCastKind() == CK_NoOp && !FnToFnCast) {
+ // Function pointer/reference casts may be needed to resolve ambiguities in
+ // case of overloaded functions, so detection of redundant casts is trickier
+ // in this case. Don't emit "redundant cast" warnings for function
+ // pointer/reference types.
+ if (SourceTypeAsWritten == DestTypeAsWritten) {
+ diag(CastExpr->getLocStart(), "redundant cast to the same type")
+ << FixItHint::CreateRemoval(ReplaceRange);
+ return;
+ }
+ }
+
+ // The rest of this check is only relevant to C++.
+ // We also disable it for Objective-C++.
+ if (!getLangOpts().CPlusPlus || getLangOpts().ObjC1 || getLangOpts().ObjC2)
+ return;
+ // Ignore code inside extern "C" {} blocks.
+ if (!match(expr(hasAncestor(linkageSpecDecl())), *CastExpr, *Result.Context)
+ .empty())
+ return;
+ // Ignore code in .c files and headers included from them, even if they are
+ // compiled as C++.
+ if (getCurrentMainFile().endswith(".c"))
+ return;
+
+ SourceManager &SM = *Result.SourceManager;
+
+ // Ignore code in .c files #included in other files (which shouldn't be done,
+ // but people still do this for test and other purposes).
+ if (SM.getFilename(SM.getSpellingLoc(CastExpr->getLocStart())).endswith(".c"))
+ return;
+
+ // Leave type spelling exactly as it was (unlike
+ // getTypeAsWritten().getAsString() which would spell enum types 'enum X').
+ StringRef DestTypeString =
+ Lexer::getSourceText(CharSourceRange::getTokenRange(
+ CastExpr->getLParenLoc().getLocWithOffset(1),
+ CastExpr->getRParenLoc().getLocWithOffset(-1)),
+ SM, getLangOpts());
+
+ auto Diag =
+ diag(CastExpr->getLocStart(), "C-style casts are discouraged; use %0");
+
+ auto ReplaceWithCast = [&](std::string CastText) {
+ const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts();
+ if (!isa<ParenExpr>(SubExpr)) {
+ CastText.push_back('(');
+ Diag << FixItHint::CreateInsertion(
+ Lexer::getLocForEndOfToken(SubExpr->getLocEnd(), 0, SM,
+ getLangOpts()),
+ ")");
+ }
+ Diag << FixItHint::CreateReplacement(ReplaceRange, CastText);
+ };
+ auto ReplaceWithNamedCast = [&](StringRef CastType) {
+ Diag << CastType;
+ ReplaceWithCast((CastType + "<" + DestTypeString + ">").str());
+ };
+
+ // Suggest appropriate C++ cast. See [expr.cast] for cast notation semantics.
+ switch (CastExpr->getCastKind()) {
+ case CK_FunctionToPointerDecay:
+ ReplaceWithNamedCast("static_cast");
+ return;
+ case CK_ConstructorConversion:
+ if (!CastExpr->getTypeAsWritten().hasQualifiers() &&
+ DestTypeAsWritten->isRecordType() &&
+ !DestTypeAsWritten->isElaboratedTypeSpecifier()) {
+ Diag << "constructor call syntax";
+ // FIXME: Validate DestTypeString, maybe.
+ ReplaceWithCast(DestTypeString.str());
+ } else {
+ ReplaceWithNamedCast("static_cast");
+ }
+ return;
+ case CK_NoOp:
+ if (FnToFnCast) {
+ ReplaceWithNamedCast("static_cast");
+ return;
+ }
+ if (SourceType == DestType) {
+ Diag << "static_cast (if needed, the cast may be redundant)";
+ ReplaceWithCast(("static_cast<" + DestTypeString + ">").str());
+ return;
+ }
+ if (needsConstCast(SourceType, DestType) &&
+ pointedUnqualifiedTypesAreEqual(SourceType, DestType)) {
+ ReplaceWithNamedCast("const_cast");
+ return;
+ }
+ if (DestType->isReferenceType()) {
+ QualType Dest = DestType.getNonReferenceType();
+ QualType Source = SourceType.getNonReferenceType();
+ if (Source == Dest.withConst() ||
+ SourceType.getNonReferenceType() == DestType.getNonReferenceType()) {
+ ReplaceWithNamedCast("const_cast");
+ return;
+ }
+ break;
+ }
+ // FALLTHROUGH
+ case clang::CK_IntegralCast:
+ // Convert integral and no-op casts between builtin types and enums to
+ // static_cast. A cast from enum to integer may be unnecessary, but it's
+ // still retained.
+ if ((SourceType->isBuiltinType() || SourceType->isEnumeralType()) &&
+ (DestType->isBuiltinType() || DestType->isEnumeralType())) {
+ ReplaceWithNamedCast("static_cast");
+ return;
+ }
+ break;
+ case CK_BitCast:
+ // FIXME: Suggest const_cast<...>(reinterpret_cast<...>(...)) replacement.
+ if (!needsConstCast(SourceType, DestType)) {
+ if (SourceType->isVoidPointerType())
+ ReplaceWithNamedCast("static_cast");
+ else
+ ReplaceWithNamedCast("reinterpret_cast");
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ Diag << "static_cast/const_cast/reinterpret_cast";
+}
+
+} // namespace readability
+} // namespace google
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.h
new file mode 100644
index 0000000..ea7e34c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.h
@@ -0,0 +1,42 @@
+//===--- AvoidCStyleCastsCheck.h - clang-tidy -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_AVOIDCSTYLECASTSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_AVOIDCSTYLECASTSCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace readability {
+
+/// Finds usages of C-style casts.
+///
+/// https://google.github.io/styleguide/cppguide.html#Casting
+///
+/// Corresponding cpplint.py check name: 'readability/casting'.
+///
+/// This check is similar to `-Wold-style-cast`, but it suggests automated fixes
+/// in some cases. The reported locations should not be different from the
+/// ones generated by `-Wold-style-cast`.
+class AvoidCStyleCastsCheck : public ClangTidyCheck {
+public:
+ AvoidCStyleCastsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace google
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_AVOIDCSTYLECASTSCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp
new file mode 100644
index 0000000..aa91ff0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp
@@ -0,0 +1,52 @@
+//===--- AvoidThrowingObjCExceptionCheck.cpp - clang-tidy------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AvoidThrowingObjCExceptionCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace objc {
+
+void AvoidThrowingObjCExceptionCheck::registerMatchers(MatchFinder *Finder) {
+ // this check should only be applied to ObjC sources.
+ if (!getLangOpts().ObjC1 && !getLangOpts().ObjC2) {
+ return;
+ }
+
+ Finder->addMatcher(objcThrowStmt().bind("throwStmt"), this);
+ Finder->addMatcher(
+ objcMessageExpr(anyOf(hasSelector("raise:format:"),
+ hasSelector("raise:format:arguments:")),
+ hasReceiverType(asString("NSException")))
+ .bind("raiseException"),
+ this);
+}
+
+void AvoidThrowingObjCExceptionCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *MatchedStmt =
+ Result.Nodes.getNodeAs<ObjCAtThrowStmt>("throwStmt");
+ const auto *MatchedExpr =
+ Result.Nodes.getNodeAs<ObjCMessageExpr>("raiseException");
+ auto SourceLoc = MatchedStmt == nullptr ? MatchedExpr->getSelectorStartLoc()
+ : MatchedStmt->getThrowLoc();
+ diag(SourceLoc,
+ "pass in NSError ** instead of throwing exception to indicate "
+ "Objective-C errors");
+}
+
+} // namespace objc
+} // namespace google
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.h
new file mode 100644
index 0000000..9498226
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/AvoidThrowingObjCExceptionCheck.h
@@ -0,0 +1,39 @@
+//===--- AvoidThrowingObjCExceptionCheck.h - clang-tidy----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_AVOID_THROWING_EXCEPTION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_AVOID_THROWING_EXCEPTION_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace objc {
+
+/// The check is to find usage of @throw invocation in Objective-C code.
+/// We should avoid using @throw for Objective-C exceptions according to
+/// the Google Objective-C Style Guide.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/google-objc-avoid-throwing-exception.html
+class AvoidThrowingObjCExceptionCheck : public ClangTidyCheck {
+ public:
+ AvoidThrowingObjCExceptionCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace objc
+} // namespace google
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_AVOID_THROWING_EXCEPTION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/CMakeLists.txt
new file mode 100644
index 0000000..1a7dd87
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/CMakeLists.txt
@@ -0,0 +1,27 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyGoogleModule
+ AvoidCStyleCastsCheck.cpp
+ AvoidThrowingObjCExceptionCheck.cpp
+ DefaultArgumentsCheck.cpp
+ ExplicitConstructorCheck.cpp
+ ExplicitMakePairCheck.cpp
+ GlobalNamesInHeadersCheck.cpp
+ GlobalVariableDeclarationCheck.cpp
+ GoogleTidyModule.cpp
+ IntegerTypesCheck.cpp
+ NonConstReferences.cpp
+ OverloadedUnaryAndCheck.cpp
+ TodoCommentCheck.cpp
+ UnnamedNamespaceInHeaderCheck.cpp
+ UsingNamespaceDirectiveCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyReadabilityModule
+ clangTidyUtils
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/DefaultArgumentsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/DefaultArgumentsCheck.cpp
new file mode 100644
index 0000000..ccbd870
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/DefaultArgumentsCheck.cpp
@@ -0,0 +1,36 @@
+//===--- DefaultArgumentsCheck.cpp - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DefaultArgumentsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace google {
+
+void DefaultArgumentsCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ cxxMethodDecl(anyOf(isOverride(), isVirtual()),
+ hasAnyParameter(parmVarDecl(hasInitializer(expr()))))
+ .bind("Decl"),
+ this);
+}
+
+void DefaultArgumentsCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<CXXMethodDecl>("Decl");
+ diag(MatchedDecl->getLocation(),
+ "default arguments on virtual or override methods are prohibited");
+}
+
+} // namespace google
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/DefaultArgumentsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/DefaultArgumentsCheck.h
new file mode 100644
index 0000000..1457a09
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/DefaultArgumentsCheck.h
@@ -0,0 +1,34 @@
+//===--- DefaultArgumentsCheck.h - clang-tidy--------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_DEFAULT_ARGUMENTS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_DEFAULT_ARGUMENTS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace google {
+
+/// Checks that default parameters are not given for virtual methods.
+///
+/// See https://google.github.io/styleguide/cppguide.html#Default_Arguments
+class DefaultArgumentsCheck : public ClangTidyCheck {
+public:
+ DefaultArgumentsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace google
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_DEFAULT_ARGUMENTS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.cpp
new file mode 100644
index 0000000..a03fb56
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.cpp
@@ -0,0 +1,156 @@
+//===--- ExplicitConstructorCheck.cpp - clang-tidy ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExplicitConstructorCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace google {
+
+void ExplicitConstructorCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus)
+ return;
+ Finder->addMatcher(
+ cxxConstructorDecl(unless(anyOf(isImplicit(), // Compiler-generated.
+ isDeleted(), isInstantiated())))
+ .bind("ctor"),
+ this);
+ Finder->addMatcher(
+ cxxConversionDecl(unless(anyOf(isExplicit(), // Already marked explicit.
+ isImplicit(), // Compiler-generated.
+ isDeleted(), isInstantiated())))
+
+ .bind("conversion"),
+ this);
+}
+
+// Looks for the token matching the predicate and returns the range of the found
+// token including trailing whitespace.
+static SourceRange FindToken(const SourceManager &Sources,
+ const LangOptions &LangOpts,
+ SourceLocation StartLoc, SourceLocation EndLoc,
+ bool (*Pred)(const Token &)) {
+ if (StartLoc.isMacroID() || EndLoc.isMacroID())
+ return SourceRange();
+ FileID File = Sources.getFileID(Sources.getSpellingLoc(StartLoc));
+ StringRef Buf = Sources.getBufferData(File);
+ const char *StartChar = Sources.getCharacterData(StartLoc);
+ Lexer Lex(StartLoc, LangOpts, StartChar, StartChar, Buf.end());
+ Lex.SetCommentRetentionState(true);
+ Token Tok;
+ do {
+ Lex.LexFromRawLexer(Tok);
+ if (Pred(Tok)) {
+ Token NextTok;
+ Lex.LexFromRawLexer(NextTok);
+ return SourceRange(Tok.getLocation(), NextTok.getLocation());
+ }
+ } while (Tok.isNot(tok::eof) && Tok.getLocation() < EndLoc);
+
+ return SourceRange();
+}
+
+static bool declIsStdInitializerList(const NamedDecl *D) {
+ // First use the fast getName() method to avoid unnecessary calls to the
+ // slow getQualifiedNameAsString().
+ return D->getName() == "initializer_list" &&
+ D->getQualifiedNameAsString() == "std::initializer_list";
+}
+
+static bool isStdInitializerList(QualType Type) {
+ Type = Type.getCanonicalType();
+ if (const auto *TS = Type->getAs<TemplateSpecializationType>()) {
+ if (const TemplateDecl *TD = TS->getTemplateName().getAsTemplateDecl())
+ return declIsStdInitializerList(TD);
+ }
+ if (const auto *RT = Type->getAs<RecordType>()) {
+ if (const auto *Specialization =
+ dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()))
+ return declIsStdInitializerList(Specialization->getSpecializedTemplate());
+ }
+ return false;
+}
+
+void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) {
+ constexpr char WarningMessage[] =
+ "%0 must be marked explicit to avoid unintentional implicit conversions";
+
+ if (const auto *Conversion =
+ Result.Nodes.getNodeAs<CXXConversionDecl>("conversion")) {
+ if (Conversion->isOutOfLine())
+ return;
+ SourceLocation Loc = Conversion->getLocation();
+ // Ignore all macros until we learn to ignore specific ones (e.g. used in
+ // gmock to define matchers).
+ if (Loc.isMacroID())
+ return;
+ diag(Loc, WarningMessage)
+ << Conversion << FixItHint::CreateInsertion(Loc, "explicit ");
+ return;
+ }
+
+ const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
+ if (Ctor->isOutOfLine() || Ctor->getNumParams() == 0 ||
+ Ctor->getMinRequiredArguments() > 1)
+ return;
+
+ bool takesInitializerList = isStdInitializerList(
+ Ctor->getParamDecl(0)->getType().getNonReferenceType());
+ if (Ctor->isExplicit() &&
+ (Ctor->isCopyOrMoveConstructor() || takesInitializerList)) {
+ auto isKWExplicit = [](const Token &Tok) {
+ return Tok.is(tok::raw_identifier) &&
+ Tok.getRawIdentifier() == "explicit";
+ };
+ SourceRange ExplicitTokenRange =
+ FindToken(*Result.SourceManager, getLangOpts(),
+ Ctor->getOuterLocStart(), Ctor->getLocEnd(), isKWExplicit);
+ StringRef ConstructorDescription;
+ if (Ctor->isMoveConstructor())
+ ConstructorDescription = "move";
+ else if (Ctor->isCopyConstructor())
+ ConstructorDescription = "copy";
+ else
+ ConstructorDescription = "initializer-list";
+
+ auto Diag = diag(Ctor->getLocation(),
+ "%0 constructor should not be declared explicit")
+ << ConstructorDescription;
+ if (ExplicitTokenRange.isValid()) {
+ Diag << FixItHint::CreateRemoval(
+ CharSourceRange::getCharRange(ExplicitTokenRange));
+ }
+ return;
+ }
+
+ if (Ctor->isExplicit() || Ctor->isCopyOrMoveConstructor() ||
+ takesInitializerList)
+ return;
+
+ bool SingleArgument =
+ Ctor->getNumParams() == 1 && !Ctor->getParamDecl(0)->isParameterPack();
+ SourceLocation Loc = Ctor->getLocation();
+ diag(Loc, WarningMessage)
+ << (SingleArgument
+ ? "single-argument constructors"
+ : "constructors that are callable with a single argument")
+ << FixItHint::CreateInsertion(Loc, "explicit ");
+}
+
+} // namespace google
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.h
new file mode 100644
index 0000000..81e6679
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/ExplicitConstructorCheck.h
@@ -0,0 +1,34 @@
+//===--- ExplicitConstructorCheck.h - clang-tidy ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_EXPLICITCONSTRUCTORCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_EXPLICITCONSTRUCTORCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace google {
+
+/// Checks that all single-argument constructors are explicit.
+///
+/// See https://google.github.io/styleguide/cppguide.html#Explicit_Constructors
+class ExplicitConstructorCheck : public ClangTidyCheck {
+public:
+ ExplicitConstructorCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace google
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_EXPLICITCONSTRUCTORCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/ExplicitMakePairCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/ExplicitMakePairCheck.cpp
new file mode 100644
index 0000000..6c2f0a3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/ExplicitMakePairCheck.cpp
@@ -0,0 +1,78 @@
+//===--- ExplicitMakePairCheck.cpp - clang-tidy -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExplicitMakePairCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace {
+AST_MATCHER(DeclRefExpr, hasExplicitTemplateArgs) {
+ return Node.hasExplicitTemplateArgs();
+}
+} // namespace
+
+namespace tidy {
+namespace google {
+namespace build {
+
+void ExplicitMakePairCheck::registerMatchers(
+ ast_matchers::MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // Look for std::make_pair with explicit template args. Ignore calls in
+ // templates.
+ Finder->addMatcher(
+ callExpr(unless(isInTemplateInstantiation()),
+ callee(expr(ignoringParenImpCasts(
+ declRefExpr(hasExplicitTemplateArgs(),
+ to(functionDecl(hasName("::std::make_pair"))))
+ .bind("declref")))))
+ .bind("call"),
+ this);
+}
+
+void ExplicitMakePairCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+ const auto *DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>("declref");
+
+ // Sanity check: The use might have overriden ::std::make_pair.
+ if (Call->getNumArgs() != 2)
+ return;
+
+ const Expr *Arg0 = Call->getArg(0)->IgnoreParenImpCasts();
+ const Expr *Arg1 = Call->getArg(1)->IgnoreParenImpCasts();
+
+ // If types don't match, we suggest replacing with std::pair and explicit
+ // template arguments. Otherwise just remove the template arguments from
+ // make_pair.
+ if (Arg0->getType() != Call->getArg(0)->getType() ||
+ Arg1->getType() != Call->getArg(1)->getType()) {
+ diag(Call->getLocStart(), "for C++11-compatibility, use pair directly")
+ << FixItHint::CreateReplacement(
+ SourceRange(DeclRef->getLocStart(), DeclRef->getLAngleLoc()),
+ "std::pair<");
+ } else {
+ diag(Call->getLocStart(),
+ "for C++11-compatibility, omit template arguments from make_pair")
+ << FixItHint::CreateRemoval(
+ SourceRange(DeclRef->getLAngleLoc(), DeclRef->getRAngleLoc()));
+ }
+}
+
+} // namespace build
+} // namespace google
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/ExplicitMakePairCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/ExplicitMakePairCheck.h
new file mode 100644
index 0000000..a29825f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/ExplicitMakePairCheck.h
@@ -0,0 +1,39 @@
+//===--- ExplicitMakePairCheck.h - clang-tidy -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_EXPLICITMAKEPAIRCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_EXPLICITMAKEPAIRCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace build {
+
+/// Check that `make_pair`'s template arguments are deduced.
+///
+/// G++ 4.6 in C++11 mode fails badly if `make_pair`'s template arguments are
+/// specified explicitly, and such use isn't intended in any case.
+///
+/// Corresponding cpplint.py check name: 'build/explicit_make_pair'.
+class ExplicitMakePairCheck : public ClangTidyCheck {
+public:
+ ExplicitMakePairCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace build
+} // namespace google
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_EXPLICITMAKEPAIRCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.cpp
new file mode 100644
index 0000000..45c5b70
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.cpp
@@ -0,0 +1,80 @@
+//===--- GlobalNamesInHeadersCheck.cpp - clang-tidy -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GlobalNamesInHeadersCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace readability {
+
+GlobalNamesInHeadersCheck::GlobalNamesInHeadersCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
+ "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
+ if (!utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions,
+ HeaderFileExtensions, ',')) {
+ llvm::errs() << "Invalid header file extension: "
+ << RawStringHeaderFileExtensions << "\n";
+ }
+}
+
+void GlobalNamesInHeadersCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions);
+}
+
+void GlobalNamesInHeadersCheck::registerMatchers(
+ ast_matchers::MatchFinder *Finder) {
+ Finder->addMatcher(decl(anyOf(usingDecl(), usingDirectiveDecl()),
+ hasDeclContext(translationUnitDecl()))
+ .bind("using_decl"),
+ this);
+}
+
+void GlobalNamesInHeadersCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *D = Result.Nodes.getNodeAs<Decl>("using_decl");
+ // If it comes from a macro, we'll assume it is fine.
+ if (D->getLocStart().isMacroID())
+ return;
+
+ // Ignore if it comes from the "main" file ...
+ if (Result.SourceManager->isInMainFile(
+ Result.SourceManager->getExpansionLoc(D->getLocStart()))) {
+ // unless that file is a header.
+ if (!utils::isSpellingLocInHeaderFile(
+ D->getLocStart(), *Result.SourceManager, HeaderFileExtensions))
+ return;
+ }
+
+ if (const auto *UsingDirective = dyn_cast<UsingDirectiveDecl>(D)) {
+ if (UsingDirective->getNominatedNamespace()->isAnonymousNamespace()) {
+ // Anynoumous namespaces inject a using directive into the AST to import
+ // the names into the containing namespace.
+ // We should not have them in headers, but there is another warning for
+ // that.
+ return;
+ }
+ }
+
+ diag(D->getLocStart(),
+ "using declarations in the global namespace in headers are prohibited");
+}
+
+} // namespace readability
+} // namespace google
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.h
new file mode 100644
index 0000000..79a6e28
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GlobalNamesInHeadersCheck.h
@@ -0,0 +1,47 @@
+//===--- GlobalNamesInHeadersCheck.h - clang-tidy ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_GLOBALNAMESINHEADERSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_GLOBALNAMESINHEADERSCHECK_H
+
+#include "../ClangTidy.h"
+#include "../utils/HeaderFileExtensionsUtils.h"
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace readability {
+
+/// Flag global namespace pollution in header files.
+/// Right now it only triggers on using declarations and directives.
+///
+/// The check supports these options:
+/// - `HeaderFileExtensions`: a comma-separated list of filename extensions
+/// of header files (the filename extensions should not contain "." prefix).
+/// "h" by default.
+/// For extension-less header files, using an empty string or leaving an
+/// empty string between "," if there are other filename extensions.
+class GlobalNamesInHeadersCheck : public ClangTidyCheck {
+public:
+ GlobalNamesInHeadersCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const std::string RawStringHeaderFileExtensions;
+ utils::HeaderFileExtensionsSet HeaderFileExtensions;
+};
+
+} // namespace readability
+} // namespace google
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_GLOBALNAMESINHEADERSCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GlobalVariableDeclarationCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GlobalVariableDeclarationCheck.cpp
new file mode 100644
index 0000000..928d334
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GlobalVariableDeclarationCheck.cpp
@@ -0,0 +1,99 @@
+//===--- GlobalVariableDeclarationCheck.cpp - clang-tidy-------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GlobalVariableDeclarationCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <string>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace objc {
+
+namespace {
+
+AST_MATCHER(VarDecl, isLocalVariable) {
+ return Node.isLocalVarDecl();
+}
+
+FixItHint generateFixItHint(const VarDecl *Decl, bool IsConst) {
+ char FC = Decl->getName()[0];
+ if (!llvm::isAlpha(FC) || Decl->getName().size() == 1) {
+ // No fix available if first character is not alphabetical character, or it
+ // is a single-character variable, since it is difficult to determine the
+ // proper fix in this case. Users should create a proper variable name by
+ // their own.
+ return FixItHint();
+ }
+ char SC = Decl->getName()[1];
+ if ((FC == 'k' || FC == 'g') && !llvm::isAlpha(SC)) {
+ // No fix available if the prefix is correct but the second character is not
+ // alphabetical, since it is difficult to determine the proper fix in this
+ // case.
+ return FixItHint();
+ }
+ auto NewName = (IsConst ? "k" : "g") +
+ llvm::StringRef(std::string(1, FC)).upper() +
+ Decl->getName().substr(1).str();
+ return FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(SourceRange(Decl->getLocation())),
+ llvm::StringRef(NewName));
+}
+} // namespace
+
+void GlobalVariableDeclarationCheck::registerMatchers(MatchFinder *Finder) {
+ // The relevant Style Guide rule only applies to Objective-C.
+ if (!getLangOpts().ObjC1 && !getLangOpts().ObjC2) {
+ return;
+ }
+ // need to add two matchers since we need to bind different ids to distinguish
+ // constants and variables. Since bind() can only be called on node matchers,
+ // we cannot make it in one matcher.
+ //
+ // Note that hasGlobalStorage() matches static variables declared locally
+ // inside a function or method, so we need to exclude those with
+ // isLocalVariable().
+ Finder->addMatcher(
+ varDecl(hasGlobalStorage(), unless(hasType(isConstQualified())),
+ unless(isLocalVariable()), unless(matchesName("::g[A-Z]")))
+ .bind("global_var"),
+ this);
+ Finder->addMatcher(varDecl(hasGlobalStorage(), hasType(isConstQualified()),
+ unless(isLocalVariable()),
+ unless(matchesName("::(k[A-Z]|[A-Z]{2,})")))
+ .bind("global_const"),
+ this);
+}
+
+void GlobalVariableDeclarationCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ if (const auto *Decl = Result.Nodes.getNodeAs<VarDecl>("global_var")) {
+ diag(Decl->getLocation(),
+ "non-const global variable '%0' must have a name which starts with "
+ "'g[A-Z]'")
+ << Decl->getName() << generateFixItHint(Decl, false);
+ }
+ if (const auto *Decl = Result.Nodes.getNodeAs<VarDecl>("global_const")) {
+ diag(Decl->getLocation(),
+ "const global variable '%0' must have a name which starts with "
+ "an appropriate prefix")
+ << Decl->getName() << generateFixItHint(Decl, true);
+ }
+}
+
+} // namespace objc
+} // namespace google
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GlobalVariableDeclarationCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GlobalVariableDeclarationCheck.h
new file mode 100644
index 0000000..ed0352b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GlobalVariableDeclarationCheck.h
@@ -0,0 +1,39 @@
+//===--- GlobalVariableDeclarationCheck.h - clang-tidy-----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_GLOBAL_VARIABLE_DECLARATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_GLOBAL_VARIABLE_DECLARATION_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace objc {
+
+/// The check for Objective-C global variables and constants naming convention.
+/// The declaration should follow the patterns of 'k[A-Z].*' (constants) or
+/// 'g[A-Z].*' (variables).
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/google-objc-global-variable-declaration.html
+class GlobalVariableDeclarationCheck : public ClangTidyCheck {
+ public:
+ GlobalVariableDeclarationCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace objc
+} // namespace google
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OBJC_GLOBAL_VARIABLE_DECLARATION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp
new file mode 100644
index 0000000..f4f4118
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp
@@ -0,0 +1,98 @@
+//===--- GoogleTidyModule.cpp - clang-tidy --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "../readability/BracesAroundStatementsCheck.h"
+#include "../readability/FunctionSizeCheck.h"
+#include "../readability/NamespaceCommentCheck.h"
+#include "AvoidCStyleCastsCheck.h"
+#include "AvoidThrowingObjCExceptionCheck.h"
+#include "DefaultArgumentsCheck.h"
+#include "ExplicitConstructorCheck.h"
+#include "ExplicitMakePairCheck.h"
+#include "GlobalNamesInHeadersCheck.h"
+#include "GlobalVariableDeclarationCheck.h"
+#include "IntegerTypesCheck.h"
+#include "NonConstReferences.h"
+#include "OverloadedUnaryAndCheck.h"
+#include "TodoCommentCheck.h"
+#include "UnnamedNamespaceInHeaderCheck.h"
+#include "UsingNamespaceDirectiveCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace google {
+
+class GoogleModule : public ClangTidyModule {
+ public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<build::ExplicitMakePairCheck>(
+ "google-build-explicit-make-pair");
+ CheckFactories.registerCheck<build::UnnamedNamespaceInHeaderCheck>(
+ "google-build-namespaces");
+ CheckFactories.registerCheck<build::UsingNamespaceDirectiveCheck>(
+ "google-build-using-namespace");
+ CheckFactories.registerCheck<DefaultArgumentsCheck>(
+ "google-default-arguments");
+ CheckFactories.registerCheck<ExplicitConstructorCheck>(
+ "google-explicit-constructor");
+ CheckFactories.registerCheck<readability::GlobalNamesInHeadersCheck>(
+ "google-global-names-in-headers");
+ CheckFactories.registerCheck<objc::AvoidThrowingObjCExceptionCheck>(
+ "google-objc-avoid-throwing-exception");
+ CheckFactories.registerCheck<objc::GlobalVariableDeclarationCheck>(
+ "google-objc-global-variable-declaration");
+ CheckFactories.registerCheck<runtime::IntegerTypesCheck>(
+ "google-runtime-int");
+ CheckFactories.registerCheck<runtime::OverloadedUnaryAndCheck>(
+ "google-runtime-operator");
+ CheckFactories.registerCheck<runtime::NonConstReferences>(
+ "google-runtime-references");
+ CheckFactories.registerCheck<readability::AvoidCStyleCastsCheck>(
+ "google-readability-casting");
+ CheckFactories.registerCheck<readability::TodoCommentCheck>(
+ "google-readability-todo");
+ CheckFactories
+ .registerCheck<clang::tidy::readability::BracesAroundStatementsCheck>(
+ "google-readability-braces-around-statements");
+ CheckFactories.registerCheck<clang::tidy::readability::FunctionSizeCheck>(
+ "google-readability-function-size");
+ CheckFactories
+ .registerCheck<clang::tidy::readability::NamespaceCommentCheck>(
+ "google-readability-namespace-comments");
+ }
+
+ ClangTidyOptions getModuleOptions() override {
+ ClangTidyOptions Options;
+ auto &Opts = Options.CheckOptions;
+ Opts["google-readability-braces-around-statements.ShortStatementLines"] =
+ "1";
+ Opts["google-readability-function-size.StatementThreshold"] = "800";
+ Opts["google-readability-namespace-comments.ShortNamespaceLines"] = "10";
+ Opts["google-readability-namespace-comments.SpacesBeforeComments"] = "2";
+ return Options;
+ }
+};
+
+// Register the GoogleTidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<GoogleModule> X("google-module",
+ "Adds Google lint checks.");
+
+} // namespace google
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the GoogleModule.
+volatile int GoogleModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.cpp
new file mode 100644
index 0000000..7f0b765
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.cpp
@@ -0,0 +1,154 @@
+//===--- IntegerTypesCheck.cpp - clang-tidy -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IntegerTypesCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/AttrKinds.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang {
+
+using namespace ast_matchers;
+
+static Token getTokenAtLoc(SourceLocation Loc,
+ const MatchFinder::MatchResult &MatchResult,
+ IdentifierTable &IdentTable) {
+ Token Tok;
+ if (Lexer::getRawToken(Loc, Tok, *MatchResult.SourceManager,
+ MatchResult.Context->getLangOpts(), false))
+ return Tok;
+
+ if (Tok.is(tok::raw_identifier)) {
+ IdentifierInfo &Info = IdentTable.get(Tok.getRawIdentifier());
+ Tok.setIdentifierInfo(&Info);
+ Tok.setKind(Info.getTokenID());
+ }
+ return Tok;
+}
+
+namespace tidy {
+namespace google {
+namespace runtime {
+
+IntegerTypesCheck::IntegerTypesCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ UnsignedTypePrefix(Options.get("UnsignedTypePrefix", "uint")),
+ SignedTypePrefix(Options.get("SignedTypePrefix", "int")),
+ TypeSuffix(Options.get("TypeSuffix", "")) {}
+
+void IntegerTypesCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "UnsignedTypePrefix", UnsignedTypePrefix);
+ Options.store(Opts, "SignedTypePrefix", SignedTypePrefix);
+ Options.store(Opts, "TypeSuffix", TypeSuffix);
+}
+
+void IntegerTypesCheck::registerMatchers(MatchFinder *Finder) {
+ // Find all TypeLocs. The relevant Style Guide rule only applies to C++.
+ if (!getLangOpts().CPlusPlus)
+ return;
+ // Match any integer types, unless they are passed to a printf-based API:
+ //
+ // http://google.github.io/styleguide/cppguide.html#64-bit_Portability
+ // "Where possible, avoid passing arguments of types specified by
+ // bitwidth typedefs to printf-based APIs."
+ Finder->addMatcher(typeLoc(loc(isInteger()),
+ unless(hasAncestor(callExpr(
+ callee(functionDecl(hasAttr(attr::Format)))))))
+ .bind("tl"),
+ this);
+ IdentTable = llvm::make_unique<IdentifierTable>(getLangOpts());
+}
+
+void IntegerTypesCheck::check(const MatchFinder::MatchResult &Result) {
+ auto TL = *Result.Nodes.getNodeAs<TypeLoc>("tl");
+ SourceLocation Loc = TL.getLocStart();
+
+ if (Loc.isInvalid() || Loc.isMacroID())
+ return;
+
+ // Look through qualification.
+ if (auto QualLoc = TL.getAs<QualifiedTypeLoc>())
+ TL = QualLoc.getUnqualifiedLoc();
+
+ auto BuiltinLoc = TL.getAs<BuiltinTypeLoc>();
+ if (!BuiltinLoc)
+ return;
+
+ Token Tok = getTokenAtLoc(Loc, Result, *IdentTable);
+ // Ensure the location actually points to one of the builting integral type
+ // names we're interested in. Otherwise, we might be getting this match from
+ // implicit code (e.g. an implicit assignment operator of a class containing
+ // an array of non-POD types).
+ if (!Tok.isOneOf(tok::kw_short, tok::kw_long, tok::kw_unsigned,
+ tok::kw_signed))
+ return;
+
+ bool IsSigned;
+ unsigned Width;
+ const TargetInfo &TargetInfo = Result.Context->getTargetInfo();
+
+ // Look for uses of short, long, long long and their unsigned versions.
+ switch (BuiltinLoc.getTypePtr()->getKind()) {
+ case BuiltinType::Short:
+ Width = TargetInfo.getShortWidth();
+ IsSigned = true;
+ break;
+ case BuiltinType::Long:
+ Width = TargetInfo.getLongWidth();
+ IsSigned = true;
+ break;
+ case BuiltinType::LongLong:
+ Width = TargetInfo.getLongLongWidth();
+ IsSigned = true;
+ break;
+ case BuiltinType::UShort:
+ Width = TargetInfo.getShortWidth();
+ IsSigned = false;
+ break;
+ case BuiltinType::ULong:
+ Width = TargetInfo.getLongWidth();
+ IsSigned = false;
+ break;
+ case BuiltinType::ULongLong:
+ Width = TargetInfo.getLongLongWidth();
+ IsSigned = false;
+ break;
+ default:
+ return;
+ }
+
+ // We allow "unsigned short port" as that's reasonably common and required by
+ // the sockets API.
+ const StringRef Port = "unsigned short port";
+ const char *Data = Result.SourceManager->getCharacterData(Loc);
+ if (!std::strncmp(Data, Port.data(), Port.size()) &&
+ !isIdentifierBody(Data[Port.size()]))
+ return;
+
+ std::string Replacement =
+ ((IsSigned ? SignedTypePrefix : UnsignedTypePrefix) + Twine(Width) +
+ TypeSuffix)
+ .str();
+
+ // We don't add a fix-it as changing the type can easily break code,
+ // e.g. when a function requires a 'long' argument on all platforms.
+ // QualTypes are printed with implicit quotes.
+ diag(Loc, "consider replacing %0 with '%1'") << BuiltinLoc.getType()
+ << Replacement;
+}
+
+} // namespace runtime
+} // namespace google
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.h
new file mode 100644
index 0000000..8d8f903
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.h
@@ -0,0 +1,49 @@
+//===--- IntegerTypesCheck.h - clang-tidy -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_INTEGERTYPESCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_INTEGERTYPESCHECK_H
+
+#include "../ClangTidy.h"
+
+#include <memory>
+
+namespace clang {
+
+class IdentifierTable;
+
+namespace tidy {
+namespace google {
+namespace runtime {
+
+/// Finds uses of `short`, `long` and `long long` and suggest replacing them
+/// with `u?intXX(_t)?`.
+///
+/// Correspondig cpplint.py check: 'runtime/int'.
+class IntegerTypesCheck : public ClangTidyCheck {
+public:
+ IntegerTypesCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Options) override;
+
+private:
+ const std::string UnsignedTypePrefix;
+ const std::string SignedTypePrefix;
+ const std::string TypeSuffix;
+
+ std::unique_ptr<IdentifierTable> IdentTable;
+};
+
+} // namespace runtime
+} // namespace google
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_INTEGERTYPESCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/NonConstReferences.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/NonConstReferences.cpp
new file mode 100644
index 0000000..856bc5b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/NonConstReferences.cpp
@@ -0,0 +1,149 @@
+//===--- NonConstReferences.cpp - clang-tidy --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NonConstReferences.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace runtime {
+
+NonConstReferences::NonConstReferences(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ WhiteListTypes(
+ utils::options::parseStringList(Options.get("WhiteListTypes", ""))) {}
+
+void NonConstReferences::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "WhiteListTypes",
+ utils::options::serializeStringList(WhiteListTypes));
+}
+
+void NonConstReferences::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(
+ parmVarDecl(
+ unless(isInstantiated()),
+ hasType(references(
+ qualType(unless(isConstQualified())).bind("referenced_type"))),
+ unless(hasType(rValueReferenceType())))
+ .bind("param"),
+ this);
+}
+
+void NonConstReferences::check(const MatchFinder::MatchResult &Result) {
+ const auto *Parameter = Result.Nodes.getNodeAs<ParmVarDecl>("param");
+ const auto *Function =
+ dyn_cast_or_null<FunctionDecl>(Parameter->getParentFunctionOrMethod());
+
+ if (Function == nullptr || Function->isImplicit())
+ return;
+
+ if (!Function->isCanonicalDecl())
+ return;
+
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(Function)) {
+ // Don't warn on implementations of an interface using references.
+ if (Method->begin_overridden_methods() != Method->end_overridden_methods())
+ return;
+ // Don't warn on lambdas, as they frequently have to conform to the
+ // interface defined elsewhere.
+ if (Method->getParent()->isLambda())
+ return;
+ }
+
+ auto ReferencedType = *Result.Nodes.getNodeAs<QualType>("referenced_type");
+
+ if (std::find_if(WhiteListTypes.begin(), WhiteListTypes.end(),
+ [&](llvm::StringRef WhiteListType) {
+ return ReferencedType.getCanonicalType().getAsString(
+ Result.Context->getPrintingPolicy()) ==
+ WhiteListType;
+ }) != WhiteListTypes.end())
+ return;
+
+ // Don't warn on function references, they shouldn't be constant.
+ if (ReferencedType->isFunctionProtoType())
+ return;
+
+ // Don't warn on dependent types in templates.
+ if (ReferencedType->isDependentType())
+ return;
+
+ if (Function->isOverloadedOperator()) {
+ switch (Function->getOverloadedOperator()) {
+ case clang::OO_LessLess:
+ case clang::OO_PlusPlus:
+ case clang::OO_MinusMinus:
+ case clang::OO_PlusEqual:
+ case clang::OO_MinusEqual:
+ case clang::OO_StarEqual:
+ case clang::OO_SlashEqual:
+ case clang::OO_PercentEqual:
+ case clang::OO_LessLessEqual:
+ case clang::OO_GreaterGreaterEqual:
+ case clang::OO_PipeEqual:
+ case clang::OO_CaretEqual:
+ case clang::OO_AmpEqual:
+ // Don't warn on the first parameter of operator<<(Stream&, ...),
+ // operator++, operator-- and operation+assignment operators.
+ if (Function->getParamDecl(0) == Parameter)
+ return;
+ break;
+ case clang::OO_GreaterGreater: {
+ auto isNonConstRef = [](clang::QualType T) {
+ return T->isReferenceType() &&
+ !T.getNonReferenceType().isConstQualified();
+ };
+ // Don't warn on parameters of stream extractors:
+ // Stream& operator>>(Stream&, Value&);
+ // Both parameters should be non-const references by convention.
+ if (isNonConstRef(Function->getParamDecl(0)->getType()) &&
+ (Function->getNumParams() < 2 || // E.g. member operator>>.
+ isNonConstRef(Function->getParamDecl(1)->getType())) &&
+ isNonConstRef(Function->getReturnType()))
+ return;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ // Some functions use references to comply with established standards.
+ if (Function->getDeclName().isIdentifier() && Function->getName() == "swap")
+ return;
+
+ // iostream parameters are typically passed by non-const reference.
+ if (StringRef(ReferencedType.getAsString()).endswith("stream"))
+ return;
+
+ if (Parameter->getName().empty()) {
+ diag(Parameter->getLocation(), "non-const reference parameter at index %0, "
+ "make it const or use a pointer")
+ << Parameter->getFunctionScopeIndex();
+ } else {
+ diag(Parameter->getLocation(),
+ "non-const reference parameter %0, make it const or use a pointer")
+ << Parameter;
+ }
+}
+
+} // namespace runtime
+} // namespace google
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/NonConstReferences.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/NonConstReferences.h
new file mode 100644
index 0000000..a665813
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/NonConstReferences.h
@@ -0,0 +1,39 @@
+//===--- NonConstReferences.h - clang-tidy ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_NON_CONST_REFERENCES_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_NON_CONST_REFERENCES_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace runtime {
+
+/// \brief Checks the usage of non-constant references in function parameters.
+///
+/// https://google.github.io/styleguide/cppguide.html#Reference_Arguments
+class NonConstReferences : public ClangTidyCheck {
+public:
+ NonConstReferences(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ const std::vector<std::string> WhiteListTypes;
+};
+
+} // namespace runtime
+} // namespace google
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_NON_CONST_REFERENCES_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/OverloadedUnaryAndCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/OverloadedUnaryAndCheck.cpp
new file mode 100644
index 0000000..84abb5f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/OverloadedUnaryAndCheck.cpp
@@ -0,0 +1,53 @@
+//===--- OverloadedUnaryAndCheck.cpp - clang-tidy ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OverloadedUnaryAndCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace runtime {
+
+void OverloadedUnaryAndCheck::registerMatchers(
+ ast_matchers::MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // Match unary methods that overload operator&.
+ Finder->addMatcher(
+ cxxMethodDecl(parameterCountIs(0), hasOverloadedOperatorName("&"))
+ .bind("overload"),
+ this);
+ // Also match freestanding unary operator& overloads. Be careful not to match
+ // binary methods.
+ Finder->addMatcher(
+ functionDecl(allOf(
+ unless(cxxMethodDecl()),
+ functionDecl(parameterCountIs(1), hasOverloadedOperatorName("&"))
+ .bind("overload"))),
+ this);
+}
+
+void OverloadedUnaryAndCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Decl = Result.Nodes.getNodeAs<FunctionDecl>("overload");
+ diag(Decl->getLocStart(),
+ "do not overload unary operator&, it is dangerous.");
+}
+
+} // namespace runtime
+} // namespace google
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/OverloadedUnaryAndCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/OverloadedUnaryAndCheck.h
new file mode 100644
index 0000000..5492eba
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/OverloadedUnaryAndCheck.h
@@ -0,0 +1,38 @@
+//===--- OverloadedUnaryAndCheck.h - clang-tidy -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OVERLOADEDUNARYANDCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OVERLOADEDUNARYANDCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace runtime {
+
+/// Finds overloads of unary `operator &`.
+///
+/// https://google.github.io/styleguide/cppguide.html#Operator_Overloading
+///
+/// Corresponding cpplint.py check name: 'runtime/operator'.
+class OverloadedUnaryAndCheck : public ClangTidyCheck {
+public:
+ OverloadedUnaryAndCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace runtime
+} // namespace google
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_OVERLOADEDUNARYANDCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/TodoCommentCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/TodoCommentCheck.cpp
new file mode 100644
index 0000000..f1c79ce
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/TodoCommentCheck.cpp
@@ -0,0 +1,66 @@
+//===--- TodoCommentCheck.cpp - clang-tidy --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TodoCommentCheck.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Preprocessor.h"
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace readability {
+
+class TodoCommentCheck::TodoCommentHandler : public CommentHandler {
+public:
+ TodoCommentHandler(TodoCommentCheck &Check, llvm::Optional<std::string> User)
+ : Check(Check), User(User ? *User : "unknown"),
+ TodoMatch("^// *TODO *(\\(.*\\))?:?( )?(.*)$") {}
+
+ bool HandleComment(Preprocessor &PP, SourceRange Range) override {
+ StringRef Text =
+ Lexer::getSourceText(CharSourceRange::getCharRange(Range),
+ PP.getSourceManager(), PP.getLangOpts());
+
+ SmallVector<StringRef, 4> Matches;
+ if (!TodoMatch.match(Text, &Matches))
+ return false;
+
+ StringRef Username = Matches[1];
+ StringRef Comment = Matches[3];
+
+ if (!Username.empty())
+ return false;
+
+ std::string NewText = ("// TODO(" + Twine(User) + "): " + Comment).str();
+
+ Check.diag(Range.getBegin(), "missing username/bug in TODO")
+ << FixItHint::CreateReplacement(CharSourceRange::getCharRange(Range),
+ NewText);
+ return false;
+ }
+
+private:
+ TodoCommentCheck &Check;
+ std::string User;
+ llvm::Regex TodoMatch;
+};
+
+TodoCommentCheck::TodoCommentCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ Handler(llvm::make_unique<TodoCommentHandler>(
+ *this, Context->getOptions().User)) {}
+
+void TodoCommentCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+ Compiler.getPreprocessor().addCommentHandler(Handler.get());
+}
+
+} // namespace readability
+} // namespace google
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/TodoCommentCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/TodoCommentCheck.h
new file mode 100644
index 0000000..dbdc366
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/TodoCommentCheck.h
@@ -0,0 +1,38 @@
+//===--- TodoCommentCheck.h - clang-tidy ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_TODOCOMMENTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_TODOCOMMENTCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace readability {
+
+/// Finds TODO comments without a username or bug number.
+///
+/// Corresponding cpplint.py check: 'readability/todo'
+class TodoCommentCheck : public ClangTidyCheck {
+public:
+ TodoCommentCheck(StringRef Name, ClangTidyContext *Context);
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+
+private:
+ class TodoCommentHandler;
+ std::unique_ptr<TodoCommentHandler> Handler;
+};
+
+} // namespace readability
+} // namespace google
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_TODOCOMMENTCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp
new file mode 100644
index 0000000..32ff6e0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.cpp
@@ -0,0 +1,63 @@
+//===--- UnnamedNamespaceInHeaderCheck.cpp - clang-tidy ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnnamedNamespaceInHeaderCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace build {
+
+UnnamedNamespaceInHeaderCheck::UnnamedNamespaceInHeaderCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
+ "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
+ if (!utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions,
+ HeaderFileExtensions, ',')) {
+ llvm::errs() << "Invalid header file extension: "
+ << RawStringHeaderFileExtensions << "\n";
+ }
+}
+
+void UnnamedNamespaceInHeaderCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions);
+}
+
+void UnnamedNamespaceInHeaderCheck::registerMatchers(
+ ast_matchers::MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (getLangOpts().CPlusPlus)
+ Finder->addMatcher(namespaceDecl(isAnonymous()).bind("anonymousNamespace"),
+ this);
+}
+
+void UnnamedNamespaceInHeaderCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *N = Result.Nodes.getNodeAs<NamespaceDecl>("anonymousNamespace");
+ SourceLocation Loc = N->getLocStart();
+ if (!Loc.isValid())
+ return;
+
+ if (utils::isPresumedLocInHeaderFile(Loc, *Result.SourceManager,
+ HeaderFileExtensions))
+ diag(Loc, "do not use unnamed namespaces in header files");
+}
+
+} // namespace build
+} // namespace google
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.h
new file mode 100644
index 0000000..4d310f5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/UnnamedNamespaceInHeaderCheck.h
@@ -0,0 +1,50 @@
+//===--- UnnamedNamespaceInHeaderCheck.h - clang-tidy -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_UNNAMEDNAMESPACEINHEADERCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_UNNAMEDNAMESPACEINHEADERCHECK_H
+
+#include "../ClangTidy.h"
+#include "../utils/HeaderFileExtensionsUtils.h"
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace build {
+
+/// Finds anonymous namespaces in headers.
+///
+/// The check supports these options:
+/// - `HeaderFileExtensions`: a comma-separated list of filename extensions of
+/// header files (The filename extensions should not contain "." prefix).
+/// "h,hh,hpp,hxx" by default.
+/// For extension-less header files, using an empty string or leaving an
+/// empty string between "," if there are other filename extensions.
+///
+/// https://google.github.io/styleguide/cppguide.html#Namespaces
+///
+/// Corresponding cpplint.py check name: 'build/namespaces'.
+class UnnamedNamespaceInHeaderCheck : public ClangTidyCheck {
+public:
+ UnnamedNamespaceInHeaderCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const std::string RawStringHeaderFileExtensions;
+ utils::HeaderFileExtensionsSet HeaderFileExtensions;
+};
+
+} // namespace build
+} // namespace google
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_UNNAMEDNAMESPACEINHEADERCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/UsingNamespaceDirectiveCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/UsingNamespaceDirectiveCheck.cpp
new file mode 100644
index 0000000..60a46f8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/UsingNamespaceDirectiveCheck.cpp
@@ -0,0 +1,66 @@
+//===--- UsingNamespaceDirectiveCheck.cpp - clang-tidy ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UsingNamespaceDirectiveCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace build {
+
+void UsingNamespaceDirectiveCheck::registerMatchers(
+ ast_matchers::MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (getLangOpts().CPlusPlus)
+ Finder->addMatcher(usingDirectiveDecl().bind("usingNamespace"), this);
+}
+
+void UsingNamespaceDirectiveCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *U = Result.Nodes.getNodeAs<UsingDirectiveDecl>("usingNamespace");
+ SourceLocation Loc = U->getLocStart();
+ if (U->isImplicit() || !Loc.isValid())
+ return;
+
+ // Do not warn if namespace is a std namespace with user-defined literals. The
+ // user-defined literals can only be used with a using directive.
+ if (isStdLiteralsNamespace(U->getNominatedNamespace()))
+ return;
+
+ diag(Loc, "do not use namespace using-directives; "
+ "use using-declarations instead");
+ // TODO: We could suggest a list of using directives replacing the using
+ // namespace directive.
+}
+
+bool UsingNamespaceDirectiveCheck::isStdLiteralsNamespace(
+ const NamespaceDecl *NS) {
+ if (!NS->getName().endswith("literals"))
+ return false;
+
+ const auto *Parent = dyn_cast_or_null<NamespaceDecl>(NS->getParent());
+ if (!Parent)
+ return false;
+
+ if (Parent->isStdNamespace())
+ return true;
+
+ return Parent->getName() == "literals" && Parent->getParent() &&
+ Parent->getParent()->isStdNamespace();
+}
+} // namespace build
+} // namespace google
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/UsingNamespaceDirectiveCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/UsingNamespaceDirectiveCheck.h
new file mode 100644
index 0000000..2be65c1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/google/UsingNamespaceDirectiveCheck.h
@@ -0,0 +1,51 @@
+//===--- UsingNamespaceDirectiveCheck.h - clang-tidy ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_USINGNAMESPACEDIRECTIVECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_USINGNAMESPACEDIRECTIVECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace build {
+
+/// Finds using namespace directives.
+///
+/// https://google.github.io/styleguide/cppguide.html#Namespaces
+///
+/// The check implements the following rule of the Google C++ Style Guide:
+///
+/// You may not use a using-directive to make all names from a namespace
+/// available.
+///
+/// \code
+/// // Forbidden -- This pollutes the namespace.
+/// using namespace foo;
+/// \endcode
+///
+/// Corresponding cpplint.py check name: `build/namespaces`.
+class UsingNamespaceDirectiveCheck : public ClangTidyCheck {
+public:
+ UsingNamespaceDirectiveCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ static bool isStdLiteralsNamespace(const NamespaceDecl *NS);
+};
+
+} // namespace build
+} // namespace google
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_USINGNAMESPACEDIRECTIVECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/CMakeLists.txt
new file mode 100644
index 0000000..eeccf62
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/CMakeLists.txt
@@ -0,0 +1,24 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyHICPPModule
+ ExceptionBaseclassCheck.cpp
+ MultiwayPathsCoveredCheck.cpp
+ NoAssemblerCheck.cpp
+ HICPPTidyModule.cpp
+ SignedBitwiseCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyBugproneModule
+ clangTidyCppCoreGuidelinesModule
+ clangTidyGoogleModule
+ clangTidyMiscModule
+ clangTidyModernizeModule
+ clangTidyPerformanceModule
+ clangTidyReadabilityModule
+ clangTidyUtils
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp
new file mode 100644
index 0000000..298759f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp
@@ -0,0 +1,50 @@
+//===--- ExceptionBaseclassCheck.cpp - clang-tidy--------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExceptionBaseclassCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace hicpp {
+
+void ExceptionBaseclassCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(
+ cxxThrowExpr(allOf(has(expr(unless(hasType(qualType(hasCanonicalType(
+ hasDeclaration(cxxRecordDecl(isSameOrDerivedFrom(
+ hasName("std::exception")))))))))),
+ has(expr(unless(cxxUnresolvedConstructExpr()))),
+ eachOf(has(expr(hasType(namedDecl().bind("decl")))),
+ anything())))
+ .bind("bad_throw"),
+ this);
+}
+
+void ExceptionBaseclassCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *BadThrow = Result.Nodes.getNodeAs<CXXThrowExpr>("bad_throw");
+
+ diag(BadThrow->getSubExpr()->getLocStart(), "throwing an exception whose "
+ "type %0 is not derived from "
+ "'std::exception'")
+ << BadThrow->getSubExpr()->getType() << BadThrow->getSourceRange();
+
+ const auto *TypeDecl = Result.Nodes.getNodeAs<NamedDecl>("decl");
+ if (TypeDecl != nullptr)
+ diag(TypeDecl->getLocStart(), "type defined here", DiagnosticIDs::Note);
+}
+
+} // namespace hicpp
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.h
new file mode 100644
index 0000000..778979d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.h
@@ -0,0 +1,35 @@
+//===--- ExceptionBaseclassCheck.h - clang-tidy------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_HICPP_EXCEPTION_BASECLASS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_HICPP_EXCEPTION_BASECLASS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace hicpp {
+
+/// Check for thrown exceptions and enforce they are all derived from std::exception.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/hicpp-exception-baseclass.html
+class ExceptionBaseclassCheck : public ClangTidyCheck {
+public:
+ ExceptionBaseclassCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace hicpp
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_HICPP_EXCEPTION_BASECLASS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/HICPPTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/HICPPTidyModule.cpp
new file mode 100644
index 0000000..d2b9fc6d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/HICPPTidyModule.cpp
@@ -0,0 +1,119 @@
+//===------- HICPPTidyModule.cpp - clang-tidy -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "../bugprone/UseAfterMoveCheck.h"
+#include "../cppcoreguidelines/AvoidGotoCheck.h"
+#include "../cppcoreguidelines/NoMallocCheck.h"
+#include "../cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.h"
+#include "../cppcoreguidelines/ProTypeMemberInitCheck.h"
+#include "../cppcoreguidelines/ProTypeVarargCheck.h"
+#include "../cppcoreguidelines/SpecialMemberFunctionsCheck.h"
+#include "../google/DefaultArgumentsCheck.h"
+#include "../google/ExplicitConstructorCheck.h"
+#include "../misc/NewDeleteOverloadsCheck.h"
+#include "../misc/StaticAssertCheck.h"
+#include "../bugprone/UndelegatedConstructorCheck.h"
+#include "../modernize/DeprecatedHeadersCheck.h"
+#include "../modernize/UseAutoCheck.h"
+#include "../modernize/UseEmplaceCheck.h"
+#include "../modernize/UseEqualsDefaultCheck.h"
+#include "../modernize/UseEqualsDeleteCheck.h"
+#include "../modernize/UseNoexceptCheck.h"
+#include "../modernize/UseNullptrCheck.h"
+#include "../modernize/UseOverrideCheck.h"
+#include "../performance/MoveConstArgCheck.h"
+#include "../performance/NoexceptMoveConstructorCheck.h"
+#include "../readability/BracesAroundStatementsCheck.h"
+#include "../readability/FunctionSizeCheck.h"
+#include "../readability/IdentifierNamingCheck.h"
+#include "ExceptionBaseclassCheck.h"
+#include "MultiwayPathsCoveredCheck.h"
+#include "NoAssemblerCheck.h"
+#include "SignedBitwiseCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace hicpp {
+
+class HICPPModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<cppcoreguidelines::AvoidGotoCheck>(
+ "hicpp-avoid-goto");
+ CheckFactories.registerCheck<readability::BracesAroundStatementsCheck>(
+ "hicpp-braces-around-statements");
+ CheckFactories.registerCheck<modernize::DeprecatedHeadersCheck>(
+ "hicpp-deprecated-headers");
+ CheckFactories.registerCheck<ExceptionBaseclassCheck>(
+ "hicpp-exception-baseclass");
+ CheckFactories.registerCheck<MultiwayPathsCoveredCheck>(
+ "hicpp-multiway-paths-covered");
+ CheckFactories.registerCheck<SignedBitwiseCheck>("hicpp-signed-bitwise");
+ CheckFactories.registerCheck<google::ExplicitConstructorCheck>(
+ "hicpp-explicit-conversions");
+ CheckFactories.registerCheck<readability::FunctionSizeCheck>(
+ "hicpp-function-size");
+ CheckFactories.registerCheck<readability::IdentifierNamingCheck>(
+ "hicpp-named-parameter");
+ CheckFactories.registerCheck<bugprone::UseAfterMoveCheck>(
+ "hicpp-invalid-access-moved");
+ CheckFactories.registerCheck<cppcoreguidelines::ProTypeMemberInitCheck>(
+ "hicpp-member-init");
+ CheckFactories.registerCheck<performance::MoveConstArgCheck>(
+ "hicpp-move-const-arg");
+ CheckFactories.registerCheck<misc::NewDeleteOverloadsCheck>(
+ "hicpp-new-delete-operators");
+ CheckFactories.registerCheck<performance::NoexceptMoveConstructorCheck>(
+ "hicpp-noexcept-move");
+ CheckFactories
+ .registerCheck<cppcoreguidelines::ProBoundsArrayToPointerDecayCheck>(
+ "hicpp-no-array-decay");
+ CheckFactories.registerCheck<NoAssemblerCheck>("hicpp-no-assembler");
+ CheckFactories.registerCheck<cppcoreguidelines::NoMallocCheck>(
+ "hicpp-no-malloc");
+ CheckFactories
+ .registerCheck<cppcoreguidelines::SpecialMemberFunctionsCheck>(
+ "hicpp-special-member-functions");
+ CheckFactories.registerCheck<misc::StaticAssertCheck>(
+ "hicpp-static-assert");
+ CheckFactories.registerCheck<modernize::UseAutoCheck>("hicpp-use-auto");
+ CheckFactories.registerCheck<bugprone::UndelegatedConstructorCheck>(
+ "hicpp-undelegated-constructor");
+ CheckFactories.registerCheck<modernize::UseEmplaceCheck>(
+ "hicpp-use-emplace");
+ CheckFactories.registerCheck<modernize::UseEqualsDefaultCheck>(
+ "hicpp-use-equals-default");
+ CheckFactories.registerCheck<modernize::UseEqualsDeleteCheck>(
+ "hicpp-use-equals-delete");
+ CheckFactories.registerCheck<modernize::UseNoexceptCheck>(
+ "hicpp-use-noexcept");
+ CheckFactories.registerCheck<modernize::UseNullptrCheck>(
+ "hicpp-use-nullptr");
+ CheckFactories.registerCheck<modernize::UseOverrideCheck>(
+ "hicpp-use-override");
+ CheckFactories.registerCheck<cppcoreguidelines::ProTypeVarargCheck>(
+ "hicpp-vararg");
+ }
+};
+
+// Register the HICPPModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<HICPPModule>
+ X("hicpp-module", "Adds High-Integrity C++ checks.");
+
+} // namespace hicpp
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the HICPPModule.
+volatile int HICPPModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/LICENSE.TXT b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/LICENSE.TXT
new file mode 100644
index 0000000..fb8f513
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/LICENSE.TXT
@@ -0,0 +1,12 @@
+------------------------------------------------------------------------------
+clang-tidy High-Integrity C++ Files
+------------------------------------------------------------------------------
+All clang-tidy files are licensed under the LLVM license with the following
+additions:
+
+Any file referencing a High-Integrity C++ Coding guideline:
+
+HIC++ Coding Standard as created by PRQA.
+
+Please see http://www.codingstandard.com/section/conditions-of-use/ for more
+information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp
new file mode 100644
index 0000000..68ae54e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp
@@ -0,0 +1,181 @@
+//===--- MultiwayPathsCoveredCheck.cpp - clang-tidy------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MultiwayPathsCoveredCheck.h"
+#include "clang/AST/ASTContext.h"
+
+#include <limits>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace hicpp {
+
+void MultiwayPathsCoveredCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "WarnOnMissingElse", WarnOnMissingElse);
+}
+
+void MultiwayPathsCoveredCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ switchStmt(
+ hasCondition(allOf(
+ // Match on switch statements that have either a bit-field or
+ // an integer condition. The ordering in 'anyOf()' is
+ // important because the last condition is the most general.
+ anyOf(ignoringImpCasts(memberExpr(hasDeclaration(
+ fieldDecl(isBitField()).bind("bitfield")))),
+ ignoringImpCasts(declRefExpr().bind("non-enum-condition"))),
+ // 'unless()' must be the last match here and must be bound,
+ // otherwise the matcher does not work correctly, because it
+ // will not explicitly ignore enum conditions.
+ unless(ignoringImpCasts(
+ declRefExpr(hasType(enumType())).bind("enum-condition"))))))
+ .bind("switch"),
+ this);
+
+ // This option is noisy, therefore matching is configurable.
+ if (WarnOnMissingElse) {
+ Finder->addMatcher(
+ ifStmt(allOf(hasParent(ifStmt()), unless(hasElse(anything()))))
+ .bind("else-if"),
+ this);
+ }
+}
+
+static std::pair<std::size_t, bool> countCaseLabels(const SwitchStmt *Switch) {
+ std::size_t CaseCount = 0;
+ bool HasDefault = false;
+
+ const SwitchCase *CurrentCase = Switch->getSwitchCaseList();
+ while (CurrentCase) {
+ ++CaseCount;
+ if (isa<DefaultStmt>(CurrentCase))
+ HasDefault = true;
+
+ CurrentCase = CurrentCase->getNextSwitchCase();
+ }
+
+ return std::make_pair(CaseCount, HasDefault);
+}
+
+/// This function calculate 2 ** Bits and returns
+/// numeric_limits<std::size_t>::max() if an overflow occured.
+static std::size_t twoPow(std::size_t Bits) {
+ return Bits >= std::numeric_limits<std::size_t>::digits
+ ? std::numeric_limits<std::size_t>::max()
+ : static_cast<size_t>(1) << Bits;
+}
+
+/// Get the number of possible values that can be switched on for the type T.
+///
+/// \return - 0 if bitcount could not be determined
+/// - numeric_limits<std::size_t>::max() when overflow appeared due to
+/// more than 64 bits type size.
+static std::size_t getNumberOfPossibleValues(QualType T,
+ const ASTContext &Context) {
+ // `isBooleanType` must come first because `bool` is an integral type as well
+ // and would not return 2 as result.
+ if (T->isBooleanType())
+ return 2;
+ else if (T->isIntegralType(Context))
+ return twoPow(Context.getTypeSize(T));
+ else
+ return 1;
+}
+
+void MultiwayPathsCoveredCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *ElseIfWithoutElse =
+ Result.Nodes.getNodeAs<IfStmt>("else-if")) {
+ diag(ElseIfWithoutElse->getLocStart(),
+ "potentially uncovered codepath; add an ending else statement");
+ return;
+ }
+ const auto *Switch = Result.Nodes.getNodeAs<SwitchStmt>("switch");
+ std::size_t SwitchCaseCount;
+ bool SwitchHasDefault;
+ std::tie(SwitchCaseCount, SwitchHasDefault) = countCaseLabels(Switch);
+
+ // Checks the sanity of 'switch' statements that actually do define
+ // a default branch but might be degenerated by having no or only one case.
+ if (SwitchHasDefault) {
+ handleSwitchWithDefault(Switch, SwitchCaseCount);
+ return;
+ }
+ // Checks all 'switch' statements that do not define a default label.
+ // Here the heavy lifting happens.
+ if (!SwitchHasDefault && SwitchCaseCount > 0) {
+ handleSwitchWithoutDefault(Switch, SwitchCaseCount, Result);
+ return;
+ }
+ // Warns for degenerated 'switch' statements that neither define a case nor
+ // a default label.
+ // FIXME: Evaluate, if emitting a fix-it to simplify that statement is
+ // reasonable.
+ if (!SwitchHasDefault && SwitchCaseCount == 0) {
+ diag(Switch->getLocStart(),
+ "switch statement without labels has no effect");
+ return;
+ }
+ llvm_unreachable("matched a case, that was not explicitly handled");
+}
+
+void MultiwayPathsCoveredCheck::handleSwitchWithDefault(
+ const SwitchStmt *Switch, std::size_t CaseCount) {
+ assert(CaseCount > 0 && "Switch statement with supposedly one default "
+ "branch did not contain any case labels");
+ if (CaseCount == 1 || CaseCount == 2)
+ diag(Switch->getLocStart(),
+ CaseCount == 1
+ ? "degenerated switch with default label only"
+ : "switch could be better written as an if/else statement");
+}
+
+void MultiwayPathsCoveredCheck::handleSwitchWithoutDefault(
+ const SwitchStmt *Switch, std::size_t CaseCount,
+ const MatchFinder::MatchResult &Result) {
+ // The matcher only works because some nodes are explicitly matched and
+ // bound but ignored. This is necessary to build the excluding logic for
+ // enums and 'switch' statements without a 'default' branch.
+ assert(!Result.Nodes.getNodeAs<DeclRefExpr>("enum-condition") &&
+ "switch over enum is handled by warnings already, explicitly ignoring "
+ "them");
+ // Determine the number of case labels. Because 'default' is not present
+ // and duplicating case labels is not allowed this number represents
+ // the number of codepaths. It can be directly compared to 'MaxPathsPossible'
+ // to see if some cases are missing.
+ // CaseCount == 0 is caught in DegenerateSwitch. Necessary because the
+ // matcher used for here does not match on degenerate 'switch'.
+ assert(CaseCount > 0 && "Switch statement without any case found. This case "
+ "should be excluded by the matcher and is handled "
+ "separatly.");
+ std::size_t MaxPathsPossible = [&]() {
+ if (const auto *GeneralCondition =
+ Result.Nodes.getNodeAs<DeclRefExpr>("non-enum-condition")) {
+ return getNumberOfPossibleValues(GeneralCondition->getType(),
+ *Result.Context);
+ }
+ if (const auto *BitfieldDecl =
+ Result.Nodes.getNodeAs<FieldDecl>("bitfield")) {
+ return twoPow(BitfieldDecl->getBitWidthValue(*Result.Context));
+ }
+
+ return static_cast<std::size_t>(0);
+ }();
+
+ // FIXME: Transform the 'switch' into an 'if' for CaseCount == 1.
+ if (CaseCount < MaxPathsPossible)
+ diag(Switch->getLocStart(),
+ CaseCount == 1 ? "switch with only one case; use an if statement"
+ : "potential uncovered code path; add a default label");
+}
+} // namespace hicpp
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/MultiwayPathsCoveredCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/MultiwayPathsCoveredCheck.h
new file mode 100644
index 0000000..498dad6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/MultiwayPathsCoveredCheck.h
@@ -0,0 +1,51 @@
+//===--- MultiwayPathsCoveredCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_HICPP_MULTIWAY_PATHS_COVERED_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_HICPP_MULTIWAY_PATHS_COVERED_H
+
+#include "../ClangTidy.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <iostream>
+
+namespace clang {
+namespace tidy {
+namespace hicpp {
+
+/// Find occasions where not all codepaths are explicitly covered in code.
+/// This includes 'switch' without a 'default'-branch and 'if'-'else if'-chains
+/// without a final 'else'-branch.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/hicpp-multiway-paths-covered.html
+class MultiwayPathsCoveredCheck : public ClangTidyCheck {
+public:
+ MultiwayPathsCoveredCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ WarnOnMissingElse(Options.get("WarnOnMissingElse", 0)) {}
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void handleSwitchWithDefault(const SwitchStmt *Switch, std::size_t CaseCount);
+ void handleSwitchWithoutDefault(
+ const SwitchStmt *Switch, std::size_t CaseCount,
+ const ast_matchers::MatchFinder::MatchResult &Result);
+ /// This option can be configured to warn on missing 'else' branches in an
+ /// 'if-else if' chain. The default is false because this option might be
+ /// noisy on some code bases.
+ const bool WarnOnMissingElse;
+};
+
+} // namespace hicpp
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_HICPP_MULTIWAY_PATHS_COVERED_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/NoAssemblerCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/NoAssemblerCheck.cpp
new file mode 100644
index 0000000..06969a8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/NoAssemblerCheck.cpp
@@ -0,0 +1,50 @@
+//===--- NoAssemblerCheck.cpp - clang-tidy---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NoAssemblerCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace hicpp {
+
+namespace {
+AST_MATCHER(VarDecl, isAsm) { return Node.hasAttr<clang::AsmLabelAttr>(); }
+const ast_matchers::internal::VariadicDynCastAllOfMatcher<Decl,
+ FileScopeAsmDecl>
+ fileScopeAsmDecl;
+} // namespace
+
+void NoAssemblerCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(asmStmt().bind("asm-stmt"), this);
+ Finder->addMatcher(fileScopeAsmDecl().bind("asm-file-scope"), this);
+ Finder->addMatcher(varDecl(isAsm()).bind("asm-var"), this);
+}
+
+void NoAssemblerCheck::check(const MatchFinder::MatchResult &Result) {
+ SourceLocation ASMLocation;
+ if (const auto *ASM = Result.Nodes.getNodeAs<AsmStmt>("asm-stmt"))
+ ASMLocation = ASM->getAsmLoc();
+ else if (const auto *ASM =
+ Result.Nodes.getNodeAs<FileScopeAsmDecl>("asm-file-scope"))
+ ASMLocation = ASM->getAsmLoc();
+ else if (const auto *ASM = Result.Nodes.getNodeAs<VarDecl>("asm-var"))
+ ASMLocation = ASM->getLocation();
+ else
+ llvm_unreachable("Unhandled case in matcher.");
+
+ diag(ASMLocation, "do not use inline assembler in safety-critical code");
+}
+
+} // namespace hicpp
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/NoAssemblerCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/NoAssemblerCheck.h
new file mode 100644
index 0000000..416ccb0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/NoAssemblerCheck.h
@@ -0,0 +1,35 @@
+//===--- NoAssemblerCheck.h - clang-tidy-------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_HICPP_NO_ASSEMBLER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_HICPP_NO_ASSEMBLER_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace hicpp {
+
+/// Find assembler statements. No fix is offered.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/hicpp-no-assembler.html
+class NoAssemblerCheck : public ClangTidyCheck {
+public:
+ NoAssemblerCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace hicpp
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_HICPP_NO_ASSEMBLER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.cpp
new file mode 100644
index 0000000..0390052
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.cpp
@@ -0,0 +1,96 @@
+//===--- SignedBitwiseCheck.cpp - clang-tidy-------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SignedBitwiseCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::ast_matchers::internal;
+
+namespace clang {
+namespace tidy {
+namespace hicpp {
+
+void SignedBitwiseCheck::registerMatchers(MatchFinder *Finder) {
+ const auto SignedIntegerOperand =
+ expr(ignoringImpCasts(hasType(isSignedInteger()))).bind("signed-operand");
+
+ // The standard [bitmask.types] allows some integral types to be implemented
+ // as signed types. Exclude these types from diagnosing for bitwise or(|) and
+ // bitwise and(&). Shifting and complementing such values is still not
+ // allowed.
+ const auto BitmaskType = namedDecl(anyOf(
+ hasName("::std::locale::category"), hasName("::std::ctype_base::mask"),
+ hasName("::std::ios_base::fmtflags"), hasName("::std::ios_base::iostate"),
+ hasName("::std::ios_base::openmode")));
+ const auto IsStdBitmask = ignoringImpCasts(declRefExpr(hasType(BitmaskType)));
+
+ // Match binary bitwise operations on signed integer arguments.
+ Finder->addMatcher(
+ binaryOperator(
+ allOf(anyOf(hasOperatorName("^"), hasOperatorName("|"),
+ hasOperatorName("&"), hasOperatorName("^="),
+ hasOperatorName("|="), hasOperatorName("&=")),
+
+ unless(allOf(hasLHS(IsStdBitmask), hasRHS(IsStdBitmask))),
+
+ hasEitherOperand(SignedIntegerOperand),
+ hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger()))))
+ .bind("binary-no-sign-interference"),
+ this);
+
+ // Shifting and complement is not allowed for any signed integer type because
+ // the sign bit may corrupt the result.
+ Finder->addMatcher(
+ binaryOperator(
+ allOf(anyOf(hasOperatorName("<<"), hasOperatorName(">>"),
+ hasOperatorName("<<="), hasOperatorName(">>=")),
+ hasEitherOperand(SignedIntegerOperand),
+ hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger()))))
+ .bind("binary-sign-interference"),
+ this);
+
+ // Match unary operations on signed integer types.
+ Finder->addMatcher(unaryOperator(allOf(hasOperatorName("~"),
+ hasUnaryOperand(SignedIntegerOperand)))
+ .bind("unary-signed"),
+ this);
+}
+
+void SignedBitwiseCheck::check(const MatchFinder::MatchResult &Result) {
+ const ast_matchers::BoundNodes &N = Result.Nodes;
+ const auto *SignedOperand = N.getNodeAs<Expr>("signed-operand");
+ assert(SignedOperand &&
+ "No signed operand found in problematic bitwise operations");
+
+ bool IsUnary = false;
+ SourceLocation Location;
+
+ if (const auto *UnaryOp = N.getNodeAs<UnaryOperator>("unary-signed")) {
+ IsUnary = true;
+ Location = UnaryOp->getLocStart();
+ } else {
+ if (const auto *BinaryOp =
+ N.getNodeAs<BinaryOperator>("binary-no-sign-interference"))
+ Location = BinaryOp->getLocStart();
+ else if (const auto *BinaryOp =
+ N.getNodeAs<BinaryOperator>("binary-sign-interference"))
+ Location = BinaryOp->getLocStart();
+ else
+ llvm_unreachable("unexpected matcher result");
+ }
+ diag(Location, "use of a signed integer operand with a "
+ "%select{binary|unary}0 bitwise operator")
+ << IsUnary << SignedOperand->getSourceRange();
+}
+
+} // namespace hicpp
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.h
new file mode 100644
index 0000000..24338ad
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.h
@@ -0,0 +1,36 @@
+//===--- SignedBitwiseCheck.h - clang-tidy-----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_HICPP_SIGNED_BITWISE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_HICPP_SIGNED_BITWISE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace hicpp {
+
+/// This check implements the rule 5.6.1 of the HICPP Standard, which disallows
+/// bitwise operations on signed integer types.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/hicpp-signed-bitwise.html
+class SignedBitwiseCheck : public ClangTidyCheck {
+public:
+ SignedBitwiseCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace hicpp
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_HICPP_SIGNED_BITWISE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
new file mode 100644
index 0000000..ce69c05
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyLLVMModule
+ HeaderGuardCheck.cpp
+ IncludeOrderCheck.cpp
+ LLVMTidyModule.cpp
+ TwineLocalCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyReadabilityModule
+ clangTidyUtils
+ clangTooling
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp
new file mode 100644
index 0000000..c0e449e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp
@@ -0,0 +1,55 @@
+//===--- HeaderGuardCheck.cpp - clang-tidy --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HeaderGuardCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace llvm {
+
+LLVMHeaderGuardCheck::LLVMHeaderGuardCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : HeaderGuardCheck(Name, Context) {}
+
+std::string LLVMHeaderGuardCheck::getHeaderGuard(StringRef Filename,
+ StringRef OldGuard) {
+ std::string Guard = tooling::getAbsolutePath(Filename);
+
+ // Sanitize the path. There are some rules for compatibility with the historic
+ // style in include/llvm and include/clang which we want to preserve.
+
+ // We don't want _INCLUDE_ in our guards.
+ size_t PosInclude = Guard.rfind("include/");
+ if (PosInclude != StringRef::npos)
+ Guard = Guard.substr(PosInclude + std::strlen("include/"));
+
+ // For clang we drop the _TOOLS_.
+ size_t PosToolsClang = Guard.rfind("tools/clang/");
+ if (PosToolsClang != StringRef::npos)
+ Guard = Guard.substr(PosToolsClang + std::strlen("tools/"));
+
+ // The remainder is LLVM_FULL_PATH_TO_HEADER_H
+ size_t PosLLVM = Guard.rfind("llvm/");
+ if (PosLLVM != StringRef::npos)
+ Guard = Guard.substr(PosLLVM);
+
+ std::replace(Guard.begin(), Guard.end(), '/', '_');
+ std::replace(Guard.begin(), Guard.end(), '.', '_');
+ std::replace(Guard.begin(), Guard.end(), '-', '_');
+
+ // The prevalent style in clang is LLVM_CLANG_FOO_BAR_H
+ if (StringRef(Guard).startswith("clang"))
+ Guard = "LLVM_" + Guard;
+
+ return StringRef(Guard).upper();
+}
+
+} // namespace llvm
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.h
new file mode 100644
index 0000000..ca2d7ef
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.h
@@ -0,0 +1,40 @@
+//===--- HeaderGuardCheck.h - clang-tidy ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_HEADER_GUARD_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_HEADER_GUARD_CHECK_H
+
+#include "../utils/HeaderGuard.h"
+
+namespace clang {
+namespace tidy {
+namespace llvm {
+
+/// Finds and fixes header guards that do not adhere to LLVM style.
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/llvm-header-guard.html
+/// The check supports these options:
+/// - `HeaderFileExtensions`: a comma-separated list of filename extensions of
+/// header files (The filename extension should not contain "." prefix).
+/// ",h,hh,hpp,hxx" by default.
+/// For extension-less header files, using an empty string or leaving an
+/// empty string between "," if there are other filename extensions.
+class LLVMHeaderGuardCheck : public utils::HeaderGuardCheck {
+public:
+ LLVMHeaderGuardCheck(StringRef Name, ClangTidyContext *Context);
+
+ bool shouldSuggestEndifComment(StringRef Filename) override { return false; }
+ std::string getHeaderGuard(StringRef Filename, StringRef OldGuard) override;
+};
+
+} // namespace llvm
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_HEADER_GUARD_CHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/IncludeOrderCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/IncludeOrderCheck.cpp
new file mode 100644
index 0000000..f1fdb39
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/IncludeOrderCheck.cpp
@@ -0,0 +1,181 @@
+//===--- IncludeOrderCheck.cpp - clang-tidy -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IncludeOrderCheck.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+
+#include <map>
+
+namespace clang {
+namespace tidy {
+namespace llvm {
+
+namespace {
+class IncludeOrderPPCallbacks : public PPCallbacks {
+public:
+ explicit IncludeOrderPPCallbacks(ClangTidyCheck &Check, SourceManager &SM)
+ : LookForMainModule(true), Check(Check), SM(SM) {}
+
+ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath,
+ const Module *Imported,
+ SrcMgr::CharacteristicKind FileType) override;
+ void EndOfMainFile() override;
+
+private:
+ struct IncludeDirective {
+ SourceLocation Loc; ///< '#' location in the include directive
+ CharSourceRange Range; ///< SourceRange for the file name
+ std::string Filename; ///< Filename as a string
+ bool IsAngled; ///< true if this was an include with angle brackets
+ bool IsMainModule; ///< true if this was the first include in a file
+ };
+
+ typedef std::vector<IncludeDirective> FileIncludes;
+ std::map<clang::FileID, FileIncludes> IncludeDirectives;
+ bool LookForMainModule;
+
+ ClangTidyCheck &Check;
+ SourceManager &SM;
+};
+} // namespace
+
+void IncludeOrderCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+ Compiler.getPreprocessor().addPPCallbacks(
+ ::llvm::make_unique<IncludeOrderPPCallbacks>(
+ *this, Compiler.getSourceManager()));
+}
+
+static int getPriority(StringRef Filename, bool IsAngled, bool IsMainModule) {
+ // We leave the main module header at the top.
+ if (IsMainModule)
+ return 0;
+
+ // LLVM and clang headers are in the penultimate position.
+ if (Filename.startswith("llvm/") || Filename.startswith("llvm-c/") ||
+ Filename.startswith("clang/") || Filename.startswith("clang-c/"))
+ return 2;
+
+ // System headers are sorted to the end.
+ if (IsAngled || Filename.startswith("gtest/"))
+ return 3;
+
+ // Other headers are inserted between the main module header and LLVM headers.
+ return 1;
+}
+
+void IncludeOrderPPCallbacks::InclusionDirective(
+ SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
+ bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath, const Module *Imported,
+ SrcMgr::CharacteristicKind FileType) {
+ // We recognize the first include as a special main module header and want
+ // to leave it in the top position.
+ IncludeDirective ID = {HashLoc, FilenameRange, FileName, IsAngled, false};
+ if (LookForMainModule && !IsAngled) {
+ ID.IsMainModule = true;
+ LookForMainModule = false;
+ }
+
+ // Bucket the include directives by the id of the file they were declared in.
+ IncludeDirectives[SM.getFileID(HashLoc)].push_back(std::move(ID));
+}
+
+void IncludeOrderPPCallbacks::EndOfMainFile() {
+ LookForMainModule = true;
+ if (IncludeDirectives.empty())
+ return;
+
+ // TODO: find duplicated includes.
+
+ // Form blocks of includes. We don't want to sort across blocks. This also
+ // implicitly makes us never reorder over #defines or #if directives.
+ // FIXME: We should be more careful about sorting below comments as we don't
+ // know if the comment refers to the next include or the whole block that
+ // follows.
+ for (auto &Bucket : IncludeDirectives) {
+ auto &FileDirectives = Bucket.second;
+ std::vector<unsigned> Blocks(1, 0);
+ for (unsigned I = 1, E = FileDirectives.size(); I != E; ++I)
+ if (SM.getExpansionLineNumber(FileDirectives[I].Loc) !=
+ SM.getExpansionLineNumber(FileDirectives[I - 1].Loc) + 1)
+ Blocks.push_back(I);
+ Blocks.push_back(FileDirectives.size()); // Sentinel value.
+
+ // Get a vector of indices.
+ std::vector<unsigned> IncludeIndices;
+ for (unsigned I = 0, E = FileDirectives.size(); I != E; ++I)
+ IncludeIndices.push_back(I);
+
+ // Sort the includes. We first sort by priority, then lexicographically.
+ for (unsigned BI = 0, BE = Blocks.size() - 1; BI != BE; ++BI)
+ std::sort(IncludeIndices.begin() + Blocks[BI],
+ IncludeIndices.begin() + Blocks[BI + 1],
+ [&FileDirectives](unsigned LHSI, unsigned RHSI) {
+ IncludeDirective &LHS = FileDirectives[LHSI];
+ IncludeDirective &RHS = FileDirectives[RHSI];
+
+ int PriorityLHS =
+ getPriority(LHS.Filename, LHS.IsAngled, LHS.IsMainModule);
+ int PriorityRHS =
+ getPriority(RHS.Filename, RHS.IsAngled, RHS.IsMainModule);
+
+ return std::tie(PriorityLHS, LHS.Filename) <
+ std::tie(PriorityRHS, RHS.Filename);
+ });
+
+ // Emit a warning for each block and fixits for all changes within that
+ // block.
+ for (unsigned BI = 0, BE = Blocks.size() - 1; BI != BE; ++BI) {
+ // Find the first include that's not in the right position.
+ unsigned I, E;
+ for (I = Blocks[BI], E = Blocks[BI + 1]; I != E; ++I)
+ if (IncludeIndices[I] != I)
+ break;
+
+ if (I == E)
+ continue;
+
+ // Emit a warning.
+ auto D = Check.diag(FileDirectives[I].Loc,
+ "#includes are not sorted properly");
+
+ // Emit fix-its for all following includes in this block.
+ for (; I != E; ++I) {
+ if (IncludeIndices[I] == I)
+ continue;
+ const IncludeDirective &CopyFrom = FileDirectives[IncludeIndices[I]];
+
+ SourceLocation FromLoc = CopyFrom.Range.getBegin();
+ const char *FromData = SM.getCharacterData(FromLoc);
+ unsigned FromLen = std::strcspn(FromData, "\n");
+
+ StringRef FixedName(FromData, FromLen);
+
+ SourceLocation ToLoc = FileDirectives[I].Range.getBegin();
+ const char *ToData = SM.getCharacterData(ToLoc);
+ unsigned ToLen = std::strcspn(ToData, "\n");
+ auto ToRange =
+ CharSourceRange::getCharRange(ToLoc, ToLoc.getLocWithOffset(ToLen));
+
+ D << FixItHint::CreateReplacement(ToRange, FixedName);
+ }
+ }
+ }
+
+ IncludeDirectives.clear();
+}
+
+} // namespace llvm
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/IncludeOrderCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/IncludeOrderCheck.h
new file mode 100644
index 0000000..ad876b9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/IncludeOrderCheck.h
@@ -0,0 +1,33 @@
+//===--- IncludeOrderCheck.h - clang-tidy -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_INCLUDE_ORDER_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_INCLUDE_ORDER_CHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace llvm {
+
+/// Checks the correct order of `#includes`.
+///
+/// See http://llvm.org/docs/CodingStandards.html#include-style
+class IncludeOrderCheck : public ClangTidyCheck {
+public:
+ IncludeOrderCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+};
+
+} // namespace llvm
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_INCLUDE_ORDER_CHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
new file mode 100644
index 0000000..ea46ca9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
@@ -0,0 +1,44 @@
+//===--- LLVMTidyModule.cpp - clang-tidy ----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "../readability/NamespaceCommentCheck.h"
+#include "HeaderGuardCheck.h"
+#include "IncludeOrderCheck.h"
+#include "TwineLocalCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace llvm {
+
+class LLVMModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<LLVMHeaderGuardCheck>("llvm-header-guard");
+ CheckFactories.registerCheck<IncludeOrderCheck>("llvm-include-order");
+ CheckFactories.registerCheck<readability::NamespaceCommentCheck>(
+ "llvm-namespace-comment");
+ CheckFactories.registerCheck<TwineLocalCheck>("llvm-twine-local");
+ }
+};
+
+// Register the LLVMTidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<LLVMModule> X("llvm-module",
+ "Adds LLVM lint checks.");
+
+} // namespace llvm
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the LLVMModule.
+volatile int LLVMModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/TwineLocalCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/TwineLocalCheck.cpp
new file mode 100644
index 0000000..67c85a6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/TwineLocalCheck.cpp
@@ -0,0 +1,66 @@
+//===--- TwineLocalCheck.cpp - clang-tidy ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TwineLocalCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace llvm {
+
+void TwineLocalCheck::registerMatchers(MatchFinder *Finder) {
+ auto TwineType =
+ qualType(hasDeclaration(recordDecl(hasName("::llvm::Twine"))));
+ Finder->addMatcher(varDecl(hasType(TwineType)).bind("variable"), this);
+}
+
+void TwineLocalCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *VD = Result.Nodes.getNodeAs<VarDecl>("variable");
+ auto Diag = diag(VD->getLocation(),
+ "twine variables are prone to use-after-free bugs");
+
+ // If this VarDecl has an initializer try to fix it.
+ if (VD->hasInit()) {
+ // Peel away implicit constructors and casts so we can see the actual type
+ // of the initializer.
+ const Expr *C = VD->getInit()->IgnoreImplicit();
+
+ while (isa<CXXConstructExpr>(C)) {
+ if (cast<CXXConstructExpr>(C)->getNumArgs() == 0)
+ break;
+ C = cast<CXXConstructExpr>(C)->getArg(0)->IgnoreParenImpCasts();
+ }
+
+ SourceRange TypeRange =
+ VD->getTypeSourceInfo()->getTypeLoc().getSourceRange();
+
+ // A real Twine, turn it into a std::string.
+ if (VD->getType()->getCanonicalTypeUnqualified() ==
+ C->getType()->getCanonicalTypeUnqualified()) {
+ SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ VD->getInit()->getLocEnd(), 0, *Result.SourceManager, getLangOpts());
+ Diag << FixItHint::CreateReplacement(TypeRange, "std::string")
+ << FixItHint::CreateInsertion(VD->getInit()->getLocStart(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ").str()");
+ } else {
+ // Just an implicit conversion. Insert the real type.
+ Diag << FixItHint::CreateReplacement(
+ TypeRange,
+ C->getType().getAsString(Result.Context->getPrintingPolicy()));
+ }
+ }
+}
+
+} // namespace llvm
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/TwineLocalCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/TwineLocalCheck.h
new file mode 100644
index 0000000..9f7979b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/llvm/TwineLocalCheck.h
@@ -0,0 +1,33 @@
+//===--- TwineLocalCheck.h - clang-tidy -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_TWINE_LOCAL_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_TWINE_LOCAL_CHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace llvm {
+
+/// Looks for local `Twine` variables which are prone to use after frees and
+/// should be generally avoided.
+class TwineLocalCheck : public ClangTidyCheck {
+public:
+ TwineLocalCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace llvm
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_TWINE_LOCAL_CHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
new file mode 100644
index 0000000..3806398
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
@@ -0,0 +1,27 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyMiscModule
+ MisplacedConstCheck.cpp
+ UnconventionalAssignOperatorCheck.cpp
+ DefinitionsInHeadersCheck.cpp
+ MiscTidyModule.cpp
+ NewDeleteOverloadsCheck.cpp
+ NonCopyableObjects.cpp
+ RedundantExpressionCheck.cpp
+ StaticAssertCheck.cpp
+ ThrowByValueCatchByReferenceCheck.cpp
+ UniqueptrResetReleaseCheck.cpp
+ UnusedAliasDeclsCheck.cpp
+ UnusedParametersCheck.cpp
+ UnusedUsingDeclsCheck.cpp
+
+ LINK_LIBS
+ clangAnalysis
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyUtils
+ clangTooling
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
new file mode 100644
index 0000000..69ef3ef
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
@@ -0,0 +1,158 @@
+//===--- DefinitionsInHeadersCheck.cpp - clang-tidy------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DefinitionsInHeadersCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+namespace {
+
+AST_MATCHER_P(NamedDecl, usesHeaderFileExtension,
+ utils::HeaderFileExtensionsSet, HeaderFileExtensions) {
+ return utils::isExpansionLocInHeaderFile(
+ Node.getLocStart(), Finder->getASTContext().getSourceManager(),
+ HeaderFileExtensions);
+}
+
+} // namespace
+
+DefinitionsInHeadersCheck::DefinitionsInHeadersCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ UseHeaderFileExtension(Options.get("UseHeaderFileExtension", true)),
+ RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
+ "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
+ if (!utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions,
+ HeaderFileExtensions, ',')) {
+ // FIXME: Find a more suitable way to handle invalid configuration
+ // options.
+ llvm::errs() << "Invalid header file extension: "
+ << RawStringHeaderFileExtensions << "\n";
+ }
+}
+
+void DefinitionsInHeadersCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "UseHeaderFileExtension", UseHeaderFileExtension);
+ Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions);
+}
+
+void DefinitionsInHeadersCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+ auto DefinitionMatcher =
+ anyOf(functionDecl(isDefinition(), unless(isDeleted())),
+ varDecl(isDefinition()));
+ if (UseHeaderFileExtension) {
+ Finder->addMatcher(namedDecl(DefinitionMatcher,
+ usesHeaderFileExtension(HeaderFileExtensions))
+ .bind("name-decl"),
+ this);
+ } else {
+ Finder->addMatcher(
+ namedDecl(DefinitionMatcher,
+ anyOf(usesHeaderFileExtension(HeaderFileExtensions),
+ unless(isExpansionInMainFile())))
+ .bind("name-decl"),
+ this);
+ }
+}
+
+void DefinitionsInHeadersCheck::check(const MatchFinder::MatchResult &Result) {
+ // Don't run the check in failing TUs.
+ if (Result.Context->getDiagnostics().hasUncompilableErrorOccurred())
+ return;
+
+ // C++ [basic.def.odr] p6:
+ // There can be more than one definition of a class type, enumeration type,
+ // inline function with external linkage, class template, non-static function
+ // template, static data member of a class template, member function of a
+ // class template, or template specialization for which some template
+ // parameters are not specifiedin a program provided that each definition
+ // appears in a different translation unit, and provided the definitions
+ // satisfy the following requirements.
+ const auto *ND = Result.Nodes.getNodeAs<NamedDecl>("name-decl");
+ assert(ND);
+ if (ND->isInvalidDecl())
+ return;
+
+ // Internal linkage variable definitions are ignored for now:
+ // const int a = 1;
+ // static int b = 1;
+ //
+ // Although these might also cause ODR violations, we can be less certain and
+ // should try to keep the false-positive rate down.
+ //
+ // FIXME: Should declarations in anonymous namespaces get the same treatment
+ // as static / const declarations?
+ if (!ND->hasExternalFormalLinkage() && !ND->isInAnonymousNamespace())
+ return;
+
+ if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
+ // Inline functions are allowed.
+ if (FD->isInlined())
+ return;
+ // Function templates are allowed.
+ if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
+ return;
+ // Ignore instantiated functions.
+ if (FD->isTemplateInstantiation())
+ return;
+ // Member function of a class template and member function of a nested class
+ // in a class template are allowed.
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ const auto *DC = MD->getDeclContext();
+ while (DC->isRecord()) {
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(DC)) {
+ if (isa<ClassTemplatePartialSpecializationDecl>(RD))
+ return;
+ if (RD->getDescribedClassTemplate())
+ return;
+ }
+ DC = DC->getParent();
+ }
+ }
+
+ bool is_full_spec = FD->getTemplateSpecializationKind() != TSK_Undeclared;
+ diag(FD->getLocation(),
+ "%select{function|full function template specialization}0 %1 defined "
+ "in a header file; function definitions in header files can lead to "
+ "ODR violations")
+ << is_full_spec << FD << FixItHint::CreateInsertion(
+ FD->getReturnTypeSourceRange().getBegin(), "inline ");
+ } else if (const auto *VD = dyn_cast<VarDecl>(ND)) {
+ // Static data members of a class template are allowed.
+ if (VD->getDeclContext()->isDependentContext() && VD->isStaticDataMember())
+ return;
+ // Ignore instantiated static data members of classes.
+ if (isTemplateInstantiation(VD->getTemplateSpecializationKind()))
+ return;
+ // Ignore variable definition within function scope.
+ if (VD->hasLocalStorage() || VD->isStaticLocal())
+ return;
+ // Ignore inline variables.
+ if (VD->isInline())
+ return;
+
+ diag(VD->getLocation(),
+ "variable %0 defined in a header file; "
+ "variable definitions in header files can lead to ODR violations")
+ << VD;
+ }
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.h
new file mode 100644
index 0000000..428b05c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.h
@@ -0,0 +1,51 @@
+//===--- DefinitionsInHeadersCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_DEFINITIONS_IN_HEADERS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_DEFINITIONS_IN_HEADERS_H
+
+#include "../ClangTidy.h"
+#include "../utils/HeaderFileExtensionsUtils.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Finds non-extern non-inline function and variable definitions in header
+/// files, which can lead to potential ODR violations.
+///
+/// The check supports these options:
+/// - `UseHeaderFileExtension`: Whether to use file extension to distinguish
+/// header files. True by default.
+/// - `HeaderFileExtensions`: a comma-separated list of filename extensions of
+/// header files (The filename extension should not contain "." prefix).
+/// ",h,hh,hpp,hxx" by default.
+/// For extension-less header files, using an empty string or leaving an
+/// empty string between "," if there are other filename extensions.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-definitions-in-headers.html
+class DefinitionsInHeadersCheck : public ClangTidyCheck {
+public:
+ DefinitionsInHeadersCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const bool UseHeaderFileExtension;
+ const std::string RawStringHeaderFileExtensions;
+ utils::HeaderFileExtensionsSet HeaderFileExtensions;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_DEFINITIONS_IN_HEADERS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
new file mode 100644
index 0000000..241689a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
@@ -0,0 +1,69 @@
+//===--- MiscTidyModule.cpp - clang-tidy ----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "DefinitionsInHeadersCheck.h"
+#include "MisplacedConstCheck.h"
+#include "NewDeleteOverloadsCheck.h"
+#include "NonCopyableObjects.h"
+#include "RedundantExpressionCheck.h"
+#include "StaticAssertCheck.h"
+#include "ThrowByValueCatchByReferenceCheck.h"
+#include "UnconventionalAssignOperatorCheck.h"
+#include "UniqueptrResetReleaseCheck.h"
+#include "UnusedAliasDeclsCheck.h"
+#include "UnusedParametersCheck.h"
+#include "UnusedUsingDeclsCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+class MiscModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<MisplacedConstCheck>("misc-misplaced-const");
+ CheckFactories.registerCheck<UnconventionalAssignOperatorCheck>(
+ "misc-unconventional-assign-operator");
+ CheckFactories.registerCheck<DefinitionsInHeadersCheck>(
+ "misc-definitions-in-headers");
+ CheckFactories.registerCheck<NewDeleteOverloadsCheck>(
+ "misc-new-delete-overloads");
+ CheckFactories.registerCheck<NonCopyableObjectsCheck>(
+ "misc-non-copyable-objects");
+ CheckFactories.registerCheck<RedundantExpressionCheck>(
+ "misc-redundant-expression");
+ CheckFactories.registerCheck<StaticAssertCheck>("misc-static-assert");
+ CheckFactories.registerCheck<ThrowByValueCatchByReferenceCheck>(
+ "misc-throw-by-value-catch-by-reference");
+ CheckFactories.registerCheck<UniqueptrResetReleaseCheck>(
+ "misc-uniqueptr-reset-release");
+ CheckFactories.registerCheck<UnusedAliasDeclsCheck>(
+ "misc-unused-alias-decls");
+ CheckFactories.registerCheck<UnusedParametersCheck>(
+ "misc-unused-parameters");
+ CheckFactories.registerCheck<UnusedUsingDeclsCheck>(
+ "misc-unused-using-decls");
+ }
+};
+
+} // namespace misc
+
+// Register the MiscTidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<misc::MiscModule>
+ X("misc-module", "Adds miscellaneous lint checks.");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the MiscModule.
+volatile int MiscModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.cpp
new file mode 100644
index 0000000..515b22c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.cpp
@@ -0,0 +1,63 @@
+//===--- MisplacedConstCheck.cpp - clang-tidy------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MisplacedConstCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void MisplacedConstCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ valueDecl(hasType(isConstQualified()),
+ hasType(typedefType(hasDeclaration(
+ typedefDecl(hasType(pointerType(unless(pointee(
+ anyOf(isConstQualified(),
+ ignoringParens(functionType())))))))
+ .bind("typedef")))))
+ .bind("decl"),
+ this);
+}
+
+static QualType guessAlternateQualification(ASTContext &Context, QualType QT) {
+ // We're given a QualType from a typedef where the qualifiers apply to the
+ // pointer instead of the pointee. Strip the const qualifier from the pointer
+ // type and add it to the pointee instead.
+ if (!QT->isPointerType())
+ return QT;
+
+ Qualifiers Quals = QT.getLocalQualifiers();
+ Quals.removeConst();
+
+ QualType NewQT = Context.getPointerType(
+ QualType(QT->getPointeeType().getTypePtr(), Qualifiers::Const));
+ return NewQT.withCVRQualifiers(Quals.getCVRQualifiers());
+}
+
+void MisplacedConstCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Var = Result.Nodes.getNodeAs<ValueDecl>("decl");
+ const auto *Typedef = Result.Nodes.getNodeAs<TypedefDecl>("typedef");
+ ASTContext &Ctx = *Result.Context;
+ QualType CanQT = Var->getType().getCanonicalType();
+
+ diag(Var->getLocation(), "%0 declared with a const-qualified typedef type; "
+ "results in the type being '%1' instead of '%2'")
+ << Var << CanQT.getAsString(Ctx.getPrintingPolicy())
+ << guessAlternateQualification(Ctx, CanQT)
+ .getAsString(Ctx.getPrintingPolicy());
+ diag(Typedef->getLocation(), "typedef declared here", DiagnosticIDs::Note);
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.h
new file mode 100644
index 0000000..410edf7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/MisplacedConstCheck.h
@@ -0,0 +1,36 @@
+//===--- MisplacedConstCheck.h - clang-tidy----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MISPLACED_CONST_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MISPLACED_CONST_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// This check diagnoses when a const qualifier is applied to a typedef to a
+/// pointer type rather than to the pointee.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-misplaced-const.html
+class MisplacedConstCheck : public ClangTidyCheck {
+public:
+ MisplacedConstCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MISPLACED_CONST_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp
new file mode 100644
index 0000000..5e29119
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.cpp
@@ -0,0 +1,213 @@
+//===--- NewDeleteOverloadsCheck.cpp - clang-tidy--------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NewDeleteOverloadsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+namespace {
+
+AST_MATCHER(FunctionDecl, isPlacementOverload) {
+ bool New;
+ switch (Node.getOverloadedOperator()) {
+ default:
+ return false;
+ case OO_New:
+ case OO_Array_New:
+ New = true;
+ break;
+ case OO_Delete:
+ case OO_Array_Delete:
+ New = false;
+ break;
+ }
+
+ // Variadic functions are always placement functions.
+ if (Node.isVariadic())
+ return true;
+
+ // Placement new is easy: it always has more than one parameter (the first
+ // parameter is always the size). If it's an overload of delete or delete[]
+ // that has only one parameter, it's never a placement delete.
+ if (New)
+ return Node.getNumParams() > 1;
+ if (Node.getNumParams() == 1)
+ return false;
+
+ // Placement delete is a little more challenging. They always have more than
+ // one parameter with the first parameter being a pointer. However, the
+ // second parameter can be a size_t for sized deallocation, and that is never
+ // a placement delete operator.
+ if (Node.getNumParams() <= 1 || Node.getNumParams() > 2)
+ return true;
+
+ const auto *FPT = Node.getType()->castAs<FunctionProtoType>();
+ ASTContext &Ctx = Node.getASTContext();
+ if (Ctx.getLangOpts().SizedDeallocation &&
+ Ctx.hasSameType(FPT->getParamType(1), Ctx.getSizeType()))
+ return false;
+
+ return true;
+}
+
+OverloadedOperatorKind getCorrespondingOverload(const FunctionDecl *FD) {
+ switch (FD->getOverloadedOperator()) {
+ default:
+ break;
+ case OO_New:
+ return OO_Delete;
+ case OO_Delete:
+ return OO_New;
+ case OO_Array_New:
+ return OO_Array_Delete;
+ case OO_Array_Delete:
+ return OO_Array_New;
+ }
+ llvm_unreachable("Not an overloaded allocation operator");
+}
+
+const char *getOperatorName(OverloadedOperatorKind K) {
+ switch (K) {
+ default:
+ break;
+ case OO_New:
+ return "operator new";
+ case OO_Delete:
+ return "operator delete";
+ case OO_Array_New:
+ return "operator new[]";
+ case OO_Array_Delete:
+ return "operator delete[]";
+ }
+ llvm_unreachable("Not an overloaded allocation operator");
+}
+
+bool areCorrespondingOverloads(const FunctionDecl *LHS,
+ const FunctionDecl *RHS) {
+ return RHS->getOverloadedOperator() == getCorrespondingOverload(LHS);
+}
+
+bool hasCorrespondingOverloadInBaseClass(const CXXMethodDecl *MD,
+ const CXXRecordDecl *RD = nullptr) {
+ if (RD) {
+ // Check the methods in the given class and accessible to derived classes.
+ for (const auto *BMD : RD->methods())
+ if (BMD->isOverloadedOperator() && BMD->getAccess() != AS_private &&
+ areCorrespondingOverloads(MD, BMD))
+ return true;
+ } else {
+ // Get the parent class of the method; we do not need to care about checking
+ // the methods in this class as the caller has already done that by looking
+ // at the declaration contexts.
+ RD = MD->getParent();
+ }
+
+ for (const auto &BS : RD->bases()) {
+ // We can't say much about a dependent base class, but to avoid false
+ // positives assume it can have a corresponding overload.
+ if (BS.getType()->isDependentType())
+ return true;
+ if (const auto *BaseRD = BS.getType()->getAsCXXRecordDecl())
+ if (hasCorrespondingOverloadInBaseClass(MD, BaseRD))
+ return true;
+ }
+
+ return false;
+}
+
+} // anonymous namespace
+
+void NewDeleteOverloadsCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // Match all operator new and operator delete overloads (including the array
+ // forms). Do not match implicit operators, placement operators, or
+ // deleted/private operators.
+ //
+ // Technically, trivially-defined operator delete seems like a reasonable
+ // thing to also skip. e.g., void operator delete(void *) {}
+ // However, I think it's more reasonable to warn in this case as the user
+ // should really be writing that as a deleted function.
+ Finder->addMatcher(
+ functionDecl(unless(anyOf(isImplicit(), isPlacementOverload(),
+ isDeleted(), cxxMethodDecl(isPrivate()))),
+ anyOf(hasOverloadedOperatorName("new"),
+ hasOverloadedOperatorName("new[]"),
+ hasOverloadedOperatorName("delete"),
+ hasOverloadedOperatorName("delete[]")))
+ .bind("func"),
+ this);
+}
+
+void NewDeleteOverloadsCheck::check(const MatchFinder::MatchResult &Result) {
+ // Add any matches we locate to the list of things to be checked at the
+ // end of the translation unit.
+ const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("func");
+ const CXXRecordDecl *RD = nullptr;
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
+ RD = MD->getParent();
+ Overloads[RD].push_back(FD);
+}
+
+void NewDeleteOverloadsCheck::onEndOfTranslationUnit() {
+ // Walk over the list of declarations we've found to see if there is a
+ // corresponding overload at the same declaration context or within a base
+ // class. If there is not, add the element to the list of declarations to
+ // diagnose.
+ SmallVector<const FunctionDecl *, 4> Diagnose;
+ for (const auto &RP : Overloads) {
+ // We don't care about the CXXRecordDecl key in the map; we use it as a way
+ // to shard the overloads by declaration context to reduce the algorithmic
+ // complexity when searching for corresponding free store functions.
+ for (const auto *Overload : RP.second) {
+ const auto *Match =
+ std::find_if(RP.second.begin(), RP.second.end(),
+ [&Overload](const FunctionDecl *FD) {
+ if (FD == Overload)
+ return false;
+ // If the declaration contexts don't match, we don't
+ // need to check any further.
+ if (FD->getDeclContext() != Overload->getDeclContext())
+ return false;
+
+ // Since the declaration contexts match, see whether
+ // the current element is the corresponding operator.
+ if (!areCorrespondingOverloads(Overload, FD))
+ return false;
+
+ return true;
+ });
+
+ if (Match == RP.second.end()) {
+ // Check to see if there is a corresponding overload in a base class
+ // context. If there isn't, or if the overload is not a class member
+ // function, then we should diagnose.
+ const auto *MD = dyn_cast<CXXMethodDecl>(Overload);
+ if (!MD || !hasCorrespondingOverloadInBaseClass(MD))
+ Diagnose.push_back(Overload);
+ }
+ }
+ }
+
+ for (const auto *FD : Diagnose)
+ diag(FD->getLocation(), "declaration of %0 has no matching declaration "
+ "of '%1' at the same scope")
+ << FD << getOperatorName(getCorrespondingOverload(FD));
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.h
new file mode 100644
index 0000000..3e99892
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/NewDeleteOverloadsCheck.h
@@ -0,0 +1,38 @@
+//===--- NewDeleteOverloadsCheck.h - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_NEWDELETEOVERLOADS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_NEWDELETEOVERLOADS_H
+
+#include "../ClangTidy.h"
+#include "llvm/ADT/SmallVector.h"
+#include <map>
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+class NewDeleteOverloadsCheck : public ClangTidyCheck {
+ std::map<const clang::CXXRecordDecl *,
+ llvm::SmallVector<const clang::FunctionDecl *, 4>>
+ Overloads;
+
+public:
+ NewDeleteOverloadsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void onEndOfTranslationUnit() override;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_NEWDELETEOVERLOADS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/NonCopyableObjects.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/NonCopyableObjects.cpp
new file mode 100644
index 0000000..de15275
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/NonCopyableObjects.cpp
@@ -0,0 +1,74 @@
+//===--- NonCopyableObjects.cpp - clang-tidy-------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NonCopyableObjects.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <algorithm>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void NonCopyableObjectsCheck::registerMatchers(MatchFinder *Finder) {
+ // There are two ways to get into trouble with objects like FILE *:
+ // dereferencing the pointer type to be a non-pointer type, and declaring
+ // the type as a non-pointer type in the first place. While the declaration
+ // itself could technically be well-formed in the case where the type is not
+ // an opaque type, it's highly suspicious behavior.
+ //
+ // POSIX types are a bit different in that it's reasonable to declare a
+ // non-pointer variable or data member of the type, but it is not reasonable
+ // to dereference a pointer to the type, or declare a parameter of non-pointer
+ // type.
+ // FIXME: it would be good to make a list that is also user-configurable so
+ // that users can add their own elements to the list. However, it may require
+ // some extra thought since POSIX types and FILE types are usable in different
+ // ways.
+
+ auto BadFILEType = hasType(
+ namedDecl(hasAnyName("::FILE", "FILE", "std::FILE")).bind("type_decl"));
+ auto BadPOSIXType =
+ hasType(namedDecl(hasAnyName("::pthread_cond_t", "::pthread_mutex_t",
+ "pthread_cond_t", "pthread_mutex_t"))
+ .bind("type_decl"));
+ auto BadEitherType = anyOf(BadFILEType, BadPOSIXType);
+
+ Finder->addMatcher(
+ namedDecl(anyOf(varDecl(BadFILEType), fieldDecl(BadFILEType)))
+ .bind("decl"),
+ this);
+ Finder->addMatcher(parmVarDecl(BadPOSIXType).bind("decl"), this);
+ Finder->addMatcher(
+ expr(unaryOperator(hasOperatorName("*"), BadEitherType)).bind("expr"),
+ this);
+}
+
+void NonCopyableObjectsCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *D = Result.Nodes.getNodeAs<NamedDecl>("decl");
+ const auto *BD = Result.Nodes.getNodeAs<NamedDecl>("type_decl");
+ const auto *E = Result.Nodes.getNodeAs<Expr>("expr");
+
+ if (D && BD)
+ diag(D->getLocation(), "%0 declared as type '%1', which is unsafe to copy"
+ "; did you mean '%1 *'?")
+ << D << BD->getName();
+ else if (E)
+ diag(E->getExprLoc(),
+ "expression has opaque data structure type %0; type should only be "
+ "used as a pointer and not dereferenced")
+ << BD;
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/NonCopyableObjects.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/NonCopyableObjects.h
new file mode 100644
index 0000000..38a45fd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/NonCopyableObjects.h
@@ -0,0 +1,33 @@
+//===--- NonCopyableObjects.h - clang-tidy-----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_NONCOPYABLEOBJECTS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_NONCOPYABLEOBJECTS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// The check flags dereferences and non-pointer declarations of objects that
+/// are not meant to be passed by value, such as C FILE objects.
+class NonCopyableObjectsCheck : public ClangTidyCheck {
+public:
+ NonCopyableObjectsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_NONCOPYABLEOBJECTS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
new file mode 100644
index 0000000..e259b6b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -0,0 +1,1081 @@
+//===--- RedundantExpressionCheck.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RedundantExpressionCheck.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/Casting.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+using namespace clang::ast_matchers;
+using namespace clang::tidy::matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+namespace {
+using llvm::APSInt;
+
+static constexpr llvm::StringLiteral KnownBannedMacroNames[] = {
+ "EAGAIN",
+ "EWOULDBLOCK",
+ "SIGCLD",
+ "SIGCHLD",
+};
+
+static bool incrementWithoutOverflow(const APSInt &Value, APSInt &Result) {
+ Result = Value;
+ ++Result;
+ return Value < Result;
+}
+
+static bool areEquivalentNameSpecifier(const NestedNameSpecifier *Left,
+ const NestedNameSpecifier *Right) {
+ llvm::FoldingSetNodeID LeftID, RightID;
+ Left->Profile(LeftID);
+ Right->Profile(RightID);
+ return LeftID == RightID;
+}
+
+static bool areEquivalentExpr(const Expr *Left, const Expr *Right) {
+ if (!Left || !Right)
+ return !Left && !Right;
+
+ Left = Left->IgnoreParens();
+ Right = Right->IgnoreParens();
+
+ // Compare classes.
+ if (Left->getStmtClass() != Right->getStmtClass())
+ return false;
+
+ // Compare children.
+ Expr::const_child_iterator LeftIter = Left->child_begin();
+ Expr::const_child_iterator RightIter = Right->child_begin();
+ while (LeftIter != Left->child_end() && RightIter != Right->child_end()) {
+ if (!areEquivalentExpr(dyn_cast<Expr>(*LeftIter),
+ dyn_cast<Expr>(*RightIter)))
+ return false;
+ ++LeftIter;
+ ++RightIter;
+ }
+ if (LeftIter != Left->child_end() || RightIter != Right->child_end())
+ return false;
+
+ // Perform extra checks.
+ switch (Left->getStmtClass()) {
+ default:
+ return false;
+
+ case Stmt::CharacterLiteralClass:
+ return cast<CharacterLiteral>(Left)->getValue() ==
+ cast<CharacterLiteral>(Right)->getValue();
+ case Stmt::IntegerLiteralClass: {
+ llvm::APInt LeftLit = cast<IntegerLiteral>(Left)->getValue();
+ llvm::APInt RightLit = cast<IntegerLiteral>(Right)->getValue();
+ return LeftLit.getBitWidth() == RightLit.getBitWidth() &&
+ LeftLit == RightLit;
+ }
+ case Stmt::FloatingLiteralClass:
+ return cast<FloatingLiteral>(Left)->getValue().bitwiseIsEqual(
+ cast<FloatingLiteral>(Right)->getValue());
+ case Stmt::StringLiteralClass:
+ return cast<StringLiteral>(Left)->getBytes() ==
+ cast<StringLiteral>(Right)->getBytes();
+ case Stmt::CXXOperatorCallExprClass:
+ return cast<CXXOperatorCallExpr>(Left)->getOperator() ==
+ cast<CXXOperatorCallExpr>(Right)->getOperator();
+ case Stmt::DependentScopeDeclRefExprClass:
+ if (cast<DependentScopeDeclRefExpr>(Left)->getDeclName() !=
+ cast<DependentScopeDeclRefExpr>(Right)->getDeclName())
+ return false;
+ return areEquivalentNameSpecifier(
+ cast<DependentScopeDeclRefExpr>(Left)->getQualifier(),
+ cast<DependentScopeDeclRefExpr>(Right)->getQualifier());
+ case Stmt::DeclRefExprClass:
+ return cast<DeclRefExpr>(Left)->getDecl() ==
+ cast<DeclRefExpr>(Right)->getDecl();
+ case Stmt::MemberExprClass:
+ return cast<MemberExpr>(Left)->getMemberDecl() ==
+ cast<MemberExpr>(Right)->getMemberDecl();
+ case Stmt::CXXFunctionalCastExprClass:
+ case Stmt::CStyleCastExprClass:
+ return cast<ExplicitCastExpr>(Left)->getTypeAsWritten() ==
+ cast<ExplicitCastExpr>(Right)->getTypeAsWritten();
+ case Stmt::CallExprClass:
+ case Stmt::ImplicitCastExprClass:
+ case Stmt::ArraySubscriptExprClass:
+ return true;
+ case Stmt::UnaryOperatorClass:
+ if (cast<UnaryOperator>(Left)->isIncrementDecrementOp())
+ return false;
+ return cast<UnaryOperator>(Left)->getOpcode() ==
+ cast<UnaryOperator>(Right)->getOpcode();
+ case Stmt::BinaryOperatorClass:
+ return cast<BinaryOperator>(Left)->getOpcode() ==
+ cast<BinaryOperator>(Right)->getOpcode();
+ }
+}
+
+// For a given expression 'x', returns whether the ranges covered by the
+// relational operators are equivalent (i.e. x <= 4 is equivalent to x < 5).
+static bool areEquivalentRanges(BinaryOperatorKind OpcodeLHS,
+ const APSInt &ValueLHS,
+ BinaryOperatorKind OpcodeRHS,
+ const APSInt &ValueRHS) {
+ assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
+ "Values must be ordered");
+ // Handle the case where constants are the same: x <= 4 <==> x <= 4.
+ if (APSInt::compareValues(ValueLHS, ValueRHS) == 0)
+ return OpcodeLHS == OpcodeRHS;
+
+ // Handle the case where constants are off by one: x <= 4 <==> x < 5.
+ APSInt ValueLHS_plus1;
+ return ((OpcodeLHS == BO_LE && OpcodeRHS == BO_LT) ||
+ (OpcodeLHS == BO_GT && OpcodeRHS == BO_GE)) &&
+ incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
+ APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0;
+}
+
+// For a given expression 'x', returns whether the ranges covered by the
+// relational operators are fully disjoint (i.e. x < 4 and x > 7).
+static bool areExclusiveRanges(BinaryOperatorKind OpcodeLHS,
+ const APSInt &ValueLHS,
+ BinaryOperatorKind OpcodeRHS,
+ const APSInt &ValueRHS) {
+ assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
+ "Values must be ordered");
+
+ // Handle cases where the constants are the same.
+ if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
+ switch (OpcodeLHS) {
+ case BO_EQ:
+ return OpcodeRHS == BO_NE || OpcodeRHS == BO_GT || OpcodeRHS == BO_LT;
+ case BO_NE:
+ return OpcodeRHS == BO_EQ;
+ case BO_LE:
+ return OpcodeRHS == BO_GT;
+ case BO_GE:
+ return OpcodeRHS == BO_LT;
+ case BO_LT:
+ return OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
+ case BO_GT:
+ return OpcodeRHS == BO_EQ || OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
+ default:
+ return false;
+ }
+ }
+
+ // Handle cases where the constants are different.
+ if ((OpcodeLHS == BO_EQ || OpcodeLHS == BO_LT || OpcodeLHS == BO_LE) &&
+ (OpcodeRHS == BO_EQ || OpcodeRHS == BO_GT || OpcodeRHS == BO_GE))
+ return true;
+
+ // Handle the case where constants are off by one: x > 5 && x < 6.
+ APSInt ValueLHS_plus1;
+ if (OpcodeLHS == BO_GT && OpcodeRHS == BO_LT &&
+ incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
+ APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
+ return true;
+
+ return false;
+}
+
+// Returns whether the ranges covered by the union of both relational
+// expressions cover the whole domain (i.e. x < 10 and x > 0).
+static bool rangesFullyCoverDomain(BinaryOperatorKind OpcodeLHS,
+ const APSInt &ValueLHS,
+ BinaryOperatorKind OpcodeRHS,
+ const APSInt &ValueRHS) {
+ assert(APSInt::compareValues(ValueLHS, ValueRHS) <= 0 &&
+ "Values must be ordered");
+
+ // Handle cases where the constants are the same: x < 5 || x >= 5.
+ if (APSInt::compareValues(ValueLHS, ValueRHS) == 0) {
+ switch (OpcodeLHS) {
+ case BO_EQ:
+ return OpcodeRHS == BO_NE;
+ case BO_NE:
+ return OpcodeRHS == BO_EQ;
+ case BO_LE:
+ return OpcodeRHS == BO_GT || OpcodeRHS == BO_GE;
+ case BO_LT:
+ return OpcodeRHS == BO_GE;
+ case BO_GE:
+ return OpcodeRHS == BO_LT || OpcodeRHS == BO_LE;
+ case BO_GT:
+ return OpcodeRHS == BO_LE;
+ default:
+ return false;
+ }
+ }
+
+ // Handle the case where constants are off by one: x <= 4 || x >= 5.
+ APSInt ValueLHS_plus1;
+ if (OpcodeLHS == BO_LE && OpcodeRHS == BO_GE &&
+ incrementWithoutOverflow(ValueLHS, ValueLHS_plus1) &&
+ APSInt::compareValues(ValueLHS_plus1, ValueRHS) == 0)
+ return true;
+
+ // Handle cases where the constants are different: x > 4 || x <= 7.
+ if ((OpcodeLHS == BO_GT || OpcodeLHS == BO_GE) &&
+ (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE))
+ return true;
+
+ // Handle cases where constants are different but both ops are !=, like:
+ // x != 5 || x != 10
+ if (OpcodeLHS == BO_NE && OpcodeRHS == BO_NE)
+ return true;
+
+ return false;
+}
+
+static bool rangeSubsumesRange(BinaryOperatorKind OpcodeLHS,
+ const APSInt &ValueLHS,
+ BinaryOperatorKind OpcodeRHS,
+ const APSInt &ValueRHS) {
+ int Comparison = APSInt::compareValues(ValueLHS, ValueRHS);
+ switch (OpcodeLHS) {
+ case BO_EQ:
+ return OpcodeRHS == BO_EQ && Comparison == 0;
+ case BO_NE:
+ return (OpcodeRHS == BO_NE && Comparison == 0) ||
+ (OpcodeRHS == BO_EQ && Comparison != 0) ||
+ (OpcodeRHS == BO_LT && Comparison >= 0) ||
+ (OpcodeRHS == BO_LE && Comparison > 0) ||
+ (OpcodeRHS == BO_GT && Comparison <= 0) ||
+ (OpcodeRHS == BO_GE && Comparison < 0);
+
+ case BO_LT:
+ return ((OpcodeRHS == BO_LT && Comparison >= 0) ||
+ (OpcodeRHS == BO_LE && Comparison > 0) ||
+ (OpcodeRHS == BO_EQ && Comparison > 0));
+ case BO_GT:
+ return ((OpcodeRHS == BO_GT && Comparison <= 0) ||
+ (OpcodeRHS == BO_GE && Comparison < 0) ||
+ (OpcodeRHS == BO_EQ && Comparison < 0));
+ case BO_LE:
+ return (OpcodeRHS == BO_LT || OpcodeRHS == BO_LE || OpcodeRHS == BO_EQ) &&
+ Comparison >= 0;
+ case BO_GE:
+ return (OpcodeRHS == BO_GT || OpcodeRHS == BO_GE || OpcodeRHS == BO_EQ) &&
+ Comparison <= 0;
+ default:
+ return false;
+ }
+}
+
+static void transformSubToCanonicalAddExpr(BinaryOperatorKind &Opcode,
+ APSInt &Value) {
+ if (Opcode == BO_Sub) {
+ Opcode = BO_Add;
+ Value = -Value;
+ }
+}
+
+AST_MATCHER(Expr, isIntegerConstantExpr) {
+ if (Node.isInstantiationDependent())
+ return false;
+ return Node.isIntegerConstantExpr(Finder->getASTContext());
+}
+
+AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
+ return areEquivalentExpr(Node.getLHS(), Node.getRHS());
+}
+
+AST_MATCHER(ConditionalOperator, expressionsAreEquivalent) {
+ return areEquivalentExpr(Node.getTrueExpr(), Node.getFalseExpr());
+}
+
+AST_MATCHER(CallExpr, parametersAreEquivalent) {
+ return Node.getNumArgs() == 2 &&
+ areEquivalentExpr(Node.getArg(0), Node.getArg(1));
+}
+
+AST_MATCHER(BinaryOperator, binaryOperatorIsInMacro) {
+ return Node.getOperatorLoc().isMacroID();
+}
+
+AST_MATCHER(ConditionalOperator, conditionalOperatorIsInMacro) {
+ return Node.getQuestionLoc().isMacroID() || Node.getColonLoc().isMacroID();
+}
+
+AST_MATCHER(Expr, isMacro) { return Node.getExprLoc().isMacroID(); }
+
+AST_MATCHER_P(Expr, expandedByMacro, ArrayRef<llvm::StringLiteral>, Names) {
+ const SourceManager &SM = Finder->getASTContext().getSourceManager();
+ const LangOptions &LO = Finder->getASTContext().getLangOpts();
+ SourceLocation Loc = Node.getExprLoc();
+ while (Loc.isMacroID()) {
+ StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM, LO);
+ if (llvm::is_contained(Names, MacroName))
+ return true;
+ Loc = SM.getImmediateMacroCallerLoc(Loc);
+ }
+ return false;
+}
+
+// Returns a matcher for integer constant expressions.
+static ast_matchers::internal::Matcher<Expr>
+matchIntegerConstantExpr(StringRef Id) {
+ std::string CstId = (Id + "-const").str();
+ return expr(isIntegerConstantExpr()).bind(CstId);
+}
+
+// Retrieves the integer expression matched by 'matchIntegerConstantExpr' with
+// name 'Id' and stores it into 'ConstExpr', the value of the expression is
+// stored into `Value`.
+static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result,
+ StringRef Id, APSInt &Value,
+ const Expr *&ConstExpr) {
+ std::string CstId = (Id + "-const").str();
+ ConstExpr = Result.Nodes.getNodeAs<Expr>(CstId);
+ return ConstExpr && ConstExpr->isIntegerConstantExpr(Value, *Result.Context);
+}
+
+// Overloaded `retrieveIntegerConstantExpr` for compatibility.
+static bool retrieveIntegerConstantExpr(const MatchFinder::MatchResult &Result,
+ StringRef Id, APSInt &Value) {
+ const Expr *ConstExpr = nullptr;
+ return retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr);
+}
+
+// Returns a matcher for symbolic expressions (matches every expression except
+// ingeter constant expressions).
+static ast_matchers::internal::Matcher<Expr> matchSymbolicExpr(StringRef Id) {
+ std::string SymId = (Id + "-sym").str();
+ return ignoringParenImpCasts(
+ expr(unless(isIntegerConstantExpr())).bind(SymId));
+}
+
+// Retrieves the expression matched by 'matchSymbolicExpr' with name 'Id' and
+// stores it into 'SymExpr'.
+static bool retrieveSymbolicExpr(const MatchFinder::MatchResult &Result,
+ StringRef Id, const Expr *&SymExpr) {
+ std::string SymId = (Id + "-sym").str();
+ if (const auto *Node = Result.Nodes.getNodeAs<Expr>(SymId)) {
+ SymExpr = Node;
+ return true;
+ }
+ return false;
+}
+
+// Match a binary operator between a symbolic expression and an integer constant
+// expression.
+static ast_matchers::internal::Matcher<Expr>
+matchBinOpIntegerConstantExpr(StringRef Id) {
+ const auto BinOpCstExpr =
+ expr(
+ anyOf(binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("|"),
+ hasOperatorName("&")),
+ hasEitherOperand(matchSymbolicExpr(Id)),
+ hasEitherOperand(matchIntegerConstantExpr(Id))),
+ binaryOperator(hasOperatorName("-"),
+ hasLHS(matchSymbolicExpr(Id)),
+ hasRHS(matchIntegerConstantExpr(Id)))))
+ .bind(Id);
+ return ignoringParenImpCasts(BinOpCstExpr);
+}
+
+// Retrieves sub-expressions matched by 'matchBinOpIntegerConstantExpr' with
+// name 'Id'.
+static bool
+retrieveBinOpIntegerConstantExpr(const MatchFinder::MatchResult &Result,
+ StringRef Id, BinaryOperatorKind &Opcode,
+ const Expr *&Symbol, APSInt &Value) {
+ if (const auto *BinExpr = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
+ Opcode = BinExpr->getOpcode();
+ return retrieveSymbolicExpr(Result, Id, Symbol) &&
+ retrieveIntegerConstantExpr(Result, Id, Value);
+ }
+ return false;
+}
+
+// Matches relational expressions: 'Expr <op> k' (i.e. x < 2, x != 3, 12 <= x).
+static ast_matchers::internal::Matcher<Expr>
+matchRelationalIntegerConstantExpr(StringRef Id) {
+ std::string CastId = (Id + "-cast").str();
+ std::string SwapId = (Id + "-swap").str();
+ std::string NegateId = (Id + "-negate").str();
+ std::string OverloadId = (Id + "-overload").str();
+
+ const auto RelationalExpr = ignoringParenImpCasts(binaryOperator(
+ isComparisonOperator(), expr().bind(Id),
+ anyOf(allOf(hasLHS(matchSymbolicExpr(Id)),
+ hasRHS(matchIntegerConstantExpr(Id))),
+ allOf(hasLHS(matchIntegerConstantExpr(Id)),
+ hasRHS(matchSymbolicExpr(Id)), expr().bind(SwapId)))));
+
+ // A cast can be matched as a comparator to zero. (i.e. if (x) is equivalent
+ // to if (x != 0)).
+ const auto CastExpr =
+ implicitCastExpr(hasCastKind(CK_IntegralToBoolean),
+ hasSourceExpression(matchSymbolicExpr(Id)))
+ .bind(CastId);
+
+ const auto NegateRelationalExpr =
+ unaryOperator(hasOperatorName("!"),
+ hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))
+ .bind(NegateId);
+
+ // Do not bind to double negation.
+ const auto NegateNegateRelationalExpr =
+ unaryOperator(hasOperatorName("!"),
+ hasUnaryOperand(unaryOperator(
+ hasOperatorName("!"),
+ hasUnaryOperand(anyOf(CastExpr, RelationalExpr)))));
+
+ const auto OverloadedOperatorExpr =
+ cxxOperatorCallExpr(
+ anyOf(hasOverloadedOperatorName("=="),
+ hasOverloadedOperatorName("!="), hasOverloadedOperatorName("<"),
+ hasOverloadedOperatorName("<="), hasOverloadedOperatorName(">"),
+ hasOverloadedOperatorName(">=")),
+ // Filter noisy false positives.
+ unless(isMacro()), unless(isInTemplateInstantiation()))
+ .bind(OverloadId);
+
+ return anyOf(RelationalExpr, CastExpr, NegateRelationalExpr,
+ NegateNegateRelationalExpr, OverloadedOperatorExpr);
+}
+
+// Checks whether a function param is non constant reference type, and may
+// be modified in the function.
+static bool isNonConstReferenceType(QualType ParamType) {
+ return ParamType->isReferenceType() &&
+ !ParamType.getNonReferenceType().isConstQualified();
+}
+
+// Checks whether the arguments of an overloaded operator can be modified in the
+// function.
+// For operators that take an instance and a constant as arguments, only the
+// first argument (the instance) needs to be checked, since the constant itself
+// is a temporary expression. Whether the second parameter is checked is
+// controlled by the parameter `ParamsToCheckCount`.
+static bool
+canOverloadedOperatorArgsBeModified(const FunctionDecl *OperatorDecl,
+ bool checkSecondParam) {
+ unsigned ParamCount = OperatorDecl->getNumParams();
+
+ // Overloaded operators declared inside a class have only one param.
+ // These functions must be declared const in order to not be able to modify
+ // the instance of the class they are called through.
+ if (ParamCount == 1 &&
+ !OperatorDecl->getType()->getAs<FunctionType>()->isConst())
+ return true;
+
+ if (isNonConstReferenceType(OperatorDecl->getParamDecl(0)->getType()))
+ return true;
+
+ return checkSecondParam && ParamCount == 2 &&
+ isNonConstReferenceType(OperatorDecl->getParamDecl(1)->getType());
+}
+
+// Retrieves sub-expressions matched by 'matchRelationalIntegerConstantExpr'
+// with name 'Id'.
+static bool retrieveRelationalIntegerConstantExpr(
+ const MatchFinder::MatchResult &Result, StringRef Id,
+ const Expr *&OperandExpr, BinaryOperatorKind &Opcode, const Expr *&Symbol,
+ APSInt &Value, const Expr *&ConstExpr) {
+ std::string CastId = (Id + "-cast").str();
+ std::string SwapId = (Id + "-swap").str();
+ std::string NegateId = (Id + "-negate").str();
+ std::string OverloadId = (Id + "-overload").str();
+
+ if (const auto *Bin = Result.Nodes.getNodeAs<BinaryOperator>(Id)) {
+ // Operand received with explicit comparator.
+ Opcode = Bin->getOpcode();
+ OperandExpr = Bin;
+
+ if (!retrieveIntegerConstantExpr(Result, Id, Value, ConstExpr))
+ return false;
+ } else if (const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(CastId)) {
+ // Operand received with implicit comparator (cast).
+ Opcode = BO_NE;
+ OperandExpr = Cast;
+ Value = APSInt(32, false);
+ } else if (const auto *OverloadedOperatorExpr =
+ Result.Nodes.getNodeAs<CXXOperatorCallExpr>(OverloadId)) {
+ const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(OverloadedOperatorExpr->getCalleeDecl());
+ if (!OverloadedFunctionDecl)
+ return false;
+
+ if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, false))
+ return false;
+
+ if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, false))
+ return false;
+
+ if (!OverloadedOperatorExpr->getArg(1)->isIntegerConstantExpr(
+ Value, *Result.Context))
+ return false;
+
+ Symbol = OverloadedOperatorExpr->getArg(0);
+ OperandExpr = OverloadedOperatorExpr;
+ Opcode = BinaryOperator::getOverloadedOpcode(OverloadedOperatorExpr->getOperator());
+
+ return BinaryOperator::isComparisonOp(Opcode);
+ } else {
+ return false;
+ }
+
+ if (!retrieveSymbolicExpr(Result, Id, Symbol))
+ return false;
+
+ if (Result.Nodes.getNodeAs<Expr>(SwapId))
+ Opcode = BinaryOperator::reverseComparisonOp(Opcode);
+ if (Result.Nodes.getNodeAs<Expr>(NegateId))
+ Opcode = BinaryOperator::negateComparisonOp(Opcode);
+ return true;
+}
+
+// Checks for expressions like (X == 4) && (Y != 9)
+static bool areSidesBinaryConstExpressions(const BinaryOperator *&BinOp, const ASTContext *AstCtx) {
+ const auto *LhsBinOp = dyn_cast<BinaryOperator>(BinOp->getLHS());
+ const auto *RhsBinOp = dyn_cast<BinaryOperator>(BinOp->getRHS());
+
+ if (!LhsBinOp || !RhsBinOp)
+ return false;
+
+ if ((LhsBinOp->getLHS()->isIntegerConstantExpr(*AstCtx) ||
+ LhsBinOp->getRHS()->isIntegerConstantExpr(*AstCtx)) &&
+ (RhsBinOp->getLHS()->isIntegerConstantExpr(*AstCtx) ||
+ RhsBinOp->getRHS()->isIntegerConstantExpr(*AstCtx)))
+ return true;
+ return false;
+}
+
+// Retrieves integer constant subexpressions from binary operator expressions
+// that have two equivalent sides.
+// E.g.: from (X == 5) && (X == 5) retrieves 5 and 5.
+static bool retrieveConstExprFromBothSides(const BinaryOperator *&BinOp,
+ BinaryOperatorKind &MainOpcode,
+ BinaryOperatorKind &SideOpcode,
+ const Expr *&LhsConst,
+ const Expr *&RhsConst,
+ const ASTContext *AstCtx) {
+ assert(areSidesBinaryConstExpressions(BinOp, AstCtx) &&
+ "Both sides of binary operator must be constant expressions!");
+
+ MainOpcode = BinOp->getOpcode();
+
+ const auto *BinOpLhs = cast<BinaryOperator>(BinOp->getLHS());
+ const auto *BinOpRhs = cast<BinaryOperator>(BinOp->getRHS());
+
+ LhsConst = BinOpLhs->getLHS()->isIntegerConstantExpr(*AstCtx)
+ ? BinOpLhs->getLHS()
+ : BinOpLhs->getRHS();
+ RhsConst = BinOpRhs->getLHS()->isIntegerConstantExpr(*AstCtx)
+ ? BinOpRhs->getLHS()
+ : BinOpRhs->getRHS();
+
+ if (!LhsConst || !RhsConst)
+ return false;
+
+ assert(BinOpLhs->getOpcode() == BinOpRhs->getOpcode() &&
+ "Sides of the binary operator must be equivalent expressions!");
+
+ SideOpcode = BinOpLhs->getOpcode();
+
+ return true;
+}
+
+static bool areExprsFromDifferentMacros(const Expr *LhsExpr,
+ const Expr *RhsExpr,
+ const ASTContext *AstCtx) {
+ if (!LhsExpr || !RhsExpr)
+ return false;
+
+ SourceLocation LhsLoc = LhsExpr->getExprLoc();
+ SourceLocation RhsLoc = RhsExpr->getExprLoc();
+
+ if (!LhsLoc.isMacroID() || !RhsLoc.isMacroID())
+ return false;
+
+ const SourceManager &SM = AstCtx->getSourceManager();
+ const LangOptions &LO = AstCtx->getLangOpts();
+
+ return !(Lexer::getImmediateMacroName(LhsLoc, SM, LO) ==
+ Lexer::getImmediateMacroName(RhsLoc, SM, LO));
+}
+
+static bool areExprsMacroAndNonMacro(const Expr *&LhsExpr,
+ const Expr *&RhsExpr) {
+ if (!LhsExpr || !RhsExpr)
+ return false;
+
+ SourceLocation LhsLoc = LhsExpr->getExprLoc();
+ SourceLocation RhsLoc = RhsExpr->getExprLoc();
+
+ return LhsLoc.isMacroID() != RhsLoc.isMacroID();
+}
+} // namespace
+
+void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
+ const auto AnyLiteralExpr = ignoringParenImpCasts(
+ anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral()));
+
+ const auto BannedIntegerLiteral =
+ integerLiteral(expandedByMacro(KnownBannedMacroNames));
+
+ // Binary with equivalent operands, like (X != 2 && X != 2).
+ Finder->addMatcher(
+ binaryOperator(anyOf(hasOperatorName("-"), hasOperatorName("/"),
+ hasOperatorName("%"), hasOperatorName("|"),
+ hasOperatorName("&"), hasOperatorName("^"),
+ matchers::isComparisonOperator(),
+ hasOperatorName("&&"), hasOperatorName("||"),
+ hasOperatorName("=")),
+ operandsAreEquivalent(),
+ // Filter noisy false positives.
+ unless(isInTemplateInstantiation()),
+ unless(binaryOperatorIsInMacro()),
+ unless(hasType(realFloatingPointType())),
+ unless(hasEitherOperand(hasType(realFloatingPointType()))),
+ unless(hasLHS(AnyLiteralExpr)),
+ unless(hasDescendant(BannedIntegerLiteral)))
+ .bind("binary"),
+ this);
+
+ // Conditional (trenary) operator with equivalent operands, like (Y ? X : X).
+ Finder->addMatcher(conditionalOperator(expressionsAreEquivalent(),
+ // Filter noisy false positives.
+ unless(conditionalOperatorIsInMacro()),
+ unless(isInTemplateInstantiation()))
+ .bind("cond"),
+ this);
+
+ // Overloaded operators with equivalent operands.
+ Finder->addMatcher(
+ cxxOperatorCallExpr(
+ anyOf(
+ hasOverloadedOperatorName("-"), hasOverloadedOperatorName("/"),
+ hasOverloadedOperatorName("%"), hasOverloadedOperatorName("|"),
+ hasOverloadedOperatorName("&"), hasOverloadedOperatorName("^"),
+ hasOverloadedOperatorName("=="), hasOverloadedOperatorName("!="),
+ hasOverloadedOperatorName("<"), hasOverloadedOperatorName("<="),
+ hasOverloadedOperatorName(">"), hasOverloadedOperatorName(">="),
+ hasOverloadedOperatorName("&&"), hasOverloadedOperatorName("||"),
+ hasOverloadedOperatorName("=")),
+ parametersAreEquivalent(),
+ // Filter noisy false positives.
+ unless(isMacro()), unless(isInTemplateInstantiation()))
+ .bind("call"),
+ this);
+
+ // Match expressions like: !(1 | 2 | 3)
+ Finder->addMatcher(
+ implicitCastExpr(
+ hasImplicitDestinationType(isInteger()),
+ has(unaryOperator(
+ hasOperatorName("!"),
+ hasUnaryOperand(ignoringParenImpCasts(binaryOperator(
+ anyOf(hasOperatorName("|"), hasOperatorName("&")),
+ hasLHS(anyOf(binaryOperator(anyOf(hasOperatorName("|"),
+ hasOperatorName("&"))),
+ integerLiteral())),
+ hasRHS(integerLiteral())))))
+ .bind("logical-bitwise-confusion"))),
+ this);
+
+ // Match expressions like: (X << 8) & 0xFF
+ Finder->addMatcher(
+ binaryOperator(hasOperatorName("&"),
+ hasEitherOperand(ignoringParenImpCasts(binaryOperator(
+ hasOperatorName("<<"),
+ hasRHS(ignoringParenImpCasts(
+ integerLiteral().bind("shift-const")))))),
+ hasEitherOperand(ignoringParenImpCasts(
+ integerLiteral().bind("and-const"))))
+ .bind("left-right-shift-confusion"),
+ this);
+
+ // Match common expressions and apply more checks to find redundant
+ // sub-expressions.
+ // a) Expr <op> K1 == K2
+ // b) Expr <op> K1 == Expr
+ // c) Expr <op> K1 == Expr <op> K2
+ // see: 'checkArithmeticExpr' and 'checkBitwiseExpr'
+ const auto BinOpCstLeft = matchBinOpIntegerConstantExpr("lhs");
+ const auto BinOpCstRight = matchBinOpIntegerConstantExpr("rhs");
+ const auto CstRight = matchIntegerConstantExpr("rhs");
+ const auto SymRight = matchSymbolicExpr("rhs");
+
+ // Match expressions like: x <op> 0xFF == 0xF00.
+ Finder->addMatcher(binaryOperator(isComparisonOperator(),
+ hasEitherOperand(BinOpCstLeft),
+ hasEitherOperand(CstRight))
+ .bind("binop-const-compare-to-const"),
+ this);
+
+ // Match expressions like: x <op> 0xFF == x.
+ Finder->addMatcher(
+ binaryOperator(isComparisonOperator(),
+ anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)),
+ allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft))))
+ .bind("binop-const-compare-to-sym"),
+ this);
+
+ // Match expressions like: x <op> 10 == x <op> 12.
+ Finder->addMatcher(binaryOperator(isComparisonOperator(),
+ hasLHS(BinOpCstLeft), hasRHS(BinOpCstRight),
+ // Already reported as redundant.
+ unless(operandsAreEquivalent()))
+ .bind("binop-const-compare-to-binop-const"),
+ this);
+
+ // Match relational expressions combined with logical operators and find
+ // redundant sub-expressions.
+ // see: 'checkRelationalExpr'
+
+ // Match expressions like: x < 2 && x > 2.
+ const auto ComparisonLeft = matchRelationalIntegerConstantExpr("lhs");
+ const auto ComparisonRight = matchRelationalIntegerConstantExpr("rhs");
+ Finder->addMatcher(
+ binaryOperator(anyOf(hasOperatorName("||"), hasOperatorName("&&")),
+ hasLHS(ComparisonLeft), hasRHS(ComparisonRight),
+ // Already reported as redundant.
+ unless(operandsAreEquivalent()))
+ .bind("comparisons-of-symbol-and-const"),
+ this);
+}
+
+void RedundantExpressionCheck::checkArithmeticExpr(
+ const MatchFinder::MatchResult &Result) {
+ APSInt LhsValue, RhsValue;
+ const Expr *LhsSymbol = nullptr, *RhsSymbol = nullptr;
+ BinaryOperatorKind LhsOpcode, RhsOpcode;
+
+ if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
+ "binop-const-compare-to-sym")) {
+ BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
+ if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
+ LhsValue) ||
+ !retrieveSymbolicExpr(Result, "rhs", RhsSymbol) ||
+ !areEquivalentExpr(LhsSymbol, RhsSymbol))
+ return;
+
+ // Check expressions: x + k == x or x - k == x.
+ if (LhsOpcode == BO_Add || LhsOpcode == BO_Sub) {
+ if ((LhsValue != 0 && Opcode == BO_EQ) ||
+ (LhsValue == 0 && Opcode == BO_NE))
+ diag(ComparisonOperator->getOperatorLoc(),
+ "logical expression is always false");
+ else if ((LhsValue == 0 && Opcode == BO_EQ) ||
+ (LhsValue != 0 && Opcode == BO_NE))
+ diag(ComparisonOperator->getOperatorLoc(),
+ "logical expression is always true");
+ }
+ } else if (const auto *ComparisonOperator =
+ Result.Nodes.getNodeAs<BinaryOperator>(
+ "binop-const-compare-to-binop-const")) {
+ BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
+
+ if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
+ LhsValue) ||
+ !retrieveBinOpIntegerConstantExpr(Result, "rhs", RhsOpcode, RhsSymbol,
+ RhsValue) ||
+ !areEquivalentExpr(LhsSymbol, RhsSymbol))
+ return;
+
+ transformSubToCanonicalAddExpr(LhsOpcode, LhsValue);
+ transformSubToCanonicalAddExpr(RhsOpcode, RhsValue);
+
+ // Check expressions: x + 1 == x + 2 or x + 1 != x + 2.
+ if (LhsOpcode == BO_Add && RhsOpcode == BO_Add) {
+ if ((Opcode == BO_EQ && APSInt::compareValues(LhsValue, RhsValue) == 0) ||
+ (Opcode == BO_NE && APSInt::compareValues(LhsValue, RhsValue) != 0)) {
+ diag(ComparisonOperator->getOperatorLoc(),
+ "logical expression is always true");
+ } else if ((Opcode == BO_EQ &&
+ APSInt::compareValues(LhsValue, RhsValue) != 0) ||
+ (Opcode == BO_NE &&
+ APSInt::compareValues(LhsValue, RhsValue) == 0)) {
+ diag(ComparisonOperator->getOperatorLoc(),
+ "logical expression is always false");
+ }
+ }
+ }
+}
+
+static bool exprEvaluatesToZero(BinaryOperatorKind Opcode, APSInt Value) {
+ return (Opcode == BO_And || Opcode == BO_AndAssign) && Value == 0;
+}
+
+static bool exprEvaluatesToBitwiseNegatedZero(BinaryOperatorKind Opcode,
+ APSInt Value) {
+ return (Opcode == BO_Or || Opcode == BO_OrAssign) && ~Value == 0;
+}
+
+static bool exprEvaluatesToSymbolic(BinaryOperatorKind Opcode, APSInt Value) {
+ return ((Opcode == BO_Or || Opcode == BO_OrAssign) && Value == 0) ||
+ ((Opcode == BO_And || Opcode == BO_AndAssign) && ~Value == 0);
+}
+
+
+void RedundantExpressionCheck::checkBitwiseExpr(
+ const MatchFinder::MatchResult &Result) {
+ if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
+ "binop-const-compare-to-const")) {
+ BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
+
+ APSInt LhsValue, RhsValue;
+ const Expr *LhsSymbol = nullptr;
+ BinaryOperatorKind LhsOpcode;
+ if (!retrieveBinOpIntegerConstantExpr(Result, "lhs", LhsOpcode, LhsSymbol,
+ LhsValue) ||
+ !retrieveIntegerConstantExpr(Result, "rhs", RhsValue))
+ return;
+
+ uint64_t LhsConstant = LhsValue.getZExtValue();
+ uint64_t RhsConstant = RhsValue.getZExtValue();
+ SourceLocation Loc = ComparisonOperator->getOperatorLoc();
+
+ // Check expression: x & k1 == k2 (i.e. x & 0xFF == 0xF00)
+ if (LhsOpcode == BO_And && (LhsConstant & RhsConstant) != RhsConstant) {
+ if (Opcode == BO_EQ)
+ diag(Loc, "logical expression is always false");
+ else if (Opcode == BO_NE)
+ diag(Loc, "logical expression is always true");
+ }
+
+ // Check expression: x | k1 == k2 (i.e. x | 0xFF == 0xF00)
+ if (LhsOpcode == BO_Or && (LhsConstant | RhsConstant) != RhsConstant) {
+ if (Opcode == BO_EQ)
+ diag(Loc, "logical expression is always false");
+ else if (Opcode == BO_NE)
+ diag(Loc, "logical expression is always true");
+ }
+ } else if (const auto *IneffectiveOperator =
+ Result.Nodes.getNodeAs<BinaryOperator>(
+ "ineffective-bitwise")) {
+ APSInt Value;
+ const Expr *Sym = nullptr, *ConstExpr = nullptr;
+
+ if (!retrieveSymbolicExpr(Result, "ineffective-bitwise", Sym) ||
+ !retrieveIntegerConstantExpr(Result, "ineffective-bitwise", Value,
+ ConstExpr))
+ return;
+
+ if((Value != 0 && ~Value != 0) || Sym->getExprLoc().isMacroID())
+ return;
+
+ SourceLocation Loc = IneffectiveOperator->getOperatorLoc();
+
+ BinaryOperatorKind Opcode = IneffectiveOperator->getOpcode();
+ if (exprEvaluatesToZero(Opcode, Value)) {
+ diag(Loc, "expression always evaluates to 0");
+ } else if (exprEvaluatesToBitwiseNegatedZero(Opcode, Value)) {
+ SourceRange ConstExprRange(ConstExpr->getLocStart(),
+ ConstExpr->getLocEnd());
+ StringRef ConstExprText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(ConstExprRange), *Result.SourceManager,
+ Result.Context->getLangOpts());
+
+ diag(Loc, "expression always evaluates to '%0'") << ConstExprText;
+
+ } else if (exprEvaluatesToSymbolic(Opcode, Value)) {
+ SourceRange SymExprRange(Sym->getLocStart(), Sym->getLocEnd());
+
+ StringRef ExprText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(SymExprRange), *Result.SourceManager,
+ Result.Context->getLangOpts());
+
+ diag(Loc, "expression always evaluates to '%0'") << ExprText;
+ }
+ }
+}
+
+void RedundantExpressionCheck::checkRelationalExpr(
+ const MatchFinder::MatchResult &Result) {
+ if (const auto *ComparisonOperator = Result.Nodes.getNodeAs<BinaryOperator>(
+ "comparisons-of-symbol-and-const")) {
+ // Matched expressions are: (x <op> k1) <REL> (x <op> k2).
+ // E.g.: (X < 2) && (X > 4)
+ BinaryOperatorKind Opcode = ComparisonOperator->getOpcode();
+
+ const Expr *LhsExpr = nullptr, *RhsExpr = nullptr;
+ const Expr *LhsSymbol = nullptr, *RhsSymbol = nullptr;
+ const Expr *LhsConst = nullptr, *RhsConst = nullptr;
+ BinaryOperatorKind LhsOpcode, RhsOpcode;
+ APSInt LhsValue, RhsValue;
+
+ if (!retrieveRelationalIntegerConstantExpr(
+ Result, "lhs", LhsExpr, LhsOpcode, LhsSymbol, LhsValue, LhsConst) ||
+ !retrieveRelationalIntegerConstantExpr(
+ Result, "rhs", RhsExpr, RhsOpcode, RhsSymbol, RhsValue, RhsConst) ||
+ !areEquivalentExpr(LhsSymbol, RhsSymbol))
+ return;
+
+ // Bring expr to a canonical form: smallest constant must be on the left.
+ if (APSInt::compareValues(LhsValue, RhsValue) > 0) {
+ std::swap(LhsExpr, RhsExpr);
+ std::swap(LhsValue, RhsValue);
+ std::swap(LhsSymbol, RhsSymbol);
+ std::swap(LhsOpcode, RhsOpcode);
+ }
+
+ // Constants come from two different macros, or one of them is a macro.
+ if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
+ areExprsMacroAndNonMacro(LhsConst, RhsConst))
+ return;
+
+ if ((Opcode == BO_LAnd || Opcode == BO_LOr) &&
+ areEquivalentRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
+ diag(ComparisonOperator->getOperatorLoc(),
+ "equivalent expression on both sides of logical operator");
+ return;
+ }
+
+ if (Opcode == BO_LAnd) {
+ if (areExclusiveRanges(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
+ diag(ComparisonOperator->getOperatorLoc(),
+ "logical expression is always false");
+ } else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
+ diag(LhsExpr->getExprLoc(), "expression is redundant");
+ } else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
+ diag(RhsExpr->getExprLoc(), "expression is redundant");
+ }
+ }
+
+ if (Opcode == BO_LOr) {
+ if (rangesFullyCoverDomain(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
+ diag(ComparisonOperator->getOperatorLoc(),
+ "logical expression is always true");
+ } else if (rangeSubsumesRange(LhsOpcode, LhsValue, RhsOpcode, RhsValue)) {
+ diag(RhsExpr->getExprLoc(), "expression is redundant");
+ } else if (rangeSubsumesRange(RhsOpcode, RhsValue, LhsOpcode, LhsValue)) {
+ diag(LhsExpr->getExprLoc(), "expression is redundant");
+ }
+ }
+ }
+}
+
+void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binary")) {
+ // If the expression's constants are macros, check whether they are
+ // intentional.
+ if (areSidesBinaryConstExpressions(BinOp, Result.Context)) {
+ const Expr *LhsConst = nullptr, *RhsConst = nullptr;
+ BinaryOperatorKind MainOpcode, SideOpcode;
+
+ if (!retrieveConstExprFromBothSides(BinOp, MainOpcode, SideOpcode,
+ LhsConst, RhsConst, Result.Context))
+ return;
+
+ if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) ||
+ areExprsMacroAndNonMacro(LhsConst, RhsConst))
+ return;
+ }
+
+ diag(BinOp->getOperatorLoc(), "both sides of operator are equivalent");
+ }
+
+ if (const auto *CondOp =
+ Result.Nodes.getNodeAs<ConditionalOperator>("cond")) {
+ const Expr *TrueExpr = CondOp->getTrueExpr();
+ const Expr *FalseExpr = CondOp->getFalseExpr();
+
+ if (areExprsFromDifferentMacros(TrueExpr, FalseExpr, Result.Context) ||
+ areExprsMacroAndNonMacro(TrueExpr, FalseExpr))
+ return;
+ diag(CondOp->getColonLoc(),
+ "'true' and 'false' expressions are equivalent");
+ }
+
+ if (const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("call")) {
+ const auto *OverloadedFunctionDecl = dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl());
+ if (!OverloadedFunctionDecl)
+ return;
+
+ if (canOverloadedOperatorArgsBeModified(OverloadedFunctionDecl, true))
+ return;
+
+ diag(Call->getOperatorLoc(),
+ "both sides of overloaded operator are equivalent");
+ }
+
+ if (const auto *NegateOperator =
+ Result.Nodes.getNodeAs<UnaryOperator>("logical-bitwise-confusion")) {
+ SourceLocation OperatorLoc = NegateOperator->getOperatorLoc();
+
+ auto Diag =
+ diag(OperatorLoc,
+ "ineffective logical negation operator used; did you mean '~'?");
+ SourceLocation LogicalNotLocation = OperatorLoc.getLocWithOffset(1);
+
+ if (!LogicalNotLocation.isMacroID())
+ Diag << FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(OperatorLoc, LogicalNotLocation), "~");
+ }
+
+ if (const auto *BinaryAndExpr = Result.Nodes.getNodeAs<BinaryOperator>(
+ "left-right-shift-confusion")) {
+ const auto *ShiftingConst = Result.Nodes.getNodeAs<Expr>("shift-const");
+ assert(ShiftingConst && "Expr* 'ShiftingConst' is nullptr!");
+ APSInt ShiftingValue;
+
+ if (!ShiftingConst->isIntegerConstantExpr(ShiftingValue, *Result.Context))
+ return;
+
+ const auto *AndConst = Result.Nodes.getNodeAs<Expr>("and-const");
+ assert(AndConst && "Expr* 'AndCont' is nullptr!");
+ APSInt AndValue;
+ if (!AndConst->isIntegerConstantExpr(AndValue, *Result.Context))
+ return;
+
+ // If ShiftingConst is shifted left with more bits than the position of the
+ // leftmost 1 in the bit representation of AndValue, AndConstant is
+ // ineffective.
+ if (AndValue.getActiveBits() > ShiftingValue)
+ return;
+
+ auto Diag = diag(BinaryAndExpr->getOperatorLoc(),
+ "ineffective bitwise and operation");
+ }
+
+ // Check for the following bound expressions:
+ // - "binop-const-compare-to-sym",
+ // - "binop-const-compare-to-binop-const",
+ // Produced message:
+ // -> "logical expression is always false/true"
+ checkArithmeticExpr(Result);
+
+ // Check for the following bound expression:
+ // - "binop-const-compare-to-const",
+ // - "ineffective-bitwise"
+ // Produced message:
+ // -> "logical expression is always false/true"
+ // -> "expression always evaluates to ..."
+ checkBitwiseExpr(Result);
+
+ // Check for te following bound expression:
+ // - "comparisons-of-symbol-and-const",
+ // Produced messages:
+ // -> "equivalent expression on both sides of logical operator",
+ // -> "logical expression is always false/true"
+ // -> "expression is redundant"
+ checkRelationalExpr(Result);
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.h
new file mode 100644
index 0000000..c0f8bf5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.h
@@ -0,0 +1,41 @@
+//===--- RedundantExpressionCheck.h - clang-tidy-----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_REDUNDANT_EXPRESSION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_REDUNDANT_EXPRESSION_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// The checker detects expressions that are redundant, because they contain
+/// ineffective, useless parts.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-redundant-expression.html
+class RedundantExpressionCheck : public ClangTidyCheck {
+public:
+ RedundantExpressionCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void checkArithmeticExpr(const ast_matchers::MatchFinder::MatchResult &R);
+ void checkBitwiseExpr(const ast_matchers::MatchFinder::MatchResult &R);
+ void checkRelationalExpr(const ast_matchers::MatchFinder::MatchResult &R);
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_REDUNDANT_EXPRESSION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/StaticAssertCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/StaticAssertCheck.cpp
new file mode 100644
index 0000000..77fb58d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/StaticAssertCheck.cpp
@@ -0,0 +1,177 @@
+//===--- StaticAssertCheck.cpp - clang-tidy -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StaticAssertCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include <string>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+StaticAssertCheck::StaticAssertCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+
+void StaticAssertCheck::registerMatchers(MatchFinder *Finder) {
+ // This checker only makes sense for languages that have static assertion
+ // capabilities: C++11 and C11.
+ if (!(getLangOpts().CPlusPlus11 || getLangOpts().C11))
+ return;
+
+ auto NegatedString = unaryOperator(
+ hasOperatorName("!"), hasUnaryOperand(ignoringImpCasts(stringLiteral())));
+ auto IsAlwaysFalse =
+ expr(anyOf(cxxBoolLiteral(equals(false)), integerLiteral(equals(0)),
+ cxxNullPtrLiteralExpr(), gnuNullExpr(), NegatedString))
+ .bind("isAlwaysFalse");
+ auto IsAlwaysFalseWithCast = ignoringParenImpCasts(anyOf(
+ IsAlwaysFalse, cStyleCastExpr(has(ignoringParenImpCasts(IsAlwaysFalse)))
+ .bind("castExpr")));
+ auto AssertExprRoot = anyOf(
+ binaryOperator(
+ anyOf(hasOperatorName("&&"), hasOperatorName("==")),
+ hasEitherOperand(ignoringImpCasts(stringLiteral().bind("assertMSG"))),
+ anyOf(binaryOperator(hasEitherOperand(IsAlwaysFalseWithCast)),
+ anything()))
+ .bind("assertExprRoot"),
+ IsAlwaysFalse);
+ auto NonConstexprFunctionCall =
+ callExpr(hasDeclaration(functionDecl(unless(isConstexpr()))));
+ auto AssertCondition =
+ expr(
+ anyOf(expr(ignoringParenCasts(anyOf(
+ AssertExprRoot, unaryOperator(hasUnaryOperand(
+ ignoringParenCasts(AssertExprRoot)))))),
+ anything()),
+ unless(findAll(NonConstexprFunctionCall)))
+ .bind("condition");
+ auto Condition =
+ anyOf(ignoringParenImpCasts(callExpr(
+ hasDeclaration(functionDecl(hasName("__builtin_expect"))),
+ hasArgument(0, AssertCondition))),
+ AssertCondition);
+
+ Finder->addMatcher(conditionalOperator(hasCondition(Condition),
+ unless(isInTemplateInstantiation()))
+ .bind("condStmt"),
+ this);
+
+ Finder->addMatcher(
+ ifStmt(hasCondition(Condition), unless(isInTemplateInstantiation()))
+ .bind("condStmt"),
+ this);
+}
+
+void StaticAssertCheck::check(const MatchFinder::MatchResult &Result) {
+ const ASTContext *ASTCtx = Result.Context;
+ const LangOptions &Opts = ASTCtx->getLangOpts();
+ const SourceManager &SM = ASTCtx->getSourceManager();
+ const auto *CondStmt = Result.Nodes.getNodeAs<Stmt>("condStmt");
+ const auto *Condition = Result.Nodes.getNodeAs<Expr>("condition");
+ const auto *IsAlwaysFalse = Result.Nodes.getNodeAs<Expr>("isAlwaysFalse");
+ const auto *AssertMSG = Result.Nodes.getNodeAs<StringLiteral>("assertMSG");
+ const auto *AssertExprRoot =
+ Result.Nodes.getNodeAs<BinaryOperator>("assertExprRoot");
+ const auto *CastExpr = Result.Nodes.getNodeAs<CStyleCastExpr>("castExpr");
+ SourceLocation AssertExpansionLoc = CondStmt->getLocStart();
+
+ if (!AssertExpansionLoc.isValid() || !AssertExpansionLoc.isMacroID())
+ return;
+
+ StringRef MacroName =
+ Lexer::getImmediateMacroName(AssertExpansionLoc, SM, Opts);
+
+ if (MacroName != "assert" || Condition->isValueDependent() ||
+ Condition->isTypeDependent() || Condition->isInstantiationDependent() ||
+ !Condition->isEvaluatable(*ASTCtx))
+ return;
+
+ // False literal is not the result of macro expansion.
+ if (IsAlwaysFalse && (!CastExpr || CastExpr->getType()->isPointerType())) {
+ SourceLocation FalseLiteralLoc =
+ SM.getImmediateSpellingLoc(IsAlwaysFalse->getExprLoc());
+ if (!FalseLiteralLoc.isMacroID())
+ return;
+
+ StringRef FalseMacroName =
+ Lexer::getImmediateMacroName(FalseLiteralLoc, SM, Opts);
+ if (FalseMacroName.compare_lower("false") == 0 ||
+ FalseMacroName.compare_lower("null") == 0)
+ return;
+ }
+
+ SourceLocation AssertLoc = SM.getImmediateMacroCallerLoc(AssertExpansionLoc);
+
+ SmallVector<FixItHint, 4> FixItHints;
+ SourceLocation LastParenLoc;
+ if (AssertLoc.isValid() && !AssertLoc.isMacroID() &&
+ (LastParenLoc = getLastParenLoc(ASTCtx, AssertLoc)).isValid()) {
+ FixItHints.push_back(
+ FixItHint::CreateReplacement(SourceRange(AssertLoc), "static_assert"));
+
+ std::string StaticAssertMSG = ", \"\"";
+ if (AssertExprRoot) {
+ FixItHints.push_back(FixItHint::CreateRemoval(
+ SourceRange(AssertExprRoot->getOperatorLoc())));
+ FixItHints.push_back(FixItHint::CreateRemoval(
+ SourceRange(AssertMSG->getLocStart(), AssertMSG->getLocEnd())));
+ StaticAssertMSG = (Twine(", \"") + AssertMSG->getString() + "\"").str();
+ }
+
+ FixItHints.push_back(
+ FixItHint::CreateInsertion(LastParenLoc, StaticAssertMSG));
+ }
+
+ diag(AssertLoc, "found assert() that could be replaced by static_assert()")
+ << FixItHints;
+}
+
+SourceLocation StaticAssertCheck::getLastParenLoc(const ASTContext *ASTCtx,
+ SourceLocation AssertLoc) {
+ const LangOptions &Opts = ASTCtx->getLangOpts();
+ const SourceManager &SM = ASTCtx->getSourceManager();
+
+ llvm::MemoryBuffer *Buffer = SM.getBuffer(SM.getFileID(AssertLoc));
+ if (!Buffer)
+ return SourceLocation();
+
+ const char *BufferPos = SM.getCharacterData(AssertLoc);
+
+ Token Token;
+ Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(AssertLoc)), Opts,
+ Buffer->getBufferStart(), BufferPos, Buffer->getBufferEnd());
+
+ // assert first left parenthesis
+ if (Lexer.LexFromRawLexer(Token) || Lexer.LexFromRawLexer(Token) ||
+ !Token.is(tok::l_paren))
+ return SourceLocation();
+
+ unsigned int ParenCount = 1;
+ while (ParenCount && !Lexer.LexFromRawLexer(Token)) {
+ if (Token.is(tok::l_paren))
+ ++ParenCount;
+ else if (Token.is(tok::r_paren))
+ --ParenCount;
+ }
+
+ return Token.getLocation();
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/StaticAssertCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/StaticAssertCheck.h
new file mode 100644
index 0000000..faefce1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/StaticAssertCheck.h
@@ -0,0 +1,41 @@
+//===--- StaticAssertCheck.h - clang-tidy -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_STATICASSERTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_STATICASSERTCHECK_H
+
+#include "../ClangTidy.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Replaces `assert()` with `static_assert()` if the condition is evaluatable
+/// at compile time.
+///
+/// The condition of `static_assert()` is evaluated at compile time which is
+/// safer and more efficient.
+class StaticAssertCheck : public ClangTidyCheck {
+public:
+ StaticAssertCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ SourceLocation getLastParenLoc(const ASTContext *ASTCtx,
+ SourceLocation AssertLoc);
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_STATICASSERTCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/ThrowByValueCatchByReferenceCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/ThrowByValueCatchByReferenceCheck.cpp
new file mode 100644
index 0000000..90398cc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/ThrowByValueCatchByReferenceCheck.cpp
@@ -0,0 +1,161 @@
+//===--- ThrowByValueCatchByReferenceCheck.cpp - clang-tidy----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ThrowByValueCatchByReferenceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/OperationKinds.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+ThrowByValueCatchByReferenceCheck::ThrowByValueCatchByReferenceCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ CheckAnonymousTemporaries(Options.get("CheckThrowTemporaries", true)) {}
+
+void ThrowByValueCatchByReferenceCheck::registerMatchers(MatchFinder *Finder) {
+ // This is a C++ only check thus we register the matchers only for C++
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(cxxThrowExpr().bind("throw"), this);
+ Finder->addMatcher(cxxCatchStmt().bind("catch"), this);
+}
+
+void ThrowByValueCatchByReferenceCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "CheckThrowTemporaries", true);
+}
+
+void ThrowByValueCatchByReferenceCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ diagnoseThrowLocations(Result.Nodes.getNodeAs<CXXThrowExpr>("throw"));
+ diagnoseCatchLocations(Result.Nodes.getNodeAs<CXXCatchStmt>("catch"),
+ *Result.Context);
+}
+
+bool ThrowByValueCatchByReferenceCheck::isFunctionParameter(
+ const DeclRefExpr *declRefExpr) {
+ return isa<ParmVarDecl>(declRefExpr->getDecl());
+}
+
+bool ThrowByValueCatchByReferenceCheck::isCatchVariable(
+ const DeclRefExpr *declRefExpr) {
+ auto *valueDecl = declRefExpr->getDecl();
+ if (auto *varDecl = dyn_cast<VarDecl>(valueDecl))
+ return varDecl->isExceptionVariable();
+ return false;
+}
+
+bool ThrowByValueCatchByReferenceCheck::isFunctionOrCatchVar(
+ const DeclRefExpr *declRefExpr) {
+ return isFunctionParameter(declRefExpr) || isCatchVariable(declRefExpr);
+}
+
+void ThrowByValueCatchByReferenceCheck::diagnoseThrowLocations(
+ const CXXThrowExpr *throwExpr) {
+ if (!throwExpr)
+ return;
+ auto *subExpr = throwExpr->getSubExpr();
+ if (!subExpr)
+ return;
+ auto qualType = subExpr->getType();
+ if (qualType->isPointerType()) {
+ // The code is throwing a pointer.
+ // In case it is strng literal, it is safe and we return.
+ auto *inner = subExpr->IgnoreParenImpCasts();
+ if (isa<StringLiteral>(inner))
+ return;
+ // If it's a variable from a catch statement, we return as well.
+ auto *declRef = dyn_cast<DeclRefExpr>(inner);
+ if (declRef && isCatchVariable(declRef)) {
+ return;
+ }
+ diag(subExpr->getLocStart(), "throw expression throws a pointer; it should "
+ "throw a non-pointer value instead");
+ }
+ // If the throw statement does not throw by pointer then it throws by value
+ // which is ok.
+ // There are addition checks that emit diagnosis messages if the thrown value
+ // is not an RValue. See:
+ // https://www.securecoding.cert.org/confluence/display/cplusplus/ERR09-CPP.+Throw+anonymous+temporaries
+ // This behavior can be influenced by an option.
+
+ // If we encounter a CXXThrowExpr, we move through all casts until you either
+ // encounter a DeclRefExpr or a CXXConstructExpr.
+ // If it's a DeclRefExpr, we emit a message if the referenced variable is not
+ // a catch variable or function parameter.
+ // When encountering a CopyOrMoveConstructor: emit message if after casts,
+ // the expression is a LValue
+ if (CheckAnonymousTemporaries) {
+ bool emit = false;
+ auto *currentSubExpr = subExpr->IgnoreImpCasts();
+ const auto *variableReference = dyn_cast<DeclRefExpr>(currentSubExpr);
+ const auto *constructorCall = dyn_cast<CXXConstructExpr>(currentSubExpr);
+ // If we have a DeclRefExpr, we flag for emitting a diagnosis message in
+ // case the referenced variable is neither a function parameter nor a
+ // variable declared in the catch statement.
+ if (variableReference)
+ emit = !isFunctionOrCatchVar(variableReference);
+ else if (constructorCall &&
+ constructorCall->getConstructor()->isCopyOrMoveConstructor()) {
+ // If we have a copy / move construction, we emit a diagnosis message if
+ // the object that we copy construct from is neither a function parameter
+ // nor a variable declared in a catch statement
+ auto argIter =
+ constructorCall
+ ->arg_begin(); // there's only one for copy constructors
+ auto *currentSubExpr = (*argIter)->IgnoreImpCasts();
+ if (currentSubExpr->isLValue()) {
+ if (auto *tmp = dyn_cast<DeclRefExpr>(currentSubExpr))
+ emit = !isFunctionOrCatchVar(tmp);
+ else if (isa<CallExpr>(currentSubExpr))
+ emit = true;
+ }
+ }
+ if (emit)
+ diag(subExpr->getLocStart(),
+ "throw expression should throw anonymous temporary values instead");
+ }
+}
+
+void ThrowByValueCatchByReferenceCheck::diagnoseCatchLocations(
+ const CXXCatchStmt *catchStmt, ASTContext &context) {
+ if (!catchStmt)
+ return;
+ auto caughtType = catchStmt->getCaughtType();
+ if (caughtType.isNull())
+ return;
+ auto *varDecl = catchStmt->getExceptionDecl();
+ if (const auto *PT = caughtType.getCanonicalType()->getAs<PointerType>()) {
+ const char *diagMsgCatchReference = "catch handler catches a pointer value; "
+ "should throw a non-pointer value and "
+ "catch by reference instead";
+ // We do not diagnose when catching pointer to strings since we also allow
+ // throwing string literals.
+ if (!PT->getPointeeType()->isAnyCharacterType())
+ diag(varDecl->getLocStart(), diagMsgCatchReference);
+ } else if (!caughtType->isReferenceType()) {
+ const char *diagMsgCatchReference = "catch handler catches by value; "
+ "should catch by reference instead";
+ // If it's not a pointer and not a reference then it must be caught "by
+ // value". In this case we should emit a diagnosis message unless the type
+ // is trivial.
+ if (!caughtType.isTrivialType(context))
+ diag(varDecl->getLocStart(), diagMsgCatchReference);
+ }
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/ThrowByValueCatchByReferenceCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/ThrowByValueCatchByReferenceCheck.h
new file mode 100644
index 0000000..a2e7df7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/ThrowByValueCatchByReferenceCheck.h
@@ -0,0 +1,51 @@
+//===--- ThrowByValueCatchByReferenceCheck.h - clang-tidy--------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_THROW_BY_VALUE_CATCH_BY_REFERENCE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_THROW_BY_VALUE_CATCH_BY_REFERENCE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+///\brief checks for locations that do not throw by value
+// or catch by reference.
+// The check is C++ only. It checks that all throw locations
+// throw by value and not by pointer. Additionally it
+// contains an option ("CheckThrowTemporaries", default value "true") that
+// checks that thrown objects are anonymous temporaries. It is also
+// acceptable for this check to throw string literals.
+// This test checks that exceptions are caught by reference
+// and not by value or pointer. It will not warn when catching
+// pointer to char, wchar_t, char16_t or char32_t. This is
+// due to not warning on throwing string literals.
+class ThrowByValueCatchByReferenceCheck : public ClangTidyCheck {
+public:
+ ThrowByValueCatchByReferenceCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void diagnoseThrowLocations(const CXXThrowExpr *throwExpr);
+ void diagnoseCatchLocations(const CXXCatchStmt *catchStmt,
+ ASTContext &context);
+ bool isFunctionParameter(const DeclRefExpr *declRefExpr);
+ bool isCatchVariable(const DeclRefExpr *declRefExpr);
+ bool isFunctionOrCatchVar(const DeclRefExpr *declRefExpr);
+ const bool CheckAnonymousTemporaries;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_THROW_BY_VALUE_CATCH_BY_REFERENCE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
new file mode 100644
index 0000000..0fd7e77
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.cpp
@@ -0,0 +1,94 @@
+//===--- UnconventionalAssignOperatorCheck.cpp - clang-tidy -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnconventionalAssignOperatorCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void UnconventionalAssignOperatorCheck::registerMatchers(
+ ast_matchers::MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ const auto HasGoodReturnType = cxxMethodDecl(returns(lValueReferenceType(
+ pointee(unless(isConstQualified()),
+ anyOf(autoType(), hasDeclaration(equalsBoundNode("class")))))));
+
+ const auto IsSelf = qualType(
+ anyOf(hasDeclaration(equalsBoundNode("class")),
+ referenceType(pointee(hasDeclaration(equalsBoundNode("class"))))));
+ const auto IsAssign =
+ cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())),
+ hasName("operator="), ofClass(recordDecl().bind("class")))
+ .bind("method");
+ const auto IsSelfAssign =
+ cxxMethodDecl(IsAssign, hasParameter(0, parmVarDecl(hasType(IsSelf))))
+ .bind("method");
+
+ Finder->addMatcher(
+ cxxMethodDecl(IsAssign, unless(HasGoodReturnType)).bind("ReturnType"),
+ this);
+
+ const auto BadSelf = referenceType(
+ anyOf(lValueReferenceType(pointee(unless(isConstQualified()))),
+ rValueReferenceType(pointee(isConstQualified()))));
+
+ Finder->addMatcher(
+ cxxMethodDecl(IsSelfAssign,
+ hasParameter(0, parmVarDecl(hasType(BadSelf))))
+ .bind("ArgumentType"),
+ this);
+
+ Finder->addMatcher(
+ cxxMethodDecl(IsSelfAssign, anyOf(isConst(), isVirtual())).bind("cv"),
+ this);
+
+ const auto IsBadReturnStatement = returnStmt(unless(has(ignoringParenImpCasts(
+ anyOf(unaryOperator(hasOperatorName("*"), hasUnaryOperand(cxxThisExpr())),
+ cxxOperatorCallExpr(argumentCountIs(1),
+ callee(unresolvedLookupExpr()),
+ hasArgument(0, cxxThisExpr())))))));
+ const auto IsGoodAssign = cxxMethodDecl(IsAssign, HasGoodReturnType);
+
+ Finder->addMatcher(returnStmt(IsBadReturnStatement, forFunction(IsGoodAssign))
+ .bind("returnStmt"),
+ this);
+}
+
+void UnconventionalAssignOperatorCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ if (const auto *RetStmt = Result.Nodes.getNodeAs<ReturnStmt>("returnStmt")) {
+ diag(RetStmt->getLocStart(), "operator=() should always return '*this'");
+ } else {
+ static const char *const Messages[][2] = {
+ {"ReturnType", "operator=() should return '%0&'"},
+ {"ArgumentType", "operator=() should take '%0 const&', '%0&&' or '%0'"},
+ {"cv", "operator=() should not be marked '%1'"}};
+
+ const auto *Method = Result.Nodes.getNodeAs<CXXMethodDecl>("method");
+ for (const auto &Message : Messages) {
+ if (Result.Nodes.getNodeAs<Decl>(Message[0]))
+ diag(Method->getLocStart(), Message[1])
+ << Method->getParent()->getName()
+ << (Method->isConst() ? "const" : "virtual");
+ }
+ }
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.h
new file mode 100644
index 0000000..ee91dca
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnconventionalAssignOperatorCheck.h
@@ -0,0 +1,42 @@
+//===--- UnconventionalAssignOperatorCheck.h - clang-tidy -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSIGNOPERATORSIGNATURECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSIGNOPERATORSIGNATURECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Finds declarations of assignment operators with the wrong return and/or
+/// argument types and definitions with good return type but wrong return
+/// statements.
+///
+/// * The return type must be `Class&`.
+/// * Works with move-assign and assign by value.
+/// * Private and deleted operators are ignored.
+/// * The operator must always return ``*this``.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-unconventional-assign-operator.html
+class UnconventionalAssignOperatorCheck : public ClangTidyCheck {
+public:
+ UnconventionalAssignOperatorCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_ASSIGNOPERATORSIGNATURECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UniqueptrResetReleaseCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UniqueptrResetReleaseCheck.cpp
new file mode 100644
index 0000000..99758d3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UniqueptrResetReleaseCheck.cpp
@@ -0,0 +1,136 @@
+//===--- UniqueptrResetReleaseCheck.cpp - clang-tidy ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UniqueptrResetReleaseCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void UniqueptrResetReleaseCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++11; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ Finder->addMatcher(
+ cxxMemberCallExpr(
+ on(expr().bind("left")), callee(memberExpr().bind("reset_member")),
+ callee(
+ cxxMethodDecl(hasName("reset"),
+ ofClass(cxxRecordDecl(hasName("::std::unique_ptr"),
+ decl().bind("left_class"))))),
+ has(ignoringParenImpCasts(cxxMemberCallExpr(
+ on(expr().bind("right")),
+ callee(memberExpr().bind("release_member")),
+ callee(cxxMethodDecl(
+ hasName("release"),
+ ofClass(cxxRecordDecl(hasName("::std::unique_ptr"),
+ decl().bind("right_class")))))))))
+ .bind("reset_call"),
+ this);
+}
+
+namespace {
+const Type *getDeleterForUniquePtr(const MatchFinder::MatchResult &Result,
+ StringRef ID) {
+ const auto *Class =
+ Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(ID);
+ if (!Class)
+ return nullptr;
+ auto DeleterArgument = Class->getTemplateArgs()[1];
+ if (DeleterArgument.getKind() != TemplateArgument::Type)
+ return nullptr;
+ return DeleterArgument.getAsType().getTypePtr();
+}
+
+bool areDeletersCompatible(const MatchFinder::MatchResult &Result) {
+ const Type *LeftDeleterType = getDeleterForUniquePtr(Result, "left_class");
+ const Type *RightDeleterType = getDeleterForUniquePtr(Result, "right_class");
+
+ if (LeftDeleterType->getUnqualifiedDesugaredType() ==
+ RightDeleterType->getUnqualifiedDesugaredType()) {
+ // Same type. We assume they are compatible.
+ // This check handles the case where the deleters are function pointers.
+ return true;
+ }
+
+ const CXXRecordDecl *LeftDeleter = LeftDeleterType->getAsCXXRecordDecl();
+ const CXXRecordDecl *RightDeleter = RightDeleterType->getAsCXXRecordDecl();
+ if (!LeftDeleter || !RightDeleter)
+ return false;
+
+ if (LeftDeleter->getCanonicalDecl() == RightDeleter->getCanonicalDecl()) {
+ // Same class. We assume they are compatible.
+ return true;
+ }
+
+ const auto *LeftAsTemplate =
+ dyn_cast<ClassTemplateSpecializationDecl>(LeftDeleter);
+ const auto *RightAsTemplate =
+ dyn_cast<ClassTemplateSpecializationDecl>(RightDeleter);
+ if (LeftAsTemplate && RightAsTemplate &&
+ LeftAsTemplate->getSpecializedTemplate() ==
+ RightAsTemplate->getSpecializedTemplate()) {
+ // They are different instantiations of the same template. We assume they
+ // are compatible.
+ // This handles things like std::default_delete<Base> vs.
+ // std::default_delete<Derived>.
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+void UniqueptrResetReleaseCheck::check(const MatchFinder::MatchResult &Result) {
+ if (!areDeletersCompatible(Result))
+ return;
+
+ const auto *ResetMember = Result.Nodes.getNodeAs<MemberExpr>("reset_member");
+ const auto *ReleaseMember =
+ Result.Nodes.getNodeAs<MemberExpr>("release_member");
+ const auto *Right = Result.Nodes.getNodeAs<Expr>("right");
+ const auto *Left = Result.Nodes.getNodeAs<Expr>("left");
+ const auto *ResetCall =
+ Result.Nodes.getNodeAs<CXXMemberCallExpr>("reset_call");
+
+ std::string LeftText = clang::Lexer::getSourceText(
+ CharSourceRange::getTokenRange(Left->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ std::string RightText = clang::Lexer::getSourceText(
+ CharSourceRange::getTokenRange(Right->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+
+ if (ResetMember->isArrow())
+ LeftText = "*" + LeftText;
+ if (ReleaseMember->isArrow())
+ RightText = "*" + RightText;
+ std::string DiagText;
+ // Even if x was rvalue, *x is not rvalue anymore.
+ if (!Right->isRValue() || ReleaseMember->isArrow()) {
+ RightText = "std::move(" + RightText + ")";
+ DiagText = "prefer ptr1 = std::move(ptr2) over ptr1.reset(ptr2.release())";
+ } else {
+ DiagText =
+ "prefer ptr = ReturnUnique() over ptr.reset(ReturnUnique().release())";
+ }
+ std::string NewText = LeftText + " = " + RightText;
+
+ diag(ResetMember->getExprLoc(), DiagText) << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(ResetCall->getSourceRange()), NewText);
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UniqueptrResetReleaseCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UniqueptrResetReleaseCheck.h
new file mode 100644
index 0000000..cf18a5a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UniqueptrResetReleaseCheck.h
@@ -0,0 +1,43 @@
+//===--- UniqueptrResetReleaseCheck.h - clang-tidy --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNIQUEPTRRESETRELEASECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNIQUEPTRRESETRELEASECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Find and replace `unique_ptr::reset(release())` with `std::move()`.
+///
+/// Example:
+///
+/// \code
+/// std::unique_ptr<Foo> x, y;
+/// x.reset(y.release()); -> x = std::move(y);
+/// \endcode
+///
+/// If `y` is already rvalue, `std::move()` is not added. `x` and `y` can also
+/// be `std::unique_ptr<Foo>*`.
+class UniqueptrResetReleaseCheck : public ClangTidyCheck {
+public:
+ UniqueptrResetReleaseCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNIQUEPTRRESETRELEASECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp
new file mode 100644
index 0000000..07165d6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp
@@ -0,0 +1,64 @@
+//===--- UnusedAliasDeclsCheck.cpp - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnusedAliasDeclsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void UnusedAliasDeclsCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++11; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ // We cannot do anything about headers (yet), as the alias declarations
+ // used in one header could be used by some other translation unit.
+ Finder->addMatcher(namespaceAliasDecl(isExpansionInMainFile()).bind("alias"),
+ this);
+ Finder->addMatcher(nestedNameSpecifier().bind("nns"), this);
+}
+
+void UnusedAliasDeclsCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *AliasDecl = Result.Nodes.getNodeAs<NamedDecl>("alias")) {
+ FoundDecls[AliasDecl] = CharSourceRange::getCharRange(
+ AliasDecl->getLocStart(),
+ Lexer::findLocationAfterToken(
+ AliasDecl->getLocEnd(), tok::semi, *Result.SourceManager,
+ getLangOpts(),
+ /*SkipTrailingWhitespaceAndNewLine=*/true));
+ return;
+ }
+
+ if (const auto *NestedName =
+ Result.Nodes.getNodeAs<NestedNameSpecifier>("nns")) {
+ if (const auto *AliasDecl = NestedName->getAsNamespaceAlias()) {
+ FoundDecls[AliasDecl] = CharSourceRange();
+ }
+ }
+}
+
+void UnusedAliasDeclsCheck::onEndOfTranslationUnit() {
+ for (const auto &FoundDecl : FoundDecls) {
+ if (!FoundDecl.second.isValid())
+ continue;
+ diag(FoundDecl.first->getLocation(), "namespace alias decl %0 is unused")
+ << FoundDecl.first << FixItHint::CreateRemoval(FoundDecl.second);
+ }
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.h
new file mode 100644
index 0000000..8cce3756
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.h
@@ -0,0 +1,37 @@
+//===--- UnusedAliasDeclsCheck.h - clang-tidy--------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSED_ALIAS_DECLS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSED_ALIAS_DECLS_H
+
+#include "../ClangTidy.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Finds unused namespace alias declarations.
+class UnusedAliasDeclsCheck : public ClangTidyCheck {
+public:
+ UnusedAliasDeclsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void onEndOfTranslationUnit() override;
+
+private:
+ llvm::DenseMap<const NamedDecl *, CharSourceRange> FoundDecls;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSED_ALIAS_DECLS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
new file mode 100644
index 0000000..1e342d1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp
@@ -0,0 +1,193 @@
+//===--- UnusedParametersCheck.cpp - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnusedParametersCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/STLExtras.h"
+#include <unordered_set>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+namespace {
+bool isOverrideMethod(const FunctionDecl *Function) {
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(Function))
+ return MD->size_overridden_methods() > 0 || MD->hasAttr<OverrideAttr>();
+ return false;
+}
+} // namespace
+
+void UnusedParametersCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ functionDecl(isDefinition(), hasBody(stmt()), hasAnyParameter(decl()))
+ .bind("function"),
+ this);
+}
+
+template <typename T>
+static CharSourceRange removeNode(const MatchFinder::MatchResult &Result,
+ const T *PrevNode, const T *Node,
+ const T *NextNode) {
+ if (NextNode)
+ return CharSourceRange::getCharRange(Node->getLocStart(),
+ NextNode->getLocStart());
+
+ if (PrevNode)
+ return CharSourceRange::getTokenRange(
+ Lexer::getLocForEndOfToken(PrevNode->getLocEnd(), 0,
+ *Result.SourceManager,
+ Result.Context->getLangOpts()),
+ Node->getLocEnd());
+
+ return CharSourceRange::getTokenRange(Node->getSourceRange());
+}
+
+static FixItHint removeParameter(const MatchFinder::MatchResult &Result,
+ const FunctionDecl *Function, unsigned Index) {
+ return FixItHint::CreateRemoval(removeNode(
+ Result, Index > 0 ? Function->getParamDecl(Index - 1) : nullptr,
+ Function->getParamDecl(Index),
+ Index + 1 < Function->getNumParams() ? Function->getParamDecl(Index + 1)
+ : nullptr));
+}
+
+static FixItHint removeArgument(const MatchFinder::MatchResult &Result,
+ const CallExpr *Call, unsigned Index) {
+ return FixItHint::CreateRemoval(removeNode(
+ Result, Index > 0 ? Call->getArg(Index - 1) : nullptr,
+ Call->getArg(Index),
+ Index + 1 < Call->getNumArgs() ? Call->getArg(Index + 1) : nullptr));
+}
+
+class UnusedParametersCheck::IndexerVisitor
+ : public RecursiveASTVisitor<IndexerVisitor> {
+public:
+ IndexerVisitor(TranslationUnitDecl *Top) { TraverseDecl(Top); }
+
+ const std::unordered_set<const CallExpr *> &
+ getFnCalls(const FunctionDecl *Fn) {
+ return Index[Fn->getCanonicalDecl()].Calls;
+ }
+
+ const std::unordered_set<const DeclRefExpr *> &
+ getOtherRefs(const FunctionDecl *Fn) {
+ return Index[Fn->getCanonicalDecl()].OtherRefs;
+ }
+
+ bool shouldTraversePostOrder() const { return true; }
+
+ bool WalkUpFromDeclRefExpr(DeclRefExpr *DeclRef) {
+ if (const auto *Fn = dyn_cast<FunctionDecl>(DeclRef->getDecl())) {
+ Fn = Fn->getCanonicalDecl();
+ Index[Fn].OtherRefs.insert(DeclRef);
+ }
+ return true;
+ }
+
+ bool WalkUpFromCallExpr(CallExpr *Call) {
+ if (const auto *Fn =
+ dyn_cast_or_null<FunctionDecl>(Call->getCalleeDecl())) {
+ Fn = Fn->getCanonicalDecl();
+ if (const auto *Ref =
+ dyn_cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit())) {
+ Index[Fn].OtherRefs.erase(Ref);
+ }
+ Index[Fn].Calls.insert(Call);
+ }
+ return true;
+ }
+
+private:
+ struct IndexEntry {
+ std::unordered_set<const CallExpr *> Calls;
+ std::unordered_set<const DeclRefExpr *> OtherRefs;
+ };
+
+ std::unordered_map<const FunctionDecl *, IndexEntry> Index;
+};
+
+UnusedParametersCheck::~UnusedParametersCheck() = default;
+
+UnusedParametersCheck::UnusedParametersCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ StrictMode(Options.getLocalOrGlobal("StrictMode", 0) != 0) {}
+
+void UnusedParametersCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "StrictMode", StrictMode);
+}
+
+void UnusedParametersCheck::warnOnUnusedParameter(
+ const MatchFinder::MatchResult &Result, const FunctionDecl *Function,
+ unsigned ParamIndex) {
+ const auto *Param = Function->getParamDecl(ParamIndex);
+ auto MyDiag = diag(Param->getLocation(), "parameter %0 is unused") << Param;
+
+ if (!Indexer) {
+ Indexer = llvm::make_unique<IndexerVisitor>(
+ Result.Context->getTranslationUnitDecl());
+ }
+
+ // Comment out parameter name for non-local functions.
+ if (Function->isExternallyVisible() ||
+ !Result.SourceManager->isInMainFile(Function->getLocation()) ||
+ !Indexer->getOtherRefs(Function).empty() || isOverrideMethod(Function)) {
+ SourceRange RemovalRange(Param->getLocation());
+ // Note: We always add a space before the '/*' to not accidentally create a
+ // '*/*' for pointer types, which doesn't start a comment. clang-format will
+ // clean this up afterwards.
+ MyDiag << FixItHint::CreateReplacement(
+ RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
+ return;
+ }
+
+ // Fix all redeclarations.
+ for (const FunctionDecl *FD : Function->redecls())
+ if (FD->param_size())
+ MyDiag << removeParameter(Result, FD, ParamIndex);
+
+ // Fix all call sites.
+ for (const CallExpr *Call : Indexer->getFnCalls(Function))
+ if (ParamIndex < Call->getNumArgs()) // See PR38055 for example.
+ MyDiag << removeArgument(Result, Call, ParamIndex);
+}
+
+void UnusedParametersCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>("function");
+ if (!Function->hasWrittenPrototype() || Function->isTemplateInstantiation())
+ return;
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(Function))
+ if (Method->isLambdaStaticInvoker())
+ return;
+ for (unsigned i = 0, e = Function->getNumParams(); i != e; ++i) {
+ const auto *Param = Function->getParamDecl(i);
+ if (Param->isUsed() || Param->isReferenced() || !Param->getDeclName() ||
+ Param->hasAttr<UnusedAttr>())
+ continue;
+
+ // In non-strict mode ignore function definitions with empty bodies
+ // (constructor initializer counts for non-empty body).
+ if (StrictMode ||
+ (Function->getBody()->child_begin() !=
+ Function->getBody()->child_end()) ||
+ (isa<CXXConstructorDecl>(Function) &&
+ cast<CXXConstructorDecl>(Function)->getNumCtorInitializers() > 0))
+ warnOnUnusedParameter(Result, Function, i);
+ }
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.h
new file mode 100644
index 0000000..b9bae26
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.h
@@ -0,0 +1,43 @@
+//===--- UnusedParametersCheck.h - clang-tidy--------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSED_PARAMETERS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSED_PARAMETERS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Finds unused parameters and fixes them, so that `-Wunused-parameter` can be
+/// turned on.
+class UnusedParametersCheck : public ClangTidyCheck {
+public:
+ UnusedParametersCheck(StringRef Name, ClangTidyContext *Context);
+ ~UnusedParametersCheck();
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ const bool StrictMode;
+ class IndexerVisitor;
+ std::unique_ptr<IndexerVisitor> Indexer;
+
+ void
+ warnOnUnusedParameter(const ast_matchers::MatchFinder::MatchResult &Result,
+ const FunctionDecl *Function, unsigned ParamIndex);
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSED_PARAMETERS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
new file mode 100644
index 0000000..b3eabdc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp
@@ -0,0 +1,167 @@
+//===--- UnusedUsingDeclsCheck.cpp - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnusedUsingDeclsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+// A function that helps to tell whether a TargetDecl in a UsingDecl will be
+// checked. Only variable, function, function template, class template, class,
+// enum declaration and enum constant declaration are considered.
+static bool ShouldCheckDecl(const Decl *TargetDecl) {
+ return isa<RecordDecl>(TargetDecl) || isa<ClassTemplateDecl>(TargetDecl) ||
+ isa<FunctionDecl>(TargetDecl) || isa<VarDecl>(TargetDecl) ||
+ isa<FunctionTemplateDecl>(TargetDecl) || isa<EnumDecl>(TargetDecl) ||
+ isa<EnumConstantDecl>(TargetDecl);
+}
+
+void UnusedUsingDeclsCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(usingDecl(isExpansionInMainFile()).bind("using"), this);
+ auto DeclMatcher = hasDeclaration(namedDecl().bind("used"));
+ Finder->addMatcher(loc(enumType(DeclMatcher)), this);
+ Finder->addMatcher(loc(recordType(DeclMatcher)), this);
+ Finder->addMatcher(loc(templateSpecializationType(DeclMatcher)), this);
+ Finder->addMatcher(declRefExpr().bind("used"), this);
+ Finder->addMatcher(callExpr(callee(unresolvedLookupExpr().bind("used"))),
+ this);
+ Finder->addMatcher(
+ callExpr(hasDeclaration(functionDecl(hasAnyTemplateArgument(
+ anyOf(refersToTemplate(templateName().bind("used")),
+ refersToDeclaration(functionDecl().bind("used"))))))),
+ this);
+ Finder->addMatcher(loc(templateSpecializationType(hasAnyTemplateArgument(
+ templateArgument().bind("used")))),
+ this);
+}
+
+void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) {
+ if (Result.Context->getDiagnostics().hasUncompilableErrorOccurred())
+ return;
+
+ if (const auto *Using = Result.Nodes.getNodeAs<UsingDecl>("using")) {
+ // Ignores using-declarations defined in macros.
+ if (Using->getLocation().isMacroID())
+ return;
+
+ // Ignores using-declarations defined in class definition.
+ if (isa<CXXRecordDecl>(Using->getDeclContext()))
+ return;
+
+ // FIXME: We ignore using-decls defined in function definitions at the
+ // moment because of false positives caused by ADL and different function
+ // scopes.
+ if (isa<FunctionDecl>(Using->getDeclContext()))
+ return;
+
+ UsingDeclContext Context(Using);
+ Context.UsingDeclRange = CharSourceRange::getCharRange(
+ Using->getLocStart(),
+ Lexer::findLocationAfterToken(
+ Using->getLocEnd(), tok::semi, *Result.SourceManager, getLangOpts(),
+ /*SkipTrailingWhitespaceAndNewLine=*/true));
+ for (const auto *UsingShadow : Using->shadows()) {
+ const auto *TargetDecl = UsingShadow->getTargetDecl()->getCanonicalDecl();
+ if (ShouldCheckDecl(TargetDecl))
+ Context.UsingTargetDecls.insert(TargetDecl);
+ }
+ if (!Context.UsingTargetDecls.empty())
+ Contexts.push_back(Context);
+ return;
+ }
+ // Mark using declarations as used by setting FoundDecls' value to zero. As
+ // the AST is walked in order, usages are only marked after a the
+ // corresponding using declaration has been found.
+ // FIXME: This currently doesn't look at whether the type reference is
+ // actually found with the help of the using declaration.
+ if (const auto *Used = Result.Nodes.getNodeAs<NamedDecl>("used")) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(Used)) {
+ removeFromFoundDecls(FD->getPrimaryTemplate());
+ } else if (const auto *Specialization =
+ dyn_cast<ClassTemplateSpecializationDecl>(Used)) {
+ Used = Specialization->getSpecializedTemplate();
+ }
+ removeFromFoundDecls(Used);
+ return;
+ }
+
+ if (const auto *Used = Result.Nodes.getNodeAs<TemplateArgument>("used")) {
+ // FIXME: Support non-type template parameters.
+ if (Used->getKind() == TemplateArgument::Template) {
+ if (const auto *TD = Used->getAsTemplate().getAsTemplateDecl())
+ removeFromFoundDecls(TD);
+ } else if (Used->getKind() == TemplateArgument::Type) {
+ if (auto *RD = Used->getAsType()->getAsCXXRecordDecl())
+ removeFromFoundDecls(RD);
+ }
+ return;
+ }
+
+ if (const auto *Used = Result.Nodes.getNodeAs<TemplateName>("used")) {
+ removeFromFoundDecls(Used->getAsTemplateDecl());
+ return;
+ }
+
+ if (const auto *DRE = Result.Nodes.getNodeAs<DeclRefExpr>("used")) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
+ if (const auto *FDT = FD->getPrimaryTemplate())
+ removeFromFoundDecls(FDT);
+ else
+ removeFromFoundDecls(FD);
+ } else if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ removeFromFoundDecls(VD);
+ } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
+ removeFromFoundDecls(ECD);
+ if (const auto *ET = ECD->getType()->getAs<EnumType>())
+ removeFromFoundDecls(ET->getDecl());
+ }
+ }
+ // Check the uninstantiated template function usage.
+ if (const auto *ULE = Result.Nodes.getNodeAs<UnresolvedLookupExpr>("used")) {
+ for (const NamedDecl *ND : ULE->decls()) {
+ if (const auto *USD = dyn_cast<UsingShadowDecl>(ND))
+ removeFromFoundDecls(USD->getTargetDecl()->getCanonicalDecl());
+ }
+ }
+}
+
+void UnusedUsingDeclsCheck::removeFromFoundDecls(const Decl *D) {
+ if (!D)
+ return;
+ // FIXME: Currently, we don't handle the using-decls being used in different
+ // scopes (such as different namespaces, different functions). Instead of
+ // giving an incorrect message, we mark all of them as used.
+ //
+ // FIXME: Use a more efficient way to find a matching context.
+ for (auto &Context : Contexts) {
+ if (Context.UsingTargetDecls.count(D->getCanonicalDecl()) > 0)
+ Context.IsUsed = true;
+ }
+}
+
+void UnusedUsingDeclsCheck::onEndOfTranslationUnit() {
+ for (const auto &Context : Contexts) {
+ if (!Context.IsUsed) {
+ diag(Context.FoundUsingDecl->getLocation(), "using decl %0 is unused")
+ << Context.FoundUsingDecl
+ << FixItHint::CreateRemoval(Context.UsingDeclRange);
+ }
+ }
+ Contexts.clear();
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.h
new file mode 100644
index 0000000..2a41a8f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.h
@@ -0,0 +1,58 @@
+//===--- UnusedUsingDeclsCheck.h - clang-tidy--------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSED_USING_DECLS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSED_USING_DECLS_H
+
+#include "../ClangTidy.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include <vector>
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Finds unused using declarations.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-unused-using-decls.html
+class UnusedUsingDeclsCheck : public ClangTidyCheck {
+public:
+ UnusedUsingDeclsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void onEndOfTranslationUnit() override;
+
+private:
+ void removeFromFoundDecls(const Decl *D);
+
+ struct UsingDeclContext {
+ explicit UsingDeclContext(const UsingDecl *FoundUsingDecl)
+ : FoundUsingDecl(FoundUsingDecl), IsUsed(false) {}
+ // A set saves all UsingShadowDecls introduced by a UsingDecl. A UsingDecl
+ // can introduce multiple UsingShadowDecls in some cases (such as
+ // overloaded functions).
+ llvm::SmallPtrSet<const Decl *, 4> UsingTargetDecls;
+ // The original UsingDecl.
+ const UsingDecl *FoundUsingDecl;
+ // The source range of the UsingDecl.
+ CharSourceRange UsingDeclRange;
+ // Whether the UsingDecl is used.
+ bool IsUsed;
+ };
+
+ std::vector<UsingDeclContext> Contexts;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSED_USING_DECLS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.cpp
new file mode 100644
index 0000000..7cdbb66
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.cpp
@@ -0,0 +1,181 @@
+//===--- AvoidBindCheck.cpp - clang-tidy-----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AvoidBindCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstddef>
+#include <string>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+namespace {
+
+enum BindArgumentKind { BK_Temporary, BK_Placeholder, BK_CallExpr, BK_Other };
+
+struct BindArgument {
+ StringRef Tokens;
+ BindArgumentKind Kind = BK_Other;
+ size_t PlaceHolderIndex = 0;
+};
+
+} // end namespace
+
+static SmallVector<BindArgument, 4>
+buildBindArguments(const MatchFinder::MatchResult &Result, const CallExpr *C) {
+ SmallVector<BindArgument, 4> BindArguments;
+ llvm::Regex MatchPlaceholder("^_([0-9]+)$");
+
+ // Start at index 1 as first argument to bind is the function name.
+ for (size_t I = 1, ArgCount = C->getNumArgs(); I < ArgCount; ++I) {
+ const Expr *E = C->getArg(I);
+ BindArgument B;
+ if (const auto *M = dyn_cast<MaterializeTemporaryExpr>(E)) {
+ const auto *TE = M->GetTemporaryExpr();
+ B.Kind = isa<CallExpr>(TE) ? BK_CallExpr : BK_Temporary;
+ }
+
+ B.Tokens = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(E->getLocStart(), E->getLocEnd()),
+ *Result.SourceManager, Result.Context->getLangOpts());
+
+ SmallVector<StringRef, 2> Matches;
+ if (B.Kind == BK_Other && MatchPlaceholder.match(B.Tokens, &Matches)) {
+ B.Kind = BK_Placeholder;
+ B.PlaceHolderIndex = std::stoi(Matches[1]);
+ }
+ BindArguments.push_back(B);
+ }
+ return BindArguments;
+}
+
+static void addPlaceholderArgs(const ArrayRef<BindArgument> Args,
+ llvm::raw_ostream &Stream) {
+ auto MaxPlaceholderIt =
+ std::max_element(Args.begin(), Args.end(),
+ [](const BindArgument &B1, const BindArgument &B2) {
+ return B1.PlaceHolderIndex < B2.PlaceHolderIndex;
+ });
+
+ // Placeholders (if present) have index 1 or greater.
+ if (MaxPlaceholderIt == Args.end() || MaxPlaceholderIt->PlaceHolderIndex == 0)
+ return;
+
+ size_t PlaceholderCount = MaxPlaceholderIt->PlaceHolderIndex;
+ Stream << "(";
+ StringRef Delimiter = "";
+ for (size_t I = 1; I <= PlaceholderCount; ++I) {
+ Stream << Delimiter << "auto && arg" << I;
+ Delimiter = ", ";
+ }
+ Stream << ")";
+}
+
+static void addFunctionCallArgs(const ArrayRef<BindArgument> Args,
+ llvm::raw_ostream &Stream) {
+ StringRef Delimiter = "";
+ for (const auto &B : Args) {
+ if (B.PlaceHolderIndex)
+ Stream << Delimiter << "arg" << B.PlaceHolderIndex;
+ else
+ Stream << Delimiter << B.Tokens;
+ Delimiter = ", ";
+ }
+}
+
+static bool isPlaceHolderIndexRepeated(const ArrayRef<BindArgument> Args) {
+ llvm::SmallSet<size_t, 4> PlaceHolderIndices;
+ for (const BindArgument &B : Args) {
+ if (B.PlaceHolderIndex) {
+ if (!PlaceHolderIndices.insert(B.PlaceHolderIndex).second)
+ return true;
+ }
+ }
+ return false;
+}
+
+void AvoidBindCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus14) // Need C++14 for generic lambdas.
+ return;
+
+ Finder->addMatcher(
+ callExpr(
+ callee(namedDecl(hasName("::std::bind"))),
+ hasArgument(0, declRefExpr(to(functionDecl().bind("f"))).bind("ref")))
+ .bind("bind"),
+ this);
+}
+
+void AvoidBindCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<CallExpr>("bind");
+ auto Diag = diag(MatchedDecl->getLocStart(), "prefer a lambda to std::bind");
+
+ const auto Args = buildBindArguments(Result, MatchedDecl);
+
+ // Do not attempt to create fixits for nested call expressions.
+ // FIXME: Create lambda capture variables to capture output of calls.
+ // NOTE: Supporting nested std::bind will be more difficult due to placeholder
+ // sharing between outer and inner std:bind invocations.
+ if (llvm::any_of(Args,
+ [](const BindArgument &B) { return B.Kind == BK_CallExpr; }))
+ return;
+
+ // Do not attempt to create fixits when placeholders are reused.
+ // Unused placeholders are supported by requiring C++14 generic lambdas.
+ // FIXME: Support this case by deducing the common type.
+ if (isPlaceHolderIndexRepeated(Args))
+ return;
+
+ const auto *F = Result.Nodes.getNodeAs<FunctionDecl>("f");
+
+ // std::bind can support argument count mismatch between its arguments and the
+ // bound function's arguments. Do not attempt to generate a fixit for such
+ // cases.
+ // FIXME: Support this case by creating unused lambda capture variables.
+ if (F->getNumParams() != Args.size())
+ return;
+
+ std::string Buffer;
+ llvm::raw_string_ostream Stream(Buffer);
+
+ bool HasCapturedArgument = llvm::any_of(
+ Args, [](const BindArgument &B) { return B.Kind == BK_Other; });
+ const auto *Ref = Result.Nodes.getNodeAs<DeclRefExpr>("ref");
+ Stream << "[" << (HasCapturedArgument ? "=" : "") << "]";
+ addPlaceholderArgs(Args, Stream);
+ Stream << " { return ";
+ Ref->printPretty(Stream, nullptr, Result.Context->getPrintingPolicy());
+ Stream << "(";
+ addFunctionCallArgs(Args, Stream);
+ Stream << "); };";
+
+ Diag << FixItHint::CreateReplacement(MatchedDecl->getSourceRange(),
+ Stream.str());
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.h
new file mode 100644
index 0000000..5ae0241
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/AvoidBindCheck.h
@@ -0,0 +1,36 @@
+//===--- AvoidBindCheck.h - clang-tidy---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_AVOID_BIND_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_AVOID_BIND_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Replace simple uses of std::bind with a lambda.
+///
+/// FIXME: Add support for function references and member function references.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-avoid-std-bind.html
+class AvoidBindCheck : public ClangTidyCheck {
+public:
+ AvoidBindCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_AVOID_BIND_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
new file mode 100644
index 0000000..f02b2ae
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -0,0 +1,42 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyModernizeModule
+ AvoidBindCheck.cpp
+ DeprecatedHeadersCheck.cpp
+ LoopConvertCheck.cpp
+ LoopConvertUtils.cpp
+ MakeSmartPtrCheck.cpp
+ MakeSharedCheck.cpp
+ MakeUniqueCheck.cpp
+ ModernizeTidyModule.cpp
+ PassByValueCheck.cpp
+ RawStringLiteralCheck.cpp
+ RedundantVoidArgCheck.cpp
+ ReplaceAutoPtrCheck.cpp
+ ReplaceRandomShuffleCheck.cpp
+ ReturnBracedInitListCheck.cpp
+ ShrinkToFitCheck.cpp
+ UnaryStaticAssertCheck.cpp
+ UseAutoCheck.cpp
+ UseBoolLiteralsCheck.cpp
+ UseDefaultMemberInitCheck.cpp
+ UseEmplaceCheck.cpp
+ UseEqualsDefaultCheck.cpp
+ UseEqualsDeleteCheck.cpp
+ UseNoexceptCheck.cpp
+ UseNullptrCheck.cpp
+ UseOverrideCheck.cpp
+ UseTransparentFunctorsCheck.cpp
+ UseUncaughtExceptionsCheck.cpp
+ UseUsingCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyReadabilityModule
+ clangTidyUtils
+ clangTooling
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.cpp
new file mode 100644
index 0000000..1ff3f89
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.cpp
@@ -0,0 +1,125 @@
+//===--- DeprecatedHeadersCheck.cpp - clang-tidy---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DeprecatedHeadersCheck.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
+
+#include <vector>
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+namespace {
+class IncludeModernizePPCallbacks : public PPCallbacks {
+public:
+ explicit IncludeModernizePPCallbacks(ClangTidyCheck &Check,
+ LangOptions LangOpts);
+
+ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath,
+ const Module *Imported,
+ SrcMgr::CharacteristicKind FileType) override;
+
+private:
+ ClangTidyCheck &Check;
+ LangOptions LangOpts;
+ llvm::StringMap<std::string> CStyledHeaderToCxx;
+ llvm::StringSet<> DeleteHeaders;
+};
+} // namespace
+
+void DeprecatedHeadersCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+ if (this->getLangOpts().CPlusPlus) {
+ Compiler.getPreprocessor().addPPCallbacks(
+ ::llvm::make_unique<IncludeModernizePPCallbacks>(*this,
+ this->getLangOpts()));
+ }
+}
+
+IncludeModernizePPCallbacks::IncludeModernizePPCallbacks(ClangTidyCheck &Check,
+ LangOptions LangOpts)
+ : Check(Check), LangOpts(LangOpts) {
+ for (const auto &KeyValue :
+ std::vector<std::pair<llvm::StringRef, std::string>>(
+ {{"assert.h", "cassert"},
+ {"complex.h", "complex"},
+ {"ctype.h", "cctype"},
+ {"errno.h", "cerrno"},
+ {"float.h", "cfloat"},
+ {"limits.h", "climits"},
+ {"locale.h", "clocale"},
+ {"math.h", "cmath"},
+ {"setjmp.h", "csetjmp"},
+ {"signal.h", "csignal"},
+ {"stdarg.h", "cstdarg"},
+ {"stddef.h", "cstddef"},
+ {"stdio.h", "cstdio"},
+ {"stdlib.h", "cstdlib"},
+ {"string.h", "cstring"},
+ {"time.h", "ctime"},
+ {"wchar.h", "cwchar"},
+ {"wctype.h", "cwctype"}})) {
+ CStyledHeaderToCxx.insert(KeyValue);
+ }
+ // Add C++ 11 headers.
+ if (LangOpts.CPlusPlus11) {
+ for (const auto &KeyValue :
+ std::vector<std::pair<llvm::StringRef, std::string>>(
+ {{"fenv.h", "cfenv"},
+ {"stdint.h", "cstdint"},
+ {"inttypes.h", "cinttypes"},
+ {"tgmath.h", "ctgmath"},
+ {"uchar.h", "cuchar"}})) {
+ CStyledHeaderToCxx.insert(KeyValue);
+ }
+ }
+ for (const auto &Key :
+ std::vector<std::string>({"stdalign.h", "stdbool.h", "iso646.h"})) {
+ DeleteHeaders.insert(Key);
+ }
+}
+
+void IncludeModernizePPCallbacks::InclusionDirective(
+ SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
+ bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath, const Module *Imported,
+ SrcMgr::CharacteristicKind FileType) {
+ // FIXME: Take care of library symbols from the global namespace.
+ //
+ // Reasonable options for the check:
+ //
+ // 1. Insert std prefix for every such symbol occurrence.
+ // 2. Insert `using namespace std;` to the beginning of TU.
+ // 3. Do nothing and let the user deal with the migration himself.
+ if (CStyledHeaderToCxx.count(FileName) != 0) {
+ std::string Replacement =
+ (llvm::Twine("<") + CStyledHeaderToCxx[FileName] + ">").str();
+ Check.diag(FilenameRange.getBegin(), "inclusion of deprecated C++ header "
+ "'%0'; consider using '%1' instead")
+ << FileName << CStyledHeaderToCxx[FileName]
+ << FixItHint::CreateReplacement(FilenameRange.getAsRange(),
+ Replacement);
+ } else if (DeleteHeaders.count(FileName) != 0) {
+ Check.diag(FilenameRange.getBegin(),
+ "including '%0' has no effect in C++; consider removing it")
+ << FileName << FixItHint::CreateRemoval(
+ SourceRange(HashLoc, FilenameRange.getEnd()));
+ }
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.h
new file mode 100644
index 0000000..ee7254e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/DeprecatedHeadersCheck.h
@@ -0,0 +1,47 @@
+//===--- DeprecatedHeadersCheck.h - clang-tidy-------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_C_HEADERS_TO_CXX_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_C_HEADERS_TO_CXX_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// This check replaces deprecated C library headers with their C++ STL
+/// alternatives.
+///
+/// Before:
+/// ~~~{.cpp}
+/// #include <header.h>
+/// ~~~
+///
+/// After:
+/// ~~~{.cpp}
+/// #include <cheader>
+/// ~~~
+///
+/// Example: ``<stdio.h> => <cstdio>``
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-deprecated-headers.html
+class DeprecatedHeadersCheck : public ClangTidyCheck {
+public:
+ DeprecatedHeadersCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_C_HEADERS_TO_CXX_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
new file mode 100644
index 0000000..54bf941
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
@@ -0,0 +1,920 @@
+//===--- LoopConvertCheck.cpp - clang-tidy---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LoopConvertCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Casting.h"
+#include <cassert>
+#include <cstring>
+#include <utility>
+
+using namespace clang::ast_matchers;
+using namespace llvm;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+static const char LoopNameArray[] = "forLoopArray";
+static const char LoopNameIterator[] = "forLoopIterator";
+static const char LoopNamePseudoArray[] = "forLoopPseudoArray";
+static const char ConditionBoundName[] = "conditionBound";
+static const char ConditionVarName[] = "conditionVar";
+static const char IncrementVarName[] = "incrementVar";
+static const char InitVarName[] = "initVar";
+static const char BeginCallName[] = "beginCall";
+static const char EndCallName[] = "endCall";
+static const char ConditionEndVarName[] = "conditionEndVar";
+static const char EndVarName[] = "endVar";
+static const char DerefByValueResultName[] = "derefByValueResult";
+static const char DerefByRefResultName[] = "derefByRefResult";
+
+// shared matchers
+static const TypeMatcher AnyType = anything();
+
+static const StatementMatcher IntegerComparisonMatcher =
+ expr(ignoringParenImpCasts(
+ declRefExpr(to(varDecl(hasType(isInteger())).bind(ConditionVarName)))));
+
+static const DeclarationMatcher InitToZeroMatcher =
+ varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral(equals(0)))))
+ .bind(InitVarName);
+
+static const StatementMatcher IncrementVarMatcher =
+ declRefExpr(to(varDecl(hasType(isInteger())).bind(IncrementVarName)));
+
+/// \brief The matcher for loops over arrays.
+///
+/// In this general example, assuming 'j' and 'k' are of integral type:
+/// \code
+/// for (int i = 0; j < 3 + 2; ++k) { ... }
+/// \endcode
+/// The following string identifiers are bound to these parts of the AST:
+/// ConditionVarName: 'j' (as a VarDecl)
+/// ConditionBoundName: '3 + 2' (as an Expr)
+/// InitVarName: 'i' (as a VarDecl)
+/// IncrementVarName: 'k' (as a VarDecl)
+/// LoopName: The entire for loop (as a ForStmt)
+///
+/// Client code will need to make sure that:
+/// - The three index variables identified by the matcher are the same
+/// VarDecl.
+/// - The index variable is only used as an array index.
+/// - All arrays indexed by the loop are the same.
+StatementMatcher makeArrayLoopMatcher() {
+ StatementMatcher ArrayBoundMatcher =
+ expr(hasType(isInteger())).bind(ConditionBoundName);
+
+ return forStmt(
+ unless(isInTemplateInstantiation()),
+ hasLoopInit(declStmt(hasSingleDecl(InitToZeroMatcher))),
+ hasCondition(anyOf(
+ binaryOperator(hasOperatorName("<"),
+ hasLHS(IntegerComparisonMatcher),
+ hasRHS(ArrayBoundMatcher)),
+ binaryOperator(hasOperatorName(">"), hasLHS(ArrayBoundMatcher),
+ hasRHS(IntegerComparisonMatcher)))),
+ hasIncrement(unaryOperator(hasOperatorName("++"),
+ hasUnaryOperand(IncrementVarMatcher))))
+ .bind(LoopNameArray);
+}
+
+/// \brief The matcher used for iterator-based for loops.
+///
+/// This matcher is more flexible than array-based loops. It will match
+/// catch loops of the following textual forms (regardless of whether the
+/// iterator type is actually a pointer type or a class type):
+///
+/// Assuming f, g, and h are of type containerType::iterator,
+/// \code
+/// for (containerType::iterator it = container.begin(),
+/// e = createIterator(); f != g; ++h) { ... }
+/// for (containerType::iterator it = container.begin();
+/// f != anotherContainer.end(); ++h) { ... }
+/// \endcode
+/// The following string identifiers are bound to the parts of the AST:
+/// InitVarName: 'it' (as a VarDecl)
+/// ConditionVarName: 'f' (as a VarDecl)
+/// LoopName: The entire for loop (as a ForStmt)
+/// In the first example only:
+/// EndVarName: 'e' (as a VarDecl)
+/// ConditionEndVarName: 'g' (as a VarDecl)
+/// In the second example only:
+/// EndCallName: 'container.end()' (as a CXXMemberCallExpr)
+///
+/// Client code will need to make sure that:
+/// - The iterator variables 'it', 'f', and 'h' are the same.
+/// - The two containers on which 'begin' and 'end' are called are the same.
+/// - If the end iterator variable 'g' is defined, it is the same as 'f'.
+StatementMatcher makeIteratorLoopMatcher() {
+ StatementMatcher BeginCallMatcher =
+ cxxMemberCallExpr(
+ argumentCountIs(0),
+ callee(cxxMethodDecl(anyOf(hasName("begin"), hasName("cbegin")))))
+ .bind(BeginCallName);
+
+ DeclarationMatcher InitDeclMatcher =
+ varDecl(hasInitializer(anyOf(ignoringParenImpCasts(BeginCallMatcher),
+ materializeTemporaryExpr(
+ ignoringParenImpCasts(BeginCallMatcher)),
+ hasDescendant(BeginCallMatcher))))
+ .bind(InitVarName);
+
+ DeclarationMatcher EndDeclMatcher =
+ varDecl(hasInitializer(anything())).bind(EndVarName);
+
+ StatementMatcher EndCallMatcher = cxxMemberCallExpr(
+ argumentCountIs(0),
+ callee(cxxMethodDecl(anyOf(hasName("end"), hasName("cend")))));
+
+ StatementMatcher IteratorBoundMatcher =
+ expr(anyOf(ignoringParenImpCasts(
+ declRefExpr(to(varDecl().bind(ConditionEndVarName)))),
+ ignoringParenImpCasts(expr(EndCallMatcher).bind(EndCallName)),
+ materializeTemporaryExpr(ignoringParenImpCasts(
+ expr(EndCallMatcher).bind(EndCallName)))));
+
+ StatementMatcher IteratorComparisonMatcher = expr(
+ ignoringParenImpCasts(declRefExpr(to(varDecl().bind(ConditionVarName)))));
+
+ auto OverloadedNEQMatcher = ignoringImplicit(
+ cxxOperatorCallExpr(hasOverloadedOperatorName("!="), argumentCountIs(2),
+ hasArgument(0, IteratorComparisonMatcher),
+ hasArgument(1, IteratorBoundMatcher)));
+
+ // This matcher tests that a declaration is a CXXRecordDecl that has an
+ // overloaded operator*(). If the operator*() returns by value instead of by
+ // reference then the return type is tagged with DerefByValueResultName.
+ internal::Matcher<VarDecl> TestDerefReturnsByValue =
+ hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(cxxRecordDecl(hasMethod(allOf(
+ hasOverloadedOperatorName("*"),
+ anyOf(
+ // Tag the return type if it's by value.
+ returns(qualType(unless(hasCanonicalType(referenceType())))
+ .bind(DerefByValueResultName)),
+ returns(
+ // Skip loops where the iterator's operator* returns an
+ // rvalue reference. This is just weird.
+ qualType(unless(hasCanonicalType(rValueReferenceType())))
+ .bind(DerefByRefResultName))))))))));
+
+ return forStmt(
+ unless(isInTemplateInstantiation()),
+ hasLoopInit(anyOf(declStmt(declCountIs(2),
+ containsDeclaration(0, InitDeclMatcher),
+ containsDeclaration(1, EndDeclMatcher)),
+ declStmt(hasSingleDecl(InitDeclMatcher)))),
+ hasCondition(
+ anyOf(binaryOperator(hasOperatorName("!="),
+ hasLHS(IteratorComparisonMatcher),
+ hasRHS(IteratorBoundMatcher)),
+ binaryOperator(hasOperatorName("!="),
+ hasLHS(IteratorBoundMatcher),
+ hasRHS(IteratorComparisonMatcher)),
+ OverloadedNEQMatcher)),
+ hasIncrement(anyOf(
+ unaryOperator(hasOperatorName("++"),
+ hasUnaryOperand(declRefExpr(
+ to(varDecl(hasType(pointsTo(AnyType)))
+ .bind(IncrementVarName))))),
+ cxxOperatorCallExpr(
+ hasOverloadedOperatorName("++"),
+ hasArgument(
+ 0, declRefExpr(to(varDecl(TestDerefReturnsByValue)
+ .bind(IncrementVarName))))))))
+ .bind(LoopNameIterator);
+}
+
+/// \brief The matcher used for array-like containers (pseudoarrays).
+///
+/// This matcher is more flexible than array-based loops. It will match
+/// loops of the following textual forms (regardless of whether the
+/// iterator type is actually a pointer type or a class type):
+///
+/// Assuming f, g, and h are of type containerType::iterator,
+/// \code
+/// for (int i = 0, j = container.size(); f < g; ++h) { ... }
+/// for (int i = 0; f < container.size(); ++h) { ... }
+/// \endcode
+/// The following string identifiers are bound to the parts of the AST:
+/// InitVarName: 'i' (as a VarDecl)
+/// ConditionVarName: 'f' (as a VarDecl)
+/// LoopName: The entire for loop (as a ForStmt)
+/// In the first example only:
+/// EndVarName: 'j' (as a VarDecl)
+/// ConditionEndVarName: 'g' (as a VarDecl)
+/// In the second example only:
+/// EndCallName: 'container.size()' (as a CXXMemberCallExpr)
+///
+/// Client code will need to make sure that:
+/// - The index variables 'i', 'f', and 'h' are the same.
+/// - The containers on which 'size()' is called is the container indexed.
+/// - The index variable is only used in overloaded operator[] or
+/// container.at().
+/// - If the end iterator variable 'g' is defined, it is the same as 'j'.
+/// - The container's iterators would not be invalidated during the loop.
+StatementMatcher makePseudoArrayLoopMatcher() {
+ // Test that the incoming type has a record declaration that has methods
+ // called 'begin' and 'end'. If the incoming type is const, then make sure
+ // these methods are also marked const.
+ //
+ // FIXME: To be completely thorough this matcher should also ensure the
+ // return type of begin/end is an iterator that dereferences to the same as
+ // what operator[] or at() returns. Such a test isn't likely to fail except
+ // for pathological cases.
+ //
+ // FIXME: Also, a record doesn't necessarily need begin() and end(). Free
+ // functions called begin() and end() taking the container as an argument
+ // are also allowed.
+ TypeMatcher RecordWithBeginEnd = qualType(anyOf(
+ qualType(
+ isConstQualified(),
+ hasUnqualifiedDesugaredType(recordType(hasDeclaration(cxxRecordDecl(
+ hasMethod(cxxMethodDecl(hasName("begin"), isConst())),
+ hasMethod(cxxMethodDecl(hasName("end"),
+ isConst())))) // hasDeclaration
+ ))), // qualType
+ qualType(unless(isConstQualified()),
+ hasUnqualifiedDesugaredType(recordType(hasDeclaration(
+ cxxRecordDecl(hasMethod(hasName("begin")),
+ hasMethod(hasName("end"))))))) // qualType
+ ));
+
+ StatementMatcher SizeCallMatcher = cxxMemberCallExpr(
+ argumentCountIs(0),
+ callee(cxxMethodDecl(anyOf(hasName("size"), hasName("length")))),
+ on(anyOf(hasType(pointsTo(RecordWithBeginEnd)),
+ hasType(RecordWithBeginEnd))));
+
+ StatementMatcher EndInitMatcher =
+ expr(anyOf(ignoringParenImpCasts(expr(SizeCallMatcher).bind(EndCallName)),
+ explicitCastExpr(hasSourceExpression(ignoringParenImpCasts(
+ expr(SizeCallMatcher).bind(EndCallName))))));
+
+ DeclarationMatcher EndDeclMatcher =
+ varDecl(hasInitializer(EndInitMatcher)).bind(EndVarName);
+
+ StatementMatcher IndexBoundMatcher =
+ expr(anyOf(ignoringParenImpCasts(declRefExpr(to(
+ varDecl(hasType(isInteger())).bind(ConditionEndVarName)))),
+ EndInitMatcher));
+
+ return forStmt(
+ unless(isInTemplateInstantiation()),
+ hasLoopInit(
+ anyOf(declStmt(declCountIs(2),
+ containsDeclaration(0, InitToZeroMatcher),
+ containsDeclaration(1, EndDeclMatcher)),
+ declStmt(hasSingleDecl(InitToZeroMatcher)))),
+ hasCondition(anyOf(
+ binaryOperator(hasOperatorName("<"),
+ hasLHS(IntegerComparisonMatcher),
+ hasRHS(IndexBoundMatcher)),
+ binaryOperator(hasOperatorName(">"), hasLHS(IndexBoundMatcher),
+ hasRHS(IntegerComparisonMatcher)))),
+ hasIncrement(unaryOperator(hasOperatorName("++"),
+ hasUnaryOperand(IncrementVarMatcher))))
+ .bind(LoopNamePseudoArray);
+}
+
+/// \brief Determine whether Init appears to be an initializing an iterator.
+///
+/// If it is, returns the object whose begin() or end() method is called, and
+/// the output parameter isArrow is set to indicate whether the initialization
+/// is called via . or ->.
+static const Expr *getContainerFromBeginEndCall(const Expr *Init, bool IsBegin,
+ bool *IsArrow) {
+ // FIXME: Maybe allow declaration/initialization outside of the for loop.
+ const auto *TheCall =
+ dyn_cast_or_null<CXXMemberCallExpr>(digThroughConstructors(Init));
+ if (!TheCall || TheCall->getNumArgs() != 0)
+ return nullptr;
+
+ const auto *Member = dyn_cast<MemberExpr>(TheCall->getCallee());
+ if (!Member)
+ return nullptr;
+ StringRef Name = Member->getMemberDecl()->getName();
+ StringRef TargetName = IsBegin ? "begin" : "end";
+ StringRef ConstTargetName = IsBegin ? "cbegin" : "cend";
+ if (Name != TargetName && Name != ConstTargetName)
+ return nullptr;
+
+ const Expr *SourceExpr = Member->getBase();
+ if (!SourceExpr)
+ return nullptr;
+
+ *IsArrow = Member->isArrow();
+ return SourceExpr;
+}
+
+/// \brief Determines the container whose begin() and end() functions are called
+/// for an iterator-based loop.
+///
+/// BeginExpr must be a member call to a function named "begin()", and EndExpr
+/// must be a member.
+static const Expr *findContainer(ASTContext *Context, const Expr *BeginExpr,
+ const Expr *EndExpr,
+ bool *ContainerNeedsDereference) {
+ // Now that we know the loop variable and test expression, make sure they are
+ // valid.
+ bool BeginIsArrow = false;
+ bool EndIsArrow = false;
+ const Expr *BeginContainerExpr =
+ getContainerFromBeginEndCall(BeginExpr, /*IsBegin=*/true, &BeginIsArrow);
+ if (!BeginContainerExpr)
+ return nullptr;
+
+ const Expr *EndContainerExpr =
+ getContainerFromBeginEndCall(EndExpr, /*IsBegin=*/false, &EndIsArrow);
+ // Disallow loops that try evil things like this (note the dot and arrow):
+ // for (IteratorType It = Obj.begin(), E = Obj->end(); It != E; ++It) { }
+ if (!EndContainerExpr || BeginIsArrow != EndIsArrow ||
+ !areSameExpr(Context, EndContainerExpr, BeginContainerExpr))
+ return nullptr;
+
+ *ContainerNeedsDereference = BeginIsArrow;
+ return BeginContainerExpr;
+}
+
+/// \brief Obtain the original source code text from a SourceRange.
+static StringRef getStringFromRange(SourceManager &SourceMgr,
+ const LangOptions &LangOpts,
+ SourceRange Range) {
+ if (SourceMgr.getFileID(Range.getBegin()) !=
+ SourceMgr.getFileID(Range.getEnd())) {
+ return StringRef(); // Empty string.
+ }
+
+ return Lexer::getSourceText(CharSourceRange(Range, true), SourceMgr,
+ LangOpts);
+}
+
+/// \brief If the given expression is actually a DeclRefExpr or a MemberExpr,
+/// find and return the underlying ValueDecl; otherwise, return NULL.
+static const ValueDecl *getReferencedVariable(const Expr *E) {
+ if (const DeclRefExpr *DRE = getDeclRef(E))
+ return dyn_cast<VarDecl>(DRE->getDecl());
+ if (const auto *Mem = dyn_cast<MemberExpr>(E->IgnoreParenImpCasts()))
+ return dyn_cast<FieldDecl>(Mem->getMemberDecl());
+ return nullptr;
+}
+
+/// \brief Returns true when the given expression is a member expression
+/// whose base is `this` (implicitly or not).
+static bool isDirectMemberExpr(const Expr *E) {
+ if (const auto *Member = dyn_cast<MemberExpr>(E->IgnoreParenImpCasts()))
+ return isa<CXXThisExpr>(Member->getBase()->IgnoreParenImpCasts());
+ return false;
+}
+
+/// \brief Given an expression that represents an usage of an element from the
+/// containter that we are iterating over, returns false when it can be
+/// guaranteed this element cannot be modified as a result of this usage.
+static bool canBeModified(ASTContext *Context, const Expr *E) {
+ if (E->getType().isConstQualified())
+ return false;
+ auto Parents = Context->getParents(*E);
+ if (Parents.size() != 1)
+ return true;
+ if (const auto *Cast = Parents[0].get<ImplicitCastExpr>()) {
+ if ((Cast->getCastKind() == CK_NoOp &&
+ Cast->getType() == E->getType().withConst()) ||
+ (Cast->getCastKind() == CK_LValueToRValue &&
+ !Cast->getType().isNull() && Cast->getType()->isFundamentalType()))
+ return false;
+ }
+ // FIXME: Make this function more generic.
+ return true;
+}
+
+/// \brief Returns true when it can be guaranteed that the elements of the
+/// container are not being modified.
+static bool usagesAreConst(ASTContext *Context, const UsageResult &Usages) {
+ for (const Usage &U : Usages) {
+ // Lambda captures are just redeclarations (VarDecl) of the same variable,
+ // not expressions. If we want to know if a variable that is captured by
+ // reference can be modified in an usage inside the lambda's body, we need
+ // to find the expression corresponding to that particular usage, later in
+ // this loop.
+ if (U.Kind != Usage::UK_CaptureByCopy && U.Kind != Usage::UK_CaptureByRef &&
+ canBeModified(Context, U.Expression))
+ return false;
+ }
+ return true;
+}
+
+/// \brief Returns true if the elements of the container are never accessed
+/// by reference.
+static bool usagesReturnRValues(const UsageResult &Usages) {
+ for (const auto &U : Usages) {
+ if (U.Expression && !U.Expression->isRValue())
+ return false;
+ }
+ return true;
+}
+
+/// \brief Returns true if the container is const-qualified.
+static bool containerIsConst(const Expr *ContainerExpr, bool Dereference) {
+ if (const auto *VDec = getReferencedVariable(ContainerExpr)) {
+ QualType CType = VDec->getType();
+ if (Dereference) {
+ if (!CType->isPointerType())
+ return false;
+ CType = CType->getPointeeType();
+ }
+ // If VDec is a reference to a container, Dereference is false,
+ // but we still need to check the const-ness of the underlying container
+ // type.
+ CType = CType.getNonReferenceType();
+ return CType.isConstQualified();
+ }
+ return false;
+}
+
+LoopConvertCheck::RangeDescriptor::RangeDescriptor()
+ : ContainerNeedsDereference(false), DerefByConstRef(false),
+ DerefByValue(false) {}
+
+LoopConvertCheck::LoopConvertCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context), TUInfo(new TUTrackingInfo),
+ MaxCopySize(std::stoull(Options.get("MaxCopySize", "16"))),
+ MinConfidence(StringSwitch<Confidence::Level>(
+ Options.get("MinConfidence", "reasonable"))
+ .Case("safe", Confidence::CL_Safe)
+ .Case("risky", Confidence::CL_Risky)
+ .Default(Confidence::CL_Reasonable)),
+ NamingStyle(StringSwitch<VariableNamer::NamingStyle>(
+ Options.get("NamingStyle", "CamelCase"))
+ .Case("camelBack", VariableNamer::NS_CamelBack)
+ .Case("lower_case", VariableNamer::NS_LowerCase)
+ .Case("UPPER_CASE", VariableNamer::NS_UpperCase)
+ .Default(VariableNamer::NS_CamelCase)) {}
+
+void LoopConvertCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "MaxCopySize", std::to_string(MaxCopySize));
+ SmallVector<std::string, 3> Confs{"risky", "reasonable", "safe"};
+ Options.store(Opts, "MinConfidence", Confs[static_cast<int>(MinConfidence)]);
+
+ SmallVector<std::string, 4> Styles{"camelBack", "CamelCase", "lower_case",
+ "UPPER_CASE"};
+ Options.store(Opts, "NamingStyle", Styles[static_cast<int>(NamingStyle)]);
+}
+
+void LoopConvertCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++. Because this checker is used for
+ // modernization, it is reasonable to run it on any C++ standard with the
+ // assumption the user is trying to modernize their codebase.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(makeArrayLoopMatcher(), this);
+ Finder->addMatcher(makeIteratorLoopMatcher(), this);
+ Finder->addMatcher(makePseudoArrayLoopMatcher(), this);
+}
+
+/// \brief Given the range of a single declaration, such as:
+/// \code
+/// unsigned &ThisIsADeclarationThatCanSpanSeveralLinesOfCode =
+/// InitializationValues[I];
+/// next_instruction;
+/// \endcode
+/// Finds the range that has to be erased to remove this declaration without
+/// leaving empty lines, by extending the range until the beginning of the
+/// next instruction.
+///
+/// We need to delete a potential newline after the deleted alias, as
+/// clang-format will leave empty lines untouched. For all other formatting we
+/// rely on clang-format to fix it.
+void LoopConvertCheck::getAliasRange(SourceManager &SM, SourceRange &Range) {
+ bool Invalid = false;
+ const char *TextAfter =
+ SM.getCharacterData(Range.getEnd().getLocWithOffset(1), &Invalid);
+ if (Invalid)
+ return;
+ unsigned Offset = std::strspn(TextAfter, " \t\r\n");
+ Range =
+ SourceRange(Range.getBegin(), Range.getEnd().getLocWithOffset(Offset));
+}
+
+/// \brief Computes the changes needed to convert a given for loop, and
+/// applies them.
+void LoopConvertCheck::doConversion(
+ ASTContext *Context, const VarDecl *IndexVar,
+ const ValueDecl *MaybeContainer, const UsageResult &Usages,
+ const DeclStmt *AliasDecl, bool AliasUseRequired, bool AliasFromForInit,
+ const ForStmt *Loop, RangeDescriptor Descriptor) {
+ auto Diag = diag(Loop->getForLoc(), "use range-based for loop instead");
+
+ std::string VarName;
+ bool VarNameFromAlias = (Usages.size() == 1) && AliasDecl;
+ bool AliasVarIsRef = false;
+ bool CanCopy = true;
+
+ if (VarNameFromAlias) {
+ const auto *AliasVar = cast<VarDecl>(AliasDecl->getSingleDecl());
+ VarName = AliasVar->getName().str();
+
+ // Use the type of the alias if it's not the same
+ QualType AliasVarType = AliasVar->getType();
+ assert(!AliasVarType.isNull() && "Type in VarDecl is null");
+ if (AliasVarType->isReferenceType()) {
+ AliasVarType = AliasVarType.getNonReferenceType();
+ AliasVarIsRef = true;
+ }
+ if (Descriptor.ElemType.isNull() ||
+ !Context->hasSameUnqualifiedType(AliasVarType, Descriptor.ElemType))
+ Descriptor.ElemType = AliasVarType;
+
+ // We keep along the entire DeclStmt to keep the correct range here.
+ SourceRange ReplaceRange = AliasDecl->getSourceRange();
+
+ std::string ReplacementText;
+ if (AliasUseRequired) {
+ ReplacementText = VarName;
+ } else if (AliasFromForInit) {
+ // FIXME: Clang includes the location of the ';' but only for DeclStmt's
+ // in a for loop's init clause. Need to put this ';' back while removing
+ // the declaration of the alias variable. This is probably a bug.
+ ReplacementText = ";";
+ } else {
+ // Avoid leaving empty lines or trailing whitespaces.
+ getAliasRange(Context->getSourceManager(), ReplaceRange);
+ }
+
+ Diag << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(ReplaceRange), ReplacementText);
+ // No further replacements are made to the loop, since the iterator or index
+ // was used exactly once - in the initialization of AliasVar.
+ } else {
+ VariableNamer Namer(&TUInfo->getGeneratedDecls(),
+ &TUInfo->getParentFinder().getStmtToParentStmtMap(),
+ Loop, IndexVar, MaybeContainer, Context, NamingStyle);
+ VarName = Namer.createIndexName();
+ // First, replace all usages of the array subscript expression with our new
+ // variable.
+ for (const auto &Usage : Usages) {
+ std::string ReplaceText;
+ SourceRange Range = Usage.Range;
+ if (Usage.Expression) {
+ // If this is an access to a member through the arrow operator, after
+ // the replacement it must be accessed through the '.' operator.
+ ReplaceText = Usage.Kind == Usage::UK_MemberThroughArrow ? VarName + "."
+ : VarName;
+ auto Parents = Context->getParents(*Usage.Expression);
+ if (Parents.size() == 1) {
+ if (const auto *Paren = Parents[0].get<ParenExpr>()) {
+ // Usage.Expression will be replaced with the new index variable,
+ // and parenthesis around a simple DeclRefExpr can always be
+ // removed.
+ Range = Paren->getSourceRange();
+ } else if (const auto *UOP = Parents[0].get<UnaryOperator>()) {
+ // If we are taking the address of the loop variable, then we must
+ // not use a copy, as it would mean taking the address of the loop's
+ // local index instead.
+ // FIXME: This won't catch cases where the address is taken outside
+ // of the loop's body (for instance, in a function that got the
+ // loop's index as a const reference parameter), or where we take
+ // the address of a member (like "&Arr[i].A.B.C").
+ if (UOP->getOpcode() == UO_AddrOf)
+ CanCopy = false;
+ }
+ }
+ } else {
+ // The Usage expression is only null in case of lambda captures (which
+ // are VarDecl). If the index is captured by value, add '&' to capture
+ // by reference instead.
+ ReplaceText =
+ Usage.Kind == Usage::UK_CaptureByCopy ? "&" + VarName : VarName;
+ }
+ TUInfo->getReplacedVars().insert(std::make_pair(Loop, IndexVar));
+ Diag << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(Range), ReplaceText);
+ }
+ }
+
+ // Now, we need to construct the new range expression.
+ SourceRange ParenRange(Loop->getLParenLoc(), Loop->getRParenLoc());
+
+ QualType Type = Context->getAutoDeductType();
+ if (!Descriptor.ElemType.isNull() && Descriptor.ElemType->isFundamentalType())
+ Type = Descriptor.ElemType.getUnqualifiedType();
+
+ // If the new variable name is from the aliased variable, then the reference
+ // type for the new variable should only be used if the aliased variable was
+ // declared as a reference.
+ bool IsCheapToCopy =
+ !Descriptor.ElemType.isNull() &&
+ Descriptor.ElemType.isTriviallyCopyableType(*Context) &&
+ // TypeInfo::Width is in bits.
+ Context->getTypeInfo(Descriptor.ElemType).Width <= 8 * MaxCopySize;
+ bool UseCopy = CanCopy && ((VarNameFromAlias && !AliasVarIsRef) ||
+ (Descriptor.DerefByConstRef && IsCheapToCopy));
+
+ if (!UseCopy) {
+ if (Descriptor.DerefByConstRef) {
+ Type = Context->getLValueReferenceType(Context->getConstType(Type));
+ } else if (Descriptor.DerefByValue) {
+ if (!IsCheapToCopy)
+ Type = Context->getRValueReferenceType(Type);
+ } else {
+ Type = Context->getLValueReferenceType(Type);
+ }
+ }
+
+ StringRef MaybeDereference = Descriptor.ContainerNeedsDereference ? "*" : "";
+ std::string TypeString = Type.getAsString(getLangOpts());
+ std::string Range = ("(" + TypeString + " " + VarName + " : " +
+ MaybeDereference + Descriptor.ContainerString + ")")
+ .str();
+ Diag << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(ParenRange), Range);
+ TUInfo->getGeneratedDecls().insert(make_pair(Loop, VarName));
+}
+
+/// \brief Returns a string which refers to the container iterated over.
+StringRef LoopConvertCheck::getContainerString(ASTContext *Context,
+ const ForStmt *Loop,
+ const Expr *ContainerExpr) {
+ StringRef ContainerString;
+ if (isa<CXXThisExpr>(ContainerExpr->IgnoreParenImpCasts())) {
+ ContainerString = "this";
+ } else {
+ ContainerString =
+ getStringFromRange(Context->getSourceManager(), Context->getLangOpts(),
+ ContainerExpr->getSourceRange());
+ }
+
+ return ContainerString;
+}
+
+/// \brief Determines what kind of 'auto' must be used after converting a for
+/// loop that iterates over an array or pseudoarray.
+void LoopConvertCheck::getArrayLoopQualifiers(ASTContext *Context,
+ const BoundNodes &Nodes,
+ const Expr *ContainerExpr,
+ const UsageResult &Usages,
+ RangeDescriptor &Descriptor) {
+ // On arrays and pseudoarrays, we must figure out the qualifiers from the
+ // usages.
+ if (usagesAreConst(Context, Usages) ||
+ containerIsConst(ContainerExpr, Descriptor.ContainerNeedsDereference)) {
+ Descriptor.DerefByConstRef = true;
+ }
+ if (usagesReturnRValues(Usages)) {
+ // If the index usages (dereference, subscript, at, ...) return rvalues,
+ // then we should not use a reference, because we need to keep the code
+ // correct if it mutates the returned objects.
+ Descriptor.DerefByValue = true;
+ }
+ // Try to find the type of the elements on the container, to check if
+ // they are trivially copyable.
+ for (const Usage &U : Usages) {
+ if (!U.Expression || U.Expression->getType().isNull())
+ continue;
+ QualType Type = U.Expression->getType().getCanonicalType();
+ if (U.Kind == Usage::UK_MemberThroughArrow) {
+ if (!Type->isPointerType()) {
+ continue;
+ }
+ Type = Type->getPointeeType();
+ }
+ Descriptor.ElemType = Type;
+ }
+}
+
+/// \brief Determines what kind of 'auto' must be used after converting an
+/// iterator based for loop.
+void LoopConvertCheck::getIteratorLoopQualifiers(ASTContext *Context,
+ const BoundNodes &Nodes,
+ RangeDescriptor &Descriptor) {
+ // The matchers for iterator loops provide bound nodes to obtain this
+ // information.
+ const auto *InitVar = Nodes.getNodeAs<VarDecl>(InitVarName);
+ QualType CanonicalInitVarType = InitVar->getType().getCanonicalType();
+ const auto *DerefByValueType =
+ Nodes.getNodeAs<QualType>(DerefByValueResultName);
+ Descriptor.DerefByValue = DerefByValueType;
+
+ if (Descriptor.DerefByValue) {
+ // If the dereference operator returns by value then test for the
+ // canonical const qualification of the init variable type.
+ Descriptor.DerefByConstRef = CanonicalInitVarType.isConstQualified();
+ Descriptor.ElemType = *DerefByValueType;
+ } else {
+ if (const auto *DerefType =
+ Nodes.getNodeAs<QualType>(DerefByRefResultName)) {
+ // A node will only be bound with DerefByRefResultName if we're dealing
+ // with a user-defined iterator type. Test the const qualification of
+ // the reference type.
+ auto ValueType = DerefType->getNonReferenceType();
+
+ Descriptor.DerefByConstRef = ValueType.isConstQualified();
+ Descriptor.ElemType = ValueType;
+ } else {
+ // By nature of the matcher this case is triggered only for built-in
+ // iterator types (i.e. pointers).
+ assert(isa<PointerType>(CanonicalInitVarType) &&
+ "Non-class iterator type is not a pointer type");
+
+ // We test for const qualification of the pointed-at type.
+ Descriptor.DerefByConstRef =
+ CanonicalInitVarType->getPointeeType().isConstQualified();
+ Descriptor.ElemType = CanonicalInitVarType->getPointeeType();
+ }
+ }
+}
+
+/// \brief Determines the parameters needed to build the range replacement.
+void LoopConvertCheck::determineRangeDescriptor(
+ ASTContext *Context, const BoundNodes &Nodes, const ForStmt *Loop,
+ LoopFixerKind FixerKind, const Expr *ContainerExpr,
+ const UsageResult &Usages, RangeDescriptor &Descriptor) {
+ Descriptor.ContainerString = getContainerString(Context, Loop, ContainerExpr);
+
+ if (FixerKind == LFK_Iterator)
+ getIteratorLoopQualifiers(Context, Nodes, Descriptor);
+ else
+ getArrayLoopQualifiers(Context, Nodes, ContainerExpr, Usages, Descriptor);
+}
+
+/// \brief Check some of the conditions that must be met for the loop to be
+/// convertible.
+bool LoopConvertCheck::isConvertible(ASTContext *Context,
+ const ast_matchers::BoundNodes &Nodes,
+ const ForStmt *Loop,
+ LoopFixerKind FixerKind) {
+ // If we already modified the range of this for loop, don't do any further
+ // updates on this iteration.
+ if (TUInfo->getReplacedVars().count(Loop))
+ return false;
+
+ // Check that we have exactly one index variable and at most one end variable.
+ const auto *LoopVar = Nodes.getNodeAs<VarDecl>(IncrementVarName);
+ const auto *CondVar = Nodes.getNodeAs<VarDecl>(ConditionVarName);
+ const auto *InitVar = Nodes.getNodeAs<VarDecl>(InitVarName);
+ if (!areSameVariable(LoopVar, CondVar) || !areSameVariable(LoopVar, InitVar))
+ return false;
+ const auto *EndVar = Nodes.getNodeAs<VarDecl>(EndVarName);
+ const auto *ConditionEndVar = Nodes.getNodeAs<VarDecl>(ConditionEndVarName);
+ if (EndVar && !areSameVariable(EndVar, ConditionEndVar))
+ return false;
+
+ // FIXME: Try to put most of this logic inside a matcher.
+ if (FixerKind == LFK_Iterator) {
+ QualType InitVarType = InitVar->getType();
+ QualType CanonicalInitVarType = InitVarType.getCanonicalType();
+
+ const auto *BeginCall = Nodes.getNodeAs<CXXMemberCallExpr>(BeginCallName);
+ assert(BeginCall && "Bad Callback. No begin call expression");
+ QualType CanonicalBeginType =
+ BeginCall->getMethodDecl()->getReturnType().getCanonicalType();
+ if (CanonicalBeginType->isPointerType() &&
+ CanonicalInitVarType->isPointerType()) {
+ // If the initializer and the variable are both pointers check if the
+ // un-qualified pointee types match, otherwise we don't use auto.
+ if (!Context->hasSameUnqualifiedType(
+ CanonicalBeginType->getPointeeType(),
+ CanonicalInitVarType->getPointeeType()))
+ return false;
+ } else if (!Context->hasSameType(CanonicalInitVarType,
+ CanonicalBeginType)) {
+ // Check for qualified types to avoid conversions from non-const to const
+ // iterator types.
+ return false;
+ }
+ } else if (FixerKind == LFK_PseudoArray) {
+ // This call is required to obtain the container.
+ const auto *EndCall = Nodes.getNodeAs<CXXMemberCallExpr>(EndCallName);
+ if (!EndCall || !dyn_cast<MemberExpr>(EndCall->getCallee()))
+ return false;
+ }
+ return true;
+}
+
+void LoopConvertCheck::check(const MatchFinder::MatchResult &Result) {
+ const BoundNodes &Nodes = Result.Nodes;
+ Confidence ConfidenceLevel(Confidence::CL_Safe);
+ ASTContext *Context = Result.Context;
+
+ const ForStmt *Loop;
+ LoopFixerKind FixerKind;
+ RangeDescriptor Descriptor;
+
+ if ((Loop = Nodes.getNodeAs<ForStmt>(LoopNameArray))) {
+ FixerKind = LFK_Array;
+ } else if ((Loop = Nodes.getNodeAs<ForStmt>(LoopNameIterator))) {
+ FixerKind = LFK_Iterator;
+ } else {
+ Loop = Nodes.getNodeAs<ForStmt>(LoopNamePseudoArray);
+ assert(Loop && "Bad Callback. No for statement");
+ FixerKind = LFK_PseudoArray;
+ }
+
+ if (!isConvertible(Context, Nodes, Loop, FixerKind))
+ return;
+
+ const auto *LoopVar = Nodes.getNodeAs<VarDecl>(IncrementVarName);
+ const auto *EndVar = Nodes.getNodeAs<VarDecl>(EndVarName);
+
+ // If the loop calls end()/size() after each iteration, lower our confidence
+ // level.
+ if (FixerKind != LFK_Array && !EndVar)
+ ConfidenceLevel.lowerTo(Confidence::CL_Reasonable);
+
+ // If the end comparison isn't a variable, we can try to work with the
+ // expression the loop variable is being tested against instead.
+ const auto *EndCall = Nodes.getNodeAs<CXXMemberCallExpr>(EndCallName);
+ const auto *BoundExpr = Nodes.getNodeAs<Expr>(ConditionBoundName);
+
+ // Find container expression of iterators and pseudoarrays, and determine if
+ // this expression needs to be dereferenced to obtain the container.
+ // With array loops, the container is often discovered during the
+ // ForLoopIndexUseVisitor traversal.
+ const Expr *ContainerExpr = nullptr;
+ if (FixerKind == LFK_Iterator) {
+ ContainerExpr = findContainer(Context, LoopVar->getInit(),
+ EndVar ? EndVar->getInit() : EndCall,
+ &Descriptor.ContainerNeedsDereference);
+ } else if (FixerKind == LFK_PseudoArray) {
+ ContainerExpr = EndCall->getImplicitObjectArgument();
+ Descriptor.ContainerNeedsDereference =
+ dyn_cast<MemberExpr>(EndCall->getCallee())->isArrow();
+ }
+
+ // We must know the container or an array length bound.
+ if (!ContainerExpr && !BoundExpr)
+ return;
+
+ ForLoopIndexUseVisitor Finder(Context, LoopVar, EndVar, ContainerExpr,
+ BoundExpr,
+ Descriptor.ContainerNeedsDereference);
+
+ // Find expressions and variables on which the container depends.
+ if (ContainerExpr) {
+ ComponentFinderASTVisitor ComponentFinder;
+ ComponentFinder.findExprComponents(ContainerExpr->IgnoreParenImpCasts());
+ Finder.addComponents(ComponentFinder.getComponents());
+ }
+
+ // Find usages of the loop index. If they are not used in a convertible way,
+ // stop here.
+ if (!Finder.findAndVerifyUsages(Loop->getBody()))
+ return;
+ ConfidenceLevel.lowerTo(Finder.getConfidenceLevel());
+
+ // Obtain the container expression, if we don't have it yet.
+ if (FixerKind == LFK_Array) {
+ ContainerExpr = Finder.getContainerIndexed()->IgnoreParenImpCasts();
+
+ // Very few loops are over expressions that generate arrays rather than
+ // array variables. Consider loops over arrays that aren't just represented
+ // by a variable to be risky conversions.
+ if (!getReferencedVariable(ContainerExpr) &&
+ !isDirectMemberExpr(ContainerExpr))
+ ConfidenceLevel.lowerTo(Confidence::CL_Risky);
+ }
+
+ // Find out which qualifiers we have to use in the loop range.
+ const UsageResult &Usages = Finder.getUsages();
+ determineRangeDescriptor(Context, Nodes, Loop, FixerKind, ContainerExpr,
+ Usages, Descriptor);
+
+ // Ensure that we do not try to move an expression dependent on a local
+ // variable declared inside the loop outside of it.
+ // FIXME: Determine when the external dependency isn't an expression converted
+ // by another loop.
+ TUInfo->getParentFinder().gatherAncestors(Context->getTranslationUnitDecl());
+ DependencyFinderASTVisitor DependencyFinder(
+ &TUInfo->getParentFinder().getStmtToParentStmtMap(),
+ &TUInfo->getParentFinder().getDeclToParentStmtMap(),
+ &TUInfo->getReplacedVars(), Loop);
+
+ if (DependencyFinder.dependsOnInsideVariable(ContainerExpr) ||
+ Descriptor.ContainerString.empty() || Usages.empty() ||
+ ConfidenceLevel.getLevel() < MinConfidence)
+ return;
+
+ doConversion(Context, LoopVar, getReferencedVariable(ContainerExpr), Usages,
+ Finder.getAliasDecl(), Finder.aliasUseRequired(),
+ Finder.aliasFromForInit(), Loop, Descriptor);
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h
new file mode 100644
index 0000000..75ab25a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.h
@@ -0,0 +1,78 @@
+//===--- LoopConvertCheck.h - clang-tidy-------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOP_CONVERT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOP_CONVERT_H
+
+#include "../ClangTidy.h"
+#include "LoopConvertUtils.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+class LoopConvertCheck : public ClangTidyCheck {
+public:
+ LoopConvertCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ struct RangeDescriptor {
+ RangeDescriptor();
+ bool ContainerNeedsDereference;
+ bool DerefByConstRef;
+ bool DerefByValue;
+ std::string ContainerString;
+ QualType ElemType;
+ };
+
+ void getAliasRange(SourceManager &SM, SourceRange &DeclRange);
+
+ void doConversion(ASTContext *Context, const VarDecl *IndexVar,
+ const ValueDecl *MaybeContainer, const UsageResult &Usages,
+ const DeclStmt *AliasDecl, bool AliasUseRequired,
+ bool AliasFromForInit, const ForStmt *Loop,
+ RangeDescriptor Descriptor);
+
+ StringRef getContainerString(ASTContext *Context, const ForStmt *Loop,
+ const Expr *ContainerExpr);
+
+ void getArrayLoopQualifiers(ASTContext *Context,
+ const ast_matchers::BoundNodes &Nodes,
+ const Expr *ContainerExpr,
+ const UsageResult &Usages,
+ RangeDescriptor &Descriptor);
+
+ void getIteratorLoopQualifiers(ASTContext *Context,
+ const ast_matchers::BoundNodes &Nodes,
+ RangeDescriptor &Descriptor);
+
+ void determineRangeDescriptor(ASTContext *Context,
+ const ast_matchers::BoundNodes &Nodes,
+ const ForStmt *Loop, LoopFixerKind FixerKind,
+ const Expr *ContainerExpr,
+ const UsageResult &Usages,
+ RangeDescriptor &Descriptor);
+
+ bool isConvertible(ASTContext *Context, const ast_matchers::BoundNodes &Nodes,
+ const ForStmt *Loop, LoopFixerKind FixerKind);
+
+ std::unique_ptr<TUTrackingInfo> TUInfo;
+ const unsigned long long MaxCopySize;
+ const Confidence::Level MinConfidence;
+ const VariableNamer::NamingStyle NamingStyle;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOP_CONVERT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp
new file mode 100644
index 0000000..f65f7a1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp
@@ -0,0 +1,909 @@
+//===--- LoopConvertUtils.cpp - clang-tidy --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LoopConvertUtils.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/Lambda.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/TokenKinds.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <string>
+#include <utility>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// \brief Tracks a stack of parent statements during traversal.
+///
+/// All this really does is inject push_back() before running
+/// RecursiveASTVisitor::TraverseStmt() and pop_back() afterwards. The Stmt atop
+/// the stack is the parent of the current statement (NULL for the topmost
+/// statement).
+bool StmtAncestorASTVisitor::TraverseStmt(Stmt *Statement) {
+ StmtAncestors.insert(std::make_pair(Statement, StmtStack.back()));
+ StmtStack.push_back(Statement);
+ RecursiveASTVisitor<StmtAncestorASTVisitor>::TraverseStmt(Statement);
+ StmtStack.pop_back();
+ return true;
+}
+
+/// \brief Keep track of the DeclStmt associated with each VarDecl.
+///
+/// Combined with StmtAncestors, this provides roughly the same information as
+/// Scope, as we can map a VarDecl to its DeclStmt, then walk up the parent tree
+/// using StmtAncestors.
+bool StmtAncestorASTVisitor::VisitDeclStmt(DeclStmt *Decls) {
+ for (const auto *decl : Decls->decls()) {
+ if (const auto *V = dyn_cast<VarDecl>(decl))
+ DeclParents.insert(std::make_pair(V, Decls));
+ }
+ return true;
+}
+
+/// \brief record the DeclRefExpr as part of the parent expression.
+bool ComponentFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *E) {
+ Components.push_back(E);
+ return true;
+}
+
+/// \brief record the MemberExpr as part of the parent expression.
+bool ComponentFinderASTVisitor::VisitMemberExpr(MemberExpr *Member) {
+ Components.push_back(Member);
+ return true;
+}
+
+/// \brief Forward any DeclRefExprs to a check on the referenced variable
+/// declaration.
+bool DependencyFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *DeclRef) {
+ if (auto *V = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
+ return VisitVarDecl(V);
+ return true;
+}
+
+/// \brief Determine if any this variable is declared inside the ContainingStmt.
+bool DependencyFinderASTVisitor::VisitVarDecl(VarDecl *V) {
+ const Stmt *Curr = DeclParents->lookup(V);
+ // First, see if the variable was declared within an inner scope of the loop.
+ while (Curr != nullptr) {
+ if (Curr == ContainingStmt) {
+ DependsOnInsideVariable = true;
+ return false;
+ }
+ Curr = StmtParents->lookup(Curr);
+ }
+
+ // Next, check if the variable was removed from existence by an earlier
+ // iteration.
+ for (const auto &I : *ReplacedVars) {
+ if (I.second == V) {
+ DependsOnInsideVariable = true;
+ return false;
+ }
+ }
+ return true;
+}
+
+/// \brief If we already created a variable for TheLoop, check to make sure
+/// that the name was not already taken.
+bool DeclFinderASTVisitor::VisitForStmt(ForStmt *TheLoop) {
+ StmtGeneratedVarNameMap::const_iterator I = GeneratedDecls->find(TheLoop);
+ if (I != GeneratedDecls->end() && I->second == Name) {
+ Found = true;
+ return false;
+ }
+ return true;
+}
+
+/// \brief If any named declaration within the AST subtree has the same name,
+/// then consider Name already taken.
+bool DeclFinderASTVisitor::VisitNamedDecl(NamedDecl *D) {
+ const IdentifierInfo *Ident = D->getIdentifier();
+ if (Ident && Ident->getName() == Name) {
+ Found = true;
+ return false;
+ }
+ return true;
+}
+
+/// \brief Forward any declaration references to the actual check on the
+/// referenced declaration.
+bool DeclFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *DeclRef) {
+ if (auto *D = dyn_cast<NamedDecl>(DeclRef->getDecl()))
+ return VisitNamedDecl(D);
+ return true;
+}
+
+/// \brief If the new variable name conflicts with any type used in the loop,
+/// then we mark that variable name as taken.
+bool DeclFinderASTVisitor::VisitTypeLoc(TypeLoc TL) {
+ QualType QType = TL.getType();
+
+ // Check if our name conflicts with a type, to handle for typedefs.
+ if (QType.getAsString() == Name) {
+ Found = true;
+ return false;
+ }
+ // Check for base type conflicts. For example, when a struct is being
+ // referenced in the body of the loop, the above getAsString() will return the
+ // whole type (ex. "struct s"), but will be caught here.
+ if (const IdentifierInfo *Ident = QType.getBaseTypeIdentifier()) {
+ if (Ident->getName() == Name) {
+ Found = true;
+ return false;
+ }
+ }
+ return true;
+}
+
+/// \brief Look through conversion/copy constructors to find the explicit
+/// initialization expression, returning it is found.
+///
+/// The main idea is that given
+/// vector<int> v;
+/// we consider either of these initializations
+/// vector<int>::iterator it = v.begin();
+/// vector<int>::iterator it(v.begin());
+/// and retrieve `v.begin()` as the expression used to initialize `it` but do
+/// not include
+/// vector<int>::iterator it;
+/// vector<int>::iterator it(v.begin(), 0); // if this constructor existed
+/// as being initialized from `v.begin()`
+const Expr *digThroughConstructors(const Expr *E) {
+ if (!E)
+ return nullptr;
+ E = E->IgnoreImplicit();
+ if (const auto *ConstructExpr = dyn_cast<CXXConstructExpr>(E)) {
+ // The initial constructor must take exactly one parameter, but base class
+ // and deferred constructors can take more.
+ if (ConstructExpr->getNumArgs() != 1 ||
+ ConstructExpr->getConstructionKind() != CXXConstructExpr::CK_Complete)
+ return nullptr;
+ E = ConstructExpr->getArg(0);
+ if (const auto *Temp = dyn_cast<MaterializeTemporaryExpr>(E))
+ E = Temp->GetTemporaryExpr();
+ return digThroughConstructors(E);
+ }
+ return E;
+}
+
+/// \brief Returns true when two Exprs are equivalent.
+bool areSameExpr(ASTContext *Context, const Expr *First, const Expr *Second) {
+ if (!First || !Second)
+ return false;
+
+ llvm::FoldingSetNodeID FirstID, SecondID;
+ First->Profile(FirstID, *Context, true);
+ Second->Profile(SecondID, *Context, true);
+ return FirstID == SecondID;
+}
+
+/// \brief Returns the DeclRefExpr represented by E, or NULL if there isn't one.
+const DeclRefExpr *getDeclRef(const Expr *E) {
+ return dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
+}
+
+/// \brief Returns true when two ValueDecls are the same variable.
+bool areSameVariable(const ValueDecl *First, const ValueDecl *Second) {
+ return First && Second &&
+ First->getCanonicalDecl() == Second->getCanonicalDecl();
+}
+
+/// \brief Determines if an expression is a declaration reference to a
+/// particular variable.
+static bool exprReferencesVariable(const ValueDecl *Target, const Expr *E) {
+ if (!Target || !E)
+ return false;
+ const DeclRefExpr *Decl = getDeclRef(E);
+ return Decl && areSameVariable(Target, Decl->getDecl());
+}
+
+/// \brief If the expression is a dereference or call to operator*(), return the
+/// operand. Otherwise, return NULL.
+static const Expr *getDereferenceOperand(const Expr *E) {
+ if (const auto *Uop = dyn_cast<UnaryOperator>(E))
+ return Uop->getOpcode() == UO_Deref ? Uop->getSubExpr() : nullptr;
+
+ if (const auto *OpCall = dyn_cast<CXXOperatorCallExpr>(E)) {
+ return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1
+ ? OpCall->getArg(0)
+ : nullptr;
+ }
+
+ return nullptr;
+}
+
+/// \brief Returns true when the Container contains an Expr equivalent to E.
+template <typename ContainerT>
+static bool containsExpr(ASTContext *Context, const ContainerT *Container,
+ const Expr *E) {
+ llvm::FoldingSetNodeID ID;
+ E->Profile(ID, *Context, true);
+ for (const auto &I : *Container) {
+ if (ID == I.second)
+ return true;
+ }
+ return false;
+}
+
+/// \brief Returns true when the index expression is a declaration reference to
+/// IndexVar.
+///
+/// If the index variable is `index`, this function returns true on
+/// arrayExpression[index];
+/// containerExpression[index];
+/// but not
+/// containerExpression[notIndex];
+static bool isIndexInSubscriptExpr(const Expr *IndexExpr,
+ const VarDecl *IndexVar) {
+ const DeclRefExpr *Idx = getDeclRef(IndexExpr);
+ return Idx && Idx->getType()->isIntegerType() &&
+ areSameVariable(IndexVar, Idx->getDecl());
+}
+
+/// \brief Returns true when the index expression is a declaration reference to
+/// IndexVar, Obj is the same expression as SourceExpr after all parens and
+/// implicit casts are stripped off.
+///
+/// If PermitDeref is true, IndexExpression may
+/// be a dereference (overloaded or builtin operator*).
+///
+/// This function is intended for array-like containers, as it makes sure that
+/// both the container and the index match.
+/// If the loop has index variable `index` and iterates over `container`, then
+/// isIndexInSubscriptExpr returns true for
+/// \code
+/// container[index]
+/// container.at(index)
+/// container->at(index)
+/// \endcode
+/// but not for
+/// \code
+/// container[notIndex]
+/// notContainer[index]
+/// \endcode
+/// If PermitDeref is true, then isIndexInSubscriptExpr additionally returns
+/// true on these expressions:
+/// \code
+/// (*container)[index]
+/// (*container).at(index)
+/// \endcode
+static bool isIndexInSubscriptExpr(ASTContext *Context, const Expr *IndexExpr,
+ const VarDecl *IndexVar, const Expr *Obj,
+ const Expr *SourceExpr, bool PermitDeref) {
+ if (!SourceExpr || !Obj || !isIndexInSubscriptExpr(IndexExpr, IndexVar))
+ return false;
+
+ if (areSameExpr(Context, SourceExpr->IgnoreParenImpCasts(),
+ Obj->IgnoreParenImpCasts()))
+ return true;
+
+ if (const Expr *InnerObj = getDereferenceOperand(Obj->IgnoreParenImpCasts()))
+ if (PermitDeref && areSameExpr(Context, SourceExpr->IgnoreParenImpCasts(),
+ InnerObj->IgnoreParenImpCasts()))
+ return true;
+
+ return false;
+}
+
+/// \brief Returns true when Opcall is a call a one-parameter dereference of
+/// IndexVar.
+///
+/// For example, if the index variable is `index`, returns true for
+/// *index
+/// but not
+/// index
+/// *notIndex
+static bool isDereferenceOfOpCall(const CXXOperatorCallExpr *OpCall,
+ const VarDecl *IndexVar) {
+ return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1 &&
+ exprReferencesVariable(IndexVar, OpCall->getArg(0));
+}
+
+/// \brief Returns true when Uop is a dereference of IndexVar.
+///
+/// For example, if the index variable is `index`, returns true for
+/// *index
+/// but not
+/// index
+/// *notIndex
+static bool isDereferenceOfUop(const UnaryOperator *Uop,
+ const VarDecl *IndexVar) {
+ return Uop->getOpcode() == UO_Deref &&
+ exprReferencesVariable(IndexVar, Uop->getSubExpr());
+}
+
+/// \brief Determines whether the given Decl defines a variable initialized to
+/// the loop object.
+///
+/// This is intended to find cases such as
+/// \code
+/// for (int i = 0; i < arraySize(arr); ++i) {
+/// T t = arr[i];
+/// // use t, do not use i
+/// }
+/// \endcode
+/// and
+/// \code
+/// for (iterator i = container.begin(), e = container.end(); i != e; ++i) {
+/// T t = *i;
+/// // use t, do not use i
+/// }
+/// \endcode
+static bool isAliasDecl(ASTContext *Context, const Decl *TheDecl,
+ const VarDecl *IndexVar) {
+ const auto *VDecl = dyn_cast<VarDecl>(TheDecl);
+ if (!VDecl)
+ return false;
+ if (!VDecl->hasInit())
+ return false;
+
+ bool OnlyCasts = true;
+ const Expr *Init = VDecl->getInit()->IgnoreParenImpCasts();
+ if (Init && isa<CXXConstructExpr>(Init)) {
+ Init = digThroughConstructors(Init);
+ OnlyCasts = false;
+ }
+ if (!Init)
+ return false;
+
+ // Check that the declared type is the same as (or a reference to) the
+ // container type.
+ if (!OnlyCasts) {
+ QualType InitType = Init->getType();
+ QualType DeclarationType = VDecl->getType();
+ if (!DeclarationType.isNull() && DeclarationType->isReferenceType())
+ DeclarationType = DeclarationType.getNonReferenceType();
+
+ if (InitType.isNull() || DeclarationType.isNull() ||
+ !Context->hasSameUnqualifiedType(DeclarationType, InitType))
+ return false;
+ }
+
+ switch (Init->getStmtClass()) {
+ case Stmt::ArraySubscriptExprClass: {
+ const auto *E = cast<ArraySubscriptExpr>(Init);
+ // We don't really care which array is used here. We check to make sure
+ // it was the correct one later, since the AST will traverse it next.
+ return isIndexInSubscriptExpr(E->getIdx(), IndexVar);
+ }
+
+ case Stmt::UnaryOperatorClass:
+ return isDereferenceOfUop(cast<UnaryOperator>(Init), IndexVar);
+
+ case Stmt::CXXOperatorCallExprClass: {
+ const auto *OpCall = cast<CXXOperatorCallExpr>(Init);
+ if (OpCall->getOperator() == OO_Star)
+ return isDereferenceOfOpCall(OpCall, IndexVar);
+ if (OpCall->getOperator() == OO_Subscript) {
+ assert(OpCall->getNumArgs() == 2);
+ return isIndexInSubscriptExpr(OpCall->getArg(1), IndexVar);
+ }
+ break;
+ }
+
+ case Stmt::CXXMemberCallExprClass: {
+ const auto *MemCall = cast<CXXMemberCallExpr>(Init);
+ // This check is needed because getMethodDecl can return nullptr if the
+ // callee is a member function pointer.
+ const auto *MDecl = MemCall->getMethodDecl();
+ if (MDecl && !isa<CXXConversionDecl>(MDecl) &&
+ MDecl->getNameAsString() == "at" && MemCall->getNumArgs() == 1) {
+ return isIndexInSubscriptExpr(MemCall->getArg(0), IndexVar);
+ }
+ return false;
+ }
+
+ default:
+ break;
+ }
+ return false;
+}
+
+/// \brief Determines whether the bound of a for loop condition expression is
+/// the same as the statically computable size of ArrayType.
+///
+/// Given
+/// \code
+/// const int N = 5;
+/// int arr[N];
+/// \endcode
+/// This is intended to permit
+/// \code
+/// for (int i = 0; i < N; ++i) { /* use arr[i] */ }
+/// for (int i = 0; i < arraysize(arr); ++i) { /* use arr[i] */ }
+/// \endcode
+static bool arrayMatchesBoundExpr(ASTContext *Context,
+ const QualType &ArrayType,
+ const Expr *ConditionExpr) {
+ if (!ConditionExpr || ConditionExpr->isValueDependent())
+ return false;
+ const ConstantArrayType *ConstType =
+ Context->getAsConstantArrayType(ArrayType);
+ if (!ConstType)
+ return false;
+ llvm::APSInt ConditionSize;
+ if (!ConditionExpr->isIntegerConstantExpr(ConditionSize, *Context))
+ return false;
+ llvm::APSInt ArraySize(ConstType->getSize());
+ return llvm::APSInt::isSameValue(ConditionSize, ArraySize);
+}
+
+ForLoopIndexUseVisitor::ForLoopIndexUseVisitor(ASTContext *Context,
+ const VarDecl *IndexVar,
+ const VarDecl *EndVar,
+ const Expr *ContainerExpr,
+ const Expr *ArrayBoundExpr,
+ bool ContainerNeedsDereference)
+ : Context(Context), IndexVar(IndexVar), EndVar(EndVar),
+ ContainerExpr(ContainerExpr), ArrayBoundExpr(ArrayBoundExpr),
+ ContainerNeedsDereference(ContainerNeedsDereference),
+ OnlyUsedAsIndex(true), AliasDecl(nullptr),
+ ConfidenceLevel(Confidence::CL_Safe), NextStmtParent(nullptr),
+ CurrStmtParent(nullptr), ReplaceWithAliasUse(false),
+ AliasFromForInit(false) {
+ if (ContainerExpr)
+ addComponent(ContainerExpr);
+}
+
+bool ForLoopIndexUseVisitor::findAndVerifyUsages(const Stmt *Body) {
+ TraverseStmt(const_cast<Stmt *>(Body));
+ return OnlyUsedAsIndex && ContainerExpr;
+}
+
+void ForLoopIndexUseVisitor::addComponents(const ComponentVector &Components) {
+ // FIXME: add sort(on ID)+unique to avoid extra work.
+ for (const auto &I : Components)
+ addComponent(I);
+}
+
+void ForLoopIndexUseVisitor::addComponent(const Expr *E) {
+ llvm::FoldingSetNodeID ID;
+ const Expr *Node = E->IgnoreParenImpCasts();
+ Node->Profile(ID, *Context, true);
+ DependentExprs.push_back(std::make_pair(Node, ID));
+}
+
+void ForLoopIndexUseVisitor::addUsage(const Usage &U) {
+ SourceLocation Begin = U.Range.getBegin();
+ if (Begin.isMacroID())
+ Begin = Context->getSourceManager().getSpellingLoc(Begin);
+
+ if (UsageLocations.insert(Begin).second)
+ Usages.push_back(U);
+}
+
+/// \brief If the unary operator is a dereference of IndexVar, include it
+/// as a valid usage and prune the traversal.
+///
+/// For example, if container.begin() and container.end() both return pointers
+/// to int, this makes sure that the initialization for `k` is not counted as an
+/// unconvertible use of the iterator `i`.
+/// \code
+/// for (int *i = container.begin(), *e = container.end(); i != e; ++i) {
+/// int k = *i + 2;
+/// }
+/// \endcode
+bool ForLoopIndexUseVisitor::TraverseUnaryDeref(UnaryOperator *Uop) {
+ // If we dereference an iterator that's actually a pointer, count the
+ // occurrence.
+ if (isDereferenceOfUop(Uop, IndexVar)) {
+ addUsage(Usage(Uop));
+ return true;
+ }
+
+ return VisitorBase::TraverseUnaryOperator(Uop);
+}
+
+/// \brief If the member expression is operator-> (overloaded or not) on
+/// IndexVar, include it as a valid usage and prune the traversal.
+///
+/// For example, given
+/// \code
+/// struct Foo { int bar(); int x; };
+/// vector<Foo> v;
+/// \endcode
+/// the following uses will be considered convertible:
+/// \code
+/// for (vector<Foo>::iterator i = v.begin(), e = v.end(); i != e; ++i) {
+/// int b = i->bar();
+/// int k = i->x + 1;
+/// }
+/// \endcode
+/// though
+/// \code
+/// for (vector<Foo>::iterator i = v.begin(), e = v.end(); i != e; ++i) {
+/// int k = i.insert(1);
+/// }
+/// for (vector<Foo>::iterator i = v.begin(), e = v.end(); i != e; ++i) {
+/// int b = e->bar();
+/// }
+/// \endcode
+/// will not.
+bool ForLoopIndexUseVisitor::TraverseMemberExpr(MemberExpr *Member) {
+ const Expr *Base = Member->getBase();
+ const DeclRefExpr *Obj = getDeclRef(Base);
+ const Expr *ResultExpr = Member;
+ QualType ExprType;
+ if (const auto *Call =
+ dyn_cast<CXXOperatorCallExpr>(Base->IgnoreParenImpCasts())) {
+ // If operator->() is a MemberExpr containing a CXXOperatorCallExpr, then
+ // the MemberExpr does not have the expression we want. We therefore catch
+ // that instance here.
+ // For example, if vector<Foo>::iterator defines operator->(), then the
+ // example `i->bar()` at the top of this function is a CXXMemberCallExpr
+ // referring to `i->` as the member function called. We want just `i`, so
+ // we take the argument to operator->() as the base object.
+ if (Call->getOperator() == OO_Arrow) {
+ assert(Call->getNumArgs() == 1 &&
+ "Operator-> takes more than one argument");
+ Obj = getDeclRef(Call->getArg(0));
+ ResultExpr = Obj;
+ ExprType = Call->getCallReturnType(*Context);
+ }
+ }
+
+ if (Obj && exprReferencesVariable(IndexVar, Obj)) {
+ // Member calls on the iterator with '.' are not allowed.
+ if (!Member->isArrow()) {
+ OnlyUsedAsIndex = false;
+ return true;
+ }
+
+ if (ExprType.isNull())
+ ExprType = Obj->getType();
+
+ if (!ExprType->isPointerType())
+ return false;
+
+ // FIXME: This works around not having the location of the arrow operator.
+ // Consider adding OperatorLoc to MemberExpr?
+ SourceLocation ArrowLoc = Lexer::getLocForEndOfToken(
+ Base->getExprLoc(), 0, Context->getSourceManager(),
+ Context->getLangOpts());
+ // If something complicated is happening (i.e. the next token isn't an
+ // arrow), give up on making this work.
+ if (ArrowLoc.isValid()) {
+ addUsage(Usage(ResultExpr, Usage::UK_MemberThroughArrow,
+ SourceRange(Base->getExprLoc(), ArrowLoc)));
+ return true;
+ }
+ }
+ return VisitorBase::TraverseMemberExpr(Member);
+}
+
+/// \brief If a member function call is the at() accessor on the container with
+/// IndexVar as the single argument, include it as a valid usage and prune
+/// the traversal.
+///
+/// Member calls on other objects will not be permitted.
+/// Calls on the iterator object are not permitted, unless done through
+/// operator->(). The one exception is allowing vector::at() for pseudoarrays.
+bool ForLoopIndexUseVisitor::TraverseCXXMemberCallExpr(
+ CXXMemberCallExpr *MemberCall) {
+ auto *Member =
+ dyn_cast<MemberExpr>(MemberCall->getCallee()->IgnoreParenImpCasts());
+ if (!Member)
+ return VisitorBase::TraverseCXXMemberCallExpr(MemberCall);
+
+ // We specifically allow an accessor named "at" to let STL in, though
+ // this is restricted to pseudo-arrays by requiring a single, integer
+ // argument.
+ const IdentifierInfo *Ident = Member->getMemberDecl()->getIdentifier();
+ if (Ident && Ident->isStr("at") && MemberCall->getNumArgs() == 1) {
+ if (isIndexInSubscriptExpr(Context, MemberCall->getArg(0), IndexVar,
+ Member->getBase(), ContainerExpr,
+ ContainerNeedsDereference)) {
+ addUsage(Usage(MemberCall));
+ return true;
+ }
+ }
+
+ if (containsExpr(Context, &DependentExprs, Member->getBase()))
+ ConfidenceLevel.lowerTo(Confidence::CL_Risky);
+
+ return VisitorBase::TraverseCXXMemberCallExpr(MemberCall);
+}
+
+/// \brief If an overloaded operator call is a dereference of IndexVar or
+/// a subscript of the container with IndexVar as the single argument,
+/// include it as a valid usage and prune the traversal.
+///
+/// For example, given
+/// \code
+/// struct Foo { int bar(); int x; };
+/// vector<Foo> v;
+/// void f(Foo);
+/// \endcode
+/// the following uses will be considered convertible:
+/// \code
+/// for (vector<Foo>::iterator i = v.begin(), e = v.end(); i != e; ++i) {
+/// f(*i);
+/// }
+/// for (int i = 0; i < v.size(); ++i) {
+/// int i = v[i] + 1;
+/// }
+/// \endcode
+bool ForLoopIndexUseVisitor::TraverseCXXOperatorCallExpr(
+ CXXOperatorCallExpr *OpCall) {
+ switch (OpCall->getOperator()) {
+ case OO_Star:
+ if (isDereferenceOfOpCall(OpCall, IndexVar)) {
+ addUsage(Usage(OpCall));
+ return true;
+ }
+ break;
+
+ case OO_Subscript:
+ if (OpCall->getNumArgs() != 2)
+ break;
+ if (isIndexInSubscriptExpr(Context, OpCall->getArg(1), IndexVar,
+ OpCall->getArg(0), ContainerExpr,
+ ContainerNeedsDereference)) {
+ addUsage(Usage(OpCall));
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return VisitorBase::TraverseCXXOperatorCallExpr(OpCall);
+}
+
+/// \brief If we encounter an array with IndexVar as the index of an
+/// ArraySubsriptExpression, note it as a consistent usage and prune the
+/// AST traversal.
+///
+/// For example, given
+/// \code
+/// const int N = 5;
+/// int arr[N];
+/// \endcode
+/// This is intended to permit
+/// \code
+/// for (int i = 0; i < N; ++i) { /* use arr[i] */ }
+/// \endcode
+/// but not
+/// \code
+/// for (int i = 0; i < N; ++i) { /* use notArr[i] */ }
+/// \endcode
+/// and further checking needs to be done later to ensure that exactly one array
+/// is referenced.
+bool ForLoopIndexUseVisitor::TraverseArraySubscriptExpr(ArraySubscriptExpr *E) {
+ Expr *Arr = E->getBase();
+ if (!isIndexInSubscriptExpr(E->getIdx(), IndexVar))
+ return VisitorBase::TraverseArraySubscriptExpr(E);
+
+ if ((ContainerExpr &&
+ !areSameExpr(Context, Arr->IgnoreParenImpCasts(),
+ ContainerExpr->IgnoreParenImpCasts())) ||
+ !arrayMatchesBoundExpr(Context, Arr->IgnoreImpCasts()->getType(),
+ ArrayBoundExpr)) {
+ // If we have already discovered the array being indexed and this isn't it
+ // or this array doesn't match, mark this loop as unconvertible.
+ OnlyUsedAsIndex = false;
+ return VisitorBase::TraverseArraySubscriptExpr(E);
+ }
+
+ if (!ContainerExpr)
+ ContainerExpr = Arr;
+
+ addUsage(Usage(E));
+ return true;
+}
+
+/// \brief If we encounter a reference to IndexVar in an unpruned branch of the
+/// traversal, mark this loop as unconvertible.
+///
+/// This implements the whitelist for convertible loops: any usages of IndexVar
+/// not explicitly considered convertible by this traversal will be caught by
+/// this function.
+///
+/// Additionally, if the container expression is more complex than just a
+/// DeclRefExpr, and some part of it is appears elsewhere in the loop, lower
+/// our confidence in the transformation.
+///
+/// For example, these are not permitted:
+/// \code
+/// for (int i = 0; i < N; ++i) { printf("arr[%d] = %d", i, arr[i]); }
+/// for (vector<int>::iterator i = container.begin(), e = container.end();
+/// i != e; ++i)
+/// i.insert(0);
+/// for (vector<int>::iterator i = container.begin(), e = container.end();
+/// i != e; ++i)
+/// if (i + 1 != e)
+/// printf("%d", *i);
+/// \endcode
+///
+/// And these will raise the risk level:
+/// \code
+/// int arr[10][20];
+/// int l = 5;
+/// for (int j = 0; j < 20; ++j)
+/// int k = arr[l][j] + l; // using l outside arr[l] is considered risky
+/// for (int i = 0; i < obj.getVector().size(); ++i)
+/// obj.foo(10); // using `obj` is considered risky
+/// \endcode
+bool ForLoopIndexUseVisitor::VisitDeclRefExpr(DeclRefExpr *E) {
+ const ValueDecl *TheDecl = E->getDecl();
+ if (areSameVariable(IndexVar, TheDecl) ||
+ exprReferencesVariable(IndexVar, E) || areSameVariable(EndVar, TheDecl) ||
+ exprReferencesVariable(EndVar, E))
+ OnlyUsedAsIndex = false;
+ if (containsExpr(Context, &DependentExprs, E))
+ ConfidenceLevel.lowerTo(Confidence::CL_Risky);
+ return true;
+}
+
+/// \brief If the loop index is captured by a lambda, replace this capture
+/// by the range-for loop variable.
+///
+/// For example:
+/// \code
+/// for (int i = 0; i < N; ++i) {
+/// auto f = [v, i](int k) {
+/// printf("%d\n", v[i] + k);
+/// };
+/// f(v[i]);
+/// }
+/// \endcode
+///
+/// Will be replaced by:
+/// \code
+/// for (auto & elem : v) {
+/// auto f = [v, elem](int k) {
+/// printf("%d\n", elem + k);
+/// };
+/// f(elem);
+/// }
+/// \endcode
+bool ForLoopIndexUseVisitor::TraverseLambdaCapture(LambdaExpr *LE,
+ const LambdaCapture *C,
+ Expr *Init) {
+ if (C->capturesVariable()) {
+ const VarDecl *VDecl = C->getCapturedVar();
+ if (areSameVariable(IndexVar, cast<ValueDecl>(VDecl))) {
+ // FIXME: if the index is captured, it will count as an usage and the
+ // alias (if any) won't work, because it is only used in case of having
+ // exactly one usage.
+ addUsage(Usage(nullptr,
+ C->getCaptureKind() == LCK_ByCopy ? Usage::UK_CaptureByCopy
+ : Usage::UK_CaptureByRef,
+ C->getLocation()));
+ }
+ }
+ return VisitorBase::TraverseLambdaCapture(LE, C, Init);
+}
+
+/// \brief If we find that another variable is created just to refer to the loop
+/// element, note it for reuse as the loop variable.
+///
+/// See the comments for isAliasDecl.
+bool ForLoopIndexUseVisitor::VisitDeclStmt(DeclStmt *S) {
+ if (!AliasDecl && S->isSingleDecl() &&
+ isAliasDecl(Context, S->getSingleDecl(), IndexVar)) {
+ AliasDecl = S;
+ if (CurrStmtParent) {
+ if (isa<IfStmt>(CurrStmtParent) || isa<WhileStmt>(CurrStmtParent) ||
+ isa<SwitchStmt>(CurrStmtParent))
+ ReplaceWithAliasUse = true;
+ else if (isa<ForStmt>(CurrStmtParent)) {
+ if (cast<ForStmt>(CurrStmtParent)->getConditionVariableDeclStmt() == S)
+ ReplaceWithAliasUse = true;
+ else
+ // It's assumed S came the for loop's init clause.
+ AliasFromForInit = true;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool ForLoopIndexUseVisitor::TraverseStmt(Stmt *S) {
+ // If this is an initialization expression for a lambda capture, prune the
+ // traversal so that we don't end up diagnosing the contained DeclRefExpr as
+ // inconsistent usage. No need to record the usage here -- this is done in
+ // TraverseLambdaCapture().
+ if (const auto *LE = dyn_cast_or_null<LambdaExpr>(NextStmtParent)) {
+ // Any child of a LambdaExpr that isn't the body is an initialization
+ // expression.
+ if (S != LE->getBody()) {
+ return true;
+ }
+ }
+
+ // All this pointer swapping is a mechanism for tracking immediate parentage
+ // of Stmts.
+ const Stmt *OldNextParent = NextStmtParent;
+ CurrStmtParent = NextStmtParent;
+ NextStmtParent = S;
+ bool Result = VisitorBase::TraverseStmt(S);
+ NextStmtParent = OldNextParent;
+ return Result;
+}
+
+std::string VariableNamer::createIndexName() {
+ // FIXME: Add in naming conventions to handle:
+ // - How to handle conflicts.
+ // - An interactive process for naming.
+ std::string IteratorName;
+ StringRef ContainerName;
+ if (TheContainer)
+ ContainerName = TheContainer->getName();
+
+ size_t Len = ContainerName.size();
+ if (Len > 1 && ContainerName.endswith(Style == NS_UpperCase ? "S" : "s")) {
+ IteratorName = ContainerName.substr(0, Len - 1);
+ // E.g.: (auto thing : things)
+ if (!declarationExists(IteratorName) || IteratorName == OldIndex->getName())
+ return IteratorName;
+ }
+
+ if (Len > 2 && ContainerName.endswith(Style == NS_UpperCase ? "S_" : "s_")) {
+ IteratorName = ContainerName.substr(0, Len - 2);
+ // E.g.: (auto thing : things_)
+ if (!declarationExists(IteratorName) || IteratorName == OldIndex->getName())
+ return IteratorName;
+ }
+
+ return OldIndex->getName();
+}
+
+/// \brief Determines whether or not the the name \a Symbol conflicts with
+/// language keywords or defined macros. Also checks if the name exists in
+/// LoopContext, any of its parent contexts, or any of its child statements.
+///
+/// We also check to see if the same identifier was generated by this loop
+/// converter in a loop nested within SourceStmt.
+bool VariableNamer::declarationExists(StringRef Symbol) {
+ assert(Context != nullptr && "Expected an ASTContext");
+ IdentifierInfo &Ident = Context->Idents.get(Symbol);
+
+ // Check if the symbol is not an identifier (ie. is a keyword or alias).
+ if (!isAnyIdentifier(Ident.getTokenID()))
+ return true;
+
+ // Check for conflicting macro definitions.
+ if (Ident.hasMacroDefinition())
+ return true;
+
+ // Determine if the symbol was generated in a parent context.
+ for (const Stmt *S = SourceStmt; S != nullptr; S = ReverseAST->lookup(S)) {
+ StmtGeneratedVarNameMap::const_iterator I = GeneratedDecls->find(S);
+ if (I != GeneratedDecls->end() && I->second == Symbol)
+ return true;
+ }
+
+ // FIXME: Rather than detecting conflicts at their usages, we should check the
+ // parent context.
+ // For some reason, lookup() always returns the pair (NULL, NULL) because its
+ // StoredDeclsMap is not initialized (i.e. LookupPtr.getInt() is false inside
+ // of DeclContext::lookup()). Why is this?
+
+ // Finally, determine if the symbol was used in the loop or a child context.
+ DeclFinderASTVisitor DeclFinder(Symbol, GeneratedDecls);
+ return DeclFinder.findUsages(SourceStmt);
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.h
new file mode 100644
index 0000000..bee77d9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.h
@@ -0,0 +1,467 @@
+//===--- LoopConvertUtils.h - clang-tidy ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOP_CONVERT_UTILS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOP_CONVERT_UTILS_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+enum LoopFixerKind { LFK_Array, LFK_Iterator, LFK_PseudoArray };
+
+/// A map used to walk the AST in reverse: maps child Stmt to parent Stmt.
+typedef llvm::DenseMap<const clang::Stmt *, const clang::Stmt *> StmtParentMap;
+
+/// A map used to walk the AST in reverse:
+/// maps VarDecl to the to parent DeclStmt.
+typedef llvm::DenseMap<const clang::VarDecl *, const clang::DeclStmt *>
+ DeclParentMap;
+
+/// A map used to track which variables have been removed by a refactoring pass.
+/// It maps the parent ForStmt to the removed index variable's VarDecl.
+typedef llvm::DenseMap<const clang::ForStmt *, const clang::VarDecl *>
+ ReplacedVarsMap;
+
+/// A map used to remember the variable names generated in a Stmt
+typedef llvm::DenseMap<const clang::Stmt *, std::string>
+ StmtGeneratedVarNameMap;
+
+/// A vector used to store the AST subtrees of an Expr.
+typedef llvm::SmallVector<const clang::Expr *, 16> ComponentVector;
+
+/// \brief Class used build the reverse AST properties needed to detect
+/// name conflicts and free variables.
+class StmtAncestorASTVisitor
+ : public clang::RecursiveASTVisitor<StmtAncestorASTVisitor> {
+public:
+ StmtAncestorASTVisitor() { StmtStack.push_back(nullptr); }
+
+ /// \brief Run the analysis on the TranslationUnitDecl.
+ ///
+ /// In case we're running this analysis multiple times, don't repeat the work.
+ void gatherAncestors(const clang::TranslationUnitDecl *T) {
+ if (StmtAncestors.empty())
+ TraverseDecl(const_cast<clang::TranslationUnitDecl *>(T));
+ }
+
+ /// Accessor for StmtAncestors.
+ const StmtParentMap &getStmtToParentStmtMap() { return StmtAncestors; }
+
+ /// Accessor for DeclParents.
+ const DeclParentMap &getDeclToParentStmtMap() { return DeclParents; }
+
+ friend class clang::RecursiveASTVisitor<StmtAncestorASTVisitor>;
+
+private:
+ StmtParentMap StmtAncestors;
+ DeclParentMap DeclParents;
+ llvm::SmallVector<const clang::Stmt *, 16> StmtStack;
+
+ bool TraverseStmt(clang::Stmt *Statement);
+ bool VisitDeclStmt(clang::DeclStmt *Statement);
+};
+
+/// Class used to find the variables and member expressions on which an
+/// arbitrary expression depends.
+class ComponentFinderASTVisitor
+ : public clang::RecursiveASTVisitor<ComponentFinderASTVisitor> {
+public:
+ ComponentFinderASTVisitor() = default;
+
+ /// Find the components of an expression and place them in a ComponentVector.
+ void findExprComponents(const clang::Expr *SourceExpr) {
+ TraverseStmt(const_cast<clang::Expr *>(SourceExpr));
+ }
+
+ /// Accessor for Components.
+ const ComponentVector &getComponents() { return Components; }
+
+ friend class clang::RecursiveASTVisitor<ComponentFinderASTVisitor>;
+
+private:
+ ComponentVector Components;
+
+ bool VisitDeclRefExpr(clang::DeclRefExpr *E);
+ bool VisitMemberExpr(clang::MemberExpr *Member);
+};
+
+/// Class used to determine if an expression is dependent on a variable declared
+/// inside of the loop where it would be used.
+class DependencyFinderASTVisitor
+ : public clang::RecursiveASTVisitor<DependencyFinderASTVisitor> {
+public:
+ DependencyFinderASTVisitor(const StmtParentMap *StmtParents,
+ const DeclParentMap *DeclParents,
+ const ReplacedVarsMap *ReplacedVars,
+ const clang::Stmt *ContainingStmt)
+ : StmtParents(StmtParents), DeclParents(DeclParents),
+ ContainingStmt(ContainingStmt), ReplacedVars(ReplacedVars) {}
+
+ /// \brief Run the analysis on Body, and return true iff the expression
+ /// depends on some variable declared within ContainingStmt.
+ ///
+ /// This is intended to protect against hoisting the container expression
+ /// outside of an inner context if part of that expression is declared in that
+ /// inner context.
+ ///
+ /// For example,
+ /// \code
+ /// const int N = 10, M = 20;
+ /// int arr[N][M];
+ /// int getRow();
+ ///
+ /// for (int i = 0; i < M; ++i) {
+ /// int k = getRow();
+ /// printf("%d:", arr[k][i]);
+ /// }
+ /// \endcode
+ /// At first glance, this loop looks like it could be changed to
+ /// \code
+ /// for (int elem : arr[k]) {
+ /// int k = getIndex();
+ /// printf("%d:", elem);
+ /// }
+ /// \endcode
+ /// But this is malformed, since `k` is used before it is defined!
+ ///
+ /// In order to avoid this, this class looks at the container expression
+ /// `arr[k]` and decides whether or not it contains a sub-expression declared
+ /// within the the loop body.
+ bool dependsOnInsideVariable(const clang::Stmt *Body) {
+ DependsOnInsideVariable = false;
+ TraverseStmt(const_cast<clang::Stmt *>(Body));
+ return DependsOnInsideVariable;
+ }
+
+ friend class clang::RecursiveASTVisitor<DependencyFinderASTVisitor>;
+
+private:
+ const StmtParentMap *StmtParents;
+ const DeclParentMap *DeclParents;
+ const clang::Stmt *ContainingStmt;
+ const ReplacedVarsMap *ReplacedVars;
+ bool DependsOnInsideVariable;
+
+ bool VisitVarDecl(clang::VarDecl *V);
+ bool VisitDeclRefExpr(clang::DeclRefExpr *D);
+};
+
+/// Class used to determine if any declarations used in a Stmt would conflict
+/// with a particular identifier. This search includes the names that don't
+/// actually appear in the AST (i.e. created by a refactoring tool) by including
+/// a map from Stmts to generated names associated with those stmts.
+class DeclFinderASTVisitor
+ : public clang::RecursiveASTVisitor<DeclFinderASTVisitor> {
+public:
+ DeclFinderASTVisitor(const std::string &Name,
+ const StmtGeneratedVarNameMap *GeneratedDecls)
+ : Name(Name), GeneratedDecls(GeneratedDecls), Found(false) {}
+
+ /// Attempts to find any usages of variables name Name in Body, returning
+ /// true when it is used in Body. This includes the generated loop variables
+ /// of ForStmts which have already been transformed.
+ bool findUsages(const clang::Stmt *Body) {
+ Found = false;
+ TraverseStmt(const_cast<clang::Stmt *>(Body));
+ return Found;
+ }
+
+ friend class clang::RecursiveASTVisitor<DeclFinderASTVisitor>;
+
+private:
+ std::string Name;
+ /// GeneratedDecls keeps track of ForStmts which have been transformed,
+ /// mapping each modified ForStmt to the variable generated in the loop.
+ const StmtGeneratedVarNameMap *GeneratedDecls;
+ bool Found;
+
+ bool VisitForStmt(clang::ForStmt *F);
+ bool VisitNamedDecl(clang::NamedDecl *D);
+ bool VisitDeclRefExpr(clang::DeclRefExpr *D);
+ bool VisitTypeLoc(clang::TypeLoc TL);
+};
+
+/// \brief The information needed to describe a valid convertible usage
+/// of an array index or iterator.
+struct Usage {
+ enum UsageKind {
+ // Regular usages of the loop index (the ones not specified below). Some
+ // examples:
+ // \code
+ // int X = 8 * Arr[i];
+ // ^~~~~~
+ // f(param1, param2, *It);
+ // ^~~
+ // if (Vec[i].SomeBool) {}
+ // ^~~~~~
+ // \endcode
+ UK_Default,
+ // Indicates whether this is an access to a member through the arrow
+ // operator on pointers or iterators.
+ UK_MemberThroughArrow,
+ // If the variable is being captured by a lambda, indicates whether the
+ // capture was done by value or by reference.
+ UK_CaptureByCopy,
+ UK_CaptureByRef
+ };
+ // The expression that is going to be converted. Null in case of lambda
+ // captures.
+ const Expr *Expression;
+
+ UsageKind Kind;
+
+ // Range that covers this usage.
+ SourceRange Range;
+
+ explicit Usage(const Expr *E)
+ : Expression(E), Kind(UK_Default), Range(Expression->getSourceRange()) {}
+ Usage(const Expr *E, UsageKind Kind, SourceRange Range)
+ : Expression(E), Kind(Kind), Range(std::move(Range)) {}
+};
+
+/// \brief A class to encapsulate lowering of the tool's confidence level.
+class Confidence {
+public:
+ enum Level {
+ // Transformations that are likely to change semantics.
+ CL_Risky,
+
+ // Transformations that might change semantics.
+ CL_Reasonable,
+
+ // Transformations that will not change semantics.
+ CL_Safe
+ };
+ /// \brief Initialize confidence level.
+ explicit Confidence(Confidence::Level Level) : CurrentLevel(Level) {}
+
+ /// \brief Lower the internal confidence level to Level, but do not raise it.
+ void lowerTo(Confidence::Level Level) {
+ CurrentLevel = std::min(Level, CurrentLevel);
+ }
+
+ /// \brief Return the internal confidence level.
+ Level getLevel() const { return CurrentLevel; }
+
+private:
+ Level CurrentLevel;
+};
+
+// The main computational result of ForLoopIndexVisitor.
+typedef llvm::SmallVector<Usage, 8> UsageResult;
+
+// General functions used by ForLoopIndexUseVisitor and LoopConvertCheck.
+const Expr *digThroughConstructors(const Expr *E);
+bool areSameExpr(ASTContext *Context, const Expr *First, const Expr *Second);
+const DeclRefExpr *getDeclRef(const Expr *E);
+bool areSameVariable(const ValueDecl *First, const ValueDecl *Second);
+
+/// \brief Discover usages of expressions consisting of index or iterator
+/// access.
+///
+/// Given an index variable, recursively crawls a for loop to discover if the
+/// index variable is used in a way consistent with range-based for loop access.
+class ForLoopIndexUseVisitor
+ : public RecursiveASTVisitor<ForLoopIndexUseVisitor> {
+public:
+ ForLoopIndexUseVisitor(ASTContext *Context, const VarDecl *IndexVar,
+ const VarDecl *EndVar, const Expr *ContainerExpr,
+ const Expr *ArrayBoundExpr,
+ bool ContainerNeedsDereference);
+
+ /// \brief Finds all uses of IndexVar in Body, placing all usages in Usages,
+ /// and returns true if IndexVar was only used in a way consistent with a
+ /// range-based for loop.
+ ///
+ /// The general strategy is to reject any DeclRefExprs referencing IndexVar,
+ /// with the exception of certain acceptable patterns.
+ /// For arrays, the DeclRefExpr for IndexVar must appear as the index of an
+ /// ArraySubscriptExpression. Iterator-based loops may dereference
+ /// IndexVar or call methods through operator-> (builtin or overloaded).
+ /// Array-like containers may use IndexVar as a parameter to the at() member
+ /// function and in overloaded operator[].
+ bool findAndVerifyUsages(const Stmt *Body);
+
+ /// \brief Add a set of components that we should consider relevant to the
+ /// container.
+ void addComponents(const ComponentVector &Components);
+
+ /// \brief Accessor for Usages.
+ const UsageResult &getUsages() const { return Usages; }
+
+ /// \brief Adds the Usage if it was not added before.
+ void addUsage(const Usage &U);
+
+ /// \brief Get the container indexed by IndexVar, if any.
+ const Expr *getContainerIndexed() const { return ContainerExpr; }
+
+ /// \brief Returns the statement declaring the variable created as an alias
+ /// for the loop element, if any.
+ const DeclStmt *getAliasDecl() const { return AliasDecl; }
+
+ /// \brief Accessor for ConfidenceLevel.
+ Confidence::Level getConfidenceLevel() const {
+ return ConfidenceLevel.getLevel();
+ }
+
+ /// \brief Indicates if the alias declaration was in a place where it cannot
+ /// simply be removed but rather replaced with a use of the alias variable.
+ /// For example, variables declared in the condition of an if, switch, or for
+ /// stmt.
+ bool aliasUseRequired() const { return ReplaceWithAliasUse; }
+
+ /// \brief Indicates if the alias declaration came from the init clause of a
+ /// nested for loop. SourceRanges provided by Clang for DeclStmts in this
+ /// case need to be adjusted.
+ bool aliasFromForInit() const { return AliasFromForInit; }
+
+private:
+ /// Typedef used in CRTP functions.
+ typedef RecursiveASTVisitor<ForLoopIndexUseVisitor> VisitorBase;
+ friend class RecursiveASTVisitor<ForLoopIndexUseVisitor>;
+
+ /// Overriden methods for RecursiveASTVisitor's traversal.
+ bool TraverseArraySubscriptExpr(ArraySubscriptExpr *E);
+ bool TraverseCXXMemberCallExpr(CXXMemberCallExpr *MemberCall);
+ bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *OpCall);
+ bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init);
+ bool TraverseMemberExpr(MemberExpr *Member);
+ bool TraverseUnaryDeref(UnaryOperator *Uop);
+ bool VisitDeclRefExpr(DeclRefExpr *E);
+ bool VisitDeclStmt(DeclStmt *S);
+ bool TraverseStmt(Stmt *S);
+
+ /// \brief Add an expression to the list of expressions on which the container
+ /// expression depends.
+ void addComponent(const Expr *E);
+
+ // Input member variables:
+ ASTContext *Context;
+ /// The index variable's VarDecl.
+ const VarDecl *IndexVar;
+ /// The loop's 'end' variable, which cannot be mentioned at all.
+ const VarDecl *EndVar;
+ /// The Expr which refers to the container.
+ const Expr *ContainerExpr;
+ /// The Expr which refers to the terminating condition for array-based loops.
+ const Expr *ArrayBoundExpr;
+ bool ContainerNeedsDereference;
+
+ // Output member variables:
+ /// A container which holds all usages of IndexVar as the index of
+ /// ArraySubscriptExpressions.
+ UsageResult Usages;
+ llvm::SmallSet<SourceLocation, 8> UsageLocations;
+ bool OnlyUsedAsIndex;
+ /// The DeclStmt for an alias to the container element.
+ const DeclStmt *AliasDecl;
+ Confidence ConfidenceLevel;
+ /// \brief A list of expressions on which ContainerExpr depends.
+ ///
+ /// If any of these expressions are encountered outside of an acceptable usage
+ /// of the loop element, lower our confidence level.
+ llvm::SmallVector<std::pair<const Expr *, llvm::FoldingSetNodeID>, 16>
+ DependentExprs;
+
+ /// The parent-in-waiting. Will become the real parent once we traverse down
+ /// one level in the AST.
+ const Stmt *NextStmtParent;
+ /// The actual parent of a node when Visit*() calls are made. Only the
+ /// parentage of DeclStmt's to possible iteration/selection statements is of
+ /// importance.
+ const Stmt *CurrStmtParent;
+
+ /// \see aliasUseRequired().
+ bool ReplaceWithAliasUse;
+ /// \see aliasFromForInit().
+ bool AliasFromForInit;
+};
+
+struct TUTrackingInfo {
+ /// \brief Reset and initialize per-TU tracking information.
+ ///
+ /// Must be called before using container accessors.
+ TUTrackingInfo() : ParentFinder(new StmtAncestorASTVisitor) {}
+
+ StmtAncestorASTVisitor &getParentFinder() { return *ParentFinder; }
+ StmtGeneratedVarNameMap &getGeneratedDecls() { return GeneratedDecls; }
+ ReplacedVarsMap &getReplacedVars() { return ReplacedVars; }
+
+private:
+ std::unique_ptr<StmtAncestorASTVisitor> ParentFinder;
+ StmtGeneratedVarNameMap GeneratedDecls;
+ ReplacedVarsMap ReplacedVars;
+};
+
+/// \brief Create names for generated variables within a particular statement.
+///
+/// VariableNamer uses a DeclContext as a reference point, checking for any
+/// conflicting declarations higher up in the context or within SourceStmt.
+/// It creates a variable name using hints from a source container and the old
+/// index, if they exist.
+class VariableNamer {
+public:
+ // Supported naming styles.
+ enum NamingStyle {
+ NS_CamelBack,
+ NS_CamelCase,
+ NS_LowerCase,
+ NS_UpperCase,
+ };
+
+ VariableNamer(StmtGeneratedVarNameMap *GeneratedDecls,
+ const StmtParentMap *ReverseAST, const clang::Stmt *SourceStmt,
+ const clang::VarDecl *OldIndex,
+ const clang::ValueDecl *TheContainer,
+ const clang::ASTContext *Context, NamingStyle Style)
+ : GeneratedDecls(GeneratedDecls), ReverseAST(ReverseAST),
+ SourceStmt(SourceStmt), OldIndex(OldIndex), TheContainer(TheContainer),
+ Context(Context), Style(Style) {}
+
+ /// \brief Generate a new index name.
+ ///
+ /// Generates the name to be used for an inserted iterator. It relies on
+ /// declarationExists() to determine that there are no naming conflicts, and
+ /// tries to use some hints from the container name and the old index name.
+ std::string createIndexName();
+
+private:
+ StmtGeneratedVarNameMap *GeneratedDecls;
+ const StmtParentMap *ReverseAST;
+ const clang::Stmt *SourceStmt;
+ const clang::VarDecl *OldIndex;
+ const clang::ValueDecl *TheContainer;
+ const clang::ASTContext *Context;
+ const NamingStyle Style;
+
+ // Determine whether or not a declaration that would conflict with Symbol
+ // exists in an outer context or in any statement contained in SourceStmt.
+ bool declarationExists(llvm::StringRef Symbol);
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOP_CONVERT_UTILS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
new file mode 100644
index 0000000..541c2cb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.cpp
@@ -0,0 +1,32 @@
+//===--- MakeSharedCheck.cpp - clang-tidy----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MakeSharedCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+MakeSharedCheck::MakeSharedCheck(StringRef Name, ClangTidyContext *Context)
+ : MakeSmartPtrCheck(Name, Context, "std::make_shared") {}
+
+MakeSharedCheck::SmartPtrTypeMatcher
+MakeSharedCheck::getSmartPointerTypeMatcher() const {
+ return qualType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(classTemplateSpecializationDecl(
+ hasName("::std::shared_ptr"), templateArgumentCountIs(1),
+ hasTemplateArgument(0, templateArgument(refersToType(
+ qualType().bind(PointerType)))))))));
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
new file mode 100644
index 0000000..cf01446
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeSharedCheck.h
@@ -0,0 +1,43 @@
+//===--- MakeSharedCheck.h - clang-tidy--------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SHARED_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SHARED_H
+
+#include "MakeSmartPtrCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Replace the pattern:
+/// \code
+/// std::shared_ptr<type>(new type(args...))
+/// \endcode
+///
+/// With the safer version:
+/// \code
+/// std::make_shared<type>(args...)
+/// \endcode
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-make-shared.html
+class MakeSharedCheck : public MakeSmartPtrCheck {
+public:
+ MakeSharedCheck(StringRef Name, ClangTidyContext *Context);
+
+protected:
+ SmartPtrTypeMatcher getSmartPointerTypeMatcher() const override;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SHARED_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
new file mode 100644
index 0000000..8deaa83
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -0,0 +1,382 @@
+//===--- MakeSmartPtrCheck.cpp - clang-tidy--------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MakeSharedCheck.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+namespace {
+
+constexpr char StdMemoryHeader[] = "memory";
+
+std::string GetNewExprName(const CXXNewExpr *NewExpr,
+ const SourceManager &SM,
+ const LangOptions &Lang) {
+ StringRef WrittenName = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(
+ NewExpr->getAllocatedTypeSourceInfo()->getTypeLoc().getSourceRange()),
+ SM, Lang);
+ if (NewExpr->isArray()) {
+ return WrittenName.str() + "[]";
+ }
+ return WrittenName.str();
+}
+
+} // namespace
+
+const char MakeSmartPtrCheck::PointerType[] = "pointerType";
+const char MakeSmartPtrCheck::ConstructorCall[] = "constructorCall";
+const char MakeSmartPtrCheck::ResetCall[] = "resetCall";
+const char MakeSmartPtrCheck::NewExpression[] = "newExpression";
+
+MakeSmartPtrCheck::MakeSmartPtrCheck(StringRef Name,
+ ClangTidyContext* Context,
+ StringRef MakeSmartPtrFunctionName)
+ : ClangTidyCheck(Name, Context),
+ IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
+ Options.getLocalOrGlobal("IncludeStyle", "llvm"))),
+ MakeSmartPtrFunctionHeader(
+ Options.get("MakeSmartPtrFunctionHeader", StdMemoryHeader)),
+ MakeSmartPtrFunctionName(
+ Options.get("MakeSmartPtrFunction", MakeSmartPtrFunctionName)),
+ IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {}
+
+void MakeSmartPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IncludeStyle", IncludeStyle);
+ Options.store(Opts, "MakeSmartPtrFunctionHeader", MakeSmartPtrFunctionHeader);
+ Options.store(Opts, "MakeSmartPtrFunction", MakeSmartPtrFunctionName);
+ Options.store(Opts, "IgnoreMacros", IgnoreMacros);
+}
+
+bool MakeSmartPtrCheck::isLanguageVersionSupported(
+ const LangOptions &LangOpts) const {
+ return LangOpts.CPlusPlus11;
+}
+
+void MakeSmartPtrCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+ if (isLanguageVersionSupported(getLangOpts())) {
+ Inserter.reset(new utils::IncludeInserter(
+ Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle));
+ Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
+ }
+}
+
+void MakeSmartPtrCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
+ if (!isLanguageVersionSupported(getLangOpts()))
+ return;
+
+ // Calling make_smart_ptr from within a member function of a type with a
+ // private or protected constructor would be ill-formed.
+ auto CanCallCtor = unless(has(ignoringImpCasts(
+ cxxConstructExpr(hasDeclaration(decl(unless(isPublic())))))));
+
+ Finder->addMatcher(
+ cxxBindTemporaryExpr(has(ignoringParenImpCasts(
+ cxxConstructExpr(
+ hasType(getSmartPointerTypeMatcher()), argumentCountIs(1),
+ hasArgument(0,
+ cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType(
+ equalsBoundNode(PointerType))))),
+ CanCallCtor)
+ .bind(NewExpression)),
+ unless(isInTemplateInstantiation()))
+ .bind(ConstructorCall)))),
+ this);
+
+ Finder->addMatcher(
+ cxxMemberCallExpr(
+ thisPointerType(getSmartPointerTypeMatcher()),
+ callee(cxxMethodDecl(hasName("reset"))),
+ hasArgument(0, cxxNewExpr(CanCallCtor).bind(NewExpression)),
+ unless(isInTemplateInstantiation()))
+ .bind(ResetCall),
+ this);
+}
+
+void MakeSmartPtrCheck::check(const MatchFinder::MatchResult &Result) {
+ // 'smart_ptr' refers to 'std::shared_ptr' or 'std::unique_ptr' or other
+ // pointer, 'make_smart_ptr' refers to 'std::make_shared' or
+ // 'std::make_unique' or other function that creates smart_ptr.
+
+ SourceManager &SM = *Result.SourceManager;
+ const auto *Construct =
+ Result.Nodes.getNodeAs<CXXConstructExpr>(ConstructorCall);
+ const auto *Reset = Result.Nodes.getNodeAs<CXXMemberCallExpr>(ResetCall);
+ const auto *Type = Result.Nodes.getNodeAs<QualType>(PointerType);
+ const auto *New = Result.Nodes.getNodeAs<CXXNewExpr>(NewExpression);
+
+ if (New->getNumPlacementArgs() != 0)
+ return;
+
+ if (Construct)
+ checkConstruct(SM, Construct, Type, New);
+ else if (Reset)
+ checkReset(SM, Reset, New);
+}
+
+void MakeSmartPtrCheck::checkConstruct(SourceManager &SM,
+ const CXXConstructExpr *Construct,
+ const QualType *Type,
+ const CXXNewExpr *New) {
+ SourceLocation ConstructCallStart = Construct->getExprLoc();
+ bool InMacro = ConstructCallStart.isMacroID();
+
+ if (InMacro && IgnoreMacros) {
+ return;
+ }
+
+ bool Invalid = false;
+ StringRef ExprStr = Lexer::getSourceText(
+ CharSourceRange::getCharRange(
+ ConstructCallStart, Construct->getParenOrBraceRange().getBegin()),
+ SM, getLangOpts(), &Invalid);
+ if (Invalid)
+ return;
+
+ auto Diag = diag(ConstructCallStart, "use %0 instead")
+ << MakeSmartPtrFunctionName;
+
+ // Disable the fix in macros.
+ if (InMacro) {
+ return;
+ }
+
+ if (!replaceNew(Diag, New, SM)) {
+ return;
+ }
+
+ // Find the location of the template's left angle.
+ size_t LAngle = ExprStr.find("<");
+ SourceLocation ConstructCallEnd;
+ if (LAngle == StringRef::npos) {
+ // If the template argument is missing (because it is part of the alias)
+ // we have to add it back.
+ ConstructCallEnd = ConstructCallStart.getLocWithOffset(ExprStr.size());
+ Diag << FixItHint::CreateInsertion(
+ ConstructCallEnd,
+ "<" + GetNewExprName(New, SM, getLangOpts()) + ">");
+ } else {
+ ConstructCallEnd = ConstructCallStart.getLocWithOffset(LAngle);
+ }
+
+ Diag << FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(ConstructCallStart, ConstructCallEnd),
+ MakeSmartPtrFunctionName);
+
+ // If the smart_ptr is built with brace enclosed direct initialization, use
+ // parenthesis instead.
+ if (Construct->isListInitialization()) {
+ SourceRange BraceRange = Construct->getParenOrBraceRange();
+ Diag << FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(
+ BraceRange.getBegin(), BraceRange.getBegin().getLocWithOffset(1)),
+ "(");
+ Diag << FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(BraceRange.getEnd(),
+ BraceRange.getEnd().getLocWithOffset(1)),
+ ")");
+ }
+
+ insertHeader(Diag, SM.getFileID(ConstructCallStart));
+}
+
+void MakeSmartPtrCheck::checkReset(SourceManager &SM,
+ const CXXMemberCallExpr *Reset,
+ const CXXNewExpr *New) {
+ const auto *Expr = cast<MemberExpr>(Reset->getCallee());
+ SourceLocation OperatorLoc = Expr->getOperatorLoc();
+ SourceLocation ResetCallStart = Reset->getExprLoc();
+ SourceLocation ExprStart = Expr->getLocStart();
+ SourceLocation ExprEnd =
+ Lexer::getLocForEndOfToken(Expr->getLocEnd(), 0, SM, getLangOpts());
+
+ bool InMacro = ExprStart.isMacroID();
+
+ if (InMacro && IgnoreMacros) {
+ return;
+ }
+
+ // There are some cases where we don't have operator ("." or "->") of the
+ // "reset" expression, e.g. call "reset()" method directly in the subclass of
+ // "std::unique_ptr<>". We skip these cases.
+ if (OperatorLoc.isInvalid()) {
+ return;
+ }
+
+ auto Diag = diag(ResetCallStart, "use %0 instead")
+ << MakeSmartPtrFunctionName;
+
+ // Disable the fix in macros.
+ if (InMacro) {
+ return;
+ }
+
+ if (!replaceNew(Diag, New, SM)) {
+ return;
+ }
+
+ Diag << FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(OperatorLoc, ExprEnd),
+ (llvm::Twine(" = ") + MakeSmartPtrFunctionName + "<" +
+ GetNewExprName(New, SM, getLangOpts()) + ">")
+ .str());
+
+ if (Expr->isArrow())
+ Diag << FixItHint::CreateInsertion(ExprStart, "*");
+
+ insertHeader(Diag, SM.getFileID(OperatorLoc));
+}
+
+bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
+ const CXXNewExpr *New,
+ SourceManager& SM) {
+ SourceLocation NewStart = New->getSourceRange().getBegin();
+ SourceLocation NewEnd = New->getSourceRange().getEnd();
+
+ // Skip when the source location of the new expression is invalid.
+ if (NewStart.isInvalid() || NewEnd.isInvalid())
+ return false;
+
+ std::string ArraySizeExpr;
+ if (const auto* ArraySize = New->getArraySize()) {
+ ArraySizeExpr = Lexer::getSourceText(CharSourceRange::getTokenRange(
+ ArraySize->getSourceRange()),
+ SM, getLangOpts())
+ .str();
+ }
+
+ switch (New->getInitializationStyle()) {
+ case CXXNewExpr::NoInit: {
+ if (ArraySizeExpr.empty()) {
+ Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd));
+ } else {
+ // New array expression without written initializer:
+ // smart_ptr<Foo[]>(new Foo[5]);
+ Diag << FixItHint::CreateReplacement(SourceRange(NewStart, NewEnd),
+ ArraySizeExpr);
+ }
+ break;
+ }
+ case CXXNewExpr::CallInit: {
+ // FIXME: Add fixes for constructors with parameters that can be created
+ // with a C++11 braced-init-list (e.g. std::vector, std::map).
+ // Unlike ordinal cases, braced list can not be deduced in
+ // std::make_smart_ptr, we need to specify the type explicitly in the fixes:
+ // struct S { S(std::initializer_list<int>, int); };
+ // struct S2 { S2(std::vector<int>); };
+ // smart_ptr<S>(new S({1, 2, 3}, 1)); // C++98 call-style initialization
+ // smart_ptr<S>(new S({}, 1));
+ // smart_ptr<S2>(new S2({1})); // implicit conversion:
+ // // std::initializer_list => std::vector
+ // The above samples have to be replaced with:
+ // std::make_smart_ptr<S>(std::initializer_list<int>({1, 2, 3}), 1);
+ // std::make_smart_ptr<S>(std::initializer_list<int>({}), 1);
+ // std::make_smart_ptr<S2>(std::vector<int>({1}));
+ if (const auto *CE = New->getConstructExpr()) {
+ for (const auto *Arg : CE->arguments()) {
+ if (isa<CXXStdInitializerListExpr>(Arg)) {
+ return false;
+ }
+ // Check whether we construct a class from a std::initializer_list.
+ // If so, we won't generate the fixes.
+ auto IsStdInitListInitConstructExpr = [](const Expr* E) {
+ assert(E);
+ if (const auto *ImplicitCE = dyn_cast<CXXConstructExpr>(E)) {
+ if (ImplicitCE->isStdInitListInitialization())
+ return true;
+ }
+ return false;
+ };
+ if (IsStdInitListInitConstructExpr(Arg->IgnoreImplicit()))
+ return false;
+ }
+ }
+ if (ArraySizeExpr.empty()) {
+ SourceRange InitRange = New->getDirectInitRange();
+ Diag << FixItHint::CreateRemoval(
+ SourceRange(NewStart, InitRange.getBegin()));
+ Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd));
+ }
+ else {
+ // New array expression with default/value initialization:
+ // smart_ptr<Foo[]>(new int[5]());
+ // smart_ptr<Foo[]>(new Foo[5]());
+ Diag << FixItHint::CreateReplacement(SourceRange(NewStart, NewEnd),
+ ArraySizeExpr);
+ }
+ break;
+ }
+ case CXXNewExpr::ListInit: {
+ // Range of the substring that we do not want to remove.
+ SourceRange InitRange;
+ if (const auto *NewConstruct = New->getConstructExpr()) {
+ if (NewConstruct->isStdInitListInitialization()) {
+ // FIXME: Add fixes for direct initialization with the initializer-list
+ // constructor. Similar to the above CallInit case, the type has to be
+ // specified explicitly in the fixes.
+ // struct S { S(std::initializer_list<int>); };
+ // smart_ptr<S>(new S{1, 2, 3}); // C++11 direct list-initialization
+ // smart_ptr<S>(new S{}); // use initializer-list consturctor
+ // The above cases have to be replaced with:
+ // std::make_smart_ptr<S>(std::initializer_list<int>({1, 2, 3}));
+ // std::make_smart_ptr<S>(std::initializer_list<int>({}));
+ return false;
+ } else {
+ // Direct initialization with ordinary constructors.
+ // struct S { S(int x); S(); };
+ // smart_ptr<S>(new S{5});
+ // smart_ptr<S>(new S{}); // use default constructor
+ // The arguments in the initialization list are going to be forwarded to
+ // the constructor, so this has to be replaced with:
+ // std::make_smart_ptr<S>(5);
+ // std::make_smart_ptr<S>();
+ InitRange = SourceRange(
+ NewConstruct->getParenOrBraceRange().getBegin().getLocWithOffset(1),
+ NewConstruct->getParenOrBraceRange().getEnd().getLocWithOffset(-1));
+ }
+ } else {
+ // Aggregate initialization.
+ // smart_ptr<Pair>(new Pair{first, second});
+ // Has to be replaced with:
+ // smart_ptr<Pair>(Pair{first, second});
+ InitRange = SourceRange(
+ New->getAllocatedTypeSourceInfo()->getTypeLoc().getLocStart(),
+ New->getInitializer()->getSourceRange().getEnd());
+ }
+ Diag << FixItHint::CreateRemoval(
+ CharSourceRange::getCharRange(NewStart, InitRange.getBegin()));
+ Diag << FixItHint::CreateRemoval(
+ SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd));
+ break;
+ }
+ }
+ return true;
+}
+
+void MakeSmartPtrCheck::insertHeader(DiagnosticBuilder &Diag, FileID FD) {
+ if (MakeSmartPtrFunctionHeader.empty()) {
+ return;
+ }
+ if (auto IncludeFixit = Inserter->CreateIncludeInsertion(
+ FD, MakeSmartPtrFunctionHeader,
+ /*IsAngled=*/MakeSmartPtrFunctionHeader == StdMemoryHeader)) {
+ Diag << *IncludeFixit;
+ }
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h
new file mode 100644
index 0000000..6622482
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.h
@@ -0,0 +1,73 @@
+//===--- MakeSmartPtrCheck.h - clang-tidy------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SMART_PTR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SMART_PTR_H
+
+#include "../ClangTidy.h"
+#include "../utils/IncludeInserter.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Base class for MakeSharedCheck and MakeUniqueCheck.
+class MakeSmartPtrCheck : public ClangTidyCheck {
+public:
+ MakeSmartPtrCheck(StringRef Name, ClangTidyContext *Context,
+ StringRef MakeSmartPtrFunctionName);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) final;
+ void registerPPCallbacks(clang::CompilerInstance &Compiler) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) final;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+protected:
+ using SmartPtrTypeMatcher = ast_matchers::internal::BindableMatcher<QualType>;
+
+ /// Returns matcher that match with different smart pointer types.
+ ///
+ /// Requires to bind pointer type (qualType) with PointerType string declared
+ /// in this class.
+ virtual SmartPtrTypeMatcher getSmartPointerTypeMatcher() const = 0;
+
+ /// Returns whether the C++ version is compatible with current check.
+ virtual bool isLanguageVersionSupported(const LangOptions &LangOpts) const;
+
+ static const char PointerType[];
+ static const char ConstructorCall[];
+ static const char ResetCall[];
+ static const char NewExpression[];
+
+private:
+ std::unique_ptr<utils::IncludeInserter> Inserter;
+ const utils::IncludeSorter::IncludeStyle IncludeStyle;
+ const std::string MakeSmartPtrFunctionHeader;
+ const std::string MakeSmartPtrFunctionName;
+ const bool IgnoreMacros;
+
+ void checkConstruct(SourceManager &SM, const CXXConstructExpr *Construct,
+ const QualType *Type, const CXXNewExpr *New);
+ void checkReset(SourceManager &SM, const CXXMemberCallExpr *Member,
+ const CXXNewExpr *New);
+
+ /// Returns true when the fixes for replacing CXXNewExpr are generated.
+ bool replaceNew(DiagnosticBuilder &Diag, const CXXNewExpr *New,
+ SourceManager &SM);
+ void insertHeader(DiagnosticBuilder &Diag, FileID FD);
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_SMART_PTR_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.cpp
new file mode 100644
index 0000000..3ebbb07
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.cpp
@@ -0,0 +1,47 @@
+//===--- MakeUniqueCheck.cpp - clang-tidy----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MakeUniqueCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+MakeUniqueCheck::MakeUniqueCheck(StringRef Name,
+ clang::tidy::ClangTidyContext *Context)
+ : MakeSmartPtrCheck(Name, Context, "std::make_unique"),
+ RequireCPlusPlus14(Options.get("MakeSmartPtrFunction", "").empty()) {}
+
+MakeUniqueCheck::SmartPtrTypeMatcher
+MakeUniqueCheck::getSmartPointerTypeMatcher() const {
+ return qualType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(classTemplateSpecializationDecl(
+ hasName("::std::unique_ptr"), templateArgumentCountIs(2),
+ hasTemplateArgument(
+ 0, templateArgument(refersToType(qualType().bind(PointerType)))),
+ hasTemplateArgument(
+ 1, templateArgument(refersToType(
+ qualType(hasDeclaration(classTemplateSpecializationDecl(
+ hasName("::std::default_delete"),
+ templateArgumentCountIs(1),
+ hasTemplateArgument(
+ 0, templateArgument(refersToType(qualType(
+ equalsBoundNode(PointerType))))))))))))))));
+}
+
+bool MakeUniqueCheck::isLanguageVersionSupported(
+ const LangOptions &LangOpts) const {
+ return RequireCPlusPlus14 ? LangOpts.CPlusPlus14 : LangOpts.CPlusPlus11;
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.h
new file mode 100644
index 0000000..587b41e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/MakeUniqueCheck.h
@@ -0,0 +1,45 @@
+//===--- MakeUniqueCheck.h - clang-tidy--------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_UNIQUE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_UNIQUE_H
+
+#include "MakeSmartPtrCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Replace the pattern:
+/// \code
+/// std::unique_ptr<type>(new type(args...))
+/// \endcode
+///
+/// With the C++14 version:
+/// \code
+/// std::make_unique<type>(args...)
+/// \endcode
+class MakeUniqueCheck : public MakeSmartPtrCheck {
+public:
+ MakeUniqueCheck(StringRef Name, ClangTidyContext *Context);
+
+protected:
+ SmartPtrTypeMatcher getSmartPointerTypeMatcher() const override;
+
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
+
+private:
+ const bool RequireCPlusPlus14;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_MAKE_UNIQUE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
new file mode 100644
index 0000000..63b7d02
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -0,0 +1,116 @@
+//===--- ModernizeTidyModule.cpp - clang-tidy -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "AvoidBindCheck.h"
+#include "DeprecatedHeadersCheck.h"
+#include "LoopConvertCheck.h"
+#include "MakeSharedCheck.h"
+#include "MakeUniqueCheck.h"
+#include "PassByValueCheck.h"
+#include "RawStringLiteralCheck.h"
+#include "RedundantVoidArgCheck.h"
+#include "ReplaceAutoPtrCheck.h"
+#include "ReplaceRandomShuffleCheck.h"
+#include "ReturnBracedInitListCheck.h"
+#include "ShrinkToFitCheck.h"
+#include "UnaryStaticAssertCheck.h"
+#include "UseAutoCheck.h"
+#include "UseBoolLiteralsCheck.h"
+#include "UseDefaultMemberInitCheck.h"
+#include "UseEmplaceCheck.h"
+#include "UseEqualsDefaultCheck.h"
+#include "UseEqualsDeleteCheck.h"
+#include "UseNoexceptCheck.h"
+#include "UseNullptrCheck.h"
+#include "UseOverrideCheck.h"
+#include "UseTransparentFunctorsCheck.h"
+#include "UseUncaughtExceptionsCheck.h"
+#include "UseUsingCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+class ModernizeModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<AvoidBindCheck>("modernize-avoid-bind");
+ CheckFactories.registerCheck<DeprecatedHeadersCheck>(
+ "modernize-deprecated-headers");
+ CheckFactories.registerCheck<LoopConvertCheck>("modernize-loop-convert");
+ CheckFactories.registerCheck<MakeSharedCheck>("modernize-make-shared");
+ CheckFactories.registerCheck<MakeUniqueCheck>("modernize-make-unique");
+ CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
+ CheckFactories.registerCheck<RawStringLiteralCheck>(
+ "modernize-raw-string-literal");
+ CheckFactories.registerCheck<RedundantVoidArgCheck>(
+ "modernize-redundant-void-arg");
+ CheckFactories.registerCheck<ReplaceAutoPtrCheck>(
+ "modernize-replace-auto-ptr");
+ CheckFactories.registerCheck<ReplaceRandomShuffleCheck>(
+ "modernize-replace-random-shuffle");
+ CheckFactories.registerCheck<ReturnBracedInitListCheck>(
+ "modernize-return-braced-init-list");
+ CheckFactories.registerCheck<ShrinkToFitCheck>("modernize-shrink-to-fit");
+ CheckFactories.registerCheck<UnaryStaticAssertCheck>(
+ "modernize-unary-static-assert");
+ CheckFactories.registerCheck<UseAutoCheck>("modernize-use-auto");
+ CheckFactories.registerCheck<UseBoolLiteralsCheck>(
+ "modernize-use-bool-literals");
+ CheckFactories.registerCheck<UseDefaultMemberInitCheck>(
+ "modernize-use-default-member-init");
+ CheckFactories.registerCheck<UseEmplaceCheck>("modernize-use-emplace");
+ CheckFactories.registerCheck<UseEqualsDefaultCheck>("modernize-use-equals-default");
+ CheckFactories.registerCheck<UseEqualsDeleteCheck>(
+ "modernize-use-equals-delete");
+ CheckFactories.registerCheck<UseNoexceptCheck>("modernize-use-noexcept");
+ CheckFactories.registerCheck<UseNullptrCheck>("modernize-use-nullptr");
+ CheckFactories.registerCheck<UseOverrideCheck>("modernize-use-override");
+ CheckFactories.registerCheck<UseTransparentFunctorsCheck>(
+ "modernize-use-transparent-functors");
+ CheckFactories.registerCheck<UseUncaughtExceptionsCheck>(
+ "modernize-use-uncaught-exceptions");
+ CheckFactories.registerCheck<UseUsingCheck>("modernize-use-using");
+ }
+
+ ClangTidyOptions getModuleOptions() override {
+ ClangTidyOptions Options;
+ auto &Opts = Options.CheckOptions;
+ // For types whose size in bytes is above this threshold, we prefer taking a
+ // const-reference than making a copy.
+ Opts["modernize-loop-convert.MaxCopySize"] = "16";
+
+ Opts["modernize-loop-convert.MinConfidence"] = "reasonable";
+ Opts["modernize-loop-convert.NamingStyle"] = "CamelCase";
+ Opts["modernize-pass-by-value.IncludeStyle"] = "llvm"; // Also: "google".
+ Opts["modernize-replace-auto-ptr.IncludeStyle"] = "llvm"; // Also: "google".
+
+ // Comma-separated list of macros that behave like NULL.
+ Opts["modernize-use-nullptr.NullMacros"] = "NULL";
+ return Options;
+ }
+};
+
+// Register the ModernizeTidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<ModernizeModule> X("modernize-module",
+ "Add modernize checks.");
+
+} // namespace modernize
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the ModernizeModule.
+volatile int ModernizeModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp
new file mode 100644
index 0000000..1ab73d5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp
@@ -0,0 +1,234 @@
+//===--- PassByValueCheck.cpp - clang-tidy---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PassByValueCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+using namespace llvm;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+namespace {
+/// \brief Matches move-constructible classes.
+///
+/// Given
+/// \code
+/// // POD types are trivially move constructible.
+/// struct Foo { int a; };
+///
+/// struct Bar {
+/// Bar(Bar &&) = deleted;
+/// int a;
+/// };
+/// \endcode
+/// recordDecl(isMoveConstructible())
+/// matches "Foo".
+AST_MATCHER(CXXRecordDecl, isMoveConstructible) {
+ for (const CXXConstructorDecl *Ctor : Node.ctors()) {
+ if (Ctor->isMoveConstructor() && !Ctor->isDeleted())
+ return true;
+ }
+ return false;
+}
+} // namespace
+
+static TypeMatcher constRefType() {
+ return lValueReferenceType(pointee(isConstQualified()));
+}
+
+static TypeMatcher nonConstValueType() {
+ return qualType(unless(anyOf(referenceType(), isConstQualified())));
+}
+
+/// \brief Whether or not \p ParamDecl is used exactly one time in \p Ctor.
+///
+/// Checks both in the init-list and the body of the constructor.
+static bool paramReferredExactlyOnce(const CXXConstructorDecl *Ctor,
+ const ParmVarDecl *ParamDecl) {
+ /// \brief \c clang::RecursiveASTVisitor that checks that the given
+ /// \c ParmVarDecl is used exactly one time.
+ ///
+ /// \see ExactlyOneUsageVisitor::hasExactlyOneUsageIn()
+ class ExactlyOneUsageVisitor
+ : public RecursiveASTVisitor<ExactlyOneUsageVisitor> {
+ friend class RecursiveASTVisitor<ExactlyOneUsageVisitor>;
+
+ public:
+ ExactlyOneUsageVisitor(const ParmVarDecl *ParamDecl)
+ : ParamDecl(ParamDecl) {}
+
+ /// \brief Whether or not the parameter variable is referred only once in
+ /// the
+ /// given constructor.
+ bool hasExactlyOneUsageIn(const CXXConstructorDecl *Ctor) {
+ Count = 0;
+ TraverseDecl(const_cast<CXXConstructorDecl *>(Ctor));
+ return Count == 1;
+ }
+
+ private:
+ /// \brief Counts the number of references to a variable.
+ ///
+ /// Stops the AST traversal if more than one usage is found.
+ bool VisitDeclRefExpr(DeclRefExpr *D) {
+ if (const ParmVarDecl *To = dyn_cast<ParmVarDecl>(D->getDecl())) {
+ if (To == ParamDecl) {
+ ++Count;
+ if (Count > 1) {
+ // No need to look further, used more than once.
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ const ParmVarDecl *ParamDecl;
+ unsigned Count;
+ };
+
+ return ExactlyOneUsageVisitor(ParamDecl).hasExactlyOneUsageIn(Ctor);
+}
+
+/// \brief Find all references to \p ParamDecl across all of the
+/// redeclarations of \p Ctor.
+static SmallVector<const ParmVarDecl *, 2>
+collectParamDecls(const CXXConstructorDecl *Ctor,
+ const ParmVarDecl *ParamDecl) {
+ SmallVector<const ParmVarDecl *, 2> Results;
+ unsigned ParamIdx = ParamDecl->getFunctionScopeIndex();
+
+ for (const FunctionDecl *Redecl : Ctor->redecls())
+ Results.push_back(Redecl->getParamDecl(ParamIdx));
+ return Results;
+}
+
+PassByValueCheck::PassByValueCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
+ Options.getLocalOrGlobal("IncludeStyle", "llvm"))),
+ ValuesOnly(Options.get("ValuesOnly", 0) != 0) {}
+
+void PassByValueCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IncludeStyle",
+ utils::IncludeSorter::toString(IncludeStyle));
+ Options.store(Opts, "ValuesOnly", ValuesOnly);
+}
+
+void PassByValueCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(
+ cxxConstructorDecl(
+ forEachConstructorInitializer(
+ cxxCtorInitializer(
+ unless(isBaseInitializer()),
+ // Clang builds a CXXConstructExpr only when it knows which
+ // constructor will be called. In dependent contexts a
+ // ParenListExpr is generated instead of a CXXConstructExpr,
+ // filtering out templates automatically for us.
+ withInitializer(cxxConstructExpr(
+ has(ignoringParenImpCasts(declRefExpr(to(
+ parmVarDecl(
+ hasType(qualType(
+ // Match only const-ref or a non-const value
+ // parameters. Rvalues and const-values
+ // shouldn't be modified.
+ ValuesOnly ? nonConstValueType()
+ : anyOf(constRefType(),
+ nonConstValueType()))))
+ .bind("Param"))))),
+ hasDeclaration(cxxConstructorDecl(
+ isCopyConstructor(), unless(isDeleted()),
+ hasDeclContext(
+ cxxRecordDecl(isMoveConstructible())))))))
+ .bind("Initializer")))
+ .bind("Ctor"),
+ this);
+}
+
+void PassByValueCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+ // Only register the preprocessor callbacks for C++; the functionality
+ // currently does not provide any benefit to other languages, despite being
+ // benign.
+ if (getLangOpts().CPlusPlus) {
+ Inserter.reset(new utils::IncludeInserter(
+ Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle));
+ Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
+ }
+}
+
+void PassByValueCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("Ctor");
+ const auto *ParamDecl = Result.Nodes.getNodeAs<ParmVarDecl>("Param");
+ const auto *Initializer =
+ Result.Nodes.getNodeAs<CXXCtorInitializer>("Initializer");
+ SourceManager &SM = *Result.SourceManager;
+
+ // If the parameter is used or anything other than the copy, do not apply
+ // the changes.
+ if (!paramReferredExactlyOnce(Ctor, ParamDecl))
+ return;
+
+ // If the parameter is trivial to copy, don't move it. Moving a trivivally
+ // copyable type will cause a problem with performance-move-const-arg
+ if (ParamDecl->getType().getNonReferenceType().isTriviallyCopyableType(
+ *Result.Context))
+ return;
+
+ auto Diag = diag(ParamDecl->getLocStart(), "pass by value and use std::move");
+
+ // Iterate over all declarations of the constructor.
+ for (const ParmVarDecl *ParmDecl : collectParamDecls(Ctor, ParamDecl)) {
+ auto ParamTL = ParmDecl->getTypeSourceInfo()->getTypeLoc();
+ auto RefTL = ParamTL.getAs<ReferenceTypeLoc>();
+
+ // Do not replace if it is already a value, skip.
+ if (RefTL.isNull())
+ continue;
+
+ TypeLoc ValueTL = RefTL.getPointeeLoc();
+ auto TypeRange = CharSourceRange::getTokenRange(ParmDecl->getLocStart(),
+ ParamTL.getLocEnd());
+ std::string ValueStr = Lexer::getSourceText(CharSourceRange::getTokenRange(
+ ValueTL.getSourceRange()),
+ SM, getLangOpts())
+ .str();
+ ValueStr += ' ';
+ Diag << FixItHint::CreateReplacement(TypeRange, ValueStr);
+ }
+
+ // Use std::move in the initialization list.
+ Diag << FixItHint::CreateInsertion(Initializer->getRParenLoc(), ")")
+ << FixItHint::CreateInsertion(
+ Initializer->getLParenLoc().getLocWithOffset(1), "std::move(");
+
+ if (auto IncludeFixit = Inserter->CreateIncludeInsertion(
+ Result.SourceManager->getFileID(Initializer->getSourceLocation()),
+ "utility",
+ /*IsAngled=*/true)) {
+ Diag << *IncludeFixit;
+ }
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.h
new file mode 100644
index 0000000..37deb3f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.h
@@ -0,0 +1,40 @@
+//===--- PassByValueCheck.h - clang-tidy-------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_PASS_BY_VALUE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_PASS_BY_VALUE_H
+
+#include "../ClangTidy.h"
+#include "../utils/IncludeInserter.h"
+
+#include <memory>
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+class PassByValueCheck : public ClangTidyCheck {
+public:
+ PassByValueCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerPPCallbacks(clang::CompilerInstance &Compiler) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ std::unique_ptr<utils::IncludeInserter> Inserter;
+ const utils::IncludeSorter::IncludeStyle IncludeStyle;
+ const bool ValuesOnly;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_PASS_BY_VALUE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.cpp
new file mode 100644
index 0000000..868c5c7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.cpp
@@ -0,0 +1,158 @@
+//===--- RawStringLiteralCheck.cpp - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RawStringLiteralCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+namespace {
+
+bool containsEscapes(StringRef HayStack, StringRef Escapes) {
+ size_t BackSlash = HayStack.find('\\');
+ if (BackSlash == StringRef::npos)
+ return false;
+
+ while (BackSlash != StringRef::npos) {
+ if (Escapes.find(HayStack[BackSlash + 1]) == StringRef::npos)
+ return false;
+ BackSlash = HayStack.find('\\', BackSlash + 2);
+ }
+
+ return true;
+}
+
+bool isRawStringLiteral(StringRef Text) {
+ // Already a raw string literal if R comes before ".
+ const size_t QuotePos = Text.find('"');
+ assert(QuotePos != StringRef::npos);
+ return (QuotePos > 0) && (Text[QuotePos - 1] == 'R');
+}
+
+bool containsEscapedCharacters(const MatchFinder::MatchResult &Result,
+ const StringLiteral *Literal,
+ const CharsBitSet &DisallowedChars) {
+ // FIXME: Handle L"", u8"", u"" and U"" literals.
+ if (!Literal->isAscii())
+ return false;
+
+ for (const unsigned char C : Literal->getBytes())
+ if (DisallowedChars.test(C))
+ return false;
+
+ CharSourceRange CharRange = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(Literal->getSourceRange()),
+ *Result.SourceManager, Result.Context->getLangOpts());
+ StringRef Text = Lexer::getSourceText(CharRange, *Result.SourceManager,
+ Result.Context->getLangOpts());
+ if (isRawStringLiteral(Text))
+ return false;
+
+ return containsEscapes(Text, R"('\"?x01)");
+}
+
+bool containsDelimiter(StringRef Bytes, const std::string &Delimiter) {
+ return Bytes.find(Delimiter.empty()
+ ? std::string(R"lit()")lit")
+ : (")" + Delimiter + R"(")")) != StringRef::npos;
+}
+
+std::string asRawStringLiteral(const StringLiteral *Literal,
+ const std::string &DelimiterStem) {
+ const StringRef Bytes = Literal->getBytes();
+ std::string Delimiter;
+ for (int I = 0; containsDelimiter(Bytes, Delimiter); ++I) {
+ Delimiter = (I == 0) ? DelimiterStem : DelimiterStem + std::to_string(I);
+ }
+
+ if (Delimiter.empty())
+ return (R"(R"()" + Bytes + R"lit()")lit").str();
+
+ return (R"(R")" + Delimiter + "(" + Bytes + ")" + Delimiter + R"(")").str();
+}
+
+} // namespace
+
+RawStringLiteralCheck::RawStringLiteralCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ DelimiterStem(Options.get("DelimiterStem", "lit")),
+ ReplaceShorterLiterals(Options.get("ReplaceShorterLiterals", false)) {
+ // Non-printing characters are disallowed:
+ // \007 = \a bell
+ // \010 = \b backspace
+ // \011 = \t horizontal tab
+ // \012 = \n new line
+ // \013 = \v vertical tab
+ // \014 = \f form feed
+ // \015 = \r carriage return
+ // \177 = delete
+ for (const unsigned char C : StringRef("\000\001\002\003\004\005\006\a"
+ "\b\t\n\v\f\r\016\017"
+ "\020\021\022\023\024\025\026\027"
+ "\030\031\032\033\034\035\036\037"
+ "\177",
+ 33))
+ DisallowedChars.set(C);
+
+ // Non-ASCII are disallowed too.
+ for (unsigned int C = 0x80u; C <= 0xFFu; ++C)
+ DisallowedChars.set(static_cast<unsigned char>(C));
+}
+
+void RawStringLiteralCheck::storeOptions(ClangTidyOptions::OptionMap &Options) {
+ ClangTidyCheck::storeOptions(Options);
+ this->Options.store(Options, "ReplaceShorterLiterals",
+ ReplaceShorterLiterals);
+}
+
+void RawStringLiteralCheck::registerMatchers(MatchFinder *Finder) {
+ // Raw string literals require C++11 or later.
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ Finder->addMatcher(
+ stringLiteral(unless(hasParent(predefinedExpr()))).bind("lit"), this);
+}
+
+void RawStringLiteralCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Literal = Result.Nodes.getNodeAs<StringLiteral>("lit");
+ if (Literal->getLocStart().isMacroID())
+ return;
+
+ if (containsEscapedCharacters(Result, Literal, DisallowedChars)) {
+ std::string Replacement = asRawStringLiteral(Literal, DelimiterStem);
+ if (ReplaceShorterLiterals ||
+ Replacement.length() <=
+ Lexer::MeasureTokenLength(Literal->getLocStart(),
+ *Result.SourceManager, getLangOpts()))
+ replaceWithRawStringLiteral(Result, Literal, Replacement);
+ }
+}
+
+void RawStringLiteralCheck::replaceWithRawStringLiteral(
+ const MatchFinder::MatchResult &Result, const StringLiteral *Literal,
+ StringRef Replacement) {
+ CharSourceRange CharRange = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(Literal->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ diag(Literal->getLocStart(),
+ "escaped string literal can be written as a raw string literal")
+ << FixItHint::CreateReplacement(CharRange, Replacement);
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.h
new file mode 100644
index 0000000..f7721f6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/RawStringLiteralCheck.h
@@ -0,0 +1,49 @@
+//===--- RawStringLiteralCheck.h - clang-tidy--------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_RAW_STRING_LITERAL_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_RAW_STRING_LITERAL_H
+
+#include "../ClangTidy.h"
+#include <bitset>
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+using CharsBitSet = std::bitset<1 << CHAR_BIT>;
+
+/// This check replaces string literals with escaped characters to
+/// raw string literals.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-raw-string-literal.html
+class RawStringLiteralCheck : public ClangTidyCheck {
+public:
+ RawStringLiteralCheck(StringRef Name, ClangTidyContext *Context);
+
+ void storeOptions(ClangTidyOptions::OptionMap &Options) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void replaceWithRawStringLiteral(
+ const ast_matchers::MatchFinder::MatchResult &Result,
+ const StringLiteral *Literal, StringRef Replacement);
+
+ std::string DelimiterStem;
+ CharsBitSet DisallowedChars;
+ const bool ReplaceShorterLiterals;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_RAW_STRING_LITERAL_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp
new file mode 100644
index 0000000..6701fa4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp
@@ -0,0 +1,248 @@
+//===- RedundantVoidArgCheck.cpp - clang-tidy -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RedundantVoidArgCheck.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+namespace {
+
+// Determine if the given QualType is a nullary function or pointer to same.
+bool protoTypeHasNoParms(QualType QT) {
+ if (auto PT = QT->getAs<PointerType>()) {
+ QT = PT->getPointeeType();
+ }
+ if (auto *MPT = QT->getAs<MemberPointerType>()) {
+ QT = MPT->getPointeeType();
+ }
+ if (auto FP = QT->getAs<FunctionProtoType>()) {
+ return FP->getNumParams() == 0;
+ }
+ return false;
+}
+
+const char FunctionId[] = "function";
+const char TypedefId[] = "typedef";
+const char FieldId[] = "field";
+const char VarId[] = "var";
+const char NamedCastId[] = "named-cast";
+const char CStyleCastId[] = "c-style-cast";
+const char ExplicitCastId[] = "explicit-cast";
+const char LambdaId[] = "lambda";
+
+} // namespace
+
+void RedundantVoidArgCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(functionDecl(parameterCountIs(0), unless(isImplicit()),
+ unless(isExternC()))
+ .bind(FunctionId),
+ this);
+ Finder->addMatcher(typedefNameDecl().bind(TypedefId), this);
+ auto ParenFunctionType = parenType(innerType(functionType()));
+ auto PointerToFunctionType = pointee(ParenFunctionType);
+ auto FunctionOrMemberPointer =
+ anyOf(hasType(pointerType(PointerToFunctionType)),
+ hasType(memberPointerType(PointerToFunctionType)));
+ Finder->addMatcher(fieldDecl(FunctionOrMemberPointer).bind(FieldId), this);
+ Finder->addMatcher(varDecl(FunctionOrMemberPointer).bind(VarId), this);
+ auto CastDestinationIsFunction =
+ hasDestinationType(pointsTo(ParenFunctionType));
+ Finder->addMatcher(
+ cStyleCastExpr(CastDestinationIsFunction).bind(CStyleCastId), this);
+ Finder->addMatcher(
+ cxxStaticCastExpr(CastDestinationIsFunction).bind(NamedCastId), this);
+ Finder->addMatcher(
+ cxxReinterpretCastExpr(CastDestinationIsFunction).bind(NamedCastId),
+ this);
+ Finder->addMatcher(
+ cxxConstCastExpr(CastDestinationIsFunction).bind(NamedCastId), this);
+ Finder->addMatcher(lambdaExpr().bind(LambdaId), this);
+}
+
+void RedundantVoidArgCheck::check(const MatchFinder::MatchResult &Result) {
+ const BoundNodes &Nodes = Result.Nodes;
+ if (const auto *Function = Nodes.getNodeAs<FunctionDecl>(FunctionId)) {
+ processFunctionDecl(Result, Function);
+ } else if (const auto *TypedefName =
+ Nodes.getNodeAs<TypedefNameDecl>(TypedefId)) {
+ processTypedefNameDecl(Result, TypedefName);
+ } else if (const auto *Member = Nodes.getNodeAs<FieldDecl>(FieldId)) {
+ processFieldDecl(Result, Member);
+ } else if (const auto *Var = Nodes.getNodeAs<VarDecl>(VarId)) {
+ processVarDecl(Result, Var);
+ } else if (const auto *NamedCast =
+ Nodes.getNodeAs<CXXNamedCastExpr>(NamedCastId)) {
+ processNamedCastExpr(Result, NamedCast);
+ } else if (const auto *CStyleCast =
+ Nodes.getNodeAs<CStyleCastExpr>(CStyleCastId)) {
+ processExplicitCastExpr(Result, CStyleCast);
+ } else if (const auto *ExplicitCast =
+ Nodes.getNodeAs<ExplicitCastExpr>(ExplicitCastId)) {
+ processExplicitCastExpr(Result, ExplicitCast);
+ } else if (const auto *Lambda = Nodes.getNodeAs<LambdaExpr>(LambdaId)) {
+ processLambdaExpr(Result, Lambda);
+ }
+}
+
+void RedundantVoidArgCheck::processFunctionDecl(
+ const MatchFinder::MatchResult &Result, const FunctionDecl *Function) {
+ if (Function->isThisDeclarationADefinition()) {
+ const Stmt *Body = Function->getBody();
+ SourceLocation Start = Function->getLocStart();
+ SourceLocation End =
+ Body ? Body->getLocStart().getLocWithOffset(-1) : Function->getLocEnd();
+ removeVoidArgumentTokens(Result, SourceRange(Start, End),
+ "function definition");
+ } else {
+ removeVoidArgumentTokens(Result, Function->getSourceRange(),
+ "function declaration");
+ }
+}
+
+void RedundantVoidArgCheck::removeVoidArgumentTokens(
+ const ast_matchers::MatchFinder::MatchResult &Result, SourceRange Range,
+ StringRef GrammarLocation) {
+ CharSourceRange CharRange =
+ Lexer::makeFileCharRange(CharSourceRange::getTokenRange(Range),
+ *Result.SourceManager, getLangOpts());
+
+ std::string DeclText =
+ Lexer::getSourceText(CharRange, *Result.SourceManager, getLangOpts())
+ .str();
+ Lexer PrototypeLexer(CharRange.getBegin(), getLangOpts(), DeclText.data(),
+ DeclText.data(), DeclText.data() + DeclText.size());
+ enum TokenState {
+ NothingYet,
+ SawLeftParen,
+ SawVoid,
+ };
+ TokenState State = NothingYet;
+ Token VoidToken;
+ Token ProtoToken;
+ std::string Diagnostic =
+ ("redundant void argument list in " + GrammarLocation).str();
+
+ while (!PrototypeLexer.LexFromRawLexer(ProtoToken)) {
+ switch (State) {
+ case NothingYet:
+ if (ProtoToken.is(tok::TokenKind::l_paren)) {
+ State = SawLeftParen;
+ }
+ break;
+ case SawLeftParen:
+ if (ProtoToken.is(tok::TokenKind::raw_identifier) &&
+ ProtoToken.getRawIdentifier() == "void") {
+ State = SawVoid;
+ VoidToken = ProtoToken;
+ } else {
+ State = NothingYet;
+ }
+ break;
+ case SawVoid:
+ State = NothingYet;
+ if (ProtoToken.is(tok::TokenKind::r_paren)) {
+ removeVoidToken(VoidToken, Diagnostic);
+ } else if (ProtoToken.is(tok::TokenKind::l_paren)) {
+ State = SawLeftParen;
+ }
+ break;
+ }
+ }
+
+ if (State == SawVoid && ProtoToken.is(tok::TokenKind::r_paren)) {
+ removeVoidToken(VoidToken, Diagnostic);
+ }
+}
+
+void RedundantVoidArgCheck::removeVoidToken(Token VoidToken,
+ StringRef Diagnostic) {
+ SourceLocation VoidLoc(VoidToken.getLocation());
+ auto VoidRange =
+ CharSourceRange::getTokenRange(VoidLoc, VoidLoc.getLocWithOffset(3));
+ diag(VoidLoc, Diagnostic) << FixItHint::CreateRemoval(VoidRange);
+}
+
+void RedundantVoidArgCheck::processTypedefNameDecl(
+ const MatchFinder::MatchResult &Result,
+ const TypedefNameDecl *TypedefName) {
+ if (protoTypeHasNoParms(TypedefName->getUnderlyingType())) {
+ removeVoidArgumentTokens(Result, TypedefName->getSourceRange(),
+ isa<TypedefDecl>(TypedefName) ? "typedef"
+ : "type alias");
+ }
+}
+
+void RedundantVoidArgCheck::processFieldDecl(
+ const MatchFinder::MatchResult &Result, const FieldDecl *Member) {
+ if (protoTypeHasNoParms(Member->getType())) {
+ removeVoidArgumentTokens(Result, Member->getSourceRange(),
+ "field declaration");
+ }
+}
+
+void RedundantVoidArgCheck::processVarDecl(
+ const MatchFinder::MatchResult &Result, const VarDecl *Var) {
+ if (protoTypeHasNoParms(Var->getType())) {
+ SourceLocation Begin = Var->getLocStart();
+ if (Var->hasInit()) {
+ SourceLocation InitStart =
+ Result.SourceManager->getExpansionLoc(Var->getInit()->getLocStart())
+ .getLocWithOffset(-1);
+ removeVoidArgumentTokens(Result, SourceRange(Begin, InitStart),
+ "variable declaration with initializer");
+ } else {
+ removeVoidArgumentTokens(Result, Var->getSourceRange(),
+ "variable declaration");
+ }
+ }
+}
+
+void RedundantVoidArgCheck::processNamedCastExpr(
+ const MatchFinder::MatchResult &Result, const CXXNamedCastExpr *NamedCast) {
+ if (protoTypeHasNoParms(NamedCast->getTypeAsWritten())) {
+ removeVoidArgumentTokens(
+ Result,
+ NamedCast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange(),
+ "named cast");
+ }
+}
+
+void RedundantVoidArgCheck::processExplicitCastExpr(
+ const MatchFinder::MatchResult &Result,
+ const ExplicitCastExpr *ExplicitCast) {
+ if (protoTypeHasNoParms(ExplicitCast->getTypeAsWritten())) {
+ removeVoidArgumentTokens(Result, ExplicitCast->getSourceRange(),
+ "cast expression");
+ }
+}
+
+void RedundantVoidArgCheck::processLambdaExpr(
+ const MatchFinder::MatchResult &Result, const LambdaExpr *Lambda) {
+ if (Lambda->getLambdaClass()->getLambdaCallOperator()->getNumParams() == 0 &&
+ Lambda->hasExplicitParameters()) {
+ SourceLocation Begin =
+ Lambda->getIntroducerRange().getEnd().getLocWithOffset(1);
+ SourceLocation End = Lambda->getBody()->getLocStart().getLocWithOffset(-1);
+ removeVoidArgumentTokens(Result, SourceRange(Begin, End),
+ "lambda expression");
+ }
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.h
new file mode 100644
index 0000000..c990ef4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.h
@@ -0,0 +1,77 @@
+//===--- RedundantVoidArgCheck.h - clang-tidy --------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REDUNDANT_VOID_ARG_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REDUNDANT_VOID_ARG_CHECK_H
+
+#include "../ClangTidy.h"
+#include "clang/Lex/Token.h"
+
+#include <string>
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// \brief Find and remove redundant void argument lists.
+///
+/// Examples:
+/// `int f(void);` becomes `int f();`
+/// `int (*f(void))(void);` becomes `int (*f())();`
+/// `typedef int (*f_t(void))(void);` becomes `typedef int (*f_t())();`
+/// `void (C::*p)(void);` becomes `void (C::*p)();`
+/// `C::C(void) {}` becomes `C::C() {}`
+/// `C::~C(void) {}` becomes `C::~C() {}`
+///
+class RedundantVoidArgCheck : public ClangTidyCheck {
+public:
+ RedundantVoidArgCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void processFunctionDecl(const ast_matchers::MatchFinder::MatchResult &Result,
+ const FunctionDecl *Function);
+
+ void
+ processTypedefNameDecl(const ast_matchers::MatchFinder::MatchResult &Result,
+ const TypedefNameDecl *Typedef);
+
+ void processFieldDecl(const ast_matchers::MatchFinder::MatchResult &Result,
+ const FieldDecl *Member);
+
+ void processVarDecl(const ast_matchers::MatchFinder::MatchResult &Result,
+ const VarDecl *Var);
+
+ void
+ processNamedCastExpr(const ast_matchers::MatchFinder::MatchResult &Result,
+ const CXXNamedCastExpr *NamedCast);
+
+ void
+ processExplicitCastExpr(const ast_matchers::MatchFinder::MatchResult &Result,
+ const ExplicitCastExpr *ExplicitCast);
+
+ void processLambdaExpr(const ast_matchers::MatchFinder::MatchResult &Result,
+ const LambdaExpr *Lambda);
+
+ void
+ removeVoidArgumentTokens(const ast_matchers::MatchFinder::MatchResult &Result,
+ SourceRange Range, StringRef GrammarLocation);
+
+ void removeVoidToken(Token VoidToken, StringRef Diagnostic);
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REDUNDANT_VOID_ARG_CHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp
new file mode 100644
index 0000000..04ecf21
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp
@@ -0,0 +1,202 @@
+//===--- ReplaceAutoPtrCheck.cpp - clang-tidy------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReplaceAutoPtrCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang;
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+namespace {
+static const char AutoPtrTokenId[] = "AutoPrTokenId";
+static const char AutoPtrOwnershipTransferId[] = "AutoPtrOwnershipTransferId";
+
+/// \brief Matches expressions that are lvalues.
+///
+/// In the following example, a[0] matches expr(isLValue()):
+/// \code
+/// std::string a[2];
+/// std::string b;
+/// b = a[0];
+/// b = "this string won't match";
+/// \endcode
+AST_MATCHER(Expr, isLValue) { return Node.getValueKind() == VK_LValue; }
+
+/// Matches declarations whose declaration context is the C++ standard library
+/// namespace std.
+///
+/// Note that inline namespaces are silently ignored during the lookup since
+/// both libstdc++ and libc++ are known to use them for versioning purposes.
+///
+/// Given:
+/// \code
+/// namespace ns {
+/// struct my_type {};
+/// using namespace std;
+/// }
+///
+/// using std::vector;
+/// using ns:my_type;
+/// using ns::list;
+/// \code
+///
+/// usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(isFromStdNamespace())))
+/// matches "using std::vector" and "using ns::list".
+AST_MATCHER(Decl, isFromStdNamespace) {
+ const DeclContext *D = Node.getDeclContext();
+
+ while (D->isInlineNamespace())
+ D = D->getParent();
+
+ if (!D->isNamespace() || !D->getParent()->isTranslationUnit())
+ return false;
+
+ const IdentifierInfo *Info = cast<NamespaceDecl>(D)->getIdentifier();
+
+ return (Info && Info->isStr("std"));
+}
+
+} // namespace
+
+ReplaceAutoPtrCheck::ReplaceAutoPtrCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
+ Options.getLocalOrGlobal("IncludeStyle", "llvm"))) {}
+
+void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IncludeStyle",
+ utils::IncludeSorter::toString(IncludeStyle));
+}
+
+void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ auto AutoPtrDecl = recordDecl(hasName("auto_ptr"), isFromStdNamespace());
+ auto AutoPtrType = qualType(hasDeclaration(AutoPtrDecl));
+
+ // std::auto_ptr<int> a;
+ // ^~~~~~~~~~~~~
+ //
+ // typedef std::auto_ptr<int> int_ptr_t;
+ // ^~~~~~~~~~~~~
+ //
+ // std::auto_ptr<int> fn(std::auto_ptr<int>);
+ // ^~~~~~~~~~~~~ ^~~~~~~~~~~~~
+ Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType,
+ // Skip elaboratedType() as the named
+ // type will match soon thereafter.
+ unless(elaboratedType()))))
+ .bind(AutoPtrTokenId),
+ this);
+
+ // using std::auto_ptr;
+ // ^~~~~~~~~~~~~~~~~~~
+ Finder->addMatcher(usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(allOf(
+ hasName("auto_ptr"), isFromStdNamespace()))))
+ .bind(AutoPtrTokenId),
+ this);
+
+ // Find ownership transfers via copy construction and assignment.
+ // AutoPtrOwnershipTransferId is bound to the the part that has to be wrapped
+ // into std::move().
+ // std::auto_ptr<int> i, j;
+ // i = j;
+ // ~~~~^
+ auto MovableArgumentMatcher =
+ expr(isLValue(), hasType(AutoPtrType)).bind(AutoPtrOwnershipTransferId);
+
+ Finder->addMatcher(
+ cxxOperatorCallExpr(hasOverloadedOperatorName("="),
+ callee(cxxMethodDecl(ofClass(AutoPtrDecl))),
+ hasArgument(1, MovableArgumentMatcher)),
+ this);
+ Finder->addMatcher(cxxConstructExpr(hasType(AutoPtrType), argumentCountIs(1),
+ hasArgument(0, MovableArgumentMatcher)),
+ this);
+}
+
+void ReplaceAutoPtrCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+ // Only register the preprocessor callbacks for C++; the functionality
+ // currently does not provide any benefit to other languages, despite being
+ // benign.
+ if (!getLangOpts().CPlusPlus)
+ return;
+ Inserter.reset(new utils::IncludeInserter(
+ Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle));
+ Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
+}
+
+void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) {
+ SourceManager &SM = *Result.SourceManager;
+ if (const auto *E =
+ Result.Nodes.getNodeAs<Expr>(AutoPtrOwnershipTransferId)) {
+ CharSourceRange Range = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOptions());
+
+ if (Range.isInvalid())
+ return;
+
+ auto Diag = diag(Range.getBegin(), "use std::move to transfer ownership")
+ << FixItHint::CreateInsertion(Range.getBegin(), "std::move(")
+ << FixItHint::CreateInsertion(Range.getEnd(), ")");
+
+ if (auto Fix =
+ Inserter->CreateIncludeInsertion(SM.getMainFileID(), "utility",
+ /*IsAngled=*/true))
+ Diag << *Fix;
+
+ return;
+ }
+
+ SourceLocation AutoPtrLoc;
+ if (const auto *TL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) {
+ // std::auto_ptr<int> i;
+ // ^
+ if (auto Loc = TL->getAs<TemplateSpecializationTypeLoc>())
+ AutoPtrLoc = Loc.getTemplateNameLoc();
+ } else if (const auto *D =
+ Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId)) {
+ // using std::auto_ptr;
+ // ^
+ AutoPtrLoc = D->getNameInfo().getBeginLoc();
+ } else {
+ llvm_unreachable("Bad Callback. No node provided.");
+ }
+
+ if (AutoPtrLoc.isMacroID())
+ AutoPtrLoc = SM.getSpellingLoc(AutoPtrLoc);
+
+ // Ensure that only the 'auto_ptr' token is replaced and not the template
+ // aliases.
+ if (StringRef(SM.getCharacterData(AutoPtrLoc), strlen("auto_ptr")) !=
+ "auto_ptr")
+ return;
+
+ SourceLocation EndLoc =
+ AutoPtrLoc.getLocWithOffset(strlen("auto_ptr") - 1);
+ diag(AutoPtrLoc, "auto_ptr is deprecated, use unique_ptr instead")
+ << FixItHint::CreateReplacement(SourceRange(AutoPtrLoc, EndLoc),
+ "unique_ptr");
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h
new file mode 100644
index 0000000..5b73d51
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.h
@@ -0,0 +1,61 @@
+//===--- ReplaceAutoPtrCheck.h - clang-tidy----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_AUTO_PTR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_AUTO_PTR_H
+
+#include "../ClangTidy.h"
+#include "../utils/IncludeInserter.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Transforms the deprecated `std::auto_ptr` into the C++11 `std::unique_ptr`.
+///
+/// Note that both the `std::auto_ptr` type and the transfer of ownership are
+/// transformed. `std::auto_ptr` provides two ways to transfer the ownership,
+/// the copy-constructor and the assignment operator. Unlike most classes these
+/// operations do not 'copy' the resource but they 'steal' it.
+/// `std::unique_ptr` uses move semantics instead, which makes the intent of
+/// transferring the resource explicit. This difference between the two smart
+/// pointers requeres to wrap the copy-ctor and assign-operator with
+/// `std::move()`.
+///
+/// For example, given:
+///
+/// \code
+/// std::auto_ptr<int> i, j;
+/// i = j;
+/// \endcode
+///
+/// This code is transformed to:
+///
+/// \code
+/// std::unique_ptr<in> i, j;
+/// i = std::move(j);
+/// \endcode
+class ReplaceAutoPtrCheck : public ClangTidyCheck {
+public:
+ ReplaceAutoPtrCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ std::unique_ptr<utils::IncludeInserter> Inserter;
+ const utils::IncludeSorter::IncludeStyle IncludeStyle;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_AUTO_PTR_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp
new file mode 100644
index 0000000..cd9aa11
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp
@@ -0,0 +1,109 @@
+//===--- ReplaceRandomShuffleCheck.cpp - clang-tidy------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReplaceRandomShuffleCheck.h"
+#include "../utils/FixItHintUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+ReplaceRandomShuffleCheck::ReplaceRandomShuffleCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
+ Options.getLocalOrGlobal("IncludeStyle", "llvm"))) {}
+
+void ReplaceRandomShuffleCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ const auto Begin = hasArgument(0, expr());
+ const auto End = hasArgument(1, expr());
+ const auto RandomFunc = hasArgument(2, expr().bind("randomFunc"));
+ Finder->addMatcher(
+ callExpr(anyOf(allOf(Begin, End, argumentCountIs(2)),
+ allOf(Begin, End, RandomFunc, argumentCountIs(3))),
+ hasDeclaration(functionDecl(hasName("::std::random_shuffle"))),
+ has(implicitCastExpr(has(declRefExpr().bind("name")))))
+ .bind("match"),
+ this);
+}
+
+void ReplaceRandomShuffleCheck::registerPPCallbacks(
+ CompilerInstance &Compiler) {
+ IncludeInserter = llvm::make_unique<utils::IncludeInserter>(
+ Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle);
+ Compiler.getPreprocessor().addPPCallbacks(
+ IncludeInserter->CreatePPCallbacks());
+}
+
+void ReplaceRandomShuffleCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IncludeStyle",
+ utils::IncludeSorter::toString(IncludeStyle));
+}
+
+void ReplaceRandomShuffleCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<DeclRefExpr>("name");
+ const auto *MatchedArgumentThree = Result.Nodes.getNodeAs<Expr>("randomFunc");
+ const auto *MatchedCallExpr = Result.Nodes.getNodeAs<CallExpr>("match");
+
+ if (MatchedCallExpr->getLocStart().isMacroID())
+ return;
+
+ auto Diag = [&] {
+ if (MatchedCallExpr->getNumArgs() == 3) {
+ auto DiagL =
+ diag(MatchedCallExpr->getLocStart(),
+ "'std::random_shuffle' has been removed in C++17; use "
+ "'std::shuffle' and an alternative random mechanism instead");
+ DiagL << FixItHint::CreateReplacement(
+ MatchedArgumentThree->getSourceRange(),
+ "std::mt19937(std::random_device()())");
+ return DiagL;
+ } else {
+ auto DiagL = diag(MatchedCallExpr->getLocStart(),
+ "'std::random_shuffle' has been removed in C++17; use "
+ "'std::shuffle' instead");
+ DiagL << FixItHint::CreateInsertion(
+ MatchedCallExpr->getRParenLoc(),
+ ", std::mt19937(std::random_device()())");
+ return DiagL;
+ }
+ }();
+
+ std::string NewName = "shuffle";
+ StringRef ContainerText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(MatchedDecl->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ if (ContainerText.startswith("std::"))
+ NewName = "std::" + NewName;
+
+ Diag << FixItHint::CreateRemoval(MatchedDecl->getSourceRange());
+ Diag << FixItHint::CreateInsertion(MatchedDecl->getLocStart(), NewName);
+
+ if (Optional<FixItHint> IncludeFixit =
+ IncludeInserter->CreateIncludeInsertion(
+ Result.Context->getSourceManager().getFileID(
+ MatchedCallExpr->getLocStart()),
+ "random", /*IsAngled=*/true))
+ Diag << IncludeFixit.getValue();
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.h
new file mode 100644
index 0000000..050d740
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.h
@@ -0,0 +1,42 @@
+//===--- ReplaceRandomShuffleCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_RANDOM_SHUFFLE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_RANDOM_SHUFFLE_H
+
+#include "../ClangTidy.h"
+#include "../utils/IncludeInserter.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// std::random_shuffle will be removed as of C++17. This check will find and
+/// replace all occurrences of std::random_shuffle with std::shuffle.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-replace-random-shuffle.html
+class ReplaceRandomShuffleCheck : public ClangTidyCheck {
+public:
+ ReplaceRandomShuffleCheck(StringRef Name, ClangTidyContext *Context);
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ std::unique_ptr<utils::IncludeInserter> IncludeInserter;
+ const utils::IncludeSorter::IncludeStyle IncludeStyle;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_RANDOM_SHUFFLE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.cpp
new file mode 100644
index 0000000..e5857f7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.cpp
@@ -0,0 +1,97 @@
+//===--- ReturnBracedInitListCheck.cpp - clang-tidy------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReturnBracedInitListCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+void ReturnBracedInitListCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++.
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ // Skip list initialization and constructors with an initializer list.
+ auto ConstructExpr =
+ cxxConstructExpr(
+ unless(anyOf(hasDeclaration(cxxConstructorDecl(isExplicit())),
+ isListInitialization(), hasDescendant(initListExpr()),
+ isInTemplateInstantiation())))
+ .bind("ctor");
+
+ auto CtorAsArgument = materializeTemporaryExpr(anyOf(
+ has(ConstructExpr), has(cxxFunctionalCastExpr(has(ConstructExpr)))));
+
+ Finder->addMatcher(
+ functionDecl(isDefinition(), // Declarations don't have return statements.
+ returns(unless(anyOf(builtinType(), autoType()))),
+ hasDescendant(returnStmt(hasReturnValue(
+ has(cxxConstructExpr(has(CtorAsArgument)))))))
+ .bind("fn"),
+ this);
+}
+
+void ReturnBracedInitListCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedFunctionDecl = Result.Nodes.getNodeAs<FunctionDecl>("fn");
+ const auto *MatchedConstructExpr =
+ Result.Nodes.getNodeAs<CXXConstructExpr>("ctor");
+
+ // Don't make replacements in macro.
+ SourceLocation Loc = MatchedConstructExpr->getExprLoc();
+ if (Loc.isMacroID())
+ return;
+
+ // Make sure that the return type matches the constructed type.
+ const QualType ReturnType =
+ MatchedFunctionDecl->getReturnType().getCanonicalType();
+ const QualType ConstructType =
+ MatchedConstructExpr->getType().getCanonicalType();
+ if (ReturnType != ConstructType)
+ return;
+
+ auto Diag = diag(Loc, "avoid repeating the return type from the "
+ "declaration; use a braced initializer list instead");
+
+ const SourceRange CallParensRange =
+ MatchedConstructExpr->getParenOrBraceRange();
+
+ // Make sure there is an explicit constructor call.
+ if (CallParensRange.isInvalid())
+ return;
+
+ // Make sure that the ctor arguments match the declaration.
+ for (unsigned I = 0, NumParams = MatchedConstructExpr->getNumArgs();
+ I < NumParams; ++I) {
+ if (const auto *VD = dyn_cast<VarDecl>(
+ MatchedConstructExpr->getConstructor()->getParamDecl(I))) {
+ if (MatchedConstructExpr->getArg(I)->getType().getCanonicalType() !=
+ VD->getType().getCanonicalType())
+ return;
+ }
+ }
+
+ // Range for constructor name and opening brace.
+ CharSourceRange CtorCallSourceRange = CharSourceRange::getTokenRange(
+ Loc, CallParensRange.getBegin().getLocWithOffset(-1));
+
+ Diag << FixItHint::CreateRemoval(CtorCallSourceRange)
+ << FixItHint::CreateReplacement(CallParensRange.getBegin(), "{")
+ << FixItHint::CreateReplacement(CallParensRange.getEnd(), "}");
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.h
new file mode 100644
index 0000000..eda982a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.h
@@ -0,0 +1,36 @@
+//===--- ReturnBracedInitListCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_RETURN_BRACED_INIT_LIST_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_RETURN_BRACED_INIT_LIST_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Use a braced init list for return statements rather than unnecessary
+/// repeating the return type name.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-return-braced-init-list.html
+class ReturnBracedInitListCheck : public ClangTidyCheck {
+public:
+ ReturnBracedInitListCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_RETURN_BRACED_INIT_LIST_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.cpp
new file mode 100644
index 0000000..f197399
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.cpp
@@ -0,0 +1,90 @@
+//===--- ShrinkToFitCheck.cpp - clang-tidy---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ShrinkToFitCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+void ShrinkToFitCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ // Swap as a function need not to be considered, because rvalue can not
+ // be bound to a non-const reference.
+ const auto ShrinkableAsMember =
+ memberExpr(member(valueDecl().bind("ContainerDecl")));
+ const auto ShrinkableAsDecl =
+ declRefExpr(hasDeclaration(valueDecl().bind("ContainerDecl")));
+ const auto CopyCtorCall = cxxConstructExpr(hasArgument(
+ 0, anyOf(ShrinkableAsMember, ShrinkableAsDecl,
+ unaryOperator(has(ignoringParenImpCasts(ShrinkableAsMember))),
+ unaryOperator(has(ignoringParenImpCasts(ShrinkableAsDecl))))));
+ const auto SwapParam =
+ expr(anyOf(memberExpr(member(equalsBoundNode("ContainerDecl"))),
+ declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl"))),
+ unaryOperator(has(ignoringParenImpCasts(
+ memberExpr(member(equalsBoundNode("ContainerDecl")))))),
+ unaryOperator(has(ignoringParenImpCasts(declRefExpr(
+ hasDeclaration(equalsBoundNode("ContainerDecl"))))))));
+
+ Finder->addMatcher(
+ cxxMemberCallExpr(
+ on(hasType(hasCanonicalType(hasDeclaration(namedDecl(
+ hasAnyName("std::basic_string", "std::deque", "std::vector")))))),
+ callee(cxxMethodDecl(hasName("swap"))),
+ has(ignoringParenImpCasts(memberExpr(hasDescendant(CopyCtorCall)))),
+ hasArgument(0, SwapParam.bind("ContainerToShrink")),
+ unless(isInTemplateInstantiation()))
+ .bind("CopyAndSwapTrick"),
+ this);
+}
+
+void ShrinkToFitCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MemberCall =
+ Result.Nodes.getNodeAs<CXXMemberCallExpr>("CopyAndSwapTrick");
+ const auto *Container = Result.Nodes.getNodeAs<Expr>("ContainerToShrink");
+ FixItHint Hint;
+
+ if (!MemberCall->getLocStart().isMacroID()) {
+ const LangOptions &Opts = getLangOpts();
+ std::string ReplacementText;
+ if (const auto *UnaryOp = llvm::dyn_cast<UnaryOperator>(Container)) {
+ ReplacementText =
+ Lexer::getSourceText(CharSourceRange::getTokenRange(
+ UnaryOp->getSubExpr()->getSourceRange()),
+ *Result.SourceManager, Opts);
+ ReplacementText += "->shrink_to_fit()";
+ } else {
+ ReplacementText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(Container->getSourceRange()),
+ *Result.SourceManager, Opts);
+ ReplacementText += ".shrink_to_fit()";
+ }
+
+ Hint = FixItHint::CreateReplacement(MemberCall->getSourceRange(),
+ ReplacementText);
+ }
+
+ diag(MemberCall->getLocStart(), "the shrink_to_fit method should be used "
+ "to reduce the capacity of a shrinkable "
+ "container")
+ << Hint;
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.h
new file mode 100644
index 0000000..1e3745c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.h
@@ -0,0 +1,37 @@
+//===--- ShrinkToFitCheck.h - clang-tidy-------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_SHRINKTOFITCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_SHRINKTOFITCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Replace copy and swap tricks on shrinkable containers with the
+/// `shrink_to_fit()` method call.
+///
+/// The `shrink_to_fit()` method is more readable and more effective than
+/// the copy and swap trick to reduce the capacity of a shrinkable container.
+/// Note that, the `shrink_to_fit()` method is only available in C++11 and up.
+class ShrinkToFitCheck : public ClangTidyCheck {
+public:
+ ShrinkToFitCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_SHRINKTOFITCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UnaryStaticAssertCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UnaryStaticAssertCheck.cpp
new file mode 100644
index 0000000..67c0063
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UnaryStaticAssertCheck.cpp
@@ -0,0 +1,45 @@
+//===--- UnaryStaticAssertCheck.cpp - clang-tidy---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnaryStaticAssertCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+void UnaryStaticAssertCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus17)
+ return;
+
+ Finder->addMatcher(staticAssertDecl().bind("static_assert"), this);
+}
+
+void UnaryStaticAssertCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedDecl =
+ Result.Nodes.getNodeAs<StaticAssertDecl>("static_assert");
+ const StringLiteral *AssertMessage = MatchedDecl->getMessage();
+
+ SourceLocation Loc = MatchedDecl->getLocation();
+
+ if (!AssertMessage || AssertMessage->getLength() ||
+ AssertMessage->getLocStart().isMacroID() || Loc.isMacroID())
+ return;
+
+ diag(Loc,
+ "use unary 'static_assert' when the string literal is an empty string")
+ << FixItHint::CreateRemoval(AssertMessage->getSourceRange());
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UnaryStaticAssertCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UnaryStaticAssertCheck.h
new file mode 100644
index 0000000..b83c2c4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UnaryStaticAssertCheck.h
@@ -0,0 +1,36 @@
+//===--- UnaryStaticAssertCheck.h - clang-tidy-------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_UNARY_STATIC_ASSERT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_UNARY_STATIC_ASSERT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Replaces a static_assert declaration with an empty message
+/// with the unary version.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-unary-static-assert.html
+class UnaryStaticAssertCheck : public ClangTidyCheck {
+public:
+ UnaryStaticAssertCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_UNARY_STATIC_ASSERT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp
new file mode 100644
index 0000000..8687162
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp
@@ -0,0 +1,503 @@
+//===--- UseAutoCheck.cpp - clang-tidy-------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseAutoCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang;
+using namespace clang::ast_matchers;
+using namespace clang::ast_matchers::internal;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+namespace {
+
+const char IteratorDeclStmtId[] = "iterator_decl";
+const char DeclWithNewId[] = "decl_new";
+const char DeclWithCastId[] = "decl_cast";
+const char DeclWithTemplateCastId[] = "decl_template";
+
+size_t GetTypeNameLength(bool RemoveStars, StringRef Text) {
+ enum CharType { Space, Alpha, Punctuation };
+ CharType LastChar = Space, BeforeSpace = Punctuation;
+ size_t NumChars = 0;
+ int TemplateTypenameCntr = 0;
+ for (const unsigned char C : Text) {
+ if (C == '<')
+ ++TemplateTypenameCntr;
+ else if (C == '>')
+ --TemplateTypenameCntr;
+ const CharType NextChar =
+ isAlphanumeric(C)
+ ? Alpha
+ : (isWhitespace(C) ||
+ (!RemoveStars && TemplateTypenameCntr == 0 && C == '*'))
+ ? Space
+ : Punctuation;
+ if (NextChar != Space) {
+ ++NumChars; // Count the non-space character.
+ if (LastChar == Space && NextChar == Alpha && BeforeSpace == Alpha)
+ ++NumChars; // Count a single space character between two words.
+ BeforeSpace = NextChar;
+ }
+ LastChar = NextChar;
+ }
+ return NumChars;
+}
+
+/// \brief Matches variable declarations that have explicit initializers that
+/// are not initializer lists.
+///
+/// Given
+/// \code
+/// iterator I = Container.begin();
+/// MyType A(42);
+/// MyType B{2};
+/// MyType C;
+/// \endcode
+///
+/// varDecl(hasWrittenNonListInitializer()) maches \c I and \c A but not \c B
+/// or \c C.
+AST_MATCHER(VarDecl, hasWrittenNonListInitializer) {
+ const Expr *Init = Node.getAnyInitializer();
+ if (!Init)
+ return false;
+
+ Init = Init->IgnoreImplicit();
+
+ // The following test is based on DeclPrinter::VisitVarDecl() to find if an
+ // initializer is implicit or not.
+ if (const auto *Construct = dyn_cast<CXXConstructExpr>(Init)) {
+ return !Construct->isListInitialization() && Construct->getNumArgs() > 0 &&
+ !Construct->getArg(0)->isDefaultArgument();
+ }
+ return Node.getInitStyle() != VarDecl::ListInit;
+}
+
+/// \brief Matches QualTypes that are type sugar for QualTypes that match \c
+/// SugarMatcher.
+///
+/// Given
+/// \code
+/// class C {};
+/// typedef C my_type;
+/// typedef my_type my_other_type;
+/// \endcode
+///
+/// qualType(isSugarFor(recordType(hasDeclaration(namedDecl(hasName("C"))))))
+/// matches \c my_type and \c my_other_type.
+AST_MATCHER_P(QualType, isSugarFor, Matcher<QualType>, SugarMatcher) {
+ QualType QT = Node;
+ while (true) {
+ if (SugarMatcher.matches(QT, Finder, Builder))
+ return true;
+
+ QualType NewQT = QT.getSingleStepDesugaredType(Finder->getASTContext());
+ if (NewQT == QT)
+ return false;
+ QT = NewQT;
+ }
+}
+
+/// \brief Matches named declarations that have one of the standard iterator
+/// names: iterator, reverse_iterator, const_iterator, const_reverse_iterator.
+///
+/// Given
+/// \code
+/// iterator I;
+/// const_iterator CI;
+/// \endcode
+///
+/// namedDecl(hasStdIteratorName()) matches \c I and \c CI.
+AST_MATCHER(NamedDecl, hasStdIteratorName) {
+ static const char *const IteratorNames[] = {"iterator", "reverse_iterator",
+ "const_iterator",
+ "const_reverse_iterator"};
+
+ for (const char *Name : IteratorNames) {
+ if (hasName(Name).matches(Node, Finder, Builder))
+ return true;
+ }
+ return false;
+}
+
+/// \brief Matches named declarations that have one of the standard container
+/// names.
+///
+/// Given
+/// \code
+/// class vector {};
+/// class forward_list {};
+/// class my_ver{};
+/// \endcode
+///
+/// recordDecl(hasStdContainerName()) matches \c vector and \c forward_list
+/// but not \c my_vec.
+AST_MATCHER(NamedDecl, hasStdContainerName) {
+ static const char *const ContainerNames[] = {
+ "array", "deque",
+ "forward_list", "list",
+ "vector",
+
+ "map", "multimap",
+ "set", "multiset",
+
+ "unordered_map", "unordered_multimap",
+ "unordered_set", "unordered_multiset",
+
+ "queue", "priority_queue",
+ "stack"};
+
+ for (const char *Name : ContainerNames) {
+ if (hasName(Name).matches(Node, Finder, Builder))
+ return true;
+ }
+ return false;
+}
+
+/// Matches declarations whose declaration context is the C++ standard library
+/// namespace std.
+///
+/// Note that inline namespaces are silently ignored during the lookup since
+/// both libstdc++ and libc++ are known to use them for versioning purposes.
+///
+/// Given:
+/// \code
+/// namespace ns {
+/// struct my_type {};
+/// using namespace std;
+/// }
+///
+/// using std::vector;
+/// using ns:my_type;
+/// using ns::list;
+/// \code
+///
+/// usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(isFromStdNamespace())))
+/// matches "using std::vector" and "using ns::list".
+AST_MATCHER(Decl, isFromStdNamespace) {
+ const DeclContext *D = Node.getDeclContext();
+
+ while (D->isInlineNamespace())
+ D = D->getParent();
+
+ if (!D->isNamespace() || !D->getParent()->isTranslationUnit())
+ return false;
+
+ const IdentifierInfo *Info = cast<NamespaceDecl>(D)->getIdentifier();
+
+ return (Info && Info->isStr("std"));
+}
+
+/// Matches declaration reference or member expressions with explicit template
+/// arguments.
+AST_POLYMORPHIC_MATCHER(hasExplicitTemplateArgs,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr,
+ MemberExpr)) {
+ return Node.hasExplicitTemplateArgs();
+}
+
+/// \brief Returns a DeclarationMatcher that matches standard iterators nested
+/// inside records with a standard container name.
+DeclarationMatcher standardIterator() {
+ return allOf(
+ namedDecl(hasStdIteratorName()),
+ hasDeclContext(recordDecl(hasStdContainerName(), isFromStdNamespace())));
+}
+
+/// \brief Returns a TypeMatcher that matches typedefs for standard iterators
+/// inside records with a standard container name.
+TypeMatcher typedefIterator() {
+ return typedefType(hasDeclaration(standardIterator()));
+}
+
+/// \brief Returns a TypeMatcher that matches records named for standard
+/// iterators nested inside records named for standard containers.
+TypeMatcher nestedIterator() {
+ return recordType(hasDeclaration(standardIterator()));
+}
+
+/// \brief Returns a TypeMatcher that matches types declared with using
+/// declarations and which name standard iterators for standard containers.
+TypeMatcher iteratorFromUsingDeclaration() {
+ auto HasIteratorDecl = hasDeclaration(namedDecl(hasStdIteratorName()));
+ // Types resulting from using declarations are represented by elaboratedType.
+ return elaboratedType(allOf(
+ // Unwrap the nested name specifier to test for one of the standard
+ // containers.
+ hasQualifier(specifiesType(templateSpecializationType(hasDeclaration(
+ namedDecl(hasStdContainerName(), isFromStdNamespace()))))),
+ // the named type is what comes after the final '::' in the type. It
+ // should name one of the standard iterator names.
+ namesType(
+ anyOf(typedefType(HasIteratorDecl), recordType(HasIteratorDecl)))));
+}
+
+/// \brief This matcher returns declaration statements that contain variable
+/// declarations with written non-list initializer for standard iterators.
+StatementMatcher makeIteratorDeclMatcher() {
+ return declStmt(unless(has(
+ varDecl(anyOf(unless(hasWrittenNonListInitializer()),
+ unless(hasType(isSugarFor(anyOf(
+ typedefIterator(), nestedIterator(),
+ iteratorFromUsingDeclaration())))))))))
+ .bind(IteratorDeclStmtId);
+}
+
+StatementMatcher makeDeclWithNewMatcher() {
+ return declStmt(
+ unless(has(varDecl(anyOf(
+ unless(hasInitializer(ignoringParenImpCasts(cxxNewExpr()))),
+ // FIXME: TypeLoc information is not reliable where CV
+ // qualifiers are concerned so these types can't be
+ // handled for now.
+ hasType(pointerType(
+ pointee(hasCanonicalType(hasLocalQualifiers())))),
+
+ // FIXME: Handle function pointers. For now we ignore them
+ // because the replacement replaces the entire type
+ // specifier source range which includes the identifier.
+ hasType(pointsTo(
+ pointsTo(parenType(innerType(functionType()))))))))))
+ .bind(DeclWithNewId);
+}
+
+StatementMatcher makeDeclWithCastMatcher() {
+ return declStmt(
+ unless(has(varDecl(unless(hasInitializer(explicitCastExpr()))))))
+ .bind(DeclWithCastId);
+}
+
+StatementMatcher makeDeclWithTemplateCastMatcher() {
+ auto ST =
+ substTemplateTypeParmType(hasReplacementType(equalsBoundNode("arg")));
+
+ auto ExplicitCall =
+ anyOf(has(memberExpr(hasExplicitTemplateArgs())),
+ has(ignoringImpCasts(declRefExpr(hasExplicitTemplateArgs()))));
+
+ auto TemplateArg =
+ hasTemplateArgument(0, refersToType(qualType().bind("arg")));
+
+ auto TemplateCall = callExpr(
+ ExplicitCall,
+ callee(functionDecl(TemplateArg,
+ returns(anyOf(ST, pointsTo(ST), references(ST))))));
+
+ return declStmt(unless(has(varDecl(
+ unless(hasInitializer(ignoringImplicit(TemplateCall)))))))
+ .bind(DeclWithTemplateCastId);
+}
+
+StatementMatcher makeCombinedMatcher() {
+ return declStmt(
+ // At least one varDecl should be a child of the declStmt to ensure
+ // it's a declaration list and avoid matching other declarations,
+ // e.g. using directives.
+ has(varDecl(unless(isImplicit()))),
+ // Skip declarations that are already using auto.
+ unless(has(varDecl(anyOf(hasType(autoType()),
+ hasType(qualType(hasDescendant(autoType()))))))),
+ anyOf(makeIteratorDeclMatcher(), makeDeclWithNewMatcher(),
+ makeDeclWithCastMatcher(), makeDeclWithTemplateCastMatcher()));
+}
+
+} // namespace
+
+UseAutoCheck::UseAutoCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ MinTypeNameLength(Options.get("MinTypeNameLength", 5)),
+ RemoveStars(Options.get("RemoveStars", 0)) {}
+
+void UseAutoCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "MinTypeNameLength", MinTypeNameLength);
+ Options.store(Opts, "RemoveStars", RemoveStars ? 1 : 0);
+}
+
+void UseAutoCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (getLangOpts().CPlusPlus) {
+ Finder->addMatcher(makeCombinedMatcher(), this);
+ }
+}
+
+void UseAutoCheck::replaceIterators(const DeclStmt *D, ASTContext *Context) {
+ for (const auto *Dec : D->decls()) {
+ const auto *V = cast<VarDecl>(Dec);
+ const Expr *ExprInit = V->getInit();
+
+ // Skip expressions with cleanups from the intializer expression.
+ if (const auto *E = dyn_cast<ExprWithCleanups>(ExprInit))
+ ExprInit = E->getSubExpr();
+
+ const auto *Construct = dyn_cast<CXXConstructExpr>(ExprInit);
+ if (!Construct)
+ continue;
+
+ // Ensure that the constructor receives a single argument.
+ if (Construct->getNumArgs() != 1)
+ return;
+
+ // Drill down to the as-written initializer.
+ const Expr *E = (*Construct->arg_begin())->IgnoreParenImpCasts();
+ if (E != E->IgnoreConversionOperator()) {
+ // We hit a conversion operator. Early-out now as they imply an implicit
+ // conversion from a different type. Could also mean an explicit
+ // conversion from the same type but that's pretty rare.
+ return;
+ }
+
+ if (const auto *NestedConstruct = dyn_cast<CXXConstructExpr>(E)) {
+ // If we ran into an implicit conversion contructor, can't convert.
+ //
+ // FIXME: The following only checks if the constructor can be used
+ // implicitly, not if it actually was. Cases where the converting
+ // constructor was used explicitly won't get converted.
+ if (NestedConstruct->getConstructor()->isConvertingConstructor(false))
+ return;
+ }
+ if (!Context->hasSameType(V->getType(), E->getType()))
+ return;
+ }
+
+ // Get the type location using the first declaration.
+ const auto *V = cast<VarDecl>(*D->decl_begin());
+
+ // WARNING: TypeLoc::getSourceRange() will include the identifier for things
+ // like function pointers. Not a concern since this action only works with
+ // iterators but something to keep in mind in the future.
+
+ SourceRange Range(V->getTypeSourceInfo()->getTypeLoc().getSourceRange());
+ diag(Range.getBegin(), "use auto when declaring iterators")
+ << FixItHint::CreateReplacement(Range, "auto");
+}
+
+void UseAutoCheck::replaceExpr(
+ const DeclStmt *D, ASTContext *Context,
+ llvm::function_ref<QualType(const Expr *)> GetType, StringRef Message) {
+ const auto *FirstDecl = dyn_cast<VarDecl>(*D->decl_begin());
+ // Ensure that there is at least one VarDecl within the DeclStmt.
+ if (!FirstDecl)
+ return;
+
+ const QualType FirstDeclType = FirstDecl->getType().getCanonicalType();
+
+ std::vector<FixItHint> StarRemovals;
+ for (const auto *Dec : D->decls()) {
+ const auto *V = cast<VarDecl>(Dec);
+ // Ensure that every DeclStmt child is a VarDecl.
+ if (!V)
+ return;
+
+ const auto *Expr = V->getInit()->IgnoreParenImpCasts();
+ // Ensure that every VarDecl has an initializer.
+ if (!Expr)
+ return;
+
+ // If VarDecl and Initializer have mismatching unqualified types.
+ if (!Context->hasSameUnqualifiedType(V->getType(), GetType(Expr)))
+ return;
+
+ // All subsequent variables in this declaration should have the same
+ // canonical type. For example, we don't want to use `auto` in
+ // `T *p = new T, **pp = new T*;`.
+ if (FirstDeclType != V->getType().getCanonicalType())
+ return;
+
+ if (RemoveStars) {
+ // Remove explicitly written '*' from declarations where there's more than
+ // one declaration in the declaration list.
+ if (Dec == *D->decl_begin())
+ continue;
+
+ auto Q = V->getTypeSourceInfo()->getTypeLoc().getAs<PointerTypeLoc>();
+ while (!Q.isNull()) {
+ StarRemovals.push_back(FixItHint::CreateRemoval(Q.getStarLoc()));
+ Q = Q.getNextTypeLoc().getAs<PointerTypeLoc>();
+ }
+ }
+ }
+
+ // FIXME: There is, however, one case we can address: when the VarDecl pointee
+ // is the same as the initializer, just more CV-qualified. However, TypeLoc
+ // information is not reliable where CV qualifiers are concerned so we can't
+ // do anything about this case for now.
+ TypeLoc Loc = FirstDecl->getTypeSourceInfo()->getTypeLoc();
+ if (!RemoveStars) {
+ while (Loc.getTypeLocClass() == TypeLoc::Pointer ||
+ Loc.getTypeLocClass() == TypeLoc::Qualified)
+ Loc = Loc.getNextTypeLoc();
+ }
+ while (Loc.getTypeLocClass() == TypeLoc::LValueReference ||
+ Loc.getTypeLocClass() == TypeLoc::RValueReference ||
+ Loc.getTypeLocClass() == TypeLoc::Qualified) {
+ Loc = Loc.getNextTypeLoc();
+ }
+ SourceRange Range(Loc.getSourceRange());
+
+ if (MinTypeNameLength != 0 &&
+ GetTypeNameLength(RemoveStars,
+ tooling::fixit::getText(Loc.getSourceRange(),
+ FirstDecl->getASTContext())) <
+ MinTypeNameLength)
+ return;
+
+ auto Diag = diag(Range.getBegin(), Message);
+
+ // Space after 'auto' to handle cases where the '*' in the pointer type is
+ // next to the identifier. This avoids changing 'int *p' into 'autop'.
+ // FIXME: This doesn't work for function pointers because the variable name
+ // is inside the type.
+ Diag << FixItHint::CreateReplacement(Range, RemoveStars ? "auto " : "auto")
+ << StarRemovals;
+}
+
+void UseAutoCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *Decl = Result.Nodes.getNodeAs<DeclStmt>(IteratorDeclStmtId)) {
+ replaceIterators(Decl, Result.Context);
+ } else if (const auto *Decl =
+ Result.Nodes.getNodeAs<DeclStmt>(DeclWithNewId)) {
+ replaceExpr(Decl, Result.Context,
+ [](const Expr *Expr) { return Expr->getType(); },
+ "use auto when initializing with new to avoid "
+ "duplicating the type name");
+ } else if (const auto *Decl =
+ Result.Nodes.getNodeAs<DeclStmt>(DeclWithCastId)) {
+ replaceExpr(
+ Decl, Result.Context,
+ [](const Expr *Expr) {
+ return cast<ExplicitCastExpr>(Expr)->getTypeAsWritten();
+ },
+ "use auto when initializing with a cast to avoid duplicating the type "
+ "name");
+ } else if (const auto *Decl =
+ Result.Nodes.getNodeAs<DeclStmt>(DeclWithTemplateCastId)) {
+ replaceExpr(
+ Decl, Result.Context,
+ [](const Expr *Expr) {
+ return cast<CallExpr>(Expr->IgnoreImplicit())
+ ->getDirectCallee()
+ ->getReturnType();
+ },
+ "use auto when initializing with a template cast to avoid duplicating "
+ "the type name");
+ } else {
+ llvm_unreachable("Bad Callback. No node provided.");
+ }
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.h
new file mode 100644
index 0000000..a061c5f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.h
@@ -0,0 +1,40 @@
+//===--- UseAutoCheck.h - clang-tidy-----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_AUTO_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_AUTO_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+class UseAutoCheck : public ClangTidyCheck {
+public:
+ UseAutoCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void replaceIterators(const DeclStmt *D, ASTContext *Context);
+ void replaceExpr(const DeclStmt *D, ASTContext *Context,
+ llvm::function_ref<QualType(const Expr *)> GetType,
+ StringRef Message);
+
+ const unsigned int MinTypeNameLength;
+ const bool RemoveStars;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_AUTO_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseBoolLiteralsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseBoolLiteralsCheck.cpp
new file mode 100644
index 0000000..ece8cd5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseBoolLiteralsCheck.cpp
@@ -0,0 +1,76 @@
+//===--- UseBoolLiteralsCheck.cpp - clang-tidy-----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseBoolLiteralsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+UseBoolLiteralsCheck::UseBoolLiteralsCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {}
+
+void UseBoolLiteralsCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ Finder->addMatcher(
+ implicitCastExpr(
+ has(ignoringParenImpCasts(integerLiteral().bind("literal"))),
+ hasImplicitDestinationType(qualType(booleanType())),
+ unless(isInTemplateInstantiation()),
+ anyOf(hasParent(explicitCastExpr().bind("cast")), anything())),
+ this);
+
+ Finder->addMatcher(
+ conditionalOperator(
+ hasParent(implicitCastExpr(
+ hasImplicitDestinationType(qualType(booleanType())),
+ unless(isInTemplateInstantiation()))),
+ eachOf(hasTrueExpression(
+ ignoringParenImpCasts(integerLiteral().bind("literal"))),
+ hasFalseExpression(
+ ignoringParenImpCasts(integerLiteral().bind("literal"))))),
+ this);
+}
+
+void UseBoolLiteralsCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Literal = Result.Nodes.getNodeAs<IntegerLiteral>("literal");
+ const auto *Cast = Result.Nodes.getNodeAs<Expr>("cast");
+ bool LiteralBooleanValue = Literal->getValue().getBoolValue();
+
+ if (Literal->isInstantiationDependent())
+ return;
+
+ const Expr *Expression = Cast ? Cast : Literal;
+
+ bool InMacro = Expression->getLocStart().isMacroID();
+
+ if (InMacro && IgnoreMacros)
+ return;
+
+ auto Diag =
+ diag(Expression->getExprLoc(),
+ "converting integer literal to bool, use bool literal instead");
+
+ if (!InMacro)
+ Diag << FixItHint::CreateReplacement(
+ Expression->getSourceRange(), LiteralBooleanValue ? "true" : "false");
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseBoolLiteralsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseBoolLiteralsCheck.h
new file mode 100644
index 0000000..c9c7363
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseBoolLiteralsCheck.h
@@ -0,0 +1,37 @@
+//===--- UseBoolLiteralsCheck.h - clang-tidy---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_BOOL_LITERALS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_BOOL_LITERALS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Finds integer literals which are cast to bool.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-bool-literals.html
+class UseBoolLiteralsCheck : public ClangTidyCheck {
+public:
+ UseBoolLiteralsCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const bool IgnoreMacros;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_BOOL_LITERALS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp
new file mode 100644
index 0000000..c14c685
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp
@@ -0,0 +1,247 @@
+//===--- UseDefaultMemberInitCheck.cpp - clang-tidy------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseDefaultMemberInitCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+static StringRef getValueOfValueInit(const QualType InitType) {
+ switch (InitType->getScalarTypeKind()) {
+ case Type::STK_CPointer:
+ case Type::STK_BlockPointer:
+ case Type::STK_ObjCObjectPointer:
+ case Type::STK_MemberPointer:
+ return "nullptr";
+
+ case Type::STK_Bool:
+ return "false";
+
+ case Type::STK_Integral:
+ switch (InitType->getAs<BuiltinType>()->getKind()) {
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ return "'\\0'";
+ case BuiltinType::WChar_U:
+ case BuiltinType::WChar_S:
+ return "L'\\0'";
+ case BuiltinType::Char16:
+ return "u'\\0'";
+ case BuiltinType::Char32:
+ return "U'\\0'";
+ default:
+ return "0";
+ }
+
+ case Type::STK_Floating:
+ switch (InitType->getAs<BuiltinType>()->getKind()) {
+ case BuiltinType::Half:
+ case BuiltinType::Float:
+ return "0.0f";
+ default:
+ return "0.0";
+ }
+
+ case Type::STK_FloatingComplex:
+ case Type::STK_IntegralComplex:
+ return getValueOfValueInit(
+ InitType->getAs<ComplexType>()->getElementType());
+ }
+ llvm_unreachable("Invalid scalar type kind");
+}
+
+static bool isZero(const Expr *E) {
+ switch (E->getStmtClass()) {
+ case Stmt::CXXNullPtrLiteralExprClass:
+ case Stmt::ImplicitValueInitExprClass:
+ return true;
+ case Stmt::InitListExprClass:
+ return cast<InitListExpr>(E)->getNumInits() == 0;
+ case Stmt::CharacterLiteralClass:
+ return !cast<CharacterLiteral>(E)->getValue();
+ case Stmt::CXXBoolLiteralExprClass:
+ return !cast<CXXBoolLiteralExpr>(E)->getValue();
+ case Stmt::IntegerLiteralClass:
+ return !cast<IntegerLiteral>(E)->getValue();
+ case Stmt::FloatingLiteralClass: {
+ llvm::APFloat Value = cast<FloatingLiteral>(E)->getValue();
+ return Value.isZero() && !Value.isNegative();
+ }
+ default:
+ return false;
+ }
+}
+
+static const Expr *ignoreUnaryPlus(const Expr *E) {
+ auto *UnaryOp = dyn_cast<UnaryOperator>(E);
+ if (UnaryOp && UnaryOp->getOpcode() == UO_Plus)
+ return UnaryOp->getSubExpr();
+ return E;
+}
+
+static const Expr *getInitializer(const Expr *E) {
+ auto *InitList = dyn_cast<InitListExpr>(E);
+ if (InitList && InitList->getNumInits() == 1)
+ return InitList->getInit(0);
+ return E;
+}
+
+static bool sameValue(const Expr *E1, const Expr *E2) {
+ E1 = ignoreUnaryPlus(getInitializer(E1->IgnoreParenImpCasts()));
+ E2 = ignoreUnaryPlus(getInitializer(E2->IgnoreParenImpCasts()));
+
+ if (isZero(E1) && isZero(E2))
+ return true;
+
+ if (E1->getStmtClass() != E2->getStmtClass())
+ return false;
+
+ switch (E1->getStmtClass()) {
+ case Stmt::UnaryOperatorClass:
+ return sameValue(cast<UnaryOperator>(E1)->getSubExpr(),
+ cast<UnaryOperator>(E2)->getSubExpr());
+ case Stmt::CharacterLiteralClass:
+ return cast<CharacterLiteral>(E1)->getValue() ==
+ cast<CharacterLiteral>(E2)->getValue();
+ case Stmt::CXXBoolLiteralExprClass:
+ return cast<CXXBoolLiteralExpr>(E1)->getValue() ==
+ cast<CXXBoolLiteralExpr>(E2)->getValue();
+ case Stmt::IntegerLiteralClass:
+ return cast<IntegerLiteral>(E1)->getValue() ==
+ cast<IntegerLiteral>(E2)->getValue();
+ case Stmt::FloatingLiteralClass:
+ return cast<FloatingLiteral>(E1)->getValue().bitwiseIsEqual(
+ cast<FloatingLiteral>(E2)->getValue());
+ case Stmt::StringLiteralClass:
+ return cast<StringLiteral>(E1)->getString() ==
+ cast<StringLiteral>(E2)->getString();
+ case Stmt::DeclRefExprClass:
+ return cast<DeclRefExpr>(E1)->getDecl() == cast<DeclRefExpr>(E2)->getDecl();
+ default:
+ return false;
+ }
+}
+
+UseDefaultMemberInitCheck::UseDefaultMemberInitCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ UseAssignment(Options.get("UseAssignment", 0) != 0),
+ IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true) != 0) {}
+
+void UseDefaultMemberInitCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "UseAssignment", UseAssignment);
+ Options.store(Opts, "IgnoreMacros", IgnoreMacros);
+}
+
+void UseDefaultMemberInitCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ auto Init =
+ anyOf(stringLiteral(), characterLiteral(), integerLiteral(),
+ unaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("-")),
+ hasUnaryOperand(integerLiteral())),
+ floatLiteral(),
+ unaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("-")),
+ hasUnaryOperand(floatLiteral())),
+ cxxBoolLiteral(), cxxNullPtrLiteralExpr(), implicitValueInitExpr(),
+ declRefExpr(to(enumConstantDecl())));
+
+ Finder->addMatcher(
+ cxxConstructorDecl(
+ isDefaultConstructor(), unless(isInstantiated()),
+ forEachConstructorInitializer(
+ cxxCtorInitializer(
+ forField(unless(anyOf(getLangOpts().CPlusPlus2a
+ ? unless(anything())
+ : isBitField(),
+ hasInClassInitializer(anything()),
+ hasParent(recordDecl(isUnion()))))),
+ isWritten(), withInitializer(ignoringImplicit(Init)))
+ .bind("default"))),
+ this);
+
+ Finder->addMatcher(
+ cxxConstructorDecl(
+ unless(ast_matchers::isTemplateInstantiation()),
+ forEachConstructorInitializer(
+ cxxCtorInitializer(forField(hasInClassInitializer(anything())),
+ isWritten(),
+ withInitializer(ignoringImplicit(Init)))
+ .bind("existing"))),
+ this);
+}
+
+void UseDefaultMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *Default =
+ Result.Nodes.getNodeAs<CXXCtorInitializer>("default"))
+ checkDefaultInit(Result, Default);
+ else if (const auto *Existing =
+ Result.Nodes.getNodeAs<CXXCtorInitializer>("existing"))
+ checkExistingInit(Result, Existing);
+ else
+ llvm_unreachable("Bad Callback. No node provided.");
+}
+
+void UseDefaultMemberInitCheck::checkDefaultInit(
+ const MatchFinder::MatchResult &Result, const CXXCtorInitializer *Init) {
+ const FieldDecl *Field = Init->getAnyMember();
+
+ SourceLocation StartLoc = Field->getLocStart();
+ if (StartLoc.isMacroID() && IgnoreMacros)
+ return;
+
+ SourceLocation FieldEnd =
+ Lexer::getLocForEndOfToken(Field->getSourceRange().getEnd(), 0,
+ *Result.SourceManager, getLangOpts());
+ SourceLocation LParenEnd = Lexer::getLocForEndOfToken(
+ Init->getLParenLoc(), 0, *Result.SourceManager, getLangOpts());
+ CharSourceRange InitRange =
+ CharSourceRange::getCharRange(LParenEnd, Init->getRParenLoc());
+
+ auto Diag =
+ diag(Field->getLocation(), "use default member initializer for %0")
+ << Field
+ << FixItHint::CreateInsertion(FieldEnd, UseAssignment ? " = " : "{")
+ << FixItHint::CreateInsertionFromRange(FieldEnd, InitRange);
+
+ if (UseAssignment && isa<ImplicitValueInitExpr>(Init->getInit()))
+ Diag << FixItHint::CreateInsertion(
+ FieldEnd, getValueOfValueInit(Init->getInit()->getType()));
+
+ if (!UseAssignment)
+ Diag << FixItHint::CreateInsertion(FieldEnd, "}");
+
+ Diag << FixItHint::CreateRemoval(Init->getSourceRange());
+}
+
+void UseDefaultMemberInitCheck::checkExistingInit(
+ const MatchFinder::MatchResult &Result, const CXXCtorInitializer *Init) {
+ const FieldDecl *Field = Init->getMember();
+
+ if (!sameValue(Field->getInClassInitializer(), Init->getInit()))
+ return;
+
+ diag(Init->getSourceLocation(), "member initializer for %0 is redundant")
+ << Field
+ << FixItHint::CreateRemoval(Init->getSourceRange());
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.h
new file mode 100644
index 0000000..d8887a0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.h
@@ -0,0 +1,46 @@
+//===--- UseDefaultMemberInitCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_MEMBER_INIT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_MEMBER_INIT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Convert a default constructor's member initializers into default member
+/// initializers. Remove member initializers that are the same as a default
+/// member initializer.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-default-member-init.html
+class UseDefaultMemberInitCheck : public ClangTidyCheck {
+public:
+ UseDefaultMemberInitCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void checkDefaultInit(const ast_matchers::MatchFinder::MatchResult &Result,
+ const CXXCtorInitializer *Init);
+ void checkExistingInit(const ast_matchers::MatchFinder::MatchResult &Result,
+ const CXXCtorInitializer *Init);
+
+ const bool UseAssignment;
+ const bool IgnoreMacros;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_MEMBER_INIT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
new file mode 100644
index 0000000..4d5d801
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
@@ -0,0 +1,177 @@
+//===--- UseEmplaceCheck.cpp - clang-tidy----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseEmplaceCheck.h"
+#include "../utils/OptionsUtils.h"
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+namespace {
+AST_MATCHER(DeclRefExpr, hasExplicitTemplateArgs) {
+ return Node.hasExplicitTemplateArgs();
+}
+
+const auto DefaultContainersWithPushBack =
+ "::std::vector; ::std::list; ::std::deque";
+const auto DefaultSmartPointers =
+ "::std::shared_ptr; ::std::unique_ptr; ::std::auto_ptr; ::std::weak_ptr";
+const auto DefaultTupleTypes = "::std::pair; ::std::tuple";
+const auto DefaultTupleMakeFunctions = "::std::make_pair; ::std::make_tuple";
+} // namespace
+
+UseEmplaceCheck::UseEmplaceCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IgnoreImplicitConstructors(Options.get("IgnoreImplicitConstructors", 0)),
+ ContainersWithPushBack(utils::options::parseStringList(Options.get(
+ "ContainersWithPushBack", DefaultContainersWithPushBack))),
+ SmartPointers(utils::options::parseStringList(
+ Options.get("SmartPointers", DefaultSmartPointers))),
+ TupleTypes(utils::options::parseStringList(
+ Options.get("TupleTypes", DefaultTupleTypes))),
+ TupleMakeFunctions(utils::options::parseStringList(
+ Options.get("TupleMakeFunctions", DefaultTupleMakeFunctions))) {}
+
+void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ // FIXME: Bunch of functionality that could be easily added:
+ // + add handling of `push_front` for std::forward_list, std::list
+ // and std::deque.
+ // + add handling of `push` for std::stack, std::queue, std::priority_queue
+ // + add handling of `insert` for stl associative container, but be careful
+ // because this requires special treatment (it could cause performance
+ // regression)
+ // + match for emplace calls that should be replaced with insertion
+ auto CallPushBack = cxxMemberCallExpr(
+ hasDeclaration(functionDecl(hasName("push_back"))),
+ on(hasType(cxxRecordDecl(hasAnyName(SmallVector<StringRef, 5>(
+ ContainersWithPushBack.begin(), ContainersWithPushBack.end()))))));
+
+ // We can't replace push_backs of smart pointer because
+ // if emplacement fails (f.e. bad_alloc in vector) we will have leak of
+ // passed pointer because smart pointer won't be constructed
+ // (and destructed) as in push_back case.
+ auto IsCtorOfSmartPtr = hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(
+ SmallVector<StringRef, 5>(SmartPointers.begin(), SmartPointers.end())))));
+
+ // Bitfields binds only to consts and emplace_back take it by universal ref.
+ auto BitFieldAsArgument = hasAnyArgument(
+ ignoringImplicit(memberExpr(hasDeclaration(fieldDecl(isBitField())))));
+
+ // Initializer list can't be passed to universal reference.
+ auto InitializerListAsArgument = hasAnyArgument(
+ ignoringImplicit(cxxConstructExpr(isListInitialization())));
+
+ // We could have leak of resource.
+ auto NewExprAsArgument = hasAnyArgument(ignoringImplicit(cxxNewExpr()));
+ // We would call another constructor.
+ auto ConstructingDerived =
+ hasParent(implicitCastExpr(hasCastKind(CastKind::CK_DerivedToBase)));
+
+ // emplace_back can't access private constructor.
+ auto IsPrivateCtor = hasDeclaration(cxxConstructorDecl(isPrivate()));
+
+ auto HasInitList = anyOf(has(ignoringImplicit(initListExpr())),
+ has(cxxStdInitializerListExpr()));
+
+ // FIXME: Discard 0/NULL (as nullptr), static inline const data members,
+ // overloaded functions and template names.
+ auto SoughtConstructExpr =
+ cxxConstructExpr(
+ unless(anyOf(IsCtorOfSmartPtr, HasInitList, BitFieldAsArgument,
+ InitializerListAsArgument, NewExprAsArgument,
+ ConstructingDerived, IsPrivateCtor)))
+ .bind("ctor");
+ auto HasConstructExpr = has(ignoringImplicit(SoughtConstructExpr));
+
+ auto MakeTuple = ignoringImplicit(
+ callExpr(
+ callee(expr(ignoringImplicit(declRefExpr(
+ unless(hasExplicitTemplateArgs()),
+ to(functionDecl(hasAnyName(SmallVector<StringRef, 2>(
+ TupleMakeFunctions.begin(), TupleMakeFunctions.end())))))))))
+ .bind("make"));
+
+ // make_something can return type convertible to container's element type.
+ // Allow the conversion only on containers of pairs.
+ auto MakeTupleCtor = ignoringImplicit(cxxConstructExpr(
+ has(materializeTemporaryExpr(MakeTuple)),
+ hasDeclaration(cxxConstructorDecl(ofClass(hasAnyName(
+ SmallVector<StringRef, 2>(TupleTypes.begin(), TupleTypes.end())))))));
+
+ auto SoughtParam = materializeTemporaryExpr(
+ anyOf(has(MakeTuple), has(MakeTupleCtor),
+ HasConstructExpr, has(cxxFunctionalCastExpr(HasConstructExpr))));
+
+ Finder->addMatcher(cxxMemberCallExpr(CallPushBack, has(SoughtParam),
+ unless(isInTemplateInstantiation()))
+ .bind("call"),
+ this);
+}
+
+void UseEmplaceCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Call = Result.Nodes.getNodeAs<CXXMemberCallExpr>("call");
+ const auto *CtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>("ctor");
+ const auto *MakeCall = Result.Nodes.getNodeAs<CallExpr>("make");
+ assert((CtorCall || MakeCall) && "No push_back parameter matched");
+
+ if (IgnoreImplicitConstructors && CtorCall && CtorCall->getNumArgs() >= 1 &&
+ CtorCall->getArg(0)->getSourceRange() == CtorCall->getSourceRange())
+ return;
+
+ const auto FunctionNameSourceRange = CharSourceRange::getCharRange(
+ Call->getExprLoc(), Call->getArg(0)->getExprLoc());
+
+ auto Diag = diag(Call->getExprLoc(), "use emplace_back instead of push_back");
+
+ if (FunctionNameSourceRange.getBegin().isMacroID())
+ return;
+
+ const auto *EmplacePrefix = MakeCall ? "emplace_back" : "emplace_back(";
+ Diag << FixItHint::CreateReplacement(FunctionNameSourceRange, EmplacePrefix);
+
+ const SourceRange CallParensRange =
+ MakeCall ? SourceRange(MakeCall->getCallee()->getLocEnd(),
+ MakeCall->getRParenLoc())
+ : CtorCall->getParenOrBraceRange();
+
+ // Finish if there is no explicit constructor call.
+ if (CallParensRange.getBegin().isInvalid())
+ return;
+
+ const SourceLocation ExprBegin =
+ MakeCall ? MakeCall->getExprLoc() : CtorCall->getExprLoc();
+
+ // Range for constructor name and opening brace.
+ const auto ParamCallSourceRange =
+ CharSourceRange::getTokenRange(ExprBegin, CallParensRange.getBegin());
+
+ Diag << FixItHint::CreateRemoval(ParamCallSourceRange)
+ << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
+ CallParensRange.getEnd(), CallParensRange.getEnd()));
+}
+
+void UseEmplaceCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "ContainersWithPushBack",
+ utils::options::serializeStringList(ContainersWithPushBack));
+ Options.store(Opts, "SmartPointers",
+ utils::options::serializeStringList(SmartPointers));
+ Options.store(Opts, "TupleTypes",
+ utils::options::serializeStringList(TupleTypes));
+ Options.store(Opts, "TupleMakeFunctions",
+ utils::options::serializeStringList(TupleMakeFunctions));
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.h
new file mode 100644
index 0000000..2efb212
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.h
@@ -0,0 +1,47 @@
+//===--- UseEmplaceCheck.h - clang-tidy--------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EMPLACE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EMPLACE_H
+
+#include "../ClangTidy.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// This check looks for cases when inserting new element into std::vector but
+/// the element is constructed temporarily.
+/// It replaces those calls for emplace_back of arguments passed to
+/// constructor of temporary object.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-emplace.html
+class UseEmplaceCheck : public ClangTidyCheck {
+public:
+ UseEmplaceCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ const bool IgnoreImplicitConstructors;
+ const std::vector<std::string> ContainersWithPushBack;
+ const std::vector<std::string> SmartPointers;
+ const std::vector<std::string> TupleTypes;
+ const std::vector<std::string> TupleMakeFunctions;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EMPLACE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
new file mode 100644
index 0000000..88f4485
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
@@ -0,0 +1,313 @@
+//===--- UseEqualsDefaultCheck.cpp - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseEqualsDefaultCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+static const char SpecialFunction[] = "SpecialFunction";
+
+/// \brief Finds all the named non-static fields of \p Record.
+static std::set<const FieldDecl *>
+getAllNamedFields(const CXXRecordDecl *Record) {
+ std::set<const FieldDecl *> Result;
+ for (const auto *Field : Record->fields()) {
+ // Static data members are not in this range.
+ if (Field->isUnnamedBitfield())
+ continue;
+ Result.insert(Field);
+ }
+ return Result;
+}
+
+/// \brief Returns the names of the direct bases of \p Record, both virtual and
+/// non-virtual.
+static std::set<const Type *> getAllDirectBases(const CXXRecordDecl *Record) {
+ std::set<const Type *> Result;
+ for (auto Base : Record->bases()) {
+ // CXXBaseSpecifier.
+ const auto *BaseType = Base.getTypeSourceInfo()->getType().getTypePtr();
+ Result.insert(BaseType);
+ }
+ return Result;
+}
+
+/// \brief Returns a matcher that matches member expressions where the base is
+/// the variable declared as \p Var and the accessed member is the one declared
+/// as \p Field.
+internal::Matcher<Expr> accessToFieldInVar(const FieldDecl *Field,
+ const ValueDecl *Var) {
+ return ignoringImpCasts(
+ memberExpr(hasObjectExpression(declRefExpr(to(varDecl(equalsNode(Var))))),
+ member(fieldDecl(equalsNode(Field)))));
+}
+
+/// \brief Check that the given constructor has copy signature and that it
+/// copy-initializes all its bases and members.
+static bool isCopyConstructorAndCanBeDefaulted(ASTContext *Context,
+ const CXXConstructorDecl *Ctor) {
+ // An explicitly-defaulted constructor cannot have default arguments.
+ if (Ctor->getMinRequiredArguments() != 1)
+ return false;
+
+ const auto *Record = Ctor->getParent();
+ const auto *Param = Ctor->getParamDecl(0);
+
+ // Base classes and members that have to be copied.
+ auto BasesToInit = getAllDirectBases(Record);
+ auto FieldsToInit = getAllNamedFields(Record);
+
+ // Ensure that all the bases are copied.
+ for (const auto *Base : BasesToInit) {
+ // The initialization of a base class should be a call to a copy
+ // constructor of the base.
+ if (match(
+ cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer(
+ isBaseInitializer(),
+ withInitializer(cxxConstructExpr(allOf(
+ hasType(equalsNode(Base)),
+ hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
+ argumentCountIs(1),
+ hasArgument(
+ 0, declRefExpr(to(varDecl(equalsNode(Param))))))))))),
+ *Ctor, *Context)
+ .empty())
+ return false;
+ }
+
+ // Ensure that all the members are copied.
+ for (const auto *Field : FieldsToInit) {
+ auto AccessToFieldInParam = accessToFieldInVar(Field, Param);
+ // The initialization is a CXXConstructExpr for class types.
+ if (match(
+ cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer(
+ isMemberInitializer(), forField(equalsNode(Field)),
+ withInitializer(anyOf(
+ AccessToFieldInParam,
+ initListExpr(has(AccessToFieldInParam)),
+ cxxConstructExpr(allOf(
+ hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
+ argumentCountIs(1),
+ hasArgument(0, AccessToFieldInParam)))))))),
+ *Ctor, *Context)
+ .empty())
+ return false;
+ }
+
+ // Ensure that we don't do anything else, like initializing an indirect base.
+ return Ctor->getNumCtorInitializers() ==
+ BasesToInit.size() + FieldsToInit.size();
+}
+
+/// \brief Checks that the given method is an overloading of the assignment
+/// operator, has copy signature, returns a reference to "*this" and copies
+/// all its members and subobjects.
+static bool isCopyAssignmentAndCanBeDefaulted(ASTContext *Context,
+ const CXXMethodDecl *Operator) {
+ const auto *Record = Operator->getParent();
+ const auto *Param = Operator->getParamDecl(0);
+
+ // Base classes and members that have to be copied.
+ auto BasesToInit = getAllDirectBases(Record);
+ auto FieldsToInit = getAllNamedFields(Record);
+
+ const auto *Compound = cast<CompoundStmt>(Operator->getBody());
+
+ // The assignment operator definition has to end with the following return
+ // statement:
+ // return *this;
+ if (Compound->body_empty() ||
+ match(returnStmt(has(ignoringParenImpCasts(unaryOperator(
+ hasOperatorName("*"), hasUnaryOperand(cxxThisExpr()))))),
+ *Compound->body_back(), *Context)
+ .empty())
+ return false;
+
+ // Ensure that all the bases are copied.
+ for (const auto *Base : BasesToInit) {
+ // Assignment operator of a base class:
+ // Base::operator=(Other);
+ //
+ // Clang translates this into:
+ // ((Base*)this)->operator=((Base)Other);
+ //
+ // So we are looking for a member call that fulfills:
+ if (match(compoundStmt(has(ignoringParenImpCasts(cxxMemberCallExpr(allOf(
+ // - The object is an implicit cast of 'this' to a pointer to
+ // a base class.
+ onImplicitObjectArgument(
+ implicitCastExpr(hasImplicitDestinationType(
+ pointsTo(type(equalsNode(Base)))),
+ hasSourceExpression(cxxThisExpr()))),
+ // - The called method is the operator=.
+ callee(cxxMethodDecl(isCopyAssignmentOperator())),
+ // - The argument is (an implicit cast to a Base of) the
+ // argument taken by "Operator".
+ argumentCountIs(1),
+ hasArgument(0,
+ declRefExpr(to(varDecl(equalsNode(Param)))))))))),
+ *Compound, *Context)
+ .empty())
+ return false;
+ }
+
+ // Ensure that all the members are copied.
+ for (const auto *Field : FieldsToInit) {
+ // The assignment of data members:
+ // Field = Other.Field;
+ // Is a BinaryOperator in non-class types, and a CXXOperatorCallExpr
+ // otherwise.
+ auto LHS = memberExpr(hasObjectExpression(cxxThisExpr()),
+ member(fieldDecl(equalsNode(Field))));
+ auto RHS = accessToFieldInVar(Field, Param);
+ if (match(
+ compoundStmt(has(ignoringParenImpCasts(stmt(anyOf(
+ binaryOperator(hasOperatorName("="), hasLHS(LHS), hasRHS(RHS)),
+ cxxOperatorCallExpr(hasOverloadedOperatorName("="),
+ argumentCountIs(2), hasArgument(0, LHS),
+ hasArgument(1, RHS))))))),
+ *Compound, *Context)
+ .empty())
+ return false;
+ }
+
+ // Ensure that we don't do anything else.
+ return Compound->size() == BasesToInit.size() + FieldsToInit.size() + 1;
+}
+
+/// \brief Returns false if the body has any non-whitespace character.
+static bool bodyEmpty(const ASTContext *Context, const CompoundStmt *Body) {
+ bool Invalid = false;
+ StringRef Text = Lexer::getSourceText(
+ CharSourceRange::getCharRange(Body->getLBracLoc().getLocWithOffset(1),
+ Body->getRBracLoc()),
+ Context->getSourceManager(), Context->getLangOpts(), &Invalid);
+ return !Invalid && std::strspn(Text.data(), " \t\r\n") == Text.size();
+}
+
+UseEqualsDefaultCheck::UseEqualsDefaultCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true) != 0) {}
+
+void UseEqualsDefaultCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IgnoreMacros", IgnoreMacros);
+}
+
+void UseEqualsDefaultCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // Destructor.
+ Finder->addMatcher(cxxDestructorDecl(isDefinition()).bind(SpecialFunction),
+ this);
+ Finder->addMatcher(
+ cxxConstructorDecl(
+ isDefinition(),
+ anyOf(
+ // Default constructor.
+ allOf(unless(hasAnyConstructorInitializer(isWritten())),
+ parameterCountIs(0)),
+ // Copy constructor.
+ allOf(isCopyConstructor(),
+ // Discard constructors that can be used as a copy
+ // constructor because all the other arguments have
+ // default values.
+ parameterCountIs(1))))
+ .bind(SpecialFunction),
+ this);
+ // Copy-assignment operator.
+ Finder->addMatcher(
+ cxxMethodDecl(isDefinition(), isCopyAssignmentOperator(),
+ // isCopyAssignmentOperator() allows the parameter to be
+ // passed by value, and in this case it cannot be
+ // defaulted.
+ hasParameter(0, hasType(lValueReferenceType())))
+ .bind(SpecialFunction),
+ this);
+}
+
+void UseEqualsDefaultCheck::check(const MatchFinder::MatchResult &Result) {
+ std::string SpecialFunctionName;
+
+ // Both CXXConstructorDecl and CXXDestructorDecl inherit from CXXMethodDecl.
+ const auto *SpecialFunctionDecl =
+ Result.Nodes.getNodeAs<CXXMethodDecl>(SpecialFunction);
+
+ if (IgnoreMacros && SpecialFunctionDecl->getLocation().isMacroID())
+ return;
+
+ // Discard explicitly deleted/defaulted special member functions and those
+ // that are not user-provided (automatically generated).
+ if (SpecialFunctionDecl->isDeleted() ||
+ SpecialFunctionDecl->isExplicitlyDefaulted() ||
+ SpecialFunctionDecl->isLateTemplateParsed() ||
+ SpecialFunctionDecl->isTemplateInstantiation() ||
+ !SpecialFunctionDecl->isUserProvided() || !SpecialFunctionDecl->hasBody())
+ return;
+
+ const auto *Body = dyn_cast<CompoundStmt>(SpecialFunctionDecl->getBody());
+ if (!Body)
+ return;
+
+ // If there is code inside the body, don't warn.
+ if (!SpecialFunctionDecl->isCopyAssignmentOperator() && !Body->body_empty())
+ return;
+
+ // If there are comments inside the body, don't do the change.
+ bool ApplyFix = SpecialFunctionDecl->isCopyAssignmentOperator() ||
+ bodyEmpty(Result.Context, Body);
+
+ std::vector<FixItHint> RemoveInitializers;
+
+ if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(SpecialFunctionDecl)) {
+ if (Ctor->getNumParams() == 0) {
+ SpecialFunctionName = "default constructor";
+ } else {
+ if (!isCopyConstructorAndCanBeDefaulted(Result.Context, Ctor))
+ return;
+ SpecialFunctionName = "copy constructor";
+ // If there are constructor initializers, they must be removed.
+ for (const auto *Init : Ctor->inits()) {
+ RemoveInitializers.emplace_back(
+ FixItHint::CreateRemoval(Init->getSourceRange()));
+ }
+ }
+ } else if (isa<CXXDestructorDecl>(SpecialFunctionDecl)) {
+ SpecialFunctionName = "destructor";
+ } else {
+ if (!isCopyAssignmentAndCanBeDefaulted(Result.Context, SpecialFunctionDecl))
+ return;
+ SpecialFunctionName = "copy-assignment operator";
+ }
+
+ // The location of the body is more useful inside a macro as spelling and
+ // expansion locations are reported.
+ SourceLocation Location = SpecialFunctionDecl->getLocation();
+ if (Location.isMacroID())
+ Location = Body->getLocStart();
+
+ auto Diag = diag(Location, "use '= default' to define a trivial " +
+ SpecialFunctionName);
+
+ if (ApplyFix)
+ Diag << FixItHint::CreateReplacement(Body->getSourceRange(), "= default;")
+ << RemoveInitializers;
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.h
new file mode 100644
index 0000000..a55c222
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.h
@@ -0,0 +1,53 @@
+//===--- UseEqualsDefaultCheck.h - clang-tidy--------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EQUALS_DEFAULT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EQUALS_DEFAULT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// \brief Replace default bodies of special member functions with '= default;'.
+/// \code
+/// struct A {
+/// A() {}
+/// ~A();
+/// };
+/// A::~A() {}
+/// \endcode
+/// Is converted to:
+/// \code
+/// struct A {
+/// A() = default;
+/// ~A();
+/// };
+/// A::~A() = default;
+/// \endcode
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-equals-default.html
+class UseEqualsDefaultCheck : public ClangTidyCheck {
+public:
+ UseEqualsDefaultCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const bool IgnoreMacros;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EQUALS_DEFAULT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.cpp
new file mode 100644
index 0000000..18190b1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.cpp
@@ -0,0 +1,78 @@
+//===--- UseEqualsDeleteCheck.cpp - clang-tidy-----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseEqualsDeleteCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+static const char SpecialFunction[] = "SpecialFunction";
+static const char DeletedNotPublic[] = "DeletedNotPublic";
+
+void UseEqualsDeleteCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ auto PrivateSpecialFn = cxxMethodDecl(
+ isPrivate(),
+ anyOf(cxxConstructorDecl(anyOf(isDefaultConstructor(),
+ isCopyConstructor(), isMoveConstructor())),
+ cxxMethodDecl(
+ anyOf(isCopyAssignmentOperator(), isMoveAssignmentOperator())),
+ cxxDestructorDecl()));
+
+ Finder->addMatcher(
+ cxxMethodDecl(
+ PrivateSpecialFn,
+ unless(anyOf(hasBody(stmt()), isDefaulted(), isDeleted(),
+ ast_matchers::isTemplateInstantiation(),
+ // Ensure that all methods except private special member
+ // functions are defined.
+ hasParent(cxxRecordDecl(hasMethod(unless(
+ anyOf(PrivateSpecialFn, hasBody(stmt()), isPure(),
+ isDefaulted(), isDeleted()))))))))
+ .bind(SpecialFunction),
+ this);
+
+ Finder->addMatcher(
+ cxxMethodDecl(isDeleted(), unless(isPublic())).bind(DeletedNotPublic),
+ this);
+}
+
+void UseEqualsDeleteCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *Func =
+ Result.Nodes.getNodeAs<CXXMethodDecl>(SpecialFunction)) {
+ SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ Func->getLocEnd(), 0, *Result.SourceManager, getLangOpts());
+
+ // FIXME: Improve FixItHint to make the method public.
+ diag(Func->getLocation(),
+ "use '= delete' to prohibit calling of a special member function")
+ << FixItHint::CreateInsertion(EndLoc, " = delete");
+ } else if (const auto *Func =
+ Result.Nodes.getNodeAs<CXXMethodDecl>(DeletedNotPublic)) {
+ // Ignore this warning in macros, since it's extremely noisy in code using
+ // DISALLOW_COPY_AND_ASSIGN-style macros and there's no easy way to
+ // automatically fix the warning when macros are in play.
+ if (Func->getLocation().isMacroID())
+ return;
+ // FIXME: Add FixItHint to make the method public.
+ diag(Func->getLocation(), "deleted member function should be public");
+ }
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.h
new file mode 100644
index 0000000..1daa1a85
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseEqualsDeleteCheck.h
@@ -0,0 +1,50 @@
+//===--- UseEqualsDeleteCheck.h - clang-tidy---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EQUALS_DELETE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EQUALS_DELETE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// \brief Mark unimplemented private special member functions with '= delete'.
+/// \code
+/// struct A {
+/// private:
+/// A(const A&);
+/// A& operator=(const A&);
+/// };
+/// \endcode
+/// Is converted to:
+/// \code
+/// struct A {
+/// private:
+/// A(const A&) = delete;
+/// A& operator=(const A&) = delete;
+/// };
+/// \endcode
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-equals-delete.html
+class UseEqualsDeleteCheck : public ClangTidyCheck {
+public:
+ UseEqualsDeleteCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_EQUALS_DELETE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.cpp
new file mode 100644
index 0000000..869381a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.cpp
@@ -0,0 +1,114 @@
+//===--- UseNoexceptCheck.cpp - clang-tidy---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseNoexceptCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+UseNoexceptCheck::UseNoexceptCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ NoexceptMacro(Options.get("ReplacementString", "")),
+ UseNoexceptFalse(Options.get("UseNoexceptFalse", true)) {}
+
+void UseNoexceptCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "ReplacementString", NoexceptMacro);
+ Options.store(Opts, "UseNoexceptFalse", UseNoexceptFalse);
+}
+
+void UseNoexceptCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ Finder->addMatcher(
+ functionDecl(
+ cxxMethodDecl(
+ hasTypeLoc(loc(functionProtoType(hasDynamicExceptionSpec()))),
+ anyOf(hasOverloadedOperatorName("delete[]"),
+ hasOverloadedOperatorName("delete"), cxxDestructorDecl()))
+ .bind("del-dtor"))
+ .bind("funcDecl"),
+ this);
+
+ Finder->addMatcher(
+ functionDecl(
+ hasTypeLoc(loc(functionProtoType(hasDynamicExceptionSpec()))),
+ unless(anyOf(hasOverloadedOperatorName("delete[]"),
+ hasOverloadedOperatorName("delete"),
+ cxxDestructorDecl())))
+ .bind("funcDecl"),
+ this);
+
+ Finder->addMatcher(
+ parmVarDecl(anyOf(hasType(pointerType(pointee(parenType(innerType(
+ functionProtoType(hasDynamicExceptionSpec())))))),
+ hasType(memberPointerType(pointee(parenType(innerType(
+ functionProtoType(hasDynamicExceptionSpec()))))))))
+ .bind("parmVarDecl"),
+ this);
+}
+
+void UseNoexceptCheck::check(const MatchFinder::MatchResult &Result) {
+ const FunctionProtoType *FnTy = nullptr;
+ bool DtorOrOperatorDel = false;
+ SourceRange Range;
+
+ if (const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("funcDecl")) {
+ DtorOrOperatorDel = Result.Nodes.getNodeAs<FunctionDecl>("del-dtor");
+ FnTy = FuncDecl->getType()->getAs<FunctionProtoType>();
+ if (const auto *TSI = FuncDecl->getTypeSourceInfo())
+ Range =
+ TSI->getTypeLoc().castAs<FunctionTypeLoc>().getExceptionSpecRange();
+ } else if (const auto *ParmDecl =
+ Result.Nodes.getNodeAs<ParmVarDecl>("parmVarDecl")) {
+ FnTy = ParmDecl->getType()
+ ->getAs<Type>()
+ ->getPointeeType()
+ ->getAs<FunctionProtoType>();
+
+ if (const auto *TSI = ParmDecl->getTypeSourceInfo())
+ Range = TSI->getTypeLoc()
+ .getNextTypeLoc()
+ .IgnoreParens()
+ .castAs<FunctionProtoTypeLoc>()
+ .getExceptionSpecRange();
+ }
+ CharSourceRange CRange = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(Range), *Result.SourceManager,
+ Result.Context->getLangOpts());
+
+ assert(FnTy && "FunctionProtoType is null.");
+ bool IsNoThrow = FnTy->isNothrow();
+ StringRef ReplacementStr =
+ IsNoThrow
+ ? NoexceptMacro.empty() ? "noexcept" : NoexceptMacro.c_str()
+ : NoexceptMacro.empty()
+ ? (DtorOrOperatorDel || UseNoexceptFalse) ? "noexcept(false)"
+ : ""
+ : "";
+
+ FixItHint FixIt;
+ if ((IsNoThrow || NoexceptMacro.empty()) && CRange.isValid())
+ FixIt = FixItHint::CreateReplacement(CRange, ReplacementStr);
+
+ diag(Range.getBegin(), "dynamic exception specification '%0' is deprecated; "
+ "consider %select{using '%2'|removing it}1 instead")
+ << Lexer::getSourceText(CRange, *Result.SourceManager,
+ Result.Context->getLangOpts())
+ << ReplacementStr.empty() << ReplacementStr << FixIt;
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.h
new file mode 100644
index 0000000..a15867b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.h
@@ -0,0 +1,49 @@
+//===--- UseNoexceptCheck.h - clang-tidy-------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_NOEXCEPT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_NOEXCEPT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// \brief Replace dynamic exception specifications, with
+/// `noexcept` (or user-defined macro) or `noexcept(false)`.
+/// \code
+/// void foo() throw();
+/// void bar() throw(int);
+/// \endcode
+/// Is converted to:
+/// \code
+/// void foo() ;
+/// void bar() noexcept(false);
+/// \endcode
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-noexcept.html
+class UseNoexceptCheck : public ClangTidyCheck {
+public:
+ UseNoexceptCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const std::string NoexceptMacro;
+ bool UseNoexceptFalse;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_NOEXCEPT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
new file mode 100644
index 0000000..476c549
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -0,0 +1,500 @@
+//===--- UseNullptrCheck.cpp - clang-tidy----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseNullptrCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang;
+using namespace clang::ast_matchers;
+using namespace llvm;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+namespace {
+
+const char CastSequence[] = "sequence";
+
+AST_MATCHER(Type, sugaredNullptrType) {
+ const Type *DesugaredType = Node.getUnqualifiedDesugaredType();
+ if (const auto *BT = dyn_cast<BuiltinType>(DesugaredType))
+ return BT->getKind() == BuiltinType::NullPtr;
+ return false;
+}
+
+/// \brief Create a matcher that finds implicit casts as well as the head of a
+/// sequence of zero or more nested explicit casts that have an implicit cast
+/// to null within.
+/// Finding sequences of explict casts is necessary so that an entire sequence
+/// can be replaced instead of just the inner-most implicit cast.
+StatementMatcher makeCastSequenceMatcher() {
+ StatementMatcher ImplicitCastToNull = implicitCastExpr(
+ anyOf(hasCastKind(CK_NullToPointer), hasCastKind(CK_NullToMemberPointer)),
+ unless(hasImplicitDestinationType(qualType(substTemplateTypeParmType()))),
+ unless(hasSourceExpression(hasType(sugaredNullptrType()))));
+
+ return castExpr(anyOf(ImplicitCastToNull,
+ explicitCastExpr(hasDescendant(ImplicitCastToNull))),
+ unless(hasAncestor(explicitCastExpr())))
+ .bind(CastSequence);
+}
+
+bool isReplaceableRange(SourceLocation StartLoc, SourceLocation EndLoc,
+ const SourceManager &SM) {
+ return SM.isWrittenInSameFile(StartLoc, EndLoc);
+}
+
+/// \brief Replaces the provided range with the text "nullptr", but only if
+/// the start and end location are both in main file.
+/// Returns true if and only if a replacement was made.
+void replaceWithNullptr(ClangTidyCheck &Check, SourceManager &SM,
+ SourceLocation StartLoc, SourceLocation EndLoc) {
+ CharSourceRange Range(SourceRange(StartLoc, EndLoc), true);
+ // Add a space if nullptr follows an alphanumeric character. This happens
+ // whenever there is an c-style explicit cast to nullptr not surrounded by
+ // parentheses and right beside a return statement.
+ SourceLocation PreviousLocation = StartLoc.getLocWithOffset(-1);
+ bool NeedsSpace = isAlphanumeric(*SM.getCharacterData(PreviousLocation));
+ Check.diag(Range.getBegin(), "use nullptr") << FixItHint::CreateReplacement(
+ Range, NeedsSpace ? " nullptr" : "nullptr");
+}
+
+/// \brief Returns the name of the outermost macro.
+///
+/// Given
+/// \code
+/// #define MY_NULL NULL
+/// \endcode
+/// If \p Loc points to NULL, this function will return the name MY_NULL.
+StringRef getOutermostMacroName(SourceLocation Loc, const SourceManager &SM,
+ const LangOptions &LO) {
+ assert(Loc.isMacroID());
+ SourceLocation OutermostMacroLoc;
+
+ while (Loc.isMacroID()) {
+ OutermostMacroLoc = Loc;
+ Loc = SM.getImmediateMacroCallerLoc(Loc);
+ }
+
+ return Lexer::getImmediateMacroName(OutermostMacroLoc, SM, LO);
+}
+
+/// \brief RecursiveASTVisitor for ensuring all nodes rooted at a given AST
+/// subtree that have file-level source locations corresponding to a macro
+/// argument have implicit NullTo(Member)Pointer nodes as ancestors.
+class MacroArgUsageVisitor : public RecursiveASTVisitor<MacroArgUsageVisitor> {
+public:
+ MacroArgUsageVisitor(SourceLocation CastLoc, const SourceManager &SM)
+ : CastLoc(CastLoc), SM(SM), Visited(false), CastFound(false),
+ InvalidFound(false) {
+ assert(CastLoc.isFileID());
+ }
+
+ bool TraverseStmt(Stmt *S) {
+ bool VisitedPreviously = Visited;
+
+ if (!RecursiveASTVisitor<MacroArgUsageVisitor>::TraverseStmt(S))
+ return false;
+
+ // The point at which VisitedPreviously is false and Visited is true is the
+ // root of a subtree containing nodes whose locations match CastLoc. It's
+ // at this point we test that the Implicit NullTo(Member)Pointer cast was
+ // found or not.
+ if (!VisitedPreviously) {
+ if (Visited && !CastFound) {
+ // Found nodes with matching SourceLocations but didn't come across a
+ // cast. This is an invalid macro arg use. Can stop traversal
+ // completely now.
+ InvalidFound = true;
+ return false;
+ }
+ // Reset state as we unwind back up the tree.
+ CastFound = false;
+ Visited = false;
+ }
+ return true;
+ }
+
+ bool VisitStmt(Stmt *S) {
+ if (SM.getFileLoc(S->getLocStart()) != CastLoc)
+ return true;
+ Visited = true;
+
+ const ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(S);
+ if (Cast && (Cast->getCastKind() == CK_NullToPointer ||
+ Cast->getCastKind() == CK_NullToMemberPointer))
+ CastFound = true;
+
+ return true;
+ }
+
+ bool TraverseInitListExpr(InitListExpr *S) {
+ // Only go through the semantic form of the InitListExpr, because
+ // ImplicitCast might not appear in the syntactic form, and this results in
+ // finding usages of the macro argument that don't have a ImplicitCast as an
+ // ancestor (thus invalidating the replacement) when they actually have.
+ return RecursiveASTVisitor<MacroArgUsageVisitor>::
+ TraverseSynOrSemInitListExpr(
+ S->isSemanticForm() ? S : S->getSemanticForm());
+ }
+
+ bool foundInvalid() const { return InvalidFound; }
+
+private:
+ SourceLocation CastLoc;
+ const SourceManager &SM;
+
+ bool Visited;
+ bool CastFound;
+ bool InvalidFound;
+};
+
+/// \brief Looks for implicit casts as well as sequences of 0 or more explicit
+/// casts with an implicit null-to-pointer cast within.
+///
+/// The matcher this visitor is used with will find a single implicit cast or a
+/// top-most explicit cast (i.e. it has no explicit casts as an ancestor) where
+/// an implicit cast is nested within. However, there is no guarantee that only
+/// explicit casts exist between the found top-most explicit cast and the
+/// possibly more than one nested implicit cast. This visitor finds all cast
+/// sequences with an implicit cast to null within and creates a replacement
+/// leaving the outermost explicit cast unchanged to avoid introducing
+/// ambiguities.
+class CastSequenceVisitor : public RecursiveASTVisitor<CastSequenceVisitor> {
+public:
+ CastSequenceVisitor(ASTContext &Context, ArrayRef<StringRef> NullMacros,
+ ClangTidyCheck &check)
+ : SM(Context.getSourceManager()), Context(Context),
+ NullMacros(NullMacros), Check(check), FirstSubExpr(nullptr),
+ PruneSubtree(false) {}
+
+ bool TraverseStmt(Stmt *S) {
+ // Stop traversing down the tree if requested.
+ if (PruneSubtree) {
+ PruneSubtree = false;
+ return true;
+ }
+ return RecursiveASTVisitor<CastSequenceVisitor>::TraverseStmt(S);
+ }
+
+ // Only VisitStmt is overridden as we shouldn't find other base AST types
+ // within a cast expression.
+ bool VisitStmt(Stmt *S) {
+ auto *C = dyn_cast<CastExpr>(S);
+ // Catch the castExpr inside cxxDefaultArgExpr.
+ if (auto *E = dyn_cast<CXXDefaultArgExpr>(S)) {
+ C = dyn_cast<CastExpr>(E->getExpr());
+ FirstSubExpr = nullptr;
+ }
+ if (!C) {
+ FirstSubExpr = nullptr;
+ return true;
+ }
+
+ auto* CastSubExpr = C->getSubExpr()->IgnoreParens();
+ // Ignore cast expressions which cast nullptr literal.
+ if (isa<CXXNullPtrLiteralExpr>(CastSubExpr)) {
+ return true;
+ }
+
+ if (!FirstSubExpr)
+ FirstSubExpr = CastSubExpr;
+
+ if (C->getCastKind() != CK_NullToPointer &&
+ C->getCastKind() != CK_NullToMemberPointer) {
+ return true;
+ }
+
+ SourceLocation StartLoc = FirstSubExpr->getLocStart();
+ SourceLocation EndLoc = FirstSubExpr->getLocEnd();
+
+ // If the location comes from a macro arg expansion, *all* uses of that
+ // arg must be checked to result in NullTo(Member)Pointer casts.
+ //
+ // If the location comes from a macro body expansion, check to see if its
+ // coming from one of the allowed 'NULL' macros.
+ if (SM.isMacroArgExpansion(StartLoc) && SM.isMacroArgExpansion(EndLoc)) {
+ SourceLocation FileLocStart = SM.getFileLoc(StartLoc),
+ FileLocEnd = SM.getFileLoc(EndLoc);
+ SourceLocation ImmediateMacroArgLoc, MacroLoc;
+ // Skip NULL macros used in macro.
+ if (!getMacroAndArgLocations(StartLoc, ImmediateMacroArgLoc, MacroLoc) ||
+ ImmediateMacroArgLoc != FileLocStart)
+ return skipSubTree();
+
+ if (isReplaceableRange(FileLocStart, FileLocEnd, SM) &&
+ allArgUsesValid(C)) {
+ replaceWithNullptr(Check, SM, FileLocStart, FileLocEnd);
+ }
+ return true;
+ }
+
+ if (SM.isMacroBodyExpansion(StartLoc) && SM.isMacroBodyExpansion(EndLoc)) {
+ StringRef OutermostMacroName =
+ getOutermostMacroName(StartLoc, SM, Context.getLangOpts());
+
+ // Check to see if the user wants to replace the macro being expanded.
+ if (std::find(NullMacros.begin(), NullMacros.end(), OutermostMacroName) ==
+ NullMacros.end()) {
+ return skipSubTree();
+ }
+
+ StartLoc = SM.getFileLoc(StartLoc);
+ EndLoc = SM.getFileLoc(EndLoc);
+ }
+
+ if (!isReplaceableRange(StartLoc, EndLoc, SM)) {
+ return skipSubTree();
+ }
+ replaceWithNullptr(Check, SM, StartLoc, EndLoc);
+
+ return true;
+ }
+
+private:
+ bool skipSubTree() {
+ PruneSubtree = true;
+ return true;
+ }
+
+ /// \brief Tests that all expansions of a macro arg, one of which expands to
+ /// result in \p CE, yield NullTo(Member)Pointer casts.
+ bool allArgUsesValid(const CastExpr *CE) {
+ SourceLocation CastLoc = CE->getLocStart();
+
+ // Step 1: Get location of macro arg and location of the macro the arg was
+ // provided to.
+ SourceLocation ArgLoc, MacroLoc;
+ if (!getMacroAndArgLocations(CastLoc, ArgLoc, MacroLoc))
+ return false;
+
+ // Step 2: Find the first ancestor that doesn't expand from this macro.
+ ast_type_traits::DynTypedNode ContainingAncestor;
+ if (!findContainingAncestor(
+ ast_type_traits::DynTypedNode::create<Stmt>(*CE), MacroLoc,
+ ContainingAncestor))
+ return false;
+
+ // Step 3:
+ // Visit children of this containing parent looking for the least-descended
+ // nodes of the containing parent which are macro arg expansions that expand
+ // from the given arg location.
+ // Visitor needs: arg loc.
+ MacroArgUsageVisitor ArgUsageVisitor(SM.getFileLoc(CastLoc), SM);
+ if (const auto *D = ContainingAncestor.get<Decl>())
+ ArgUsageVisitor.TraverseDecl(const_cast<Decl *>(D));
+ else if (const auto *S = ContainingAncestor.get<Stmt>())
+ ArgUsageVisitor.TraverseStmt(const_cast<Stmt *>(S));
+ else
+ llvm_unreachable("Unhandled ContainingAncestor node type");
+
+ return !ArgUsageVisitor.foundInvalid();
+ }
+
+ /// \brief Given the SourceLocation for a macro arg expansion, finds the
+ /// non-macro SourceLocation of the macro the arg was passed to and the
+ /// non-macro SourceLocation of the argument in the arg list to that macro.
+ /// These results are returned via \c MacroLoc and \c ArgLoc respectively.
+ /// These values are undefined if the return value is false.
+ ///
+ /// \returns false if one of the returned SourceLocations would be a
+ /// SourceLocation pointing within the definition of another macro.
+ bool getMacroAndArgLocations(SourceLocation Loc, SourceLocation &ArgLoc,
+ SourceLocation &MacroLoc) {
+ assert(Loc.isMacroID() && "Only reasonble to call this on macros");
+
+ ArgLoc = Loc;
+
+ // Find the location of the immediate macro expansion.
+ while (true) {
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(ArgLoc);
+ const SrcMgr::SLocEntry *E = &SM.getSLocEntry(LocInfo.first);
+ const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
+
+ SourceLocation OldArgLoc = ArgLoc;
+ ArgLoc = Expansion.getExpansionLocStart();
+ if (!Expansion.isMacroArgExpansion()) {
+ if (!MacroLoc.isFileID())
+ return false;
+
+ StringRef Name =
+ Lexer::getImmediateMacroName(OldArgLoc, SM, Context.getLangOpts());
+ return std::find(NullMacros.begin(), NullMacros.end(), Name) !=
+ NullMacros.end();
+ }
+
+ MacroLoc = SM.getExpansionRange(ArgLoc).getBegin();
+
+ ArgLoc = Expansion.getSpellingLoc().getLocWithOffset(LocInfo.second);
+ if (ArgLoc.isFileID())
+ return true;
+
+ // If spelling location resides in the same FileID as macro expansion
+ // location, it means there is no inner macro.
+ FileID MacroFID = SM.getFileID(MacroLoc);
+ if (SM.isInFileID(ArgLoc, MacroFID)) {
+ // Don't transform this case. If the characters that caused the
+ // null-conversion come from within a macro, they can't be changed.
+ return false;
+ }
+ }
+
+ llvm_unreachable("getMacroAndArgLocations");
+ }
+
+ /// \brief Tests if TestMacroLoc is found while recursively unravelling
+ /// expansions starting at TestLoc. TestMacroLoc.isFileID() must be true.
+ /// Implementation is very similar to getMacroAndArgLocations() except in this
+ /// case, it's not assumed that TestLoc is expanded from a macro argument.
+ /// While unravelling expansions macro arguments are handled as with
+ /// getMacroAndArgLocations() but in this function macro body expansions are
+ /// also handled.
+ ///
+ /// False means either:
+ /// - TestLoc is not from a macro expansion.
+ /// - TestLoc is from a different macro expansion.
+ bool expandsFrom(SourceLocation TestLoc, SourceLocation TestMacroLoc) {
+ if (TestLoc.isFileID()) {
+ return false;
+ }
+
+ SourceLocation Loc = TestLoc, MacroLoc;
+
+ while (true) {
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ const SrcMgr::SLocEntry *E = &SM.getSLocEntry(LocInfo.first);
+ const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
+
+ Loc = Expansion.getExpansionLocStart();
+
+ if (!Expansion.isMacroArgExpansion()) {
+ if (Loc.isFileID()) {
+ return Loc == TestMacroLoc;
+ }
+ // Since Loc is still a macro ID and it's not an argument expansion, we
+ // don't need to do the work of handling an argument expansion. Simply
+ // keep recursively expanding until we hit a FileID or a macro arg
+ // expansion or a macro arg expansion.
+ continue;
+ }
+
+ MacroLoc = SM.getImmediateExpansionRange(Loc).getBegin();
+ if (MacroLoc.isFileID() && MacroLoc == TestMacroLoc) {
+ // Match made.
+ return true;
+ }
+
+ Loc = Expansion.getSpellingLoc().getLocWithOffset(LocInfo.second);
+ if (Loc.isFileID()) {
+ // If we made it this far without finding a match, there is no match to
+ // be made.
+ return false;
+ }
+ }
+
+ llvm_unreachable("expandsFrom");
+ }
+
+ /// \brief Given a starting point \c Start in the AST, find an ancestor that
+ /// doesn't expand from the macro called at file location \c MacroLoc.
+ ///
+ /// \pre MacroLoc.isFileID()
+ /// \returns true if such an ancestor was found, false otherwise.
+ bool findContainingAncestor(ast_type_traits::DynTypedNode Start,
+ SourceLocation MacroLoc,
+ ast_type_traits::DynTypedNode &Result) {
+ // Below we're only following the first parent back up the AST. This should
+ // be fine since for the statements we care about there should only be one
+ // parent, except for the case specified below.
+
+ assert(MacroLoc.isFileID());
+
+ while (true) {
+ const auto &Parents = Context.getParents(Start);
+ if (Parents.empty())
+ return false;
+ if (Parents.size() > 1) {
+ // If there are more than one parents, don't do the replacement unless
+ // they are InitListsExpr (semantic and syntactic form). In this case we
+ // can choose any one here, and the ASTVisitor will take care of
+ // traversing the right one.
+ for (const auto &Parent : Parents) {
+ if (!Parent.get<InitListExpr>())
+ return false;
+ }
+ }
+
+ const ast_type_traits::DynTypedNode &Parent = Parents[0];
+
+ SourceLocation Loc;
+ if (const auto *D = Parent.get<Decl>())
+ Loc = D->getLocStart();
+ else if (const auto *S = Parent.get<Stmt>())
+ Loc = S->getLocStart();
+
+ // TypeLoc and NestedNameSpecifierLoc are members of the parent map. Skip
+ // them and keep going up.
+ if (Loc.isValid()) {
+ if (!expandsFrom(Loc, MacroLoc)) {
+ Result = Parent;
+ return true;
+ }
+ }
+ Start = Parent;
+ }
+
+ llvm_unreachable("findContainingAncestor");
+ }
+
+private:
+ SourceManager &SM;
+ ASTContext &Context;
+ ArrayRef<StringRef> NullMacros;
+ ClangTidyCheck &Check;
+ Expr *FirstSubExpr;
+ bool PruneSubtree;
+};
+
+} // namespace
+
+UseNullptrCheck::UseNullptrCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ NullMacrosStr(Options.get("NullMacros", "")) {
+ StringRef(NullMacrosStr).split(NullMacros, ",");
+}
+
+void UseNullptrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "NullMacros", NullMacrosStr);
+}
+
+void UseNullptrCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matcher for C++. Because this checker is used for
+ // modernization, it is reasonable to run it on any C++ standard with the
+ // assumption the user is trying to modernize their codebase.
+ if (getLangOpts().CPlusPlus)
+ Finder->addMatcher(makeCastSequenceMatcher(), this);
+}
+
+void UseNullptrCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *NullCast = Result.Nodes.getNodeAs<CastExpr>(CastSequence);
+ assert(NullCast && "Bad Callback. No node provided");
+
+ // Given an implicit null-ptr cast or an explicit cast with an implicit
+ // null-to-pointer cast within use CastSequenceVisitor to identify sequences
+ // of explicit casts that can be converted into 'nullptr'.
+ CastSequenceVisitor(*Result.Context, NullMacros, *this)
+ .TraverseStmt(const_cast<CastExpr *>(NullCast));
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
new file mode 100644
index 0000000..4b33f1e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
@@ -0,0 +1,35 @@
+//===--- UseNullptrCheck.h - clang-tidy--------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_NULLPTR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_NULLPTR_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+class UseNullptrCheck : public ClangTidyCheck {
+public:
+ UseNullptrCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const std::string NullMacrosStr;
+ SmallVector<StringRef, 1> NullMacros;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_NULLPTR_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
new file mode 100644
index 0000000..9429eb2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
@@ -0,0 +1,207 @@
+//===--- UseOverrideCheck.cpp - clang-tidy --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseOverrideCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+void UseOverrideCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matcher for C++11.
+ if (getLangOpts().CPlusPlus11)
+ Finder->addMatcher(cxxMethodDecl(isOverride()).bind("method"), this);
+}
+
+// Re-lex the tokens to get precise locations to insert 'override' and remove
+// 'virtual'.
+static SmallVector<Token, 16>
+ParseTokens(CharSourceRange Range, const MatchFinder::MatchResult &Result) {
+ const SourceManager &Sources = *Result.SourceManager;
+ std::pair<FileID, unsigned> LocInfo =
+ Sources.getDecomposedLoc(Range.getBegin());
+ StringRef File = Sources.getBufferData(LocInfo.first);
+ const char *TokenBegin = File.data() + LocInfo.second;
+ Lexer RawLexer(Sources.getLocForStartOfFile(LocInfo.first),
+ Result.Context->getLangOpts(), File.begin(), TokenBegin,
+ File.end());
+ SmallVector<Token, 16> Tokens;
+ Token Tok;
+ int NestedParens = 0;
+ while (!RawLexer.LexFromRawLexer(Tok)) {
+ if ((Tok.is(tok::semi) || Tok.is(tok::l_brace)) && NestedParens == 0)
+ break;
+ if (Sources.isBeforeInTranslationUnit(Range.getEnd(), Tok.getLocation()))
+ break;
+ if (Tok.is(tok::l_paren))
+ ++NestedParens;
+ else if (Tok.is(tok::r_paren))
+ --NestedParens;
+ if (Tok.is(tok::raw_identifier)) {
+ IdentifierInfo &Info = Result.Context->Idents.get(StringRef(
+ Sources.getCharacterData(Tok.getLocation()), Tok.getLength()));
+ Tok.setIdentifierInfo(&Info);
+ Tok.setKind(Info.getTokenID());
+ }
+ Tokens.push_back(Tok);
+ }
+ return Tokens;
+}
+
+static StringRef GetText(const Token &Tok, const SourceManager &Sources) {
+ return StringRef(Sources.getCharacterData(Tok.getLocation()),
+ Tok.getLength());
+}
+
+void UseOverrideCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Method = Result.Nodes.getNodeAs<FunctionDecl>("method");
+ const SourceManager &Sources = *Result.SourceManager;
+
+ assert(Method != nullptr);
+ if (Method->getInstantiatedFromMemberFunction() != nullptr)
+ Method = Method->getInstantiatedFromMemberFunction();
+
+ if (Method->isImplicit() || Method->getLocation().isMacroID() ||
+ Method->isOutOfLine())
+ return;
+
+ bool HasVirtual = Method->isVirtualAsWritten();
+ bool HasOverride = Method->getAttr<OverrideAttr>();
+ bool HasFinal = Method->getAttr<FinalAttr>();
+
+ bool OnlyVirtualSpecified = HasVirtual && !HasOverride && !HasFinal;
+ unsigned KeywordCount = HasVirtual + HasOverride + HasFinal;
+
+ if (!OnlyVirtualSpecified && KeywordCount == 1)
+ return; // Nothing to do.
+
+ std::string Message;
+
+ if (OnlyVirtualSpecified) {
+ Message =
+ "prefer using 'override' or (rarely) 'final' instead of 'virtual'";
+ } else if (KeywordCount == 0) {
+ Message = "annotate this function with 'override' or (rarely) 'final'";
+ } else {
+ StringRef Redundant =
+ HasVirtual ? (HasOverride && HasFinal ? "'virtual' and 'override' are"
+ : "'virtual' is")
+ : "'override' is";
+ StringRef Correct = HasFinal ? "'final'" : "'override'";
+
+ Message = (llvm::Twine(Redundant) +
+ " redundant since the function is already declared " + Correct)
+ .str();
+ }
+
+ DiagnosticBuilder Diag = diag(Method->getLocation(), Message);
+
+ CharSourceRange FileRange = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(Method->getSourceRange()), Sources,
+ getLangOpts());
+
+ if (!FileRange.isValid())
+ return;
+
+ // FIXME: Instead of re-lexing and looking for specific macros such as
+ // 'ABSTRACT', properly store the location of 'virtual' and '= 0' in each
+ // FunctionDecl.
+ SmallVector<Token, 16> Tokens = ParseTokens(FileRange, Result);
+
+ // Add 'override' on inline declarations that don't already have it.
+ if (!HasFinal && !HasOverride) {
+ SourceLocation InsertLoc;
+ StringRef ReplacementText = "override ";
+ SourceLocation MethodLoc = Method->getLocation();
+
+ for (Token T : Tokens) {
+ if (T.is(tok::kw___attribute) &&
+ !Sources.isBeforeInTranslationUnit(T.getLocation(), MethodLoc)) {
+ InsertLoc = T.getLocation();
+ break;
+ }
+ }
+
+ if (Method->hasAttrs()) {
+ for (const clang::Attr *A : Method->getAttrs()) {
+ if (!A->isImplicit() && !A->isInherited()) {
+ SourceLocation Loc =
+ Sources.getExpansionLoc(A->getRange().getBegin());
+ if ((!InsertLoc.isValid() ||
+ Sources.isBeforeInTranslationUnit(Loc, InsertLoc)) &&
+ !Sources.isBeforeInTranslationUnit(Loc, MethodLoc))
+ InsertLoc = Loc;
+ }
+ }
+ }
+
+ if (InsertLoc.isInvalid() && Method->doesThisDeclarationHaveABody() &&
+ Method->getBody() && !Method->isDefaulted()) {
+ // For methods with inline definition, add the override keyword at the
+ // end of the declaration of the function, but prefer to put it on the
+ // same line as the declaration if the beginning brace for the start of
+ // the body falls on the next line.
+ ReplacementText = " override";
+ auto LastTokenIter = std::prev(Tokens.end());
+ // When try statement is used instead of compound statement as
+ // method body - insert override keyword before it.
+ if (LastTokenIter->is(tok::kw_try))
+ LastTokenIter = std::prev(LastTokenIter);
+ InsertLoc = LastTokenIter->getEndLoc();
+ }
+
+ if (!InsertLoc.isValid()) {
+ // For declarations marked with "= 0" or "= [default|delete]", the end
+ // location will point until after those markings. Therefore, the override
+ // keyword shouldn't be inserted at the end, but before the '='.
+ if (Tokens.size() > 2 && (GetText(Tokens.back(), Sources) == "0" ||
+ Tokens.back().is(tok::kw_default) ||
+ Tokens.back().is(tok::kw_delete)) &&
+ GetText(Tokens[Tokens.size() - 2], Sources) == "=") {
+ InsertLoc = Tokens[Tokens.size() - 2].getLocation();
+ // Check if we need to insert a space.
+ if ((Tokens[Tokens.size() - 2].getFlags() & Token::LeadingSpace) == 0)
+ ReplacementText = " override ";
+ } else if (GetText(Tokens.back(), Sources) == "ABSTRACT") {
+ InsertLoc = Tokens.back().getLocation();
+ }
+ }
+
+ if (!InsertLoc.isValid()) {
+ InsertLoc = FileRange.getEnd();
+ ReplacementText = " override";
+ }
+ Diag << FixItHint::CreateInsertion(InsertLoc, ReplacementText);
+ }
+
+ if (HasFinal && HasOverride) {
+ SourceLocation OverrideLoc = Method->getAttr<OverrideAttr>()->getLocation();
+ Diag << FixItHint::CreateRemoval(
+ CharSourceRange::getTokenRange(OverrideLoc, OverrideLoc));
+ }
+
+ if (HasVirtual) {
+ for (Token Tok : Tokens) {
+ if (Tok.is(tok::kw_virtual)) {
+ Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
+ Tok.getLocation(), Tok.getLocation()));
+ break;
+ }
+ }
+ }
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h
new file mode 100644
index 0000000..83ce7da
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.h
@@ -0,0 +1,32 @@
+//===--- UseOverrideCheck.h - clang-tidy ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEOVERRIDECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEOVERRIDECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Use C++11's `override` and remove `virtual` where applicable.
+class UseOverrideCheck : public ClangTidyCheck {
+public:
+ UseOverrideCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEOVERRIDECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp
new file mode 100644
index 0000000..7f59200
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp
@@ -0,0 +1,131 @@
+//===--- UseTransparentFunctorsCheck.cpp - clang-tidy----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseTransparentFunctorsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+UseTransparentFunctorsCheck::UseTransparentFunctorsCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context), SafeMode(Options.get("SafeMode", 0)) {}
+
+void UseTransparentFunctorsCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "SafeMode", SafeMode ? 1 : 0);
+}
+
+void UseTransparentFunctorsCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus14)
+ return;
+
+ const auto TransparentFunctors =
+ classTemplateSpecializationDecl(
+ unless(hasAnyTemplateArgument(refersToType(voidType()))),
+ hasAnyName("::std::plus", "::std::minus", "::std::multiplies",
+ "::std::divides", "::std::modulus", "::std::negate",
+ "::std::equal_to", "::std::not_equal_to", "::std::greater",
+ "::std::less", "::std::greater_equal", "::std::less_equal",
+ "::std::logical_and", "::std::logical_or",
+ "::std::logical_not", "::std::bit_and", "::std::bit_or",
+ "::std::bit_xor", "::std::bit_not"))
+ .bind("FunctorClass");
+
+ // Non-transparent functor mentioned as a template parameter. FIXIT.
+ Finder->addMatcher(
+ loc(qualType(
+ unless(elaboratedType()),
+ hasDeclaration(classTemplateSpecializationDecl(
+ unless(hasAnyTemplateArgument(templateArgument(refersToType(
+ qualType(pointsTo(qualType(isAnyCharacter()))))))),
+ hasAnyTemplateArgument(
+ templateArgument(refersToType(qualType(hasDeclaration(
+ TransparentFunctors))))
+ .bind("Functor"))))))
+ .bind("FunctorParentLoc"),
+ this);
+
+ if (SafeMode)
+ return;
+
+ // Non-transparent functor constructed. No FIXIT. There is no easy way
+ // to rule out the problematic char* vs string case.
+ Finder->addMatcher(cxxConstructExpr(hasDeclaration(cxxMethodDecl(
+ ofClass(TransparentFunctors))),
+ unless(isInTemplateInstantiation()))
+ .bind("FuncInst"),
+ this);
+}
+
+static const StringRef Message = "prefer transparent functors '%0'";
+
+template <typename T> static T getInnerTypeLocAs(TypeLoc Loc) {
+ T Result;
+ while (Result.isNull() && !Loc.isNull()) {
+ Result = Loc.getAs<T>();
+ Loc = Loc.getNextTypeLoc();
+ }
+ return Result;
+}
+
+void UseTransparentFunctorsCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *FuncClass =
+ Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("FunctorClass");
+ if (const auto *FuncInst =
+ Result.Nodes.getNodeAs<CXXConstructExpr>("FuncInst")) {
+ diag(FuncInst->getLocStart(), Message)
+ << (FuncClass->getName() + "<>").str();
+ return;
+ }
+
+ const auto *Functor = Result.Nodes.getNodeAs<TemplateArgument>("Functor");
+ const auto FunctorParentLoc =
+ Result.Nodes.getNodeAs<TypeLoc>("FunctorParentLoc")
+ ->getAs<TemplateSpecializationTypeLoc>();
+
+ if (!FunctorParentLoc)
+ return;
+
+ unsigned ArgNum = 0;
+ const auto *FunctorParentType =
+ FunctorParentLoc.getType()->castAs<TemplateSpecializationType>();
+ for (; ArgNum < FunctorParentType->getNumArgs(); ++ArgNum) {
+ const TemplateArgument &Arg = FunctorParentType->getArg(ArgNum);
+ if (Arg.getKind() != TemplateArgument::Type)
+ continue;
+ QualType ParentArgType = Arg.getAsType();
+ if (ParentArgType->isRecordType() &&
+ ParentArgType->getAsCXXRecordDecl() ==
+ Functor->getAsType()->getAsCXXRecordDecl())
+ break;
+ }
+ // Functor is a default template argument.
+ if (ArgNum == FunctorParentType->getNumArgs())
+ return;
+ TemplateArgumentLoc FunctorLoc = FunctorParentLoc.getArgLoc(ArgNum);
+ auto FunctorTypeLoc = getInnerTypeLocAs<TemplateSpecializationTypeLoc>(
+ FunctorLoc.getTypeSourceInfo()->getTypeLoc());
+ if (FunctorTypeLoc.isNull())
+ return;
+
+ SourceLocation ReportLoc = FunctorLoc.getLocation();
+ diag(ReportLoc, Message) << (FuncClass->getName() + "<>").str()
+ << FixItHint::CreateRemoval(
+ FunctorTypeLoc.getArgLoc(0).getSourceRange());
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.h
new file mode 100644
index 0000000..4bdce76
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.h
@@ -0,0 +1,37 @@
+//===--- UseTransparentFunctorsCheck.h - clang-tidy--------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_TRANSPARENT_FUNCTORS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_TRANSPARENT_FUNCTORS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Prefer using transparent functors to non-transparent ones.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-transparent-functors.html
+class UseTransparentFunctorsCheck : public ClangTidyCheck {
+public:
+ UseTransparentFunctorsCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+private:
+ const bool SafeMode;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_TRANSPARENT_FUNCTORS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp
new file mode 100644
index 0000000..9ac6e1d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp
@@ -0,0 +1,104 @@
+//===--- UseUncaughtExceptionsCheck.cpp - clang-tidy--------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseUncaughtExceptionsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+void UseUncaughtExceptionsCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus17)
+ return;
+
+ std::string MatchText = "::std::uncaught_exception";
+
+ // Using declaration: warning and fix-it.
+ Finder->addMatcher(
+ usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(hasName(MatchText))))
+ .bind("using_decl"),
+ this);
+
+ // DeclRefExpr: warning, no fix-it.
+ Finder->addMatcher(declRefExpr(allOf(to(functionDecl(hasName(MatchText))),
+ unless(callExpr())))
+ .bind("decl_ref_expr"),
+ this);
+
+ // CallExpr: warning, fix-it.
+ Finder->addMatcher(
+ callExpr(allOf(hasDeclaration(functionDecl(hasName(MatchText))),
+ unless(hasAncestor(initListExpr()))))
+ .bind("call_expr"),
+ this);
+ // CallExpr in initialisation list: warning, fix-it with avoiding narrowing
+ // conversions.
+ Finder->addMatcher(
+ callExpr(allOf(hasAncestor(initListExpr()),
+ hasDeclaration(functionDecl(hasName(MatchText)))))
+ .bind("init_call_expr"),
+ this);
+}
+
+void UseUncaughtExceptionsCheck::check(const MatchFinder::MatchResult &Result) {
+ SourceLocation BeginLoc;
+ SourceLocation EndLoc;
+ const CallExpr *C = Result.Nodes.getNodeAs<CallExpr>("init_call_expr");
+ bool WarnOnly = false;
+
+ if (C) {
+ BeginLoc = C->getLocStart();
+ EndLoc = C->getLocEnd();
+ } else if (const auto *E = Result.Nodes.getNodeAs<CallExpr>("call_expr")) {
+ BeginLoc = E->getLocStart();
+ EndLoc = E->getLocEnd();
+ } else if (const auto *D =
+ Result.Nodes.getNodeAs<DeclRefExpr>("decl_ref_expr")) {
+ BeginLoc = D->getLocStart();
+ EndLoc = D->getLocEnd();
+ WarnOnly = true;
+ } else {
+ const auto *U = Result.Nodes.getNodeAs<UsingDecl>("using_decl");
+ assert(U && "Null pointer, no node provided");
+ BeginLoc = U->getNameInfo().getBeginLoc();
+ EndLoc = U->getNameInfo().getEndLoc();
+ }
+
+ auto Diag = diag(BeginLoc, "'std::uncaught_exception' is deprecated, use "
+ "'std::uncaught_exceptions' instead");
+
+ if (!BeginLoc.isMacroID()) {
+ StringRef Text =
+ Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
+ *Result.SourceManager, getLangOpts());
+
+ Text.consume_back("()");
+ int TextLength = Text.size();
+
+ if (WarnOnly) {
+ return;
+ }
+
+ if (!C) {
+ Diag << FixItHint::CreateInsertion(BeginLoc.getLocWithOffset(TextLength),
+ "s");
+ } else {
+ Diag << FixItHint::CreateReplacement(C->getSourceRange(),
+ "std::uncaught_exceptions() > 0");
+ }
+ }
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.h
new file mode 100644
index 0000000..2b9660c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.h
@@ -0,0 +1,37 @@
+//===--- UseUncaughtExceptionsCheck.h - clang-tidy------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_UNCAUGHT_EXCEPTIONS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_UNCAUGHT_EXCEPTIONS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// This check will warn on calls to std::uncaught_exception and replace them with calls to
+/// std::uncaught_exceptions, since std::uncaught_exception was deprecated in C++17. In case of
+/// macro ID there will be only a warning without fixits.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-uncaught-exceptions.html
+class UseUncaughtExceptionsCheck : public ClangTidyCheck {
+public:
+ UseUncaughtExceptionsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_UNCAUGHT_EXCEPTIONS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
new file mode 100644
index 0000000..cc6d77d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
@@ -0,0 +1,113 @@
+//===--- UseUsingCheck.cpp - clang-tidy------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseUsingCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+UseUsingCheck::UseUsingCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {}
+
+void UseUsingCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus11)
+ return;
+ Finder->addMatcher(typedefDecl().bind("typedef"), this);
+}
+
+// Checks if 'typedef' keyword can be removed - we do it only if
+// it is the only declaration in a declaration chain.
+static bool CheckRemoval(SourceManager &SM, SourceLocation StartLoc,
+ ASTContext &Context) {
+ assert(StartLoc.isFileID() && "StartLoc must not be in a macro");
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(StartLoc);
+ StringRef File = SM.getBufferData(LocInfo.first);
+ const char *TokenBegin = File.data() + LocInfo.second;
+ Lexer DeclLexer(SM.getLocForStartOfFile(LocInfo.first), Context.getLangOpts(),
+ File.begin(), TokenBegin, File.end());
+
+ Token Tok;
+ int ParenLevel = 0;
+ bool FoundTypedef = false;
+
+ while (!DeclLexer.LexFromRawLexer(Tok) && !Tok.is(tok::semi)) {
+ switch (Tok.getKind()) {
+ case tok::l_brace:
+ case tok::r_brace:
+ // This might be the `typedef struct {...} T;` case.
+ return false;
+ case tok::l_paren:
+ ParenLevel++;
+ break;
+ case tok::r_paren:
+ ParenLevel--;
+ break;
+ case tok::comma:
+ if (ParenLevel == 0) {
+ // If there is comma and we are not between open parenthesis then it is
+ // two or more declarations in this chain.
+ return false;
+ }
+ break;
+ case tok::raw_identifier:
+ if (Tok.getRawIdentifier() == "typedef") {
+ FoundTypedef = true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Sanity check against weird macro cases.
+ return FoundTypedef;
+}
+
+void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<TypedefDecl>("typedef");
+ if (MatchedDecl->getLocation().isInvalid())
+ return;
+
+ auto &Context = *Result.Context;
+ auto &SM = *Result.SourceManager;
+
+ SourceLocation StartLoc = MatchedDecl->getLocStart();
+
+ if (StartLoc.isMacroID() && IgnoreMacros)
+ return;
+
+ auto Diag =
+ diag(StartLoc, "use 'using' instead of 'typedef'");
+
+ // do not fix if there is macro or array
+ if (MatchedDecl->getUnderlyingType()->isArrayType() || StartLoc.isMacroID())
+ return;
+
+ if (CheckRemoval(SM, StartLoc, Context)) {
+ auto printPolicy = PrintingPolicy(getLangOpts());
+ printPolicy.SuppressScope = true;
+ printPolicy.ConstantArraySizeAsWritten = true;
+ printPolicy.UseVoidForZeroParams = false;
+
+ Diag << FixItHint::CreateReplacement(
+ MatchedDecl->getSourceRange(),
+ "using " + MatchedDecl->getNameAsString() + " = " +
+ MatchedDecl->getUnderlyingType().getAsString(printPolicy));
+ }
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
new file mode 100644
index 0000000..022eef0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.h
@@ -0,0 +1,40 @@
+//===--- UseUsingCheck.h - clang-tidy----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_USING_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_USING_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Check finds typedefs and replaces it with usings.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-using.html
+class UseUsingCheck : public ClangTidyCheck {
+
+ const bool IgnoreMacros;
+
+public:
+ UseUsingCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override {
+ Options.store(Opts, "IgnoreMacros", IgnoreMacros);
+ }
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_USING_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/BufferDerefCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/BufferDerefCheck.cpp
new file mode 100644
index 0000000..8e2c0e3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/BufferDerefCheck.cpp
@@ -0,0 +1,132 @@
+//===--- BufferDerefCheck.cpp - clang-tidy---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BufferDerefCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/StaticAnalyzer/Checkers/MPIFunctionClassifier.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace mpi {
+
+void BufferDerefCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(callExpr().bind("CE"), this);
+}
+
+void BufferDerefCheck::check(const MatchFinder::MatchResult &Result) {
+ static ento::mpi::MPIFunctionClassifier FuncClassifier(*Result.Context);
+ const auto *CE = Result.Nodes.getNodeAs<CallExpr>("CE");
+ if (!CE->getDirectCallee())
+ return;
+
+ const IdentifierInfo *Identifier = CE->getDirectCallee()->getIdentifier();
+ if (!Identifier || !FuncClassifier.isMPIType(Identifier))
+ return;
+
+ // These containers are used, to capture the type and expression of a buffer.
+ SmallVector<const Type *, 1> BufferTypes;
+ SmallVector<const Expr *, 1> BufferExprs;
+
+ // Adds the type and expression of a buffer that is used in the MPI call
+ // expression to the captured containers.
+ auto addBuffer = [&CE, &Result, &BufferTypes,
+ &BufferExprs](const size_t BufferIdx) {
+ // Skip null pointer constants and in place 'operators'.
+ if (CE->getArg(BufferIdx)->isNullPointerConstant(
+ *Result.Context, Expr::NPC_ValueDependentIsNull) ||
+ tooling::fixit::getText(*CE->getArg(BufferIdx), *Result.Context) ==
+ "MPI_IN_PLACE")
+ return;
+
+ const Expr *ArgExpr = CE->getArg(BufferIdx);
+ if (!ArgExpr)
+ return;
+ const Type *ArgType = ArgExpr->IgnoreImpCasts()->getType().getTypePtr();
+ if (!ArgType)
+ return;
+ BufferExprs.push_back(ArgExpr);
+ BufferTypes.push_back(ArgType);
+ };
+
+ // Collect buffer types and argument expressions for all buffers used in the
+ // MPI call expression. The number passed to the lambda corresponds to the
+ // argument index of the currently verified MPI function call.
+ if (FuncClassifier.isPointToPointType(Identifier)) {
+ addBuffer(0);
+ } else if (FuncClassifier.isCollectiveType(Identifier)) {
+ if (FuncClassifier.isReduceType(Identifier)) {
+ addBuffer(0);
+ addBuffer(1);
+ } else if (FuncClassifier.isScatterType(Identifier) ||
+ FuncClassifier.isGatherType(Identifier) ||
+ FuncClassifier.isAlltoallType(Identifier)) {
+ addBuffer(0);
+ addBuffer(3);
+ } else if (FuncClassifier.isBcastType(Identifier)) {
+ addBuffer(0);
+ }
+ }
+
+ checkBuffers(BufferTypes, BufferExprs);
+}
+
+void BufferDerefCheck::checkBuffers(ArrayRef<const Type *> BufferTypes,
+ ArrayRef<const Expr *> BufferExprs) {
+ for (size_t i = 0; i < BufferTypes.size(); ++i) {
+ unsigned IndirectionCount = 0;
+ const Type *BufferType = BufferTypes[i];
+ llvm::SmallVector<IndirectionType, 1> Indirections;
+
+ // Capture the depth and types of indirections for the passed buffer.
+ while (true) {
+ if (BufferType->isPointerType()) {
+ BufferType = BufferType->getPointeeType().getTypePtr();
+ Indirections.push_back(IndirectionType::Pointer);
+ } else if (BufferType->isArrayType()) {
+ BufferType = BufferType->getArrayElementTypeNoTypeQual();
+ Indirections.push_back(IndirectionType::Array);
+ } else {
+ break;
+ }
+ ++IndirectionCount;
+ }
+
+ if (IndirectionCount > 1) {
+ // Referencing an array with '&' is valid, as this also points to the
+ // beginning of the array.
+ if (IndirectionCount == 2 &&
+ Indirections[0] == IndirectionType::Pointer &&
+ Indirections[1] == IndirectionType::Array)
+ return;
+
+ // Build the indirection description in reverse order of discovery.
+ std::string IndirectionDesc;
+ for (auto It = Indirections.rbegin(); It != Indirections.rend(); ++It) {
+ if (!IndirectionDesc.empty())
+ IndirectionDesc += "->";
+ if (*It == IndirectionType::Pointer) {
+ IndirectionDesc += "pointer";
+ } else {
+ IndirectionDesc += "array";
+ }
+ }
+
+ const auto Loc = BufferExprs[i]->getSourceRange().getBegin();
+ diag(Loc, "buffer is insufficiently dereferenced: %0") << IndirectionDesc;
+ }
+ }
+}
+
+} // namespace mpi
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/BufferDerefCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/BufferDerefCheck.h
new file mode 100644
index 0000000..8490fa1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/BufferDerefCheck.h
@@ -0,0 +1,51 @@
+//===--- BufferDerefCheck.h - clang-tidy-------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MPI_BUFFER_DEREF_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MPI_BUFFER_DEREF_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace mpi {
+
+/// This check verifies if a buffer passed to an MPI (Message Passing Interface)
+/// function is sufficiently dereferenced. Buffers should be passed as a single
+/// pointer or array. As MPI function signatures specify void * for their buffer
+/// types, insufficiently dereferenced buffers can be passed, like for example
+/// as double pointers or multidimensional arrays, without a compiler warning
+/// emitted.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/mpi-buffer-deref.html
+class BufferDerefCheck : public ClangTidyCheck {
+public:
+ BufferDerefCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ /// Checks for all buffers in an MPI call if they are sufficiently
+ /// dereferenced.
+ ///
+ /// \param BufferTypes buffer types
+ /// \param BufferExprs buffer arguments as expressions
+ void checkBuffers(ArrayRef<const Type *> BufferTypes,
+ ArrayRef<const Expr *> BufferExprs);
+
+ enum class IndirectionType : unsigned char { Pointer, Array };
+};
+
+} // namespace mpi
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MPI_BUFFER_DEREF_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/CMakeLists.txt
new file mode 100644
index 0000000..3658434
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/CMakeLists.txt
@@ -0,0 +1,17 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyMPIModule
+ BufferDerefCheck.cpp
+ MPITidyModule.cpp
+ TypeMismatchCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyUtils
+ clangTooling
+ clangStaticAnalyzerCheckers
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/MPITidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/MPITidyModule.cpp
new file mode 100644
index 0000000..55e187d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/MPITidyModule.cpp
@@ -0,0 +1,39 @@
+//===--- MPITidyModule.cpp - clang-tidy -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "BufferDerefCheck.h"
+#include "TypeMismatchCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace mpi {
+
+class MPIModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<BufferDerefCheck>("mpi-buffer-deref");
+ CheckFactories.registerCheck<TypeMismatchCheck>("mpi-type-mismatch");
+ }
+};
+
+} // namespace mpi
+
+// Register the MPITidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<mpi::MPIModule>
+ X("mpi-module", "Adds MPI clang-tidy checks.");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the MPIModule.
+volatile int MPIModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
new file mode 100644
index 0000000..a1f92b8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp
@@ -0,0 +1,335 @@
+//===--- TypeMismatchCheck.cpp - clang-tidy--------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TypeMismatchCheck.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/StaticAnalyzer/Checkers/MPIFunctionClassifier.h"
+#include "clang/Tooling/FixIt.h"
+#include <map>
+#include <unordered_set>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace mpi {
+
+/// Check if a BuiltinType::Kind matches the MPI datatype.
+///
+/// \param MultiMap datatype group
+/// \param Kind buffer type kind
+/// \param MPIDatatype name of the MPI datatype
+///
+/// \returns true if the pair matches
+static bool
+isMPITypeMatching(const std::multimap<BuiltinType::Kind, std::string> &MultiMap,
+ const BuiltinType::Kind Kind,
+ const std::string &MPIDatatype) {
+ auto ItPair = MultiMap.equal_range(Kind);
+ while (ItPair.first != ItPair.second) {
+ if (ItPair.first->second == MPIDatatype)
+ return true;
+ ++ItPair.first;
+ }
+ return false;
+}
+
+/// Check if the MPI datatype is a standard type.
+///
+/// \param MPIDatatype name of the MPI datatype
+///
+/// \returns true if the type is a standard type
+static bool isStandardMPIDatatype(const std::string &MPIDatatype) {
+ static std::unordered_set<std::string> AllTypes = {
+ "MPI_C_BOOL",
+ "MPI_CHAR",
+ "MPI_SIGNED_CHAR",
+ "MPI_UNSIGNED_CHAR",
+ "MPI_WCHAR",
+ "MPI_INT",
+ "MPI_LONG",
+ "MPI_SHORT",
+ "MPI_LONG_LONG",
+ "MPI_LONG_LONG_INT",
+ "MPI_UNSIGNED",
+ "MPI_UNSIGNED_SHORT",
+ "MPI_UNSIGNED_LONG",
+ "MPI_UNSIGNED_LONG_LONG",
+ "MPI_FLOAT",
+ "MPI_DOUBLE",
+ "MPI_LONG_DOUBLE",
+ "MPI_C_COMPLEX",
+ "MPI_C_FLOAT_COMPLEX",
+ "MPI_C_DOUBLE_COMPLEX",
+ "MPI_C_LONG_DOUBLE_COMPLEX",
+ "MPI_INT8_T",
+ "MPI_INT16_T",
+ "MPI_INT32_T",
+ "MPI_INT64_T",
+ "MPI_UINT8_T",
+ "MPI_UINT16_T",
+ "MPI_UINT32_T",
+ "MPI_UINT64_T",
+ "MPI_CXX_BOOL",
+ "MPI_CXX_FLOAT_COMPLEX",
+ "MPI_CXX_DOUBLE_COMPLEX",
+ "MPI_CXX_LONG_DOUBLE_COMPLEX"};
+
+ return AllTypes.find(MPIDatatype) != AllTypes.end();
+}
+
+/// Check if a BuiltinType matches the MPI datatype.
+///
+/// \param Builtin the builtin type
+/// \param BufferTypeName buffer type name, gets assigned
+/// \param MPIDatatype name of the MPI datatype
+/// \param LO language options
+///
+/// \returns true if the type matches
+static bool isBuiltinTypeMatching(const BuiltinType *Builtin,
+ std::string &BufferTypeName,
+ const std::string &MPIDatatype,
+ const LangOptions &LO) {
+ static std::multimap<BuiltinType::Kind, std::string> BuiltinMatches = {
+ // On some systems like PPC or ARM, 'char' is unsigned by default which is
+ // why distinct signedness for the buffer and MPI type is tolerated.
+ {BuiltinType::SChar, "MPI_CHAR"},
+ {BuiltinType::SChar, "MPI_SIGNED_CHAR"},
+ {BuiltinType::SChar, "MPI_UNSIGNED_CHAR"},
+ {BuiltinType::Char_S, "MPI_CHAR"},
+ {BuiltinType::Char_S, "MPI_SIGNED_CHAR"},
+ {BuiltinType::Char_S, "MPI_UNSIGNED_CHAR"},
+ {BuiltinType::UChar, "MPI_CHAR"},
+ {BuiltinType::UChar, "MPI_SIGNED_CHAR"},
+ {BuiltinType::UChar, "MPI_UNSIGNED_CHAR"},
+ {BuiltinType::Char_U, "MPI_CHAR"},
+ {BuiltinType::Char_U, "MPI_SIGNED_CHAR"},
+ {BuiltinType::Char_U, "MPI_UNSIGNED_CHAR"},
+ {BuiltinType::WChar_S, "MPI_WCHAR"},
+ {BuiltinType::WChar_U, "MPI_WCHAR"},
+ {BuiltinType::Bool, "MPI_C_BOOL"},
+ {BuiltinType::Bool, "MPI_CXX_BOOL"},
+ {BuiltinType::Short, "MPI_SHORT"},
+ {BuiltinType::Int, "MPI_INT"},
+ {BuiltinType::Long, "MPI_LONG"},
+ {BuiltinType::LongLong, "MPI_LONG_LONG"},
+ {BuiltinType::LongLong, "MPI_LONG_LONG_INT"},
+ {BuiltinType::UShort, "MPI_UNSIGNED_SHORT"},
+ {BuiltinType::UInt, "MPI_UNSIGNED"},
+ {BuiltinType::ULong, "MPI_UNSIGNED_LONG"},
+ {BuiltinType::ULongLong, "MPI_UNSIGNED_LONG_LONG"},
+ {BuiltinType::Float, "MPI_FLOAT"},
+ {BuiltinType::Double, "MPI_DOUBLE"},
+ {BuiltinType::LongDouble, "MPI_LONG_DOUBLE"}};
+
+ if (!isMPITypeMatching(BuiltinMatches, Builtin->getKind(), MPIDatatype)) {
+ BufferTypeName = Builtin->getName(LO);
+ return false;
+ }
+
+ return true;
+}
+
+/// Check if a complex float/double/long double buffer type matches
+/// the MPI datatype.
+///
+/// \param Complex buffer type
+/// \param BufferTypeName buffer type name, gets assigned
+/// \param MPIDatatype name of the MPI datatype
+/// \param LO language options
+///
+/// \returns true if the type matches or the buffer type is unknown
+static bool isCComplexTypeMatching(const ComplexType *const Complex,
+ std::string &BufferTypeName,
+ const std::string &MPIDatatype,
+ const LangOptions &LO) {
+ static std::multimap<BuiltinType::Kind, std::string> ComplexCMatches = {
+ {BuiltinType::Float, "MPI_C_COMPLEX"},
+ {BuiltinType::Float, "MPI_C_FLOAT_COMPLEX"},
+ {BuiltinType::Double, "MPI_C_DOUBLE_COMPLEX"},
+ {BuiltinType::LongDouble, "MPI_C_LONG_DOUBLE_COMPLEX"}};
+
+ const auto *Builtin =
+ Complex->getElementType().getTypePtr()->getAs<BuiltinType>();
+
+ if (Builtin &&
+ !isMPITypeMatching(ComplexCMatches, Builtin->getKind(), MPIDatatype)) {
+ BufferTypeName = (llvm::Twine(Builtin->getName(LO)) + " _Complex").str();
+ return false;
+ }
+ return true;
+}
+
+/// Check if a complex<float/double/long double> templated buffer type matches
+/// the MPI datatype.
+///
+/// \param Template buffer type
+/// \param BufferTypeName buffer type name, gets assigned
+/// \param MPIDatatype name of the MPI datatype
+/// \param LO language options
+///
+/// \returns true if the type matches or the buffer type is unknown
+static bool
+isCXXComplexTypeMatching(const TemplateSpecializationType *const Template,
+ std::string &BufferTypeName,
+ const std::string &MPIDatatype,
+ const LangOptions &LO) {
+ static std::multimap<BuiltinType::Kind, std::string> ComplexCXXMatches = {
+ {BuiltinType::Float, "MPI_CXX_FLOAT_COMPLEX"},
+ {BuiltinType::Double, "MPI_CXX_DOUBLE_COMPLEX"},
+ {BuiltinType::LongDouble, "MPI_CXX_LONG_DOUBLE_COMPLEX"}};
+
+ if (Template->getAsCXXRecordDecl()->getName() != "complex")
+ return true;
+
+ const auto *Builtin =
+ Template->getArg(0).getAsType().getTypePtr()->getAs<BuiltinType>();
+
+ if (Builtin &&
+ !isMPITypeMatching(ComplexCXXMatches, Builtin->getKind(), MPIDatatype)) {
+ BufferTypeName =
+ (llvm::Twine("complex<") + Builtin->getName(LO) + ">").str();
+ return false;
+ }
+
+ return true;
+}
+
+/// Check if a fixed size width buffer type matches the MPI datatype.
+///
+/// \param Typedef buffer type
+/// \param BufferTypeName buffer type name, gets assigned
+/// \param MPIDatatype name of the MPI datatype
+///
+/// \returns true if the type matches or the buffer type is unknown
+static bool isTypedefTypeMatching(const TypedefType *const Typedef,
+ std::string &BufferTypeName,
+ const std::string &MPIDatatype) {
+ static llvm::StringMap<std::string> FixedWidthMatches = {
+ {"int8_t", "MPI_INT8_T"}, {"int16_t", "MPI_INT16_T"},
+ {"int32_t", "MPI_INT32_T"}, {"int64_t", "MPI_INT64_T"},
+ {"uint8_t", "MPI_UINT8_T"}, {"uint16_t", "MPI_UINT16_T"},
+ {"uint32_t", "MPI_UINT32_T"}, {"uint64_t", "MPI_UINT64_T"}};
+
+ const auto it = FixedWidthMatches.find(Typedef->getDecl()->getName());
+ // Check if the typedef is known and not matching the MPI datatype.
+ if (it != FixedWidthMatches.end() && it->getValue() != MPIDatatype) {
+ BufferTypeName = Typedef->getDecl()->getName();
+ return false;
+ }
+ return true;
+}
+
+/// Get the unqualified, dereferenced type of an argument.
+///
+/// \param CE call expression
+/// \param idx argument index
+///
+/// \returns type of the argument
+static const Type *argumentType(const CallExpr *const CE, const size_t idx) {
+ const QualType QT = CE->getArg(idx)->IgnoreImpCasts()->getType();
+ return QT.getTypePtr()->getPointeeOrArrayElementType();
+}
+
+void TypeMismatchCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(callExpr().bind("CE"), this);
+}
+
+void TypeMismatchCheck::check(const MatchFinder::MatchResult &Result) {
+ static ento::mpi::MPIFunctionClassifier FuncClassifier(*Result.Context);
+ const auto *const CE = Result.Nodes.getNodeAs<CallExpr>("CE");
+ if (!CE->getDirectCallee())
+ return;
+
+ const IdentifierInfo *Identifier = CE->getDirectCallee()->getIdentifier();
+ if (!Identifier || !FuncClassifier.isMPIType(Identifier))
+ return;
+
+ // These containers are used, to capture buffer, MPI datatype pairs.
+ SmallVector<const Type *, 1> BufferTypes;
+ SmallVector<const Expr *, 1> BufferExprs;
+ SmallVector<StringRef, 1> MPIDatatypes;
+
+ // Adds a buffer, MPI datatype pair of an MPI call expression to the
+ // containers. For buffers, the type and expression is captured.
+ auto addPair = [&CE, &Result, &BufferTypes, &BufferExprs, &MPIDatatypes](
+ const size_t BufferIdx, const size_t DatatypeIdx) {
+ // Skip null pointer constants and in place 'operators'.
+ if (CE->getArg(BufferIdx)->isNullPointerConstant(
+ *Result.Context, Expr::NPC_ValueDependentIsNull) ||
+ tooling::fixit::getText(*CE->getArg(BufferIdx), *Result.Context) ==
+ "MPI_IN_PLACE")
+ return;
+
+ StringRef MPIDatatype =
+ tooling::fixit::getText(*CE->getArg(DatatypeIdx), *Result.Context);
+
+ const Type *ArgType = argumentType(CE, BufferIdx);
+ // Skip unknown MPI datatypes and void pointers.
+ if (!isStandardMPIDatatype(MPIDatatype) || ArgType->isVoidType())
+ return;
+
+ BufferTypes.push_back(ArgType);
+ BufferExprs.push_back(CE->getArg(BufferIdx));
+ MPIDatatypes.push_back(MPIDatatype);
+ };
+
+ // Collect all buffer, MPI datatype pairs for the inspected call expression.
+ if (FuncClassifier.isPointToPointType(Identifier)) {
+ addPair(0, 2);
+ } else if (FuncClassifier.isCollectiveType(Identifier)) {
+ if (FuncClassifier.isReduceType(Identifier)) {
+ addPair(0, 3);
+ addPair(1, 3);
+ } else if (FuncClassifier.isScatterType(Identifier) ||
+ FuncClassifier.isGatherType(Identifier) ||
+ FuncClassifier.isAlltoallType(Identifier)) {
+ addPair(0, 2);
+ addPair(3, 5);
+ } else if (FuncClassifier.isBcastType(Identifier)) {
+ addPair(0, 2);
+ }
+ }
+ checkArguments(BufferTypes, BufferExprs, MPIDatatypes, getLangOpts());
+}
+
+void TypeMismatchCheck::checkArguments(ArrayRef<const Type *> BufferTypes,
+ ArrayRef<const Expr *> BufferExprs,
+ ArrayRef<StringRef> MPIDatatypes,
+ const LangOptions &LO) {
+ std::string BufferTypeName;
+
+ for (size_t i = 0; i < MPIDatatypes.size(); ++i) {
+ const Type *const BT = BufferTypes[i];
+ bool Error = false;
+
+ if (const auto *Typedef = BT->getAs<TypedefType>()) {
+ Error = !isTypedefTypeMatching(Typedef, BufferTypeName, MPIDatatypes[i]);
+ } else if (const auto *Complex = BT->getAs<ComplexType>()) {
+ Error =
+ !isCComplexTypeMatching(Complex, BufferTypeName, MPIDatatypes[i], LO);
+ } else if (const auto *Template = BT->getAs<TemplateSpecializationType>()) {
+ Error = !isCXXComplexTypeMatching(Template, BufferTypeName,
+ MPIDatatypes[i], LO);
+ } else if (const auto *Builtin = BT->getAs<BuiltinType>()) {
+ Error =
+ !isBuiltinTypeMatching(Builtin, BufferTypeName, MPIDatatypes[i], LO);
+ }
+
+ if (Error) {
+ const auto Loc = BufferExprs[i]->getSourceRange().getBegin();
+ diag(Loc, "buffer type '%0' does not match the MPI datatype '%1'")
+ << BufferTypeName << MPIDatatypes[i];
+ }
+ }
+}
+
+} // namespace mpi
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.h
new file mode 100644
index 0000000..dd56c46
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.h
@@ -0,0 +1,51 @@
+//===--- TypeMismatchCheck.h - clang-tidy------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MPI_TYPE_MISMATCH_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MPI_TYPE_MISMATCH_H
+
+#include "../ClangTidy.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+namespace clang {
+namespace tidy {
+namespace mpi {
+
+/// This check verifies if buffer type and MPI (Message Passing Interface)
+/// datatype pairs match. All MPI datatypes defined by the MPI standard (3.1)
+/// are verified by this check. User defined typedefs, custom MPI datatypes and
+/// null pointer constants are skipped, in the course of verification.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/mpi-type-mismatch.html
+class TypeMismatchCheck : public ClangTidyCheck {
+public:
+ TypeMismatchCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ /// Check if the buffer type MPI datatype pairs match.
+ ///
+ /// \param BufferTypes buffer types
+ /// \param BufferExprs buffer arguments as expressions
+ /// \param MPIDatatypes MPI datatype
+ /// \param LO language options
+ void checkArguments(ArrayRef<const Type *> BufferTypes,
+ ArrayRef<const Expr *> BufferExprs,
+ ArrayRef<StringRef> MPIDatatypes, const LangOptions &LO);
+};
+
+} // namespace mpi
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MPI_TYPE_MISMATCH_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/AvoidNSErrorInitCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/AvoidNSErrorInitCheck.cpp
new file mode 100644
index 0000000..86c4656
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/AvoidNSErrorInitCheck.cpp
@@ -0,0 +1,41 @@
+//===--- AvoidNSErrorInitCheck.cpp - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AvoidNSErrorInitCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace objc {
+
+void AvoidNSErrorInitCheck::registerMatchers(MatchFinder *Finder) {
+ // this check should only be applied to ObjC sources.
+ if (!getLangOpts().ObjC1 && !getLangOpts().ObjC2) {
+ return;
+ }
+ Finder->addMatcher(objcMessageExpr(hasSelector("init"),
+ hasReceiverType(asString("NSError *")))
+ .bind("nserrorInit"),
+ this);
+}
+
+void AvoidNSErrorInitCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedExpr =
+ Result.Nodes.getNodeAs<ObjCMessageExpr>("nserrorInit");
+ diag(MatchedExpr->getLocStart(),
+ "use errorWithDomain:code:userInfo: or initWithDomain:code:userInfo: to "
+ "create a new NSError");
+}
+
+} // namespace objc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/AvoidNSErrorInitCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/AvoidNSErrorInitCheck.h
new file mode 100644
index 0000000..bec19b2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/AvoidNSErrorInitCheck.h
@@ -0,0 +1,36 @@
+//===--- AvoidNSErrorInitCheck.h - clang-tidy--------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_AVOIDNSERRORINITCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_AVOIDNSERRORINITCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace objc {
+
+/// Finds usages of [NSSError init]. It is not the proper way of creating
+/// NSError. errorWithDomain:code:userInfo: should be used instead.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/objc-avoid-nserror-init.html
+class AvoidNSErrorInitCheck : public ClangTidyCheck {
+ public:
+ AvoidNSErrorInitCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace objc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_AVOIDNSERRORINITCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/AvoidSpinlockCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/AvoidSpinlockCheck.cpp
new file mode 100644
index 0000000..21ec364
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/AvoidSpinlockCheck.cpp
@@ -0,0 +1,37 @@
+//===--- AvoidSpinlockCheck.cpp - clang-tidy-------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AvoidSpinlockCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace objc {
+
+void AvoidSpinlockCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ callExpr(callee((functionDecl(hasAnyName(
+ "OSSpinlockLock", "OSSpinlockUnlock", "OSSpinlockTry")))))
+ .bind("spinlock"),
+ this);
+}
+
+void AvoidSpinlockCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedExpr = Result.Nodes.getNodeAs<CallExpr>("spinlock");
+ diag(MatchedExpr->getLocStart(),
+ "use os_unfair_lock_lock() or dispatch queue APIs instead of the "
+ "deprecated OSSpinLock");
+}
+
+} // namespace objc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/AvoidSpinlockCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/AvoidSpinlockCheck.h
new file mode 100644
index 0000000..d9dbf8c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/AvoidSpinlockCheck.h
@@ -0,0 +1,36 @@
+//===--- AvoidSpinlockCheck.h - clang-tidy-----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_AVOID_SPINLOCK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_AVOID_SPINLOCK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace objc {
+
+/// Finds usages of OSSpinlock, which is deprecated due to potential livelock
+/// problems.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/objc-avoid-spinlock.html
+class AvoidSpinlockCheck : public ClangTidyCheck {
+ public:
+ AvoidSpinlockCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace objc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_AVOID_SPINLOCK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/CMakeLists.txt
new file mode 100644
index 0000000..4063bba
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/CMakeLists.txt
@@ -0,0 +1,17 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyObjCModule
+ AvoidNSErrorInitCheck.cpp
+ AvoidSpinlockCheck.cpp
+ ForbiddenSubclassingCheck.cpp
+ ObjCTidyModule.cpp
+ PropertyDeclarationCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyUtils
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/ForbiddenSubclassingCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/ForbiddenSubclassingCheck.cpp
new file mode 100644
index 0000000..e78cb99
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/ForbiddenSubclassingCheck.cpp
@@ -0,0 +1,122 @@
+//===--- ForbiddenSubclassingCheck.cpp - clang-tidy -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ForbiddenSubclassingCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/SmallVector.h"
+#include "../utils/OptionsUtils.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace objc {
+
+namespace {
+
+constexpr char DefaultForbiddenSuperClassNames[] =
+ "ABNewPersonViewController;"
+ "ABPeoplePickerNavigationController;"
+ "ABPersonViewController;"
+ "ABUnknownPersonViewController;"
+ "NSHashTable;"
+ "NSMapTable;"
+ "NSPointerArray;"
+ "NSPointerFunctions;"
+ "NSTimer;"
+ "UIActionSheet;"
+ "UIAlertView;"
+ "UIImagePickerController;"
+ "UITextInputMode;"
+ "UIWebView";
+
+/// \brief Matches Objective-C classes that directly or indirectly
+/// have a superclass matching \c Base.
+///
+/// Note that a class is not considered to be a subclass of itself.
+///
+/// Example matches Y, Z
+/// (matcher = objcInterfaceDecl(hasName("X")))
+/// \code
+/// @interface X
+/// @end
+/// @interface Y : X // directly derived
+/// @end
+/// @interface Z : Y // indirectly derived
+/// @end
+/// \endcode
+AST_MATCHER_P(ObjCInterfaceDecl, isSubclassOf,
+ ast_matchers::internal::Matcher<ObjCInterfaceDecl>, Base) {
+ for (const auto *SuperClass = Node.getSuperClass();
+ SuperClass != nullptr;
+ SuperClass = SuperClass->getSuperClass()) {
+ if (Base.matches(*SuperClass, Finder, Builder)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+ForbiddenSubclassingCheck::ForbiddenSubclassingCheck(
+ StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ ForbiddenSuperClassNames(
+ utils::options::parseStringList(
+ Options.get("ClassNames", DefaultForbiddenSuperClassNames))) {
+}
+
+void ForbiddenSubclassingCheck::registerMatchers(MatchFinder *Finder) {
+ // this check should only be applied to ObjC sources.
+ if (!getLangOpts().ObjC1 && !getLangOpts().ObjC2) {
+ return;
+ }
+ Finder->addMatcher(
+ objcInterfaceDecl(
+ isSubclassOf(
+ objcInterfaceDecl(
+ hasAnyName(
+ std::vector<StringRef>(
+ ForbiddenSuperClassNames.begin(),
+ ForbiddenSuperClassNames.end())))
+ .bind("superclass")))
+ .bind("subclass"),
+ this);
+}
+
+void ForbiddenSubclassingCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *SubClass = Result.Nodes.getNodeAs<ObjCInterfaceDecl>(
+ "subclass");
+ assert(SubClass != nullptr);
+ const auto *SuperClass = Result.Nodes.getNodeAs<ObjCInterfaceDecl>(
+ "superclass");
+ assert(SuperClass != nullptr);
+ diag(SubClass->getLocation(),
+ "Objective-C interface %0 subclasses %1, which is not "
+ "intended to be subclassed")
+ << SubClass
+ << SuperClass;
+}
+
+void ForbiddenSubclassingCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(
+ Opts,
+ "ForbiddenSuperClassNames",
+ utils::options::serializeStringList(ForbiddenSuperClassNames));
+}
+
+} // namespace objc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/ForbiddenSubclassingCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/ForbiddenSubclassingCheck.h
new file mode 100644
index 0000000..6c7e08b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/ForbiddenSubclassingCheck.h
@@ -0,0 +1,42 @@
+//===--- ForbiddenSubclassingCheck.h - clang-tidy ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_FORBIDDEN_SUBCLASSING_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_FORBIDDEN_SUBCLASSING_CHECK_H
+
+#include "../ClangTidy.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tidy {
+namespace objc {
+
+/// Finds Objective-C classes which have a superclass which is
+/// documented to not support subclassing.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/objc-forbidden-subclassing.html
+class ForbiddenSubclassingCheck : public ClangTidyCheck {
+public:
+ ForbiddenSubclassingCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Options) override;
+
+private:
+ const std::vector<std::string> ForbiddenSuperClassNames;
+};
+
+} // namespace objc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_FORBIDDEN_SUBCLASSING_CHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/ObjCTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/ObjCTidyModule.cpp
new file mode 100644
index 0000000..19152c2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/ObjCTidyModule.cpp
@@ -0,0 +1,50 @@
+//===--- ObjCTidyModule.cpp - clang-tidy --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "AvoidNSErrorInitCheck.h"
+#include "AvoidSpinlockCheck.h"
+#include "ForbiddenSubclassingCheck.h"
+#include "PropertyDeclarationCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace objc {
+
+class ObjCModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<AvoidNSErrorInitCheck>(
+ "objc-avoid-nserror-init");
+ CheckFactories.registerCheck<AvoidSpinlockCheck>(
+ "objc-avoid-spinlock");
+ CheckFactories.registerCheck<ForbiddenSubclassingCheck>(
+ "objc-forbidden-subclassing");
+ CheckFactories.registerCheck<PropertyDeclarationCheck>(
+ "objc-property-declaration");
+ }
+};
+
+// Register the ObjCTidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<ObjCModule> X(
+ "objc-module",
+ "Adds Objective-C lint checks.");
+
+} // namespace objc
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the ObjCModule.
+volatile int ObjCModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/PropertyDeclarationCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/PropertyDeclarationCheck.cpp
new file mode 100644
index 0000000..d7715fa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/PropertyDeclarationCheck.cpp
@@ -0,0 +1,263 @@
+//===--- PropertyDeclarationCheck.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PropertyDeclarationCheck.h"
+#include <algorithm>
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/CharInfo.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Regex.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace objc {
+
+namespace {
+
+// For StandardProperty the naming style is 'lowerCamelCase'.
+// For CategoryProperty especially in categories of system class,
+// to avoid naming conflict, the suggested naming style is
+// 'abc_lowerCamelCase' (adding lowercase prefix followed by '_').
+enum NamingStyle {
+ StandardProperty = 1,
+ CategoryProperty = 2,
+};
+
+/// The acronyms are aggregated from multiple sources including
+/// https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/APIAbbreviations.html#//apple_ref/doc/uid/20001285-BCIHCGAE
+///
+/// Keep this list sorted.
+constexpr llvm::StringLiteral DefaultSpecialAcronyms[] = {
+ "[2-9]G",
+ "ACL",
+ "API",
+ "AR",
+ "ARGB",
+ "ASCII",
+ "AV",
+ "BGRA",
+ "CA",
+ "CF",
+ "CG",
+ "CI",
+ "CRC",
+ "CV",
+ "CMYK",
+ "DNS",
+ "FPS",
+ "FTP",
+ "GIF",
+ "GL",
+ "GPS",
+ "GUID",
+ "HD",
+ "HDR",
+ "HMAC",
+ "HTML",
+ "HTTP",
+ "HTTPS",
+ "HUD",
+ "ID",
+ "JPG",
+ "JS",
+ "LAN",
+ "LZW",
+ "MAC",
+ "MD",
+ "MDNS",
+ "MIDI",
+ "NS",
+ "OS",
+ "PDF",
+ "PIN",
+ "PNG",
+ "POI",
+ "PSTN",
+ "PTR",
+ "QA",
+ "QOS",
+ "RGB",
+ "RGBA",
+ "RGBX",
+ "RIPEMD",
+ "ROM",
+ "RPC",
+ "RTF",
+ "RTL",
+ "SC",
+ "SDK",
+ "SHA",
+ "SQL",
+ "SSO",
+ "TCP",
+ "TIFF",
+ "TTS",
+ "UI",
+ "URI",
+ "URL",
+ "UUID",
+ "VC",
+ "VOIP",
+ "VPN",
+ "VR",
+ "W",
+ "WAN",
+ "X",
+ "XML",
+ "Y",
+ "Z",
+};
+
+/// For now we will only fix 'CamelCase' or 'abc_CamelCase' property to
+/// 'camelCase' or 'abc_camelCase'. For other cases the users need to
+/// come up with a proper name by their own.
+/// FIXME: provide fix for snake_case to snakeCase
+FixItHint generateFixItHint(const ObjCPropertyDecl *Decl, NamingStyle Style) {
+ auto Name = Decl->getName();
+ auto NewName = Decl->getName().str();
+ size_t Index = 0;
+ if (Style == CategoryProperty) {
+ Index = Name.find_first_of('_') + 1;
+ NewName.replace(0, Index - 1, Name.substr(0, Index - 1).lower());
+ }
+ if (Index < Name.size()) {
+ NewName[Index] = tolower(NewName[Index]);
+ if (NewName != Name) {
+ return FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(SourceRange(Decl->getLocation())),
+ llvm::StringRef(NewName));
+ }
+ }
+ return FixItHint();
+}
+
+std::string AcronymsGroupRegex(llvm::ArrayRef<std::string> EscapedAcronyms) {
+ return "(" +
+ llvm::join(EscapedAcronyms.begin(), EscapedAcronyms.end(), "s?|") +
+ "s?)";
+}
+
+std::string validPropertyNameRegex(llvm::ArrayRef<std::string> EscapedAcronyms,
+ bool UsedInMatcher) {
+ // Allow any of these names:
+ // foo
+ // fooBar
+ // url
+ // urlString
+ // URL
+ // URLString
+ // bundleID
+ std::string StartMatcher = UsedInMatcher ? "::" : "^";
+ std::string AcronymsMatcher = AcronymsGroupRegex(EscapedAcronyms);
+ return StartMatcher + "(" + AcronymsMatcher + "[A-Z]?)?[a-z]+[a-z0-9]*(" +
+ AcronymsMatcher + "|([A-Z][a-z0-9]+)|A|I)*$";
+}
+
+bool hasCategoryPropertyPrefix(llvm::StringRef PropertyName) {
+ auto RegexExp = llvm::Regex("^[a-zA-Z]+_[a-zA-Z0-9][a-zA-Z0-9_]+$");
+ return RegexExp.match(PropertyName);
+}
+
+bool prefixedPropertyNameValid(llvm::StringRef PropertyName,
+ llvm::ArrayRef<std::string> Acronyms) {
+ size_t Start = PropertyName.find_first_of('_');
+ assert(Start != llvm::StringRef::npos && Start + 1 < PropertyName.size());
+ auto Prefix = PropertyName.substr(0, Start);
+ if (Prefix.lower() != Prefix) {
+ return false;
+ }
+ auto RegexExp =
+ llvm::Regex(llvm::StringRef(validPropertyNameRegex(Acronyms, false)));
+ return RegexExp.match(PropertyName.substr(Start + 1));
+}
+} // namespace
+
+PropertyDeclarationCheck::PropertyDeclarationCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ SpecialAcronyms(
+ utils::options::parseStringList(Options.get("Acronyms", ""))),
+ IncludeDefaultAcronyms(Options.get("IncludeDefaultAcronyms", true)),
+ EscapedAcronyms() {}
+
+void PropertyDeclarationCheck::registerMatchers(MatchFinder *Finder) {
+ // this check should only be applied to ObjC sources.
+ if (!getLangOpts().ObjC1 && !getLangOpts().ObjC2) {
+ return;
+ }
+ if (IncludeDefaultAcronyms) {
+ EscapedAcronyms.reserve(llvm::array_lengthof(DefaultSpecialAcronyms) +
+ SpecialAcronyms.size());
+ // No need to regex-escape the default acronyms.
+ EscapedAcronyms.insert(EscapedAcronyms.end(),
+ std::begin(DefaultSpecialAcronyms),
+ std::end(DefaultSpecialAcronyms));
+ } else {
+ EscapedAcronyms.reserve(SpecialAcronyms.size());
+ }
+ // In case someone defines a prefix which includes a regex
+ // special character, regex-escape all the user-defined prefixes.
+ std::transform(SpecialAcronyms.begin(), SpecialAcronyms.end(),
+ std::back_inserter(EscapedAcronyms),
+ [](const std::string &s) { return llvm::Regex::escape(s); });
+ Finder->addMatcher(
+ objcPropertyDecl(
+ // the property name should be in Lower Camel Case like
+ // 'lowerCamelCase'
+ unless(matchesName(validPropertyNameRegex(EscapedAcronyms, true))))
+ .bind("property"),
+ this);
+}
+
+void PropertyDeclarationCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedDecl =
+ Result.Nodes.getNodeAs<ObjCPropertyDecl>("property");
+ assert(MatchedDecl->getName().size() > 0);
+ auto *DeclContext = MatchedDecl->getDeclContext();
+ auto *CategoryDecl = llvm::dyn_cast<ObjCCategoryDecl>(DeclContext);
+
+ auto AcronymsRegex =
+ llvm::Regex("^" + AcronymsGroupRegex(EscapedAcronyms) + "$");
+ if (AcronymsRegex.match(MatchedDecl->getName())) {
+ return;
+ }
+ if (CategoryDecl != nullptr &&
+ hasCategoryPropertyPrefix(MatchedDecl->getName())) {
+ if (!prefixedPropertyNameValid(MatchedDecl->getName(), EscapedAcronyms) ||
+ CategoryDecl->IsClassExtension()) {
+ NamingStyle Style = CategoryDecl->IsClassExtension() ? StandardProperty
+ : CategoryProperty;
+ diag(MatchedDecl->getLocation(),
+ "property name '%0' not using lowerCamelCase style or not prefixed "
+ "in a category, according to the Apple Coding Guidelines")
+ << MatchedDecl->getName() << generateFixItHint(MatchedDecl, Style);
+ }
+ return;
+ }
+ diag(MatchedDecl->getLocation(),
+ "property name '%0' not using lowerCamelCase style or not prefixed in "
+ "a category, according to the Apple Coding Guidelines")
+ << MatchedDecl->getName()
+ << generateFixItHint(MatchedDecl, StandardProperty);
+}
+
+void PropertyDeclarationCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "Acronyms",
+ utils::options::serializeStringList(SpecialAcronyms));
+ Options.store(Opts, "IncludeDefaultAcronyms", IncludeDefaultAcronyms);
+}
+
+} // namespace objc
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/PropertyDeclarationCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/PropertyDeclarationCheck.h
new file mode 100644
index 0000000..b2683ba
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/objc/PropertyDeclarationCheck.h
@@ -0,0 +1,46 @@
+//===--- PropertyDeclarationCheck.h - clang-tidy-----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_PROPERTY_DECLARATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_PROPERTY_DECLARATION_H
+
+#include "../ClangTidy.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tidy {
+namespace objc {
+
+/// Finds Objective-C property declarations which
+/// are not in Lower Camel Case.
+///
+/// The format of property should look like:
+/// @property(nonatomic) NSString *lowerCamelCase;
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/objc-property-declaration.html
+class PropertyDeclarationCheck : public ClangTidyCheck {
+public:
+ PropertyDeclarationCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Options) override;
+
+private:
+ const std::vector<std::string> SpecialAcronyms;
+ const bool IncludeDefaultAcronyms;
+ std::vector<std::string> EscapedAcronyms;
+};
+
+} // namespace objc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_PROPERTY_DECLARATION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
new file mode 100644
index 0000000..ac417bc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
@@ -0,0 +1,25 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyPerformanceModule
+ FasterStringFindCheck.cpp
+ ForRangeCopyCheck.cpp
+ ImplicitConversionInLoopCheck.cpp
+ InefficientAlgorithmCheck.cpp
+ InefficientStringConcatenationCheck.cpp
+ InefficientVectorOperationCheck.cpp
+ MoveConstArgCheck.cpp
+ MoveConstructorInitCheck.cpp
+ NoexceptMoveConstructorCheck.cpp
+ PerformanceTidyModule.cpp
+ TypePromotionInMathFnCheck.cpp
+ UnnecessaryCopyInitialization.cpp
+ UnnecessaryValueParamCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyUtils
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
new file mode 100644
index 0000000..eddc52b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.cpp
@@ -0,0 +1,104 @@
+//===--- FasterStringFindCheck.cpp - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FasterStringFindCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+namespace {
+
+llvm::Optional<std::string> MakeCharacterLiteral(const StringLiteral *Literal) {
+ std::string Result;
+ {
+ llvm::raw_string_ostream OS(Result);
+ Literal->outputString(OS);
+ }
+ // Now replace the " with '.
+ auto pos = Result.find_first_of('"');
+ if (pos == Result.npos)
+ return llvm::None;
+ Result[pos] = '\'';
+ pos = Result.find_last_of('"');
+ if (pos == Result.npos)
+ return llvm::None;
+ Result[pos] = '\'';
+ return Result;
+}
+
+AST_MATCHER_FUNCTION(ast_matchers::internal::Matcher<Expr>,
+ hasSubstitutedType) {
+ return hasType(qualType(anyOf(substTemplateTypeParmType(),
+ hasDescendant(substTemplateTypeParmType()))));
+}
+
+} // namespace
+
+FasterStringFindCheck::FasterStringFindCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ StringLikeClasses(utils::options::parseStringList(
+ Options.get("StringLikeClasses", "std::basic_string"))) {}
+
+void FasterStringFindCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "StringLikeClasses",
+ utils::options::serializeStringList(StringLikeClasses));
+}
+
+void FasterStringFindCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ const auto SingleChar =
+ expr(ignoringParenCasts(stringLiteral(hasSize(1)).bind("literal")));
+ const auto StringFindFunctions =
+ hasAnyName("find", "rfind", "find_first_of", "find_first_not_of",
+ "find_last_of", "find_last_not_of");
+
+ Finder->addMatcher(
+ cxxMemberCallExpr(
+ callee(functionDecl(StringFindFunctions).bind("func")),
+ anyOf(argumentCountIs(1), argumentCountIs(2)),
+ hasArgument(0, SingleChar),
+ on(expr(
+ hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(
+ recordDecl(hasAnyName(SmallVector<StringRef, 4>(
+ StringLikeClasses.begin(), StringLikeClasses.end()))))))),
+ unless(hasSubstitutedType())))),
+ this);
+}
+
+void FasterStringFindCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Literal = Result.Nodes.getNodeAs<StringLiteral>("literal");
+ const auto *FindFunc = Result.Nodes.getNodeAs<FunctionDecl>("func");
+
+ auto Replacement = MakeCharacterLiteral(Literal);
+ if (!Replacement)
+ return;
+
+ diag(Literal->getLocStart(), "%0 called with a string literal consisting of "
+ "a single character; consider using the more "
+ "effective overload accepting a character")
+ << FindFunc << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(Literal->getLocStart(),
+ Literal->getLocEnd()),
+ *Replacement);
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.h
new file mode 100644
index 0000000..ff666f2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/FasterStringFindCheck.h
@@ -0,0 +1,43 @@
+//===--- FasterStringFindCheck.h - clang-tidy--------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_FASTER_STRING_FIND_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_FASTER_STRING_FIND_H
+
+#include "../ClangTidy.h"
+
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// Optimize calls to std::string::find() and friends when the needle passed is
+/// a single character string literal.
+/// The character literal overload is more efficient.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/performance-faster-string-find.html
+class FasterStringFindCheck : public ClangTidyCheck {
+public:
+ FasterStringFindCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ const std::vector<std::string> StringLikeClasses;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_FASTER_STRING_FIND_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
new file mode 100644
index 0000000..2358aac
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
@@ -0,0 +1,95 @@
+//===--- ForRangeCopyCheck.cpp - clang-tidy--------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ForRangeCopyCheck.h"
+#include "../utils/ExprMutationAnalyzer.h"
+#include "../utils/FixItHintUtils.h"
+#include "../utils/TypeTraits.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+ForRangeCopyCheck::ForRangeCopyCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ WarnOnAllAutoCopies(Options.get("WarnOnAllAutoCopies", 0)) {}
+
+void ForRangeCopyCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "WarnOnAllAutoCopies", WarnOnAllAutoCopies);
+}
+
+void ForRangeCopyCheck::registerMatchers(MatchFinder *Finder) {
+ // Match loop variables that are not references or pointers or are already
+ // initialized through MaterializeTemporaryExpr which indicates a type
+ // conversion.
+ auto LoopVar = varDecl(
+ hasType(hasCanonicalType(unless(anyOf(referenceType(), pointerType())))),
+ unless(hasInitializer(expr(hasDescendant(materializeTemporaryExpr())))));
+ Finder->addMatcher(cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar")))
+ .bind("forRange"),
+ this);
+}
+
+void ForRangeCopyCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Var = Result.Nodes.getNodeAs<VarDecl>("loopVar");
+ // Ignore code in macros since we can't place the fixes correctly.
+ if (Var->getLocStart().isMacroID())
+ return;
+ if (handleConstValueCopy(*Var, *Result.Context))
+ return;
+ const auto *ForRange = Result.Nodes.getNodeAs<CXXForRangeStmt>("forRange");
+ handleCopyIsOnlyConstReferenced(*Var, *ForRange, *Result.Context);
+}
+
+bool ForRangeCopyCheck::handleConstValueCopy(const VarDecl &LoopVar,
+ ASTContext &Context) {
+ if (WarnOnAllAutoCopies) {
+ // For aggressive check just test that loop variable has auto type.
+ if (!isa<AutoType>(LoopVar.getType()))
+ return false;
+ } else if (!LoopVar.getType().isConstQualified()) {
+ return false;
+ }
+ llvm::Optional<bool> Expensive =
+ utils::type_traits::isExpensiveToCopy(LoopVar.getType(), Context);
+ if (!Expensive || !*Expensive)
+ return false;
+ auto Diagnostic =
+ diag(LoopVar.getLocation(),
+ "the loop variable's type is not a reference type; this creates a "
+ "copy in each iteration; consider making this a reference")
+ << utils::fixit::changeVarDeclToReference(LoopVar, Context);
+ if (!LoopVar.getType().isConstQualified())
+ Diagnostic << utils::fixit::changeVarDeclToConst(LoopVar);
+ return true;
+}
+
+bool ForRangeCopyCheck::handleCopyIsOnlyConstReferenced(
+ const VarDecl &LoopVar, const CXXForRangeStmt &ForRange,
+ ASTContext &Context) {
+ llvm::Optional<bool> Expensive =
+ utils::type_traits::isExpensiveToCopy(LoopVar.getType(), Context);
+ if (LoopVar.getType().isConstQualified() || !Expensive || !*Expensive)
+ return false;
+ if (utils::ExprMutationAnalyzer(ForRange.getBody(), &Context)
+ .isMutated(&LoopVar))
+ return false;
+ diag(LoopVar.getLocation(),
+ "loop variable is copied but only used as const reference; consider "
+ "making it a const reference")
+ << utils::fixit::changeVarDeclToConst(LoopVar)
+ << utils::fixit::changeVarDeclToReference(LoopVar, Context);
+ return true;
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.h
new file mode 100644
index 0000000..f88a126
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.h
@@ -0,0 +1,49 @@
+//===--- ForRangeCopyCheck.h - clang-tidy------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_FORRANGECOPYCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_FORRANGECOPYCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// A check that detects copied loop variables and suggests using const
+/// references.
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/performance-for-range-copy.html
+class ForRangeCopyCheck : public ClangTidyCheck {
+public:
+ ForRangeCopyCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ // Checks if the loop variable is a const value and expensive to copy. If so
+ // suggests it be converted to a const reference.
+ bool handleConstValueCopy(const VarDecl &LoopVar, ASTContext &Context);
+
+ // Checks if the loop variable is a non-const value and whether only
+ // const methods are invoked on it or whether it is only used as a const
+ // reference argument. If so it suggests it be made a const reference.
+ bool handleCopyIsOnlyConstReferenced(const VarDecl &LoopVar,
+ const CXXForRangeStmt &ForRange,
+ ASTContext &Context);
+
+ const bool WarnOnAllAutoCopies;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_FORRANGECOPYCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp
new file mode 100644
index 0000000..1a5605f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp
@@ -0,0 +1,104 @@
+//===--- ImplicitConversionInLoopCheck.cpp - clang-tidy--------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ImplicitConversionInLoopCheck.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+// Checks if the stmt is a ImplicitCastExpr with a CastKind that is not a NoOp.
+// The subtelty is that in some cases (user defined conversions), we can
+// get to ImplicitCastExpr inside each other, with the outer one a NoOp. In this
+// case we skip the first cast expr.
+static bool IsNonTrivialImplicitCast(const Stmt *ST) {
+ if (const auto *ICE = dyn_cast<ImplicitCastExpr>(ST)) {
+ return (ICE->getCastKind() != CK_NoOp) ||
+ IsNonTrivialImplicitCast(ICE->getSubExpr());
+ }
+ return false;
+}
+
+void ImplicitConversionInLoopCheck::registerMatchers(MatchFinder *Finder) {
+ // We look for const ref loop variables that (optionally inside an
+ // ExprWithCleanup) materialize a temporary, and contain a implicit
+ // conversion. The check on the implicit conversion is done in check() because
+ // we can't access implicit conversion subnode via matchers: has() skips casts
+ // and materialize! We also bind on the call to operator* to get the proper
+ // type in the diagnostic message. We use both cxxOperatorCallExpr for user
+ // defined operator and unaryOperator when the iterator is a pointer, like
+ // for arrays or std::array.
+ //
+ // Note that when the implicit conversion is done through a user defined
+ // conversion operator, the node is a CXXMemberCallExpr, not a
+ // CXXOperatorCallExpr, so it should not get caught by the
+ // cxxOperatorCallExpr() matcher.
+ Finder->addMatcher(
+ cxxForRangeStmt(hasLoopVariable(
+ varDecl(
+ hasType(qualType(references(qualType(isConstQualified())))),
+ hasInitializer(
+ expr(anyOf(hasDescendant(
+ cxxOperatorCallExpr().bind("operator-call")),
+ hasDescendant(unaryOperator(hasOperatorName("*"))
+ .bind("operator-call"))))
+ .bind("init")))
+ .bind("faulty-var"))),
+ this);
+}
+
+void ImplicitConversionInLoopCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *VD = Result.Nodes.getNodeAs<VarDecl>("faulty-var");
+ const auto *Init = Result.Nodes.getNodeAs<Expr>("init");
+ const auto *OperatorCall =
+ Result.Nodes.getNodeAs<Expr>("operator-call");
+
+ if (const auto *Cleanup = dyn_cast<ExprWithCleanups>(Init))
+ Init = Cleanup->getSubExpr();
+
+ const auto *Materialized = dyn_cast<MaterializeTemporaryExpr>(Init);
+ if (!Materialized)
+ return;
+
+ // We ignore NoOp casts. Those are generated if the * operator on the
+ // iterator returns a value instead of a reference, and the loop variable
+ // is a reference. This situation is fine (it probably produces the same
+ // code at the end).
+ if (IsNonTrivialImplicitCast(Materialized->getTemporary()))
+ ReportAndFix(Result.Context, VD, OperatorCall);
+}
+
+void ImplicitConversionInLoopCheck::ReportAndFix(
+ const ASTContext *Context, const VarDecl *VD,
+ const Expr *OperatorCall) {
+ // We only match on const ref, so we should print a const ref version of the
+ // type.
+ QualType ConstType = OperatorCall->getType().withConst();
+ QualType ConstRefType = Context->getLValueReferenceType(ConstType);
+ const char Message[] =
+ "the type of the loop variable %0 is different from the one returned "
+ "by the iterator and generates an implicit conversion; you can either "
+ "change the type to the matching one (%1 but 'const auto&' is always a "
+ "valid option) or remove the reference to make it explicit that you are "
+ "creating a new value";
+ diag(VD->getLocStart(), Message) << VD << ConstRefType;
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.h
new file mode 100644
index 0000000..55cb84c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.h
@@ -0,0 +1,38 @@
+//===--- ImplicitConversionInLoopCheck.h - clang-tidy------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_IMPLICIT_CONVERSION_IN_LOOP_CHECK_H_
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_IMPLICIT_CONVERSION_IN_LOOP_CHECK_H_
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+// Checks that in a for range loop, if the provided type is a reference, then
+// the underlying type is the one returned by the iterator (i.e. that there
+// isn't any implicit conversion).
+class ImplicitConversionInLoopCheck : public ClangTidyCheck {
+public:
+ ImplicitConversionInLoopCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void ReportAndFix(const ASTContext *Context, const VarDecl *VD,
+ const Expr *OperatorCall);
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_IMPLICIT_CONVERSION_IN_LOOP_CHECK_H_
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientAlgorithmCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientAlgorithmCheck.cpp
new file mode 100644
index 0000000..4471d07
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientAlgorithmCheck.cpp
@@ -0,0 +1,163 @@
+//===--- InefficientAlgorithmCheck.cpp - clang-tidy------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InefficientAlgorithmCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+static bool areTypesCompatible(QualType Left, QualType Right) {
+ if (const auto *LeftRefType = Left->getAs<ReferenceType>())
+ Left = LeftRefType->getPointeeType();
+ if (const auto *RightRefType = Right->getAs<ReferenceType>())
+ Right = RightRefType->getPointeeType();
+ return Left->getCanonicalTypeUnqualified() ==
+ Right->getCanonicalTypeUnqualified();
+}
+
+void InefficientAlgorithmCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ const auto Algorithms =
+ hasAnyName("::std::find", "::std::count", "::std::equal_range",
+ "::std::lower_bound", "::std::upper_bound");
+ const auto ContainerMatcher = classTemplateSpecializationDecl(hasAnyName(
+ "::std::set", "::std::map", "::std::multiset", "::std::multimap",
+ "::std::unordered_set", "::std::unordered_map",
+ "::std::unordered_multiset", "::std::unordered_multimap"));
+
+ const auto Matcher =
+ callExpr(
+ callee(functionDecl(Algorithms)),
+ hasArgument(
+ 0, cxxConstructExpr(has(ignoringParenImpCasts(cxxMemberCallExpr(
+ callee(cxxMethodDecl(hasName("begin"))),
+ on(declRefExpr(
+ hasDeclaration(decl().bind("IneffContObj")),
+ anyOf(hasType(ContainerMatcher.bind("IneffCont")),
+ hasType(pointsTo(
+ ContainerMatcher.bind("IneffContPtr")))))
+ .bind("IneffContExpr"))))))),
+ hasArgument(
+ 1, cxxConstructExpr(has(ignoringParenImpCasts(cxxMemberCallExpr(
+ callee(cxxMethodDecl(hasName("end"))),
+ on(declRefExpr(
+ hasDeclaration(equalsBoundNode("IneffContObj"))))))))),
+ hasArgument(2, expr().bind("AlgParam")),
+ unless(isInTemplateInstantiation()))
+ .bind("IneffAlg");
+
+ Finder->addMatcher(Matcher, this);
+}
+
+void InefficientAlgorithmCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *AlgCall = Result.Nodes.getNodeAs<CallExpr>("IneffAlg");
+ const auto *IneffCont =
+ Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("IneffCont");
+ bool PtrToContainer = false;
+ if (!IneffCont) {
+ IneffCont =
+ Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("IneffContPtr");
+ PtrToContainer = true;
+ }
+ const llvm::StringRef IneffContName = IneffCont->getName();
+ const bool Unordered =
+ IneffContName.find("unordered") != llvm::StringRef::npos;
+ const bool Maplike = IneffContName.find("map") != llvm::StringRef::npos;
+
+ // Store if the key type of the container is compatible with the value
+ // that is searched for.
+ QualType ValueType = AlgCall->getArg(2)->getType();
+ QualType KeyType =
+ IneffCont->getTemplateArgs()[0].getAsType().getCanonicalType();
+ const bool CompatibleTypes = areTypesCompatible(KeyType, ValueType);
+
+ // Check if the comparison type for the algorithm and the container matches.
+ if (AlgCall->getNumArgs() == 4 && !Unordered) {
+ const Expr *Arg = AlgCall->getArg(3);
+ const QualType AlgCmp =
+ Arg->getType().getUnqualifiedType().getCanonicalType();
+ const unsigned CmpPosition =
+ (IneffContName.find("map") == llvm::StringRef::npos) ? 1 : 2;
+ const QualType ContainerCmp = IneffCont->getTemplateArgs()[CmpPosition]
+ .getAsType()
+ .getUnqualifiedType()
+ .getCanonicalType();
+ if (AlgCmp != ContainerCmp) {
+ diag(Arg->getLocStart(),
+ "different comparers used in the algorithm and the container");
+ return;
+ }
+ }
+
+ const auto *AlgDecl = AlgCall->getDirectCallee();
+ if (!AlgDecl)
+ return;
+
+ if (Unordered && AlgDecl->getName().find("bound") != llvm::StringRef::npos)
+ return;
+
+ const auto *AlgParam = Result.Nodes.getNodeAs<Expr>("AlgParam");
+ const auto *IneffContExpr = Result.Nodes.getNodeAs<Expr>("IneffContExpr");
+ FixItHint Hint;
+
+ SourceManager &SM = *Result.SourceManager;
+ LangOptions LangOpts = getLangOpts();
+
+ CharSourceRange CallRange =
+ CharSourceRange::getTokenRange(AlgCall->getSourceRange());
+
+ // FIXME: Create a common utility to extract a file range that the given token
+ // sequence is exactly spelled at (without macro argument expansions etc.).
+ // We can't use Lexer::makeFileCharRange here, because for
+ //
+ // #define F(x) x
+ // x(a b c);
+ //
+ // it will return "x(a b c)", when given the range "a"-"c". It makes sense for
+ // removals, but not for replacements.
+ //
+ // This code is over-simplified, but works for many real cases.
+ if (SM.isMacroArgExpansion(CallRange.getBegin()) &&
+ SM.isMacroArgExpansion(CallRange.getEnd())) {
+ CallRange.setBegin(SM.getSpellingLoc(CallRange.getBegin()));
+ CallRange.setEnd(SM.getSpellingLoc(CallRange.getEnd()));
+ }
+
+ if (!CallRange.getBegin().isMacroID() && !Maplike && CompatibleTypes) {
+ StringRef ContainerText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(IneffContExpr->getSourceRange()), SM,
+ LangOpts);
+ StringRef ParamText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(AlgParam->getSourceRange()), SM,
+ LangOpts);
+ std::string ReplacementText =
+ (llvm::Twine(ContainerText) + (PtrToContainer ? "->" : ".") +
+ AlgDecl->getName() + "(" + ParamText + ")")
+ .str();
+ Hint = FixItHint::CreateReplacement(CallRange, ReplacementText);
+ }
+
+ diag(AlgCall->getLocStart(),
+ "this STL algorithm call should be replaced with a container method")
+ << Hint;
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientAlgorithmCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientAlgorithmCheck.h
new file mode 100644
index 0000000..72506cf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientAlgorithmCheck.h
@@ -0,0 +1,36 @@
+//===--- InefficientAlgorithmCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_INEFFICIENTALGORITHMCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_INEFFICIENTALGORITHMCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// Warns on inefficient use of STL algorithms on associative containers.
+///
+/// Associative containers implements some of the algorithms as methods which
+/// should be preferred to the algorithms in the algorithm header. The methods
+/// can take advanatage of the order of the elements.
+class InefficientAlgorithmCheck : public ClangTidyCheck {
+public:
+ InefficientAlgorithmCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_INEFFICIENTALGORITHMCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientStringConcatenationCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientStringConcatenationCheck.cpp
new file mode 100644
index 0000000..a17916d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientStringConcatenationCheck.cpp
@@ -0,0 +1,88 @@
+//===--- InefficientStringConcatenationCheck.cpp - clang-tidy--------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InefficientStringConcatenationCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+void InefficientStringConcatenationCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "StrictMode", StrictMode);
+}
+
+InefficientStringConcatenationCheck::InefficientStringConcatenationCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ StrictMode(Options.getLocalOrGlobal("StrictMode", 0)) {}
+
+void InefficientStringConcatenationCheck::registerMatchers(
+ MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ const auto BasicStringType =
+ hasType(qualType(hasUnqualifiedDesugaredType(recordType(
+ hasDeclaration(cxxRecordDecl(hasName("::std::basic_string")))))));
+
+ const auto BasicStringPlusOperator = cxxOperatorCallExpr(
+ hasOverloadedOperatorName("+"),
+ hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType))));
+
+ const auto PlusOperator =
+ cxxOperatorCallExpr(
+ hasOverloadedOperatorName("+"),
+ hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType))),
+ hasDescendant(BasicStringPlusOperator))
+ .bind("plusOperator");
+
+ const auto AssignOperator = cxxOperatorCallExpr(
+ hasOverloadedOperatorName("="),
+ hasArgument(0, declRefExpr(BasicStringType,
+ hasDeclaration(decl().bind("lhsStrT")))
+ .bind("lhsStr")),
+ hasArgument(1, stmt(hasDescendant(declRefExpr(
+ hasDeclaration(decl(equalsBoundNode("lhsStrT"))))))),
+ hasDescendant(BasicStringPlusOperator));
+
+ if (StrictMode) {
+ Finder->addMatcher(cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator)),
+ this);
+ } else {
+ Finder->addMatcher(
+ cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator),
+ hasAncestor(stmt(anyOf(cxxForRangeStmt(),
+ whileStmt(), forStmt())))),
+ this);
+ }
+}
+
+void InefficientStringConcatenationCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *LhsStr = Result.Nodes.getNodeAs<DeclRefExpr>("lhsStr");
+ const auto *PlusOperator =
+ Result.Nodes.getNodeAs<CXXOperatorCallExpr>("plusOperator");
+ const auto DiagMsg =
+ "string concatenation results in allocation of unnecessary temporary "
+ "strings; consider using 'operator+=' or 'string::append()' instead";
+
+ if (LhsStr)
+ diag(LhsStr->getExprLoc(), DiagMsg);
+ else if (PlusOperator)
+ diag(PlusOperator->getExprLoc(), DiagMsg);
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientStringConcatenationCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientStringConcatenationCheck.h
new file mode 100644
index 0000000..12a154c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientStringConcatenationCheck.h
@@ -0,0 +1,41 @@
+//===--- InefficientStringConcatenationCheck.h - clang-tidy-----------*- C++
+//-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_INEFFICIENTSTRINGCONCATENATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_INEFFICIENTSTRINGCONCATENATION_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// This check is to warn about the performance overhead arising from
+/// concatenating strings, using the operator+, instead of operator+=.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/performance-inefficient-string-concatenation.html
+class InefficientStringConcatenationCheck : public ClangTidyCheck {
+public:
+ InefficientStringConcatenationCheck(StringRef Name,
+ ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ const bool StrictMode;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_INEFFICIENTSTRINGCONCATENATION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp
new file mode 100644
index 0000000..33c68f0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp
@@ -0,0 +1,214 @@
+//===--- InefficientVectorOperationCheck.cpp - clang-tidy------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InefficientVectorOperationCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "../utils/DeclRefExprUtils.h"
+#include "../utils/OptionsUtils.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+namespace {
+
+// Matcher names. Given the code:
+//
+// \code
+// void f() {
+// vector<T> v;
+// for (int i = 0; i < 10 + 1; ++i) {
+// v.push_back(i);
+// }
+// }
+// \endcode
+//
+// The matcher names are bound to following parts of the AST:
+// - LoopCounterName: The entire for loop (as ForStmt).
+// - LoopParentName: The body of function f (as CompoundStmt).
+// - VectorVarDeclName: 'v' in (as VarDecl).
+// - VectorVarDeclStmatName: The entire 'std::vector<T> v;' statement (as
+// DeclStmt).
+// - PushBackOrEmplaceBackCallName: 'v.push_back(i)' (as cxxMemberCallExpr).
+// - LoopInitVarName: 'i' (as VarDecl).
+// - LoopEndExpr: '10+1' (as Expr).
+static const char LoopCounterName[] = "for_loop_counter";
+static const char LoopParentName[] = "loop_parent";
+static const char VectorVarDeclName[] = "vector_var_decl";
+static const char VectorVarDeclStmtName[] = "vector_var_decl_stmt";
+static const char PushBackOrEmplaceBackCallName[] = "append_call";
+static const char LoopInitVarName[] = "loop_init_var";
+static const char LoopEndExprName[] = "loop_end_expr";
+
+static const char RangeLoopName[] = "for_range_loop";
+
+ast_matchers::internal::Matcher<Expr> supportedContainerTypesMatcher() {
+ return hasType(cxxRecordDecl(hasAnyName(
+ "::std::vector", "::std::set", "::std::unordered_set", "::std::map",
+ "::std::unordered_map", "::std::array", "::std::deque")));
+}
+
+} // namespace
+
+InefficientVectorOperationCheck::InefficientVectorOperationCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ VectorLikeClasses(utils::options::parseStringList(
+ Options.get("VectorLikeClasses", "::std::vector"))) {}
+
+void InefficientVectorOperationCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "VectorLikeClasses",
+ utils::options::serializeStringList(VectorLikeClasses));
+}
+
+void InefficientVectorOperationCheck::registerMatchers(MatchFinder *Finder) {
+ const auto VectorDecl = cxxRecordDecl(hasAnyName(SmallVector<StringRef, 5>(
+ VectorLikeClasses.begin(), VectorLikeClasses.end())));
+ const auto VectorDefaultConstructorCall = cxxConstructExpr(
+ hasType(VectorDecl),
+ hasDeclaration(cxxConstructorDecl(isDefaultConstructor())));
+ const auto VectorVarDecl =
+ varDecl(hasInitializer(VectorDefaultConstructorCall))
+ .bind(VectorVarDeclName);
+ const auto VectorAppendCallExpr =
+ cxxMemberCallExpr(
+ callee(cxxMethodDecl(hasAnyName("push_back", "emplace_back"))),
+ on(hasType(VectorDecl)),
+ onImplicitObjectArgument(declRefExpr(to(VectorVarDecl))))
+ .bind(PushBackOrEmplaceBackCallName);
+ const auto VectorAppendCall = expr(ignoringImplicit(VectorAppendCallExpr));
+ const auto VectorVarDefStmt =
+ declStmt(hasSingleDecl(equalsBoundNode(VectorVarDeclName)))
+ .bind(VectorVarDeclStmtName);
+
+ const auto LoopVarInit =
+ declStmt(hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0))))
+ .bind(LoopInitVarName)));
+ const auto RefersToLoopVar = ignoringParenImpCasts(
+ declRefExpr(to(varDecl(equalsBoundNode(LoopInitVarName)))));
+
+ // Matchers for the loop whose body has only 1 push_back/emplace_back calling
+ // statement.
+ const auto HasInterestingLoopBody =
+ hasBody(anyOf(compoundStmt(statementCountIs(1), has(VectorAppendCall)),
+ VectorAppendCall));
+ const auto InInterestingCompoundStmt =
+ hasParent(compoundStmt(has(VectorVarDefStmt)).bind(LoopParentName));
+
+ // Match counter-based for loops:
+ // for (int i = 0; i < n; ++i) { v.push_back(...); }
+ //
+ // FIXME: Support more types of counter-based loops like decrement loops.
+ Finder->addMatcher(
+ forStmt(
+ hasLoopInit(LoopVarInit),
+ hasCondition(binaryOperator(
+ hasOperatorName("<"), hasLHS(RefersToLoopVar),
+ hasRHS(expr(unless(hasDescendant(expr(RefersToLoopVar))))
+ .bind(LoopEndExprName)))),
+ hasIncrement(unaryOperator(hasOperatorName("++"),
+ hasUnaryOperand(RefersToLoopVar))),
+ HasInterestingLoopBody, InInterestingCompoundStmt)
+ .bind(LoopCounterName),
+ this);
+
+ // Match for-range loops:
+ // for (const auto& E : data) { v.push_back(...); }
+ //
+ // FIXME: Support more complex range-expressions.
+ Finder->addMatcher(
+ cxxForRangeStmt(
+ hasRangeInit(declRefExpr(supportedContainerTypesMatcher())),
+ HasInterestingLoopBody, InInterestingCompoundStmt)
+ .bind(RangeLoopName),
+ this);
+}
+
+void InefficientVectorOperationCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ auto* Context = Result.Context;
+ if (Context->getDiagnostics().hasUncompilableErrorOccurred())
+ return;
+
+ const SourceManager &SM = *Result.SourceManager;
+ const auto *VectorVarDecl =
+ Result.Nodes.getNodeAs<VarDecl>(VectorVarDeclName);
+ const auto *ForLoop = Result.Nodes.getNodeAs<ForStmt>(LoopCounterName);
+ const auto *RangeLoop =
+ Result.Nodes.getNodeAs<CXXForRangeStmt>(RangeLoopName);
+ const auto *VectorAppendCall =
+ Result.Nodes.getNodeAs<CXXMemberCallExpr>(PushBackOrEmplaceBackCallName);
+ const auto *LoopEndExpr = Result.Nodes.getNodeAs<Expr>(LoopEndExprName);
+ const auto *LoopParent = Result.Nodes.getNodeAs<CompoundStmt>(LoopParentName);
+
+ const Stmt *LoopStmt = ForLoop;
+ if (!LoopStmt)
+ LoopStmt = RangeLoop;
+
+ llvm::SmallPtrSet<const DeclRefExpr *, 16> AllVectorVarRefs =
+ utils::decl_ref_expr::allDeclRefExprs(*VectorVarDecl, *LoopParent,
+ *Context);
+ for (const auto *Ref : AllVectorVarRefs) {
+ // Skip cases where there are usages (defined as DeclRefExpr that refers to
+ // "v") of vector variable `v` before the for loop. We consider these usages
+ // are operations causing memory preallocation (e.g. "v.resize(n)",
+ // "v.reserve(n)").
+ //
+ // FIXME: make it more intelligent to identify the pre-allocating operations
+ // before the for loop.
+ if (SM.isBeforeInTranslationUnit(Ref->getLocation(),
+ LoopStmt->getLocStart())) {
+ return;
+ }
+ }
+
+ llvm::StringRef VectorVarName = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(
+ VectorAppendCall->getImplicitObjectArgument()->getSourceRange()),
+ SM, Context->getLangOpts());
+
+ std::string ReserveStmt;
+ // Handle for-range loop cases.
+ if (RangeLoop) {
+ // Get the range-expression in a for-range statement represented as
+ // `for (range-declarator: range-expression)`.
+ StringRef RangeInitExpName = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(
+ RangeLoop->getRangeInit()->getSourceRange()),
+ SM, Context->getLangOpts());
+
+ ReserveStmt =
+ (VectorVarName + ".reserve(" + RangeInitExpName + ".size()" + ");\n")
+ .str();
+ } else if (ForLoop) {
+ // Handle counter-based loop cases.
+ StringRef LoopEndSource = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(LoopEndExpr->getSourceRange()), SM,
+ Context->getLangOpts());
+ ReserveStmt = (VectorVarName + ".reserve(" + LoopEndSource + ");\n").str();
+ }
+
+ auto Diag =
+ diag(VectorAppendCall->getLocStart(),
+ "%0 is called inside a loop; "
+ "consider pre-allocating the vector capacity before the loop")
+ << VectorAppendCall->getMethodDecl()->getDeclName();
+
+ if (!ReserveStmt.empty())
+ Diag << FixItHint::CreateInsertion(LoopStmt->getLocStart(), ReserveStmt);
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.h
new file mode 100644
index 0000000..1427ff1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.h
@@ -0,0 +1,39 @@
+//===--- InefficientVectorOperationCheck.h - clang-tidy----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_INEFFICIENT_VECTOR_OPERATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_INEFFICIENT_VECTOR_OPERATION_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// Finds possible inefficient `std::vector` operations (e.g. `push_back`) in
+/// for loops that may cause unnecessary memory reallocations.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/performance-inefficient-vector-operation.html
+class InefficientVectorOperationCheck : public ClangTidyCheck {
+public:
+ InefficientVectorOperationCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ const std::vector<std::string> VectorLikeClasses;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_INEFFICIENT_VECTOR_OPERATION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp
new file mode 100644
index 0000000..8d49480
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp
@@ -0,0 +1,121 @@
+//===--- MoveConstArgCheck.cpp - clang-tidy -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MoveConstArgCheck.h"
+
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+static void ReplaceCallWithArg(const CallExpr *Call, DiagnosticBuilder &Diag,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ const Expr *Arg = Call->getArg(0);
+
+ CharSourceRange BeforeArgumentsRange = Lexer::makeFileCharRange(
+ CharSourceRange::getCharRange(Call->getLocStart(), Arg->getLocStart()),
+ SM, LangOpts);
+ CharSourceRange AfterArgumentsRange = Lexer::makeFileCharRange(
+ CharSourceRange::getCharRange(Call->getLocEnd(),
+ Call->getLocEnd().getLocWithOffset(1)),
+ SM, LangOpts);
+
+ if (BeforeArgumentsRange.isValid() && AfterArgumentsRange.isValid()) {
+ Diag << FixItHint::CreateRemoval(BeforeArgumentsRange)
+ << FixItHint::CreateRemoval(AfterArgumentsRange);
+ }
+}
+
+void MoveConstArgCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "CheckTriviallyCopyableMove", CheckTriviallyCopyableMove);
+}
+
+void MoveConstArgCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ auto MoveCallMatcher =
+ callExpr(callee(functionDecl(hasName("::std::move"))), argumentCountIs(1),
+ unless(isInTemplateInstantiation()))
+ .bind("call-move");
+
+ Finder->addMatcher(MoveCallMatcher, this);
+
+ auto ConstParamMatcher = forEachArgumentWithParam(
+ MoveCallMatcher, parmVarDecl(hasType(references(isConstQualified()))));
+
+ Finder->addMatcher(callExpr(ConstParamMatcher).bind("receiving-expr"), this);
+ Finder->addMatcher(cxxConstructExpr(ConstParamMatcher).bind("receiving-expr"),
+ this);
+}
+
+void MoveConstArgCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *CallMove = Result.Nodes.getNodeAs<CallExpr>("call-move");
+ const auto *ReceivingExpr = Result.Nodes.getNodeAs<Expr>("receiving-expr");
+ const Expr *Arg = CallMove->getArg(0);
+ SourceManager &SM = Result.Context->getSourceManager();
+
+ CharSourceRange MoveRange =
+ CharSourceRange::getCharRange(CallMove->getSourceRange());
+ CharSourceRange FileMoveRange =
+ Lexer::makeFileCharRange(MoveRange, SM, getLangOpts());
+ if (!FileMoveRange.isValid())
+ return;
+
+ bool IsConstArg = Arg->getType().isConstQualified();
+ bool IsTriviallyCopyable =
+ Arg->getType().isTriviallyCopyableType(*Result.Context);
+
+ if (IsConstArg || IsTriviallyCopyable) {
+ if (const CXXRecordDecl *R = Arg->getType()->getAsCXXRecordDecl()) {
+ // According to [expr.prim.lambda]p3, "whether the closure type is
+ // trivially copyable" property can be changed by the implementation of
+ // the language, so we shouldn't rely on it when issuing diagnostics.
+ if (R->isLambda())
+ return;
+ // Don't warn when the type is not copyable.
+ for (const auto *Ctor : R->ctors()) {
+ if (Ctor->isCopyConstructor() && Ctor->isDeleted())
+ return;
+ }
+ }
+
+ if (!IsConstArg && IsTriviallyCopyable && !CheckTriviallyCopyableMove)
+ return;
+
+ bool IsVariable = isa<DeclRefExpr>(Arg);
+ const auto *Var =
+ IsVariable ? dyn_cast<DeclRefExpr>(Arg)->getDecl() : nullptr;
+ auto Diag = diag(FileMoveRange.getBegin(),
+ "std::move of the %select{|const }0"
+ "%select{expression|variable %4}1 "
+ "%select{|of the trivially-copyable type %5 }2"
+ "has no effect; remove std::move()"
+ "%select{| or make the variable non-const}3")
+ << IsConstArg << IsVariable << IsTriviallyCopyable
+ << (IsConstArg && IsVariable && !IsTriviallyCopyable) << Var
+ << Arg->getType();
+
+ ReplaceCallWithArg(CallMove, Diag, SM, getLangOpts());
+ } else if (ReceivingExpr) {
+ auto Diag = diag(FileMoveRange.getBegin(),
+ "passing result of std::move() as a const reference "
+ "argument; no move will actually happen");
+
+ ReplaceCallWithArg(CallMove, Diag, SM, getLangOpts());
+ }
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.h
new file mode 100644
index 0000000..13ed9ae
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.h
@@ -0,0 +1,43 @@
+//===--- MoveConstArgCheck.h - clang-tidy -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// Find casts of calculation results to bigger type. Typically from int to
+///
+/// There is one option:
+///
+/// - `CheckTriviallyCopyableMove`: Whether to check for trivially-copyable
+// types as their objects are not moved but copied. Enabled by default.
+class MoveConstArgCheck : public ClangTidyCheck {
+public:
+ MoveConstArgCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ CheckTriviallyCopyableMove(
+ Options.get("CheckTriviallyCopyableMove", true)) {}
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const bool CheckTriviallyCopyableMove;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/MoveConstructorInitCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/MoveConstructorInitCheck.cpp
new file mode 100644
index 0000000..055e4f0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/MoveConstructorInitCheck.cpp
@@ -0,0 +1,110 @@
+//===--- MoveConstructorInitCheck.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MoveConstructorInitCheck.h"
+#include "../utils/Matchers.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+MoveConstructorInitCheck::MoveConstructorInitCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
+ Options.getLocalOrGlobal("IncludeStyle", "llvm"))) {}
+
+void MoveConstructorInitCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++11; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ Finder->addMatcher(
+ cxxConstructorDecl(
+ unless(isImplicit()),
+ allOf(isMoveConstructor(),
+ hasAnyConstructorInitializer(
+ cxxCtorInitializer(
+ withInitializer(cxxConstructExpr(hasDeclaration(
+ cxxConstructorDecl(isCopyConstructor())
+ .bind("ctor")))))
+ .bind("move-init")))),
+ this);
+}
+
+void MoveConstructorInitCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *CopyCtor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
+ const auto *Initializer =
+ Result.Nodes.getNodeAs<CXXCtorInitializer>("move-init");
+
+ // Do not diagnose if the expression used to perform the initialization is a
+ // trivially-copyable type.
+ QualType QT = Initializer->getInit()->getType();
+ if (QT.isTriviallyCopyableType(*Result.Context))
+ return;
+
+ if (QT.isConstQualified())
+ return;
+
+ const auto *RD = QT->getAsCXXRecordDecl();
+ if (RD && RD->isTriviallyCopyable())
+ return;
+
+ // Diagnose when the class type has a move constructor available, but the
+ // ctor-initializer uses the copy constructor instead.
+ const CXXConstructorDecl *Candidate = nullptr;
+ for (const auto *Ctor : CopyCtor->getParent()->ctors()) {
+ if (Ctor->isMoveConstructor() && Ctor->getAccess() <= AS_protected &&
+ !Ctor->isDeleted()) {
+ // The type has a move constructor that is at least accessible to the
+ // initializer.
+ //
+ // FIXME: Determine whether the move constructor is a viable candidate
+ // for the ctor-initializer, perhaps provide a fixit that suggests
+ // using std::move().
+ Candidate = Ctor;
+ break;
+ }
+ }
+
+ if (Candidate) {
+ // There's a move constructor candidate that the caller probably intended
+ // to call instead.
+ diag(Initializer->getSourceLocation(),
+ "move constructor initializes %0 by calling a copy constructor")
+ << (Initializer->isBaseInitializer() ? "base class" : "class member");
+ diag(CopyCtor->getLocation(), "copy constructor being called",
+ DiagnosticIDs::Note);
+ diag(Candidate->getLocation(), "candidate move constructor here",
+ DiagnosticIDs::Note);
+ }
+}
+
+void MoveConstructorInitCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+ Inserter.reset(new utils::IncludeInserter(
+ Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle));
+ Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
+}
+
+void MoveConstructorInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IncludeStyle",
+ utils::IncludeSorter::toString(IncludeStyle));
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/MoveConstructorInitCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/MoveConstructorInitCheck.h
new file mode 100644
index 0000000..3b7dda0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/MoveConstructorInitCheck.h
@@ -0,0 +1,44 @@
+//===--- MoveConstructorInitCheck.h - clang-tidy-----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_MOVECONSTRUCTORINITCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_MOVECONSTRUCTORINITCHECK_H
+
+#include "../ClangTidy.h"
+#include "../utils/IncludeInserter.h"
+
+#include <memory>
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// The check flags user-defined move constructors that have a ctor-initializer
+/// initializing a member or base class through a copy constructor instead of a
+/// move constructor.
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/performance-move-constructor-init.html
+class MoveConstructorInitCheck : public ClangTidyCheck {
+public:
+ MoveConstructorInitCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void registerPPCallbacks(clang::CompilerInstance &Compiler) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ std::unique_ptr<utils::IncludeInserter> Inserter;
+ const utils::IncludeSorter::IncludeStyle IncludeStyle;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_MOVECONSTRUCTORINITCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
new file mode 100644
index 0000000..111f24d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
@@ -0,0 +1,72 @@
+//===--- NoexceptMoveConstructorCheck.cpp - clang-tidy---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NoexceptMoveConstructorCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++11; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ Finder->addMatcher(
+ cxxMethodDecl(anyOf(cxxConstructorDecl(), hasOverloadedOperatorName("=")),
+ unless(isImplicit()), unless(isDeleted()))
+ .bind("decl"),
+ this);
+}
+
+void NoexceptMoveConstructorCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ if (const auto *Decl = Result.Nodes.getNodeAs<CXXMethodDecl>("decl")) {
+ StringRef MethodType = "assignment operator";
+ if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Decl)) {
+ if (!Ctor->isMoveConstructor())
+ return;
+ MethodType = "constructor";
+ } else if (!Decl->isMoveAssignmentOperator()) {
+ return;
+ }
+
+ const auto *ProtoType = Decl->getType()->getAs<FunctionProtoType>();
+
+ if (isUnresolvedExceptionSpec(ProtoType->getExceptionSpecType()))
+ return;
+
+ if (!isNoexceptExceptionSpec(ProtoType->getExceptionSpecType())) {
+ diag(Decl->getLocation(), "move %0s should be marked noexcept")
+ << MethodType;
+ // FIXME: Add a fixit.
+ return;
+ }
+
+ // Don't complain about nothrow(false), but complain on nothrow(expr)
+ // where expr evaluates to false.
+ if (ProtoType->canThrow() == CT_Can) {
+ Expr *E = ProtoType->getNoexceptExpr();
+ if (!isa<CXXBoolLiteralExpr>(ProtoType->getNoexceptExpr())) {
+ diag(E->getExprLoc(),
+ "noexcept specifier on the move %0 evaluates to 'false'")
+ << MethodType;
+ }
+ }
+ }
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h
new file mode 100644
index 0000000..9687ab1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h
@@ -0,0 +1,38 @@
+//===--- NoexceptMoveConstructorCheck.h - clang-tidy-------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTMOVECONSTRUCTORCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTMOVECONSTRUCTORCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// The check flags user-defined move constructors and assignment operators not
+/// marked with `noexcept` or marked with `noexcept(expr)` where `expr`
+/// evaluates to `false` (but is not a `false` literal itself).
+///
+/// Move constructors of all the types used with STL containers, for example,
+/// need to be declared `noexcept`. Otherwise STL will choose copy constructors
+/// instead. The same is valid for move assignment operations.
+class NoexceptMoveConstructorCheck : public ClangTidyCheck {
+public:
+ NoexceptMoveConstructorCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTMOVECONSTRUCTORCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
new file mode 100644
index 0000000..646c659
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
@@ -0,0 +1,71 @@
+//===--- PeformanceTidyModule.cpp - clang-tidy ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "FasterStringFindCheck.h"
+#include "ForRangeCopyCheck.h"
+#include "ImplicitConversionInLoopCheck.h"
+#include "InefficientAlgorithmCheck.h"
+#include "InefficientStringConcatenationCheck.h"
+#include "InefficientVectorOperationCheck.h"
+#include "MoveConstArgCheck.h"
+#include "MoveConstructorInitCheck.h"
+#include "NoexceptMoveConstructorCheck.h"
+#include "TypePromotionInMathFnCheck.h"
+#include "UnnecessaryCopyInitialization.h"
+#include "UnnecessaryValueParamCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+class PerformanceModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<FasterStringFindCheck>(
+ "performance-faster-string-find");
+ CheckFactories.registerCheck<ForRangeCopyCheck>(
+ "performance-for-range-copy");
+ CheckFactories.registerCheck<ImplicitConversionInLoopCheck>(
+ "performance-implicit-conversion-in-loop");
+ CheckFactories.registerCheck<InefficientAlgorithmCheck>(
+ "performance-inefficient-algorithm");
+ CheckFactories.registerCheck<InefficientStringConcatenationCheck>(
+ "performance-inefficient-string-concatenation");
+ CheckFactories.registerCheck<InefficientVectorOperationCheck>(
+ "performance-inefficient-vector-operation");
+ CheckFactories.registerCheck<MoveConstArgCheck>(
+ "performance-move-const-arg");
+ CheckFactories.registerCheck<MoveConstructorInitCheck>(
+ "performance-move-constructor-init");
+ CheckFactories.registerCheck<NoexceptMoveConstructorCheck>(
+ "performance-noexcept-move-constructor");
+ CheckFactories.registerCheck<TypePromotionInMathFnCheck>(
+ "performance-type-promotion-in-math-fn");
+ CheckFactories.registerCheck<UnnecessaryCopyInitialization>(
+ "performance-unnecessary-copy-initialization");
+ CheckFactories.registerCheck<UnnecessaryValueParamCheck>(
+ "performance-unnecessary-value-param");
+ }
+};
+
+// Register the PerformanceModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<PerformanceModule>
+ X("performance-module", "Adds performance checks.");
+
+} // namespace performance
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the PerformanceModule.
+volatile int PerformanceModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/TypePromotionInMathFnCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/TypePromotionInMathFnCheck.cpp
new file mode 100644
index 0000000..441bad3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/TypePromotionInMathFnCheck.cpp
@@ -0,0 +1,205 @@
+//===--- TypePromotionInMathFnCheck.cpp - clang-tidy-----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TypePromotionInMathFnCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/StringSet.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+namespace {
+AST_MATCHER_P(Type, isBuiltinType, BuiltinType::Kind, Kind) {
+ if (const auto *BT = dyn_cast<BuiltinType>(&Node)) {
+ return BT->getKind() == Kind;
+ }
+ return false;
+}
+} // anonymous namespace
+
+TypePromotionInMathFnCheck::TypePromotionInMathFnCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
+ Options.getLocalOrGlobal("IncludeStyle", "llvm"))) {}
+
+void TypePromotionInMathFnCheck::registerPPCallbacks(
+ CompilerInstance &Compiler) {
+ IncludeInserter = llvm::make_unique<utils::IncludeInserter>(
+ Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle);
+ Compiler.getPreprocessor().addPPCallbacks(
+ IncludeInserter->CreatePPCallbacks());
+}
+
+void TypePromotionInMathFnCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IncludeStyle",
+ utils::IncludeSorter::toString(IncludeStyle));
+}
+
+void TypePromotionInMathFnCheck::registerMatchers(MatchFinder *Finder) {
+ constexpr BuiltinType::Kind IntTy = BuiltinType::Int;
+ constexpr BuiltinType::Kind LongTy = BuiltinType::Long;
+ constexpr BuiltinType::Kind FloatTy = BuiltinType::Float;
+ constexpr BuiltinType::Kind DoubleTy = BuiltinType::Double;
+ constexpr BuiltinType::Kind LongDoubleTy = BuiltinType::LongDouble;
+
+ auto hasBuiltinTyParam = [](int Pos, BuiltinType::Kind Kind) {
+ return hasParameter(Pos, hasType(isBuiltinType(Kind)));
+ };
+ auto hasBuiltinTyArg = [](int Pos, BuiltinType::Kind Kind) {
+ return hasArgument(Pos, hasType(isBuiltinType(Kind)));
+ };
+
+ // Match calls to foo(double) with a float argument.
+ auto OneDoubleArgFns = hasAnyName(
+ "::acos", "::acosh", "::asin", "::asinh", "::atan", "::atanh", "::cbrt",
+ "::ceil", "::cos", "::cosh", "::erf", "::erfc", "::exp", "::exp2",
+ "::expm1", "::fabs", "::floor", "::ilogb", "::lgamma", "::llrint",
+ "::log", "::log10", "::log1p", "::log2", "::logb", "::lrint", "::modf",
+ "::nearbyint", "::rint", "::round", "::sin", "::sinh", "::sqrt", "::tan",
+ "::tanh", "::tgamma", "::trunc", "::llround", "::lround");
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(OneDoubleArgFns, parameterCountIs(1),
+ hasBuiltinTyParam(0, DoubleTy))),
+ hasBuiltinTyArg(0, FloatTy))
+ .bind("call"),
+ this);
+
+ // Match calls to foo(double, double) where both args are floats.
+ auto TwoDoubleArgFns = hasAnyName("::atan2", "::copysign", "::fdim", "::fmax",
+ "::fmin", "::fmod", "::hypot", "::ldexp",
+ "::nextafter", "::pow", "::remainder");
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(TwoDoubleArgFns, parameterCountIs(2),
+ hasBuiltinTyParam(0, DoubleTy),
+ hasBuiltinTyParam(1, DoubleTy))),
+ hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy))
+ .bind("call"),
+ this);
+
+ // Match calls to fma(double, double, double) where all args are floats.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasName("::fma"), parameterCountIs(3),
+ hasBuiltinTyParam(0, DoubleTy),
+ hasBuiltinTyParam(1, DoubleTy),
+ hasBuiltinTyParam(2, DoubleTy))),
+ hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy),
+ hasBuiltinTyArg(2, FloatTy))
+ .bind("call"),
+ this);
+
+ // Match calls to frexp(double, int*) where the first arg is a float.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(
+ hasName("::frexp"), parameterCountIs(2),
+ hasBuiltinTyParam(0, DoubleTy),
+ hasParameter(1, parmVarDecl(hasType(pointerType(
+ pointee(isBuiltinType(IntTy)))))))),
+ hasBuiltinTyArg(0, FloatTy))
+ .bind("call"),
+ this);
+
+ // Match calls to nexttoward(double, long double) where the first arg is a
+ // float.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasName("::nexttoward"), parameterCountIs(2),
+ hasBuiltinTyParam(0, DoubleTy),
+ hasBuiltinTyParam(1, LongDoubleTy))),
+ hasBuiltinTyArg(0, FloatTy))
+ .bind("call"),
+ this);
+
+ // Match calls to remquo(double, double, int*) where the first two args are
+ // floats.
+ Finder->addMatcher(
+ callExpr(
+ callee(functionDecl(
+ hasName("::remquo"), parameterCountIs(3),
+ hasBuiltinTyParam(0, DoubleTy), hasBuiltinTyParam(1, DoubleTy),
+ hasParameter(2, parmVarDecl(hasType(pointerType(
+ pointee(isBuiltinType(IntTy)))))))),
+ hasBuiltinTyArg(0, FloatTy), hasBuiltinTyArg(1, FloatTy))
+ .bind("call"),
+ this);
+
+ // Match calls to scalbln(double, long) where the first arg is a float.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasName("::scalbln"), parameterCountIs(2),
+ hasBuiltinTyParam(0, DoubleTy),
+ hasBuiltinTyParam(1, LongTy))),
+ hasBuiltinTyArg(0, FloatTy))
+ .bind("call"),
+ this);
+
+ // Match calls to scalbn(double, int) where the first arg is a float.
+ Finder->addMatcher(
+ callExpr(callee(functionDecl(hasName("::scalbn"), parameterCountIs(2),
+ hasBuiltinTyParam(0, DoubleTy),
+ hasBuiltinTyParam(1, IntTy))),
+ hasBuiltinTyArg(0, FloatTy))
+ .bind("call"),
+ this);
+
+ // modf(double, double*) is omitted because the second parameter forces the
+ // type -- there's no conversion from float* to double*.
+}
+
+void TypePromotionInMathFnCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+ assert(Call != nullptr);
+
+ StringRef OldFnName = Call->getDirectCallee()->getName();
+
+ // In C++ mode, we prefer std::foo to ::foof. But some of these suggestions
+ // are only valid in C++11 and newer.
+ static llvm::StringSet<> Cpp11OnlyFns = {
+ "acosh", "asinh", "atanh", "cbrt", "copysign", "erf",
+ "erfc", "exp2", "expm1", "fdim", "fma", "fmax",
+ "fmin", "hypot", "ilogb", "lgamma", "llrint", "llround",
+ "log1p", "log2", "logb", "lrint", "lround", "nearbyint",
+ "nextafter", "nexttoward", "remainder", "remquo", "rint", "round",
+ "scalbln", "scalbn", "tgamma", "trunc"};
+ bool StdFnRequiresCpp11 = Cpp11OnlyFns.count(OldFnName);
+
+ std::string NewFnName;
+ bool FnInCmath = false;
+ if (getLangOpts().CPlusPlus &&
+ (!StdFnRequiresCpp11 || getLangOpts().CPlusPlus11)) {
+ NewFnName = ("std::" + OldFnName).str();
+ FnInCmath = true;
+ } else {
+ NewFnName = (OldFnName + "f").str();
+ }
+
+ auto Diag = diag(Call->getExprLoc(), "call to '%0' promotes float to double")
+ << OldFnName
+ << FixItHint::CreateReplacement(
+ Call->getCallee()->getSourceRange(), NewFnName);
+
+ // Suggest including <cmath> if the function we're suggesting is declared in
+ // <cmath> and it's not already included. We never have to suggest including
+ // <math.h>, because the functions we're suggesting moving away from are all
+ // declared in <math.h>.
+ if (FnInCmath)
+ if (auto IncludeFixit = IncludeInserter->CreateIncludeInsertion(
+ Result.Context->getSourceManager().getFileID(Call->getLocStart()),
+ "cmath", /*IsAngled=*/true))
+ Diag << *IncludeFixit;
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/TypePromotionInMathFnCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/TypePromotionInMathFnCheck.h
new file mode 100644
index 0000000..2242957
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/TypePromotionInMathFnCheck.h
@@ -0,0 +1,47 @@
+//===--- TypePromotionInMathFnCheck.h - clang-tidy---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_TYPE_PROMOTION_IN_MATH_FN_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_TYPE_PROMOTION_IN_MATH_FN_H
+
+#include "../ClangTidy.h"
+#include "../utils/IncludeInserter.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// Finds calls to C math library functions with implicit float to double
+/// promotions.
+///
+/// For example, warns on ::sin(0.f), because this funciton's parameter is a
+/// double. You probably meant to call std::sin(0.f) (in C++), or sinf(0.f) (in
+/// C).
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/performance-type-promotion-in-math-fn.html
+class TypePromotionInMathFnCheck : public ClangTidyCheck {
+public:
+ TypePromotionInMathFnCheck(StringRef Name, ClangTidyContext *Context);
+
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ std::unique_ptr<utils::IncludeInserter> IncludeInserter;
+ const utils::IncludeSorter::IncludeStyle IncludeStyle;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_TYPE_PROMOTION_IN_MATH_FN_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
new file mode 100644
index 0000000..177497c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp
@@ -0,0 +1,149 @@
+//===--- UnnecessaryCopyInitialization.cpp - clang-tidy--------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnnecessaryCopyInitialization.h"
+
+#include "../utils/DeclRefExprUtils.h"
+#include "../utils/FixItHintUtils.h"
+#include "../utils/Matchers.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+namespace {
+
+void recordFixes(const VarDecl &Var, ASTContext &Context,
+ DiagnosticBuilder &Diagnostic) {
+ Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context);
+ if (!Var.getType().isLocalConstQualified())
+ Diagnostic << utils::fixit::changeVarDeclToConst(Var);
+}
+
+} // namespace
+
+using namespace ::clang::ast_matchers;
+using utils::decl_ref_expr::isOnlyUsedAsConst;
+
+void UnnecessaryCopyInitialization::registerMatchers(MatchFinder *Finder) {
+ auto ConstReference = referenceType(pointee(qualType(isConstQualified())));
+ auto ConstOrConstReference =
+ allOf(anyOf(ConstReference, isConstQualified()),
+ unless(allOf(pointerType(), unless(pointerType(pointee(
+ qualType(isConstQualified())))))));
+
+ // Match method call expressions where the `this` argument is only used as
+ // const, this will be checked in `check()` part. This returned const
+ // reference is highly likely to outlive the local const reference of the
+ // variable being declared. The assumption is that the const reference being
+ // returned either points to a global static variable or to a member of the
+ // called object.
+ auto ConstRefReturningMethodCall =
+ cxxMemberCallExpr(callee(cxxMethodDecl(returns(ConstReference))),
+ on(declRefExpr(to(varDecl().bind("objectArg")))));
+ auto ConstRefReturningFunctionCall =
+ callExpr(callee(functionDecl(returns(ConstReference))),
+ unless(callee(cxxMethodDecl())));
+
+ auto localVarCopiedFrom = [](const internal::Matcher<Expr> &CopyCtorArg) {
+ return compoundStmt(
+ forEachDescendant(
+ declStmt(
+ has(varDecl(hasLocalStorage(),
+ hasType(matchers::isExpensiveToCopy()),
+ unless(isImplicit()),
+ hasInitializer(
+ cxxConstructExpr(
+ hasDeclaration(cxxConstructorDecl(
+ isCopyConstructor())),
+ hasArgument(0, CopyCtorArg))
+ .bind("ctorCall")))
+ .bind("newVarDecl")))
+ .bind("declStmt")))
+ .bind("blockStmt");
+ };
+
+ Finder->addMatcher(localVarCopiedFrom(anyOf(ConstRefReturningFunctionCall,
+ ConstRefReturningMethodCall)),
+ this);
+
+ Finder->addMatcher(localVarCopiedFrom(declRefExpr(
+ to(varDecl(hasLocalStorage()).bind("oldVarDecl")))),
+ this);
+}
+
+void UnnecessaryCopyInitialization::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *NewVar = Result.Nodes.getNodeAs<VarDecl>("newVarDecl");
+ const auto *OldVar = Result.Nodes.getNodeAs<VarDecl>("oldVarDecl");
+ const auto *ObjectArg = Result.Nodes.getNodeAs<VarDecl>("objectArg");
+ const auto *BlockStmt = Result.Nodes.getNodeAs<Stmt>("blockStmt");
+ const auto *CtorCall = Result.Nodes.getNodeAs<CXXConstructExpr>("ctorCall");
+ // Do not propose fixes if the DeclStmt has multiple VarDecls or in macros
+ // since we cannot place them correctly.
+ bool IssueFix =
+ Result.Nodes.getNodeAs<DeclStmt>("declStmt")->isSingleDecl() &&
+ !NewVar->getLocation().isMacroID();
+
+ // A constructor that looks like T(const T& t, bool arg = false) counts as a
+ // copy only when it is called with default arguments for the arguments after
+ // the first.
+ for (unsigned int i = 1; i < CtorCall->getNumArgs(); ++i)
+ if (!CtorCall->getArg(i)->isDefaultArgument())
+ return;
+
+ if (OldVar == nullptr) {
+ handleCopyFromMethodReturn(*NewVar, *BlockStmt, IssueFix, ObjectArg,
+ *Result.Context);
+ } else {
+ handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, IssueFix,
+ *Result.Context);
+ }
+}
+
+void UnnecessaryCopyInitialization::handleCopyFromMethodReturn(
+ const VarDecl &Var, const Stmt &BlockStmt, bool IssueFix,
+ const VarDecl *ObjectArg, ASTContext &Context) {
+ bool IsConstQualified = Var.getType().isConstQualified();
+ if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context))
+ return;
+ if (ObjectArg != nullptr &&
+ !isOnlyUsedAsConst(*ObjectArg, BlockStmt, Context))
+ return;
+
+ auto Diagnostic =
+ diag(Var.getLocation(),
+ IsConstQualified ? "the const qualified variable %0 is "
+ "copy-constructed from a const reference; "
+ "consider making it a const reference"
+ : "the variable %0 is copy-constructed from a "
+ "const reference but is only used as const "
+ "reference; consider making it a const reference")
+ << &Var;
+ if (IssueFix)
+ recordFixes(Var, Context, Diagnostic);
+}
+
+void UnnecessaryCopyInitialization::handleCopyFromLocalVar(
+ const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt,
+ bool IssueFix, ASTContext &Context) {
+ if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) ||
+ !isOnlyUsedAsConst(OldVar, BlockStmt, Context))
+ return;
+
+ auto Diagnostic = diag(NewVar.getLocation(),
+ "local copy %0 of the variable %1 is never modified; "
+ "consider avoiding the copy")
+ << &NewVar << &OldVar;
+ if (IssueFix)
+ recordFixes(NewVar, Context, Diagnostic);
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
new file mode 100644
index 0000000..8ed4142
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.h
@@ -0,0 +1,47 @@
+//===--- UnnecessaryCopyInitialization.h - clang-tidy------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_UNNECESSARY_COPY_INITIALIZATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_UNNECESSARY_COPY_INITIALIZATION_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+// The check detects local variable declarations that are copy initialized with
+// the const reference of a function call or the const reference of a method
+// call whose object is guaranteed to outlive the variable's scope and suggests
+// to use a const reference.
+//
+// The check currently only understands a subset of variables that are
+// guaranteed to outlive the const reference returned, namely: const variables,
+// const references, and const pointers to const.
+class UnnecessaryCopyInitialization : public ClangTidyCheck {
+public:
+ UnnecessaryCopyInitialization(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt,
+ bool IssueFix, const VarDecl *ObjectArg,
+ ASTContext &Context);
+ void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar,
+ const Stmt &BlockStmt, bool IssueFix,
+ ASTContext &Context);
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_UNNECESSARY_COPY_INITIALIZATION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
new file mode 100644
index 0000000..e277ad3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
@@ -0,0 +1,207 @@
+//===--- UnnecessaryValueParamCheck.cpp - clang-tidy-----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnnecessaryValueParamCheck.h"
+
+#include "../utils/DeclRefExprUtils.h"
+#include "../utils/FixItHintUtils.h"
+#include "../utils/Matchers.h"
+#include "../utils/TypeTraits.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+namespace {
+
+std::string paramNameOrIndex(StringRef Name, size_t Index) {
+ return (Name.empty() ? llvm::Twine('#') + llvm::Twine(Index + 1)
+ : llvm::Twine('\'') + Name + llvm::Twine('\''))
+ .str();
+}
+
+template <typename S>
+bool isSubset(const S &SubsetCandidate, const S &SupersetCandidate) {
+ for (const auto &E : SubsetCandidate)
+ if (SupersetCandidate.count(E) == 0)
+ return false;
+ return true;
+}
+
+bool isReferencedOutsideOfCallExpr(const FunctionDecl &Function,
+ ASTContext &Context) {
+ auto Matches = match(declRefExpr(to(functionDecl(equalsNode(&Function))),
+ unless(hasAncestor(callExpr()))),
+ Context);
+ return !Matches.empty();
+}
+
+bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl,
+ ASTContext &Context) {
+ auto Matches =
+ match(decl(forEachDescendant(declRefExpr(
+ equalsNode(&DeclRef),
+ unless(hasAncestor(stmt(anyOf(forStmt(), cxxForRangeStmt(),
+ whileStmt(), doStmt()))))))),
+ Decl, Context);
+ return Matches.empty();
+}
+
+bool isExplicitTemplateSpecialization(const FunctionDecl &Function) {
+ if (const auto *SpecializationInfo = Function.getTemplateSpecializationInfo())
+ if (SpecializationInfo->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization)
+ return true;
+ if (const auto *Method = llvm::dyn_cast<CXXMethodDecl>(&Function))
+ if (Method->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization &&
+ Method->getMemberSpecializationInfo()->isExplicitSpecialization())
+ return true;
+ return false;
+}
+
+} // namespace
+
+UnnecessaryValueParamCheck::UnnecessaryValueParamCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
+ Options.getLocalOrGlobal("IncludeStyle", "llvm"))) {}
+
+void UnnecessaryValueParamCheck::registerMatchers(MatchFinder *Finder) {
+ // This check is specific to C++ and doesn't apply to languages like
+ // Objective-C.
+ if (!getLangOpts().CPlusPlus)
+ return;
+ const auto ExpensiveValueParamDecl =
+ parmVarDecl(hasType(hasCanonicalType(allOf(
+ unless(referenceType()), matchers::isExpensiveToCopy()))),
+ decl().bind("param"));
+ Finder->addMatcher(
+ functionDecl(hasBody(stmt()), isDefinition(), unless(isImplicit()),
+ unless(cxxMethodDecl(anyOf(isOverride(), isFinal()))),
+ has(typeLoc(forEach(ExpensiveValueParamDecl))),
+ unless(isInstantiated()), decl().bind("functionDecl")),
+ this);
+}
+
+void UnnecessaryValueParamCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Param = Result.Nodes.getNodeAs<ParmVarDecl>("param");
+ const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>("functionDecl");
+ const size_t Index = std::find(Function->parameters().begin(),
+ Function->parameters().end(), Param) -
+ Function->parameters().begin();
+ bool IsConstQualified =
+ Param->getType().getCanonicalType().isConstQualified();
+
+ auto AllDeclRefExprs = utils::decl_ref_expr::allDeclRefExprs(
+ *Param, *Function, *Result.Context);
+ auto ConstDeclRefExprs = utils::decl_ref_expr::constReferenceDeclRefExprs(
+ *Param, *Function, *Result.Context);
+
+ // Do not trigger on non-const value parameters when they are not only used as
+ // const.
+ if (!isSubset(AllDeclRefExprs, ConstDeclRefExprs))
+ return;
+
+ // If the parameter is non-const, check if it has a move constructor and is
+ // only referenced once to copy-construct another object or whether it has a
+ // move assignment operator and is only referenced once when copy-assigned.
+ // In this case wrap DeclRefExpr with std::move() to avoid the unnecessary
+ // copy.
+ if (!IsConstQualified && AllDeclRefExprs.size() == 1) {
+ auto CanonicalType = Param->getType().getCanonicalType();
+ const auto &DeclRefExpr = **AllDeclRefExprs.begin();
+
+ if (!hasLoopStmtAncestor(DeclRefExpr, *Function, *Result.Context) &&
+ ((utils::type_traits::hasNonTrivialMoveConstructor(CanonicalType) &&
+ utils::decl_ref_expr::isCopyConstructorArgument(
+ DeclRefExpr, *Function, *Result.Context)) ||
+ (utils::type_traits::hasNonTrivialMoveAssignment(CanonicalType) &&
+ utils::decl_ref_expr::isCopyAssignmentArgument(
+ DeclRefExpr, *Function, *Result.Context)))) {
+ handleMoveFix(*Param, DeclRefExpr, *Result.Context);
+ return;
+ }
+ }
+
+ auto Diag =
+ diag(Param->getLocation(),
+ IsConstQualified ? "the const qualified parameter %0 is "
+ "copied for each invocation; consider "
+ "making it a reference"
+ : "the parameter %0 is copied for each "
+ "invocation but only used as a const reference; "
+ "consider making it a const reference")
+ << paramNameOrIndex(Param->getName(), Index);
+ // Do not propose fixes when:
+ // 1. the ParmVarDecl is in a macro, since we cannot place them correctly
+ // 2. the function is virtual as it might break overrides
+ // 3. the function is referenced outside of a call expression within the
+ // compilation unit as the signature change could introduce build errors.
+ // 4. the function is an explicit template specialization.
+ const auto *Method = llvm::dyn_cast<CXXMethodDecl>(Function);
+ if (Param->getLocStart().isMacroID() || (Method && Method->isVirtual()) ||
+ isReferencedOutsideOfCallExpr(*Function, *Result.Context) ||
+ isExplicitTemplateSpecialization(*Function))
+ return;
+ for (const auto *FunctionDecl = Function; FunctionDecl != nullptr;
+ FunctionDecl = FunctionDecl->getPreviousDecl()) {
+ const auto &CurrentParam = *FunctionDecl->getParamDecl(Index);
+ Diag << utils::fixit::changeVarDeclToReference(CurrentParam,
+ *Result.Context);
+ // The parameter of each declaration needs to be checked individually as to
+ // whether it is const or not as constness can differ between definition and
+ // declaration.
+ if (!CurrentParam.getType().getCanonicalType().isConstQualified())
+ Diag << utils::fixit::changeVarDeclToConst(CurrentParam);
+ }
+}
+
+void UnnecessaryValueParamCheck::registerPPCallbacks(
+ CompilerInstance &Compiler) {
+ Inserter.reset(new utils::IncludeInserter(
+ Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle));
+ Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
+}
+
+void UnnecessaryValueParamCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IncludeStyle",
+ utils::IncludeSorter::toString(IncludeStyle));
+}
+
+void UnnecessaryValueParamCheck::handleMoveFix(const ParmVarDecl &Var,
+ const DeclRefExpr &CopyArgument,
+ const ASTContext &Context) {
+ auto Diag = diag(CopyArgument.getLocStart(),
+ "parameter %0 is passed by value and only copied once; "
+ "consider moving it to avoid unnecessary copies")
+ << &Var;
+ // Do not propose fixes in macros since we cannot place them correctly.
+ if (CopyArgument.getLocStart().isMacroID())
+ return;
+ const auto &SM = Context.getSourceManager();
+ auto EndLoc = Lexer::getLocForEndOfToken(CopyArgument.getLocation(), 0, SM,
+ Context.getLangOpts());
+ Diag << FixItHint::CreateInsertion(CopyArgument.getLocStart(), "std::move(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
+ if (auto IncludeFixit = Inserter->CreateIncludeInsertion(
+ SM.getFileID(CopyArgument.getLocStart()), "utility",
+ /*IsAngled=*/true))
+ Diag << *IncludeFixit;
+}
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
new file mode 100644
index 0000000..cbf0a3b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
@@ -0,0 +1,45 @@
+//===--- UnnecessaryValueParamCheck.h - clang-tidy---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_UNNECESSARY_VALUE_PARAM_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_UNNECESSARY_VALUE_PARAM_H
+
+#include "../ClangTidy.h"
+#include "../utils/IncludeInserter.h"
+
+namespace clang {
+namespace tidy {
+namespace performance {
+
+/// \brief A check that flags value parameters of expensive to copy types that
+/// can safely be converted to const references.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/performance-unnecessary-value-param.html
+class UnnecessaryValueParamCheck : public ClangTidyCheck {
+public:
+ UnnecessaryValueParamCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+ void handleMoveFix(const ParmVarDecl &Var, const DeclRefExpr &CopyArgument,
+ const ASTContext &Context);
+
+ std::unique_ptr<utils::IncludeInserter> Inserter;
+ const utils::IncludeSorter::IncludeStyle IncludeStyle;
+};
+
+} // namespace performance
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_UNNECESSARY_VALUE_PARAM_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/plugin/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/plugin/CMakeLists.txt
new file mode 100644
index 0000000..3540b2b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/plugin/CMakeLists.txt
@@ -0,0 +1,30 @@
+add_clang_library(clangTidyPlugin
+ ClangTidyPlugin.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFrontend
+ clangSema
+ clangTidy
+ clangTidyAbseilModule
+ clangTidyAndroidModule
+ clangTidyBoostModule
+ clangTidyBugproneModule
+ clangTidyCERTModule
+ clangTidyCppCoreGuidelinesModule
+ clangTidyFuchsiaModule
+ clangTidyGoogleModule
+ clangTidyHICPPModule
+ clangTidyLLVMModule
+ clangTidyMiscModule
+ clangTidyModernizeModule
+ clangTidyMPIModule
+ clangTidyObjCModule
+ clangTidyPerformanceModule
+ clangTidyPortabilityModule
+ clangTidyReadabilityModule
+ clangTidyZirconModule
+ clangTooling
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp
new file mode 100644
index 0000000..3455612
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp
@@ -0,0 +1,167 @@
+//===- ClangTidyPlugin.cpp - clang-tidy as a clang plugin -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Frontend/MultiplexConsumer.h"
+
+namespace clang {
+namespace tidy {
+
+/// The core clang tidy plugin action. This just provides the AST consumer and
+/// command line flag parsing for using clang-tidy as a clang plugin.
+class ClangTidyPluginAction : public PluginASTAction {
+ /// Wrapper to grant the context the same lifetime as the action. We use
+ /// MultiplexConsumer to avoid writing out all the forwarding methods.
+ class WrapConsumer : public MultiplexConsumer {
+ std::unique_ptr<ClangTidyContext> Context;
+
+ public:
+ WrapConsumer(std::unique_ptr<ClangTidyContext> Context,
+ std::vector<std::unique_ptr<ASTConsumer>> Consumer)
+ : MultiplexConsumer(std::move(Consumer)), Context(std::move(Context)) {}
+ };
+
+public:
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef File) override {
+ // Insert the current diagnostics engine.
+ Context->setDiagnosticsEngine(&Compiler.getDiagnostics());
+
+ // Create the AST consumer.
+ ClangTidyASTConsumerFactory Factory(*Context);
+ std::vector<std::unique_ptr<ASTConsumer>> Vec;
+ Vec.push_back(Factory.CreateASTConsumer(Compiler, File));
+
+ return llvm::make_unique<WrapConsumer>(std::move(Context), std::move(Vec));
+ }
+
+ bool ParseArgs(const CompilerInstance &,
+ const std::vector<std::string> &Args) override {
+ ClangTidyGlobalOptions GlobalOptions;
+ ClangTidyOptions DefaultOptions;
+ ClangTidyOptions OverrideOptions;
+
+ // Parse the extra command line args.
+ // FIXME: This is very limited at the moment.
+ for (StringRef Arg : Args)
+ if (Arg.startswith("-checks="))
+ OverrideOptions.Checks = Arg.substr(strlen("-checks="));
+
+ auto Options = llvm::make_unique<FileOptionsProvider>(
+ GlobalOptions, DefaultOptions, OverrideOptions);
+ Context = llvm::make_unique<ClangTidyContext>(std::move(Options));
+ return true;
+ }
+
+private:
+ std::unique_ptr<ClangTidyContext> Context;
+};
+} // namespace tidy
+} // namespace clang
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the clang-tidy plugin.
+volatile int ClangTidyPluginAnchorSource = 0;
+
+static clang::FrontendPluginRegistry::Add<clang::tidy::ClangTidyPluginAction>
+ X("clang-tidy", "clang-tidy");
+
+namespace clang {
+namespace tidy {
+
+// This anchor is used to force the linker to link the AbseilModule.
+extern volatile int AbseilModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED AbseilModuleAnchorDestination =
+ AbseilModuleAnchorSource;
+
+// This anchor is used to force the linker to link the AndroidModule.
+extern volatile int AndroidModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED AndroidModuleAnchorDestination =
+ AndroidModuleAnchorSource;
+
+// This anchor is used to force the linker to link the BoostModule.
+extern volatile int BoostModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED BoostModuleAnchorDestination =
+ BoostModuleAnchorSource;
+
+// This anchor is used to force the linker to link the CERTModule.
+extern volatile int CERTModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED CERTModuleAnchorDestination =
+ CERTModuleAnchorSource;
+
+// This anchor is used to force the linker to link the CppCoreGuidelinesModule.
+extern volatile int CppCoreGuidelinesModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED CppCoreGuidelinesModuleAnchorDestination =
+ CppCoreGuidelinesModuleAnchorSource;
+
+// This anchor is used to force the linker to link the FuchsiaModule.
+extern volatile int FuchsiaModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED FuchsiaModuleAnchorDestination =
+ FuchsiaModuleAnchorSource;
+
+// This anchor is used to force the linker to link the GoogleModule.
+extern volatile int GoogleModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED GoogleModuleAnchorDestination =
+ GoogleModuleAnchorSource;
+
+// This anchor is used to force the linker to link the HICPPModule.
+extern volatile int HICPPModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED HICPPModuleAnchorDestination =
+ HICPPModuleAnchorSource;
+
+// This anchor is used to force the linker to link the LLVMModule.
+extern volatile int LLVMModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED LLVMModuleAnchorDestination =
+ LLVMModuleAnchorSource;
+
+// This anchor is used to force the linker to link the MiscModule.
+extern volatile int MiscModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED MiscModuleAnchorDestination =
+ MiscModuleAnchorSource;
+
+// This anchor is used to force the linker to link the ModernizeModule.
+extern volatile int ModernizeModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED ModernizeModuleAnchorDestination =
+ ModernizeModuleAnchorSource;
+
+// This anchor is used to force the linker to link the MPIModule.
+extern volatile int MPIModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED MPIModuleAnchorDestination =
+ MPIModuleAnchorSource;
+
+// This anchor is used to force the linker to link the ObjCModule.
+extern volatile int ObjCModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED ObjCModuleAnchorDestination =
+ ObjCModuleAnchorSource;
+
+// This anchor is used to force the linker to link the PerformanceModule.
+extern volatile int PerformanceModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED PerformanceModuleAnchorDestination =
+ PerformanceModuleAnchorSource;
+
+// This anchor is used to force the linker to link the PortabilityModule.
+extern volatile int PortabilityModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED PortabilityModuleAnchorDestination =
+ PortabilityModuleAnchorSource;
+
+// This anchor is used to force the linker to link the ReadabilityModule.
+extern volatile int ReadabilityModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED ReadabilityModuleAnchorDestination =
+ ReadabilityModuleAnchorSource;
+
+// This anchor is used to force the linker to link the ZirconModule.
+extern volatile int ZirconModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED ZirconModuleAnchorDestination =
+ ZirconModuleAnchorSource;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/portability/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/portability/CMakeLists.txt
new file mode 100644
index 0000000..0420a18
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/portability/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyPortabilityModule
+ PortabilityTidyModule.cpp
+ SIMDIntrinsicsCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyUtils
+ clangTooling
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp
new file mode 100644
index 0000000..013cbcf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp
@@ -0,0 +1,38 @@
+//===--- PortabilityTidyModule.cpp - clang-tidy ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "SIMDIntrinsicsCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace portability {
+
+class PortabilityModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<SIMDIntrinsicsCheck>(
+ "portability-simd-intrinsics");
+ }
+};
+
+// Register the PortabilityModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<PortabilityModule>
+ X("portability-module", "Adds portability-related checks.");
+
+} // namespace portability
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the PortabilityModule.
+volatile int PortabilityModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/portability/SIMDIntrinsicsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/portability/SIMDIntrinsicsCheck.cpp
new file mode 100644
index 0000000..d5434cc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/portability/SIMDIntrinsicsCheck.cpp
@@ -0,0 +1,160 @@
+//===--- SIMDIntrinsicsCheck.cpp - clang-tidy------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SIMDIntrinsicsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Regex.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace portability {
+
+namespace {
+
+// If the callee has parameter of VectorType or pointer to VectorType,
+// or the return type is VectorType, we consider it a vector function
+// and a candidate for checking.
+AST_MATCHER(FunctionDecl, isVectorFunction) {
+ bool IsVector = Node.getReturnType()->isVectorType();
+ for (const ParmVarDecl *Parm : Node.parameters()) {
+ QualType Type = Parm->getType();
+ if (Type->isPointerType())
+ Type = Type->getPointeeType();
+ if (Type->isVectorType())
+ IsVector = true;
+ }
+ return IsVector;
+}
+
+} // namespace
+
+static StringRef TrySuggestPPC(StringRef Name) {
+ if (!Name.consume_front("vec_"))
+ return {};
+
+ static const llvm::StringMap<StringRef> Mapping{
+ // [simd.alg]
+ {"max", "$std::max"},
+ {"min", "$std::min"},
+
+ // [simd.binary]
+ {"add", "operator+ on $simd objects"},
+ {"sub", "operator- on $simd objects"},
+ {"mul", "operator* on $simd objects"},
+ };
+
+ auto It = Mapping.find(Name);
+ if (It != Mapping.end())
+ return It->second;
+ return {};
+}
+
+static StringRef TrySuggestX86(StringRef Name) {
+ if (!(Name.consume_front("_mm_") || Name.consume_front("_mm256_") ||
+ Name.consume_front("_mm512_")))
+ return {};
+
+ // [simd.alg]
+ if (Name.startswith("max_"))
+ return "$simd::max";
+ if (Name.startswith("min_"))
+ return "$simd::min";
+
+ // [simd.binary]
+ if (Name.startswith("add_"))
+ return "operator+ on $simd objects";
+ if (Name.startswith("sub_"))
+ return "operator- on $simd objects";
+ if (Name.startswith("mul_"))
+ return "operator* on $simd objects";
+
+ return {};
+}
+
+SIMDIntrinsicsCheck::SIMDIntrinsicsCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context), Std(Options.get("Std", "")),
+ Suggest(Options.get("Suggest", 0) != 0) {}
+
+void SIMDIntrinsicsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "Std", "");
+ Options.store(Opts, "Suggest", 0);
+}
+
+void SIMDIntrinsicsCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus11)
+ return;
+ // If Std is not specified, infer it from the language options.
+ // libcxx implementation backports it to C++11 std::experimental::simd.
+ if (Std.empty())
+ Std = getLangOpts().CPlusPlus2a ? "std" : "std::experimental";
+
+ Finder->addMatcher(callExpr(callee(functionDecl(allOf(
+ matchesName("^::(_mm_|_mm256_|_mm512_|vec_)"),
+ isVectorFunction()))),
+ unless(isExpansionInSystemHeader()))
+ .bind("call"),
+ this);
+}
+
+void SIMDIntrinsicsCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+ assert(Call != nullptr);
+ const FunctionDecl *Callee = Call->getDirectCallee();
+ if (!Callee)
+ return;
+
+ StringRef Old = Callee->getName();
+ StringRef New;
+ llvm::Triple::ArchType Arch =
+ Result.Context->getTargetInfo().getTriple().getArch();
+
+ // We warn or suggest if this SIMD intrinsic function has a std::simd
+ // replacement.
+ switch (Arch) {
+ default:
+ break;
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ New = TrySuggestPPC(Old);
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ New = TrySuggestX86(Old);
+ break;
+ }
+
+ // We have found a std::simd replacement.
+ if (!New.empty()) {
+ std::string Message;
+ // If Suggest is true, give a P0214 alternative, otherwise point it out it
+ // is non-portable.
+ if (Suggest) {
+ Message = (Twine("'") + Old + "' can be replaced by " + New).str();
+ Message = llvm::Regex("\\$std").sub(Std, Message);
+ Message =
+ llvm::Regex("\\$simd").sub((Std.str() + "::simd").str(), Message);
+ } else {
+ Message = (Twine("'") + Old + "' is a non-portable " +
+ llvm::Triple::getArchTypeName(Arch) + " intrinsic function")
+ .str();
+ }
+ diag(Call->getExprLoc(), Message);
+ }
+}
+
+} // namespace portability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/portability/SIMDIntrinsicsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/portability/SIMDIntrinsicsCheck.h
new file mode 100644
index 0000000..ebcc855
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/portability/SIMDIntrinsicsCheck.h
@@ -0,0 +1,42 @@
+//===--- SIMDIntrinsicsCheck.h - clang-tidy----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SIMD_INTRINSICS_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SIMD_INTRINSICS_CHECK_H
+
+#include "../ClangTidy.h"
+
+#include "llvm/ADT/SmallString.h"
+
+namespace clang {
+namespace tidy {
+namespace portability {
+
+/// Find SIMD intrinsics calls and suggest std::experimental::simd alternatives.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/portability-simd-intrinsics.html
+class SIMDIntrinsicsCheck : public ClangTidyCheck {
+public:
+ SIMDIntrinsicsCheck(StringRef Name, ClangTidyContext *Context);
+
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+ private:
+ llvm::SmallString<32> Std;
+ const bool Suggest;
+};
+
+} // namespace portability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SIMD_INTRINSICS_CHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/AvoidConstParamsInDecls.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/AvoidConstParamsInDecls.cpp
new file mode 100644
index 0000000..70329e8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/AvoidConstParamsInDecls.cpp
@@ -0,0 +1,122 @@
+//===--- AvoidConstParamsInDecls.cpp - clang-tidy--------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AvoidConstParamsInDecls.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/Optional.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+namespace {
+
+SourceRange getTypeRange(const ParmVarDecl &Param) {
+ if (Param.getIdentifier() != nullptr)
+ return SourceRange(Param.getLocStart(),
+ Param.getLocEnd().getLocWithOffset(-1));
+ return Param.getSourceRange();
+}
+
+} // namespace
+
+void AvoidConstParamsInDecls::registerMatchers(MatchFinder *Finder) {
+ const auto ConstParamDecl =
+ parmVarDecl(hasType(qualType(isConstQualified()))).bind("param");
+ Finder->addMatcher(
+ functionDecl(unless(isDefinition()),
+ // Lambdas are always their own definition, but they
+ // generate a non-definition FunctionDecl too. Ignore those.
+ // Class template instantiations have a non-definition
+ // CXXMethodDecl for methods that aren't used in this
+ // translation unit. Ignore those, as the template will have
+ // already been checked.
+ unless(cxxMethodDecl(ofClass(cxxRecordDecl(anyOf(
+ isLambda(), ast_matchers::isTemplateInstantiation()))))),
+ has(typeLoc(forEach(ConstParamDecl))))
+ .bind("func"),
+ this);
+}
+
+// Re-lex the tokens to get precise location of last 'const'
+static llvm::Optional<Token> ConstTok(CharSourceRange Range,
+ const MatchFinder::MatchResult &Result) {
+ const SourceManager &Sources = *Result.SourceManager;
+ std::pair<FileID, unsigned> LocInfo =
+ Sources.getDecomposedLoc(Range.getBegin());
+ StringRef File = Sources.getBufferData(LocInfo.first);
+ const char *TokenBegin = File.data() + LocInfo.second;
+ Lexer RawLexer(Sources.getLocForStartOfFile(LocInfo.first),
+ Result.Context->getLangOpts(), File.begin(), TokenBegin,
+ File.end());
+ Token Tok;
+ llvm::Optional<Token> ConstTok;
+ while (!RawLexer.LexFromRawLexer(Tok)) {
+ if (Sources.isBeforeInTranslationUnit(Range.getEnd(), Tok.getLocation()))
+ break;
+ if (Tok.is(tok::raw_identifier)) {
+ IdentifierInfo &Info = Result.Context->Idents.get(StringRef(
+ Sources.getCharacterData(Tok.getLocation()), Tok.getLength()));
+ Tok.setIdentifierInfo(&Info);
+ Tok.setKind(Info.getTokenID());
+ }
+ if (Tok.is(tok::kw_const))
+ ConstTok = Tok;
+ }
+ return ConstTok;
+}
+
+void AvoidConstParamsInDecls::check(const MatchFinder::MatchResult &Result) {
+ const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
+ const auto *Param = Result.Nodes.getNodeAs<ParmVarDecl>("param");
+
+ if (!Param->getType().isLocalConstQualified())
+ return;
+
+ auto Diag = diag(Param->getLocStart(),
+ "parameter %0 is const-qualified in the function "
+ "declaration; const-qualification of parameters only has an "
+ "effect in function definitions");
+ if (Param->getName().empty()) {
+ for (unsigned int i = 0; i < Func->getNumParams(); ++i) {
+ if (Param == Func->getParamDecl(i)) {
+ Diag << (i + 1);
+ break;
+ }
+ }
+ } else {
+ Diag << Param;
+ }
+
+ if (Param->getLocStart().isMacroID() != Param->getLocEnd().isMacroID()) {
+ // Do not offer a suggestion if the part of the variable declaration comes
+ // from a macro.
+ return;
+ }
+
+ CharSourceRange FileRange = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(getTypeRange(*Param)),
+ *Result.SourceManager, getLangOpts());
+
+ if (!FileRange.isValid())
+ return;
+
+ auto Tok = ConstTok(FileRange, Result);
+ if (!Tok)
+ return;
+ Diag << FixItHint::CreateRemoval(
+ CharSourceRange::getTokenRange(Tok->getLocation(), Tok->getLocation()));
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/AvoidConstParamsInDecls.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/AvoidConstParamsInDecls.h
new file mode 100644
index 0000000..f2d91e8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/AvoidConstParamsInDecls.h
@@ -0,0 +1,34 @@
+//===--- AvoidConstParamsInDecls.h - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOID_CONST_PARAMS_IN_DECLS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOID_CONST_PARAMS_IN_DECLS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+// Detect function declarations that have const value parameters and discourage
+// them.
+class AvoidConstParamsInDecls : public ClangTidyCheck {
+public:
+ AvoidConstParamsInDecls(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOID_CONST_PARAMS_IN_DECLS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp
new file mode 100644
index 0000000..1bff668
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp
@@ -0,0 +1,278 @@
+//===--- BracesAroundStatementsCheck.cpp - clang-tidy ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BracesAroundStatementsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+namespace {
+
+tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM,
+ const ASTContext *Context) {
+ Token Tok;
+ SourceLocation Beginning =
+ Lexer::GetBeginningOfToken(Loc, SM, Context->getLangOpts());
+ const bool Invalid =
+ Lexer::getRawToken(Beginning, Tok, SM, Context->getLangOpts());
+ assert(!Invalid && "Expected a valid token.");
+
+ if (Invalid)
+ return tok::NUM_TOKENS;
+
+ return Tok.getKind();
+}
+
+SourceLocation forwardSkipWhitespaceAndComments(SourceLocation Loc,
+ const SourceManager &SM,
+ const ASTContext *Context) {
+ assert(Loc.isValid());
+ for (;;) {
+ while (isWhitespace(*SM.getCharacterData(Loc)))
+ Loc = Loc.getLocWithOffset(1);
+
+ tok::TokenKind TokKind = getTokenKind(Loc, SM, Context);
+ if (TokKind == tok::NUM_TOKENS || TokKind != tok::comment)
+ return Loc;
+
+ // Fast-forward current token.
+ Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts());
+ }
+}
+
+SourceLocation findEndLocation(SourceLocation LastTokenLoc,
+ const SourceManager &SM,
+ const ASTContext *Context) {
+ SourceLocation Loc =
+ Lexer::GetBeginningOfToken(LastTokenLoc, SM, Context->getLangOpts());
+ // Loc points to the beginning of the last (non-comment non-ws) token
+ // before end or ';'.
+ assert(Loc.isValid());
+ bool SkipEndWhitespaceAndComments = true;
+ tok::TokenKind TokKind = getTokenKind(Loc, SM, Context);
+ if (TokKind == tok::NUM_TOKENS || TokKind == tok::semi ||
+ TokKind == tok::r_brace) {
+ // If we are at ";" or "}", we found the last token. We could use as well
+ // `if (isa<NullStmt>(S))`, but it wouldn't work for nested statements.
+ SkipEndWhitespaceAndComments = false;
+ }
+
+ Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts());
+ // Loc points past the last token before end or after ';'.
+ if (SkipEndWhitespaceAndComments) {
+ Loc = forwardSkipWhitespaceAndComments(Loc, SM, Context);
+ tok::TokenKind TokKind = getTokenKind(Loc, SM, Context);
+ if (TokKind == tok::semi)
+ Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts());
+ }
+
+ for (;;) {
+ assert(Loc.isValid());
+ while (isHorizontalWhitespace(*SM.getCharacterData(Loc))) {
+ Loc = Loc.getLocWithOffset(1);
+ }
+
+ if (isVerticalWhitespace(*SM.getCharacterData(Loc))) {
+ // EOL, insert brace before.
+ break;
+ }
+ tok::TokenKind TokKind = getTokenKind(Loc, SM, Context);
+ if (TokKind != tok::comment) {
+ // Non-comment token, insert brace before.
+ break;
+ }
+
+ SourceLocation TokEndLoc =
+ Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts());
+ SourceRange TokRange(Loc, TokEndLoc);
+ StringRef Comment = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(TokRange), SM, Context->getLangOpts());
+ if (Comment.startswith("/*") && Comment.find('\n') != StringRef::npos) {
+ // Multi-line block comment, insert brace before.
+ break;
+ }
+ // else: Trailing comment, insert brace after the newline.
+
+ // Fast-forward current token.
+ Loc = TokEndLoc;
+ }
+ return Loc;
+}
+
+} // namespace
+
+BracesAroundStatementsCheck::BracesAroundStatementsCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ // Always add braces by default.
+ ShortStatementLines(Options.get("ShortStatementLines", 0U)) {}
+
+void BracesAroundStatementsCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "ShortStatementLines", ShortStatementLines);
+}
+
+void BracesAroundStatementsCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(ifStmt().bind("if"), this);
+ Finder->addMatcher(whileStmt().bind("while"), this);
+ Finder->addMatcher(doStmt().bind("do"), this);
+ Finder->addMatcher(forStmt().bind("for"), this);
+ Finder->addMatcher(cxxForRangeStmt().bind("for-range"), this);
+}
+
+void BracesAroundStatementsCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const SourceManager &SM = *Result.SourceManager;
+ const ASTContext *Context = Result.Context;
+
+ // Get location of closing parenthesis or 'do' to insert opening brace.
+ if (auto S = Result.Nodes.getNodeAs<ForStmt>("for")) {
+ checkStmt(Result, S->getBody(), S->getRParenLoc());
+ } else if (auto S = Result.Nodes.getNodeAs<CXXForRangeStmt>("for-range")) {
+ checkStmt(Result, S->getBody(), S->getRParenLoc());
+ } else if (auto S = Result.Nodes.getNodeAs<DoStmt>("do")) {
+ checkStmt(Result, S->getBody(), S->getDoLoc(), S->getWhileLoc());
+ } else if (auto S = Result.Nodes.getNodeAs<WhileStmt>("while")) {
+ SourceLocation StartLoc = findRParenLoc(S, SM, Context);
+ if (StartLoc.isInvalid())
+ return;
+ checkStmt(Result, S->getBody(), StartLoc);
+ } else if (auto S = Result.Nodes.getNodeAs<IfStmt>("if")) {
+ SourceLocation StartLoc = findRParenLoc(S, SM, Context);
+ if (StartLoc.isInvalid())
+ return;
+ if (ForceBracesStmts.erase(S))
+ ForceBracesStmts.insert(S->getThen());
+ bool BracedIf = checkStmt(Result, S->getThen(), StartLoc, S->getElseLoc());
+ const Stmt *Else = S->getElse();
+ if (Else && BracedIf)
+ ForceBracesStmts.insert(Else);
+ if (Else && !isa<IfStmt>(Else)) {
+ // Omit 'else if' statements here, they will be handled directly.
+ checkStmt(Result, Else, S->getElseLoc());
+ }
+ } else {
+ llvm_unreachable("Invalid match");
+ }
+}
+
+/// Find location of right parenthesis closing condition.
+template <typename IfOrWhileStmt>
+SourceLocation
+BracesAroundStatementsCheck::findRParenLoc(const IfOrWhileStmt *S,
+ const SourceManager &SM,
+ const ASTContext *Context) {
+ // Skip macros.
+ if (S->getLocStart().isMacroID())
+ return SourceLocation();
+
+ SourceLocation CondEndLoc = S->getCond()->getLocEnd();
+ if (const DeclStmt *CondVar = S->getConditionVariableDeclStmt())
+ CondEndLoc = CondVar->getLocEnd();
+
+ if (!CondEndLoc.isValid()) {
+ return SourceLocation();
+ }
+
+ SourceLocation PastCondEndLoc =
+ Lexer::getLocForEndOfToken(CondEndLoc, 0, SM, Context->getLangOpts());
+ if (PastCondEndLoc.isInvalid())
+ return SourceLocation();
+ SourceLocation RParenLoc =
+ forwardSkipWhitespaceAndComments(PastCondEndLoc, SM, Context);
+ if (RParenLoc.isInvalid())
+ return SourceLocation();
+ tok::TokenKind TokKind = getTokenKind(RParenLoc, SM, Context);
+ if (TokKind != tok::r_paren)
+ return SourceLocation();
+ return RParenLoc;
+}
+
+/// Determine if the statement needs braces around it, and add them if it does.
+/// Returns true if braces where added.
+bool BracesAroundStatementsCheck::checkStmt(
+ const MatchFinder::MatchResult &Result, const Stmt *S,
+ SourceLocation InitialLoc, SourceLocation EndLocHint) {
+ // 1) If there's a corresponding "else" or "while", the check inserts "} "
+ // right before that token.
+ // 2) If there's a multi-line block comment starting on the same line after
+ // the location we're inserting the closing brace at, or there's a non-comment
+ // token, the check inserts "\n}" right before that token.
+ // 3) Otherwise the check finds the end of line (possibly after some block or
+ // line comments) and inserts "\n}" right before that EOL.
+ if (!S || isa<CompoundStmt>(S)) {
+ // Already inside braces.
+ return false;
+ }
+
+ if (!InitialLoc.isValid())
+ return false;
+ const SourceManager &SM = *Result.SourceManager;
+ const ASTContext *Context = Result.Context;
+
+ // Treat macros.
+ CharSourceRange FileRange = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(S->getSourceRange()), SM,
+ Context->getLangOpts());
+ if (FileRange.isInvalid())
+ return false;
+
+ // Convert InitialLoc to file location, if it's on the same macro expansion
+ // level as the start of the statement. We also need file locations for
+ // Lexer::getLocForEndOfToken working properly.
+ InitialLoc = Lexer::makeFileCharRange(
+ CharSourceRange::getCharRange(InitialLoc, S->getLocStart()),
+ SM, Context->getLangOpts())
+ .getBegin();
+ if (InitialLoc.isInvalid())
+ return false;
+ SourceLocation StartLoc =
+ Lexer::getLocForEndOfToken(InitialLoc, 0, SM, Context->getLangOpts());
+
+ // StartLoc points at the location of the opening brace to be inserted.
+ SourceLocation EndLoc;
+ std::string ClosingInsertion;
+ if (EndLocHint.isValid()) {
+ EndLoc = EndLocHint;
+ ClosingInsertion = "} ";
+ } else {
+ const auto FREnd = FileRange.getEnd().getLocWithOffset(-1);
+ EndLoc = findEndLocation(FREnd, SM, Context);
+ ClosingInsertion = "\n}";
+ }
+
+ assert(StartLoc.isValid());
+ assert(EndLoc.isValid());
+ // Don't require braces for statements spanning less than certain number of
+ // lines.
+ if (ShortStatementLines && !ForceBracesStmts.erase(S)) {
+ unsigned StartLine = SM.getSpellingLineNumber(StartLoc);
+ unsigned EndLine = SM.getSpellingLineNumber(EndLoc);
+ if (EndLine - StartLine < ShortStatementLines)
+ return false;
+ }
+
+ auto Diag = diag(StartLoc, "statement should be inside braces");
+ Diag << FixItHint::CreateInsertion(StartLoc, " {")
+ << FixItHint::CreateInsertion(EndLoc, ClosingInsertion);
+ return true;
+}
+
+void BracesAroundStatementsCheck::onEndOfTranslationUnit() {
+ ForceBracesStmts.clear();
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h
new file mode 100644
index 0000000..919ca46
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h
@@ -0,0 +1,69 @@
+//===--- BracesAroundStatementsCheck.h - clang-tidy -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_BRACESAROUNDSTATEMENTSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_BRACESAROUNDSTATEMENTSCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Checks that bodies of `if` statements and loops (`for`, `range-for`,
+/// `do-while`, and `while`) are inside braces
+///
+/// Before:
+///
+/// \code
+/// if (condition)
+/// statement;
+/// \endcode
+///
+/// After:
+///
+/// \code
+/// if (condition) {
+/// statement;
+/// }
+/// \endcode
+///
+/// Additionally, one can define an option `ShortStatementLines` defining the
+/// minimal number of lines that the statement should have in order to trigger
+/// this check.
+///
+/// The number of lines is counted from the end of condition or initial keyword
+/// (`do`/`else`) until the last line of the inner statement. Default value 0
+/// means that braces will be added to all statements (not having them already).
+class BracesAroundStatementsCheck : public ClangTidyCheck {
+public:
+ BracesAroundStatementsCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void onEndOfTranslationUnit() override;
+
+private:
+ bool checkStmt(const ast_matchers::MatchFinder::MatchResult &Result,
+ const Stmt *S, SourceLocation StartLoc,
+ SourceLocation EndLocHint = SourceLocation());
+ template <typename IfOrWhileStmt>
+ SourceLocation findRParenLoc(const IfOrWhileStmt *S, const SourceManager &SM,
+ const ASTContext *Context);
+
+private:
+ std::set<const Stmt *> ForceBracesStmts;
+ const unsigned ShortStatementLines;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_BRACESAROUNDSTATEMENTSCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
new file mode 100644
index 0000000..961ad88
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -0,0 +1,42 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyReadabilityModule
+ AvoidConstParamsInDecls.cpp
+ BracesAroundStatementsCheck.cpp
+ ContainerSizeEmptyCheck.cpp
+ DeleteNullPointerCheck.cpp
+ DeletedDefaultCheck.cpp
+ ElseAfterReturnCheck.cpp
+ FunctionSizeCheck.cpp
+ IdentifierNamingCheck.cpp
+ ImplicitBoolConversionCheck.cpp
+ InconsistentDeclarationParameterNameCheck.cpp
+ MisleadingIndentationCheck.cpp
+ MisplacedArrayIndexCheck.cpp
+ NamedParameterCheck.cpp
+ NamespaceCommentCheck.cpp
+ NonConstParameterCheck.cpp
+ ReadabilityTidyModule.cpp
+ RedundantControlFlowCheck.cpp
+ RedundantDeclarationCheck.cpp
+ RedundantFunctionPtrDereferenceCheck.cpp
+ RedundantMemberInitCheck.cpp
+ RedundantStringCStrCheck.cpp
+ RedundantSmartptrGetCheck.cpp
+ RedundantStringInitCheck.cpp
+ SimplifyBooleanExprCheck.cpp
+ SimplifySubscriptExprCheck.cpp
+ StaticAccessedThroughInstanceCheck.cpp
+ StaticDefinitionInAnonymousNamespaceCheck.cpp
+ StringCompareCheck.cpp
+ UniqueptrDeleteReleaseCheck.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyUtils
+ clangTooling
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
new file mode 100644
index 0000000..5604354
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
@@ -0,0 +1,225 @@
+//===--- ContainerSizeEmptyCheck.cpp - clang-tidy -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "ContainerSizeEmptyCheck.h"
+#include "../utils/ASTUtils.h"
+#include "../utils/Matchers.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+using utils::IsBinaryOrTernary;
+
+ContainerSizeEmptyCheck::ContainerSizeEmptyCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+
+void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ const auto ValidContainer = qualType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(cxxRecordDecl(isSameOrDerivedFrom(
+ namedDecl(
+ has(cxxMethodDecl(
+ isConst(), parameterCountIs(0), isPublic(),
+ hasName("size"),
+ returns(qualType(isInteger(), unless(booleanType()))))
+ .bind("size")),
+ has(cxxMethodDecl(isConst(), parameterCountIs(0), isPublic(),
+ hasName("empty"), returns(booleanType()))
+ .bind("empty")))
+ .bind("container")))))));
+
+ const auto WrongUse = anyOf(
+ hasParent(binaryOperator(
+ matchers::isComparisonOperator(),
+ hasEitherOperand(ignoringImpCasts(anyOf(
+ integerLiteral(equals(1)), integerLiteral(equals(0))))))
+ .bind("SizeBinaryOp")),
+ hasParent(implicitCastExpr(
+ hasImplicitDestinationType(booleanType()),
+ anyOf(
+ hasParent(unaryOperator(hasOperatorName("!")).bind("NegOnSize")),
+ anything()))),
+ hasParent(explicitCastExpr(hasDestinationType(booleanType()))));
+
+ Finder->addMatcher(
+ cxxMemberCallExpr(on(expr(anyOf(hasType(ValidContainer),
+ hasType(pointsTo(ValidContainer)),
+ hasType(references(ValidContainer))))),
+ callee(cxxMethodDecl(hasName("size"))), WrongUse,
+ unless(hasAncestor(cxxMethodDecl(
+ ofClass(equalsBoundNode("container"))))))
+ .bind("SizeCallExpr"),
+ this);
+
+ // Empty constructor matcher.
+ const auto DefaultConstructor = cxxConstructExpr(
+ hasDeclaration(cxxConstructorDecl(isDefaultConstructor())));
+ // Comparison to empty string or empty constructor.
+ const auto WrongComparend = anyOf(
+ ignoringImpCasts(stringLiteral(hasSize(0))),
+ ignoringImpCasts(cxxBindTemporaryExpr(has(DefaultConstructor))),
+ ignoringImplicit(DefaultConstructor),
+ cxxConstructExpr(
+ hasDeclaration(cxxConstructorDecl(isCopyConstructor())),
+ has(expr(ignoringImpCasts(DefaultConstructor)))),
+ cxxConstructExpr(
+ hasDeclaration(cxxConstructorDecl(isMoveConstructor())),
+ has(expr(ignoringImpCasts(DefaultConstructor)))));
+ // Match the object being compared.
+ const auto STLArg =
+ anyOf(unaryOperator(
+ hasOperatorName("*"),
+ hasUnaryOperand(
+ expr(hasType(pointsTo(ValidContainer))).bind("Pointee"))),
+ expr(hasType(ValidContainer)).bind("STLObject"));
+ Finder->addMatcher(
+ cxxOperatorCallExpr(
+ anyOf(hasOverloadedOperatorName("=="),
+ hasOverloadedOperatorName("!=")),
+ anyOf(allOf(hasArgument(0, WrongComparend), hasArgument(1, STLArg)),
+ allOf(hasArgument(0, STLArg), hasArgument(1, WrongComparend))),
+ unless(hasAncestor(
+ cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
+ .bind("BinCmp"),
+ this);
+}
+
+void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MemberCall =
+ Result.Nodes.getNodeAs<CXXMemberCallExpr>("SizeCallExpr");
+ const auto *BinCmp = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("BinCmp");
+ const auto *BinaryOp = Result.Nodes.getNodeAs<BinaryOperator>("SizeBinaryOp");
+ const auto *Pointee = Result.Nodes.getNodeAs<Expr>("Pointee");
+ const auto *E =
+ MemberCall
+ ? MemberCall->getImplicitObjectArgument()
+ : (Pointee ? Pointee : Result.Nodes.getNodeAs<Expr>("STLObject"));
+ FixItHint Hint;
+ std::string ReplacementText =
+ Lexer::getSourceText(CharSourceRange::getTokenRange(E->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ if (BinCmp && IsBinaryOrTernary(E)) {
+ // Not just a DeclRefExpr, so parenthesize to be on the safe side.
+ ReplacementText = "(" + ReplacementText + ")";
+ }
+ if (E->getType()->isPointerType())
+ ReplacementText += "->empty()";
+ else
+ ReplacementText += ".empty()";
+
+ if (BinCmp) {
+ if (BinCmp->getOperator() == OO_ExclaimEqual) {
+ ReplacementText = "!" + ReplacementText;
+ }
+ Hint =
+ FixItHint::CreateReplacement(BinCmp->getSourceRange(), ReplacementText);
+ } else if (BinaryOp) { // Determine the correct transformation.
+ bool Negation = false;
+ const bool ContainerIsLHS =
+ !llvm::isa<IntegerLiteral>(BinaryOp->getLHS()->IgnoreImpCasts());
+ const auto OpCode = BinaryOp->getOpcode();
+ uint64_t Value = 0;
+ if (ContainerIsLHS) {
+ if (const auto *Literal = llvm::dyn_cast<IntegerLiteral>(
+ BinaryOp->getRHS()->IgnoreImpCasts()))
+ Value = Literal->getValue().getLimitedValue();
+ else
+ return;
+ } else {
+ Value =
+ llvm::dyn_cast<IntegerLiteral>(BinaryOp->getLHS()->IgnoreImpCasts())
+ ->getValue()
+ .getLimitedValue();
+ }
+
+ // Constant that is not handled.
+ if (Value > 1)
+ return;
+
+ if (Value == 1 && (OpCode == BinaryOperatorKind::BO_EQ ||
+ OpCode == BinaryOperatorKind::BO_NE))
+ return;
+
+ // Always true, no warnings for that.
+ if ((OpCode == BinaryOperatorKind::BO_GE && Value == 0 && ContainerIsLHS) ||
+ (OpCode == BinaryOperatorKind::BO_LE && Value == 0 && !ContainerIsLHS))
+ return;
+
+ // Do not warn for size > 1, 1 < size, size <= 1, 1 >= size.
+ if (Value == 1) {
+ if ((OpCode == BinaryOperatorKind::BO_GT && ContainerIsLHS) ||
+ (OpCode == BinaryOperatorKind::BO_LT && !ContainerIsLHS))
+ return;
+ if ((OpCode == BinaryOperatorKind::BO_LE && ContainerIsLHS) ||
+ (OpCode == BinaryOperatorKind::BO_GE && !ContainerIsLHS))
+ return;
+ }
+
+ if (OpCode == BinaryOperatorKind::BO_NE && Value == 0)
+ Negation = true;
+ if ((OpCode == BinaryOperatorKind::BO_GT ||
+ OpCode == BinaryOperatorKind::BO_GE) &&
+ ContainerIsLHS)
+ Negation = true;
+ if ((OpCode == BinaryOperatorKind::BO_LT ||
+ OpCode == BinaryOperatorKind::BO_LE) &&
+ !ContainerIsLHS)
+ Negation = true;
+
+ if (Negation)
+ ReplacementText = "!" + ReplacementText;
+ Hint = FixItHint::CreateReplacement(BinaryOp->getSourceRange(),
+ ReplacementText);
+
+ } else {
+ // If there is a conversion above the size call to bool, it is safe to just
+ // replace size with empty.
+ if (const auto *UnaryOp =
+ Result.Nodes.getNodeAs<UnaryOperator>("NegOnSize"))
+ Hint = FixItHint::CreateReplacement(UnaryOp->getSourceRange(),
+ ReplacementText);
+ else
+ Hint = FixItHint::CreateReplacement(MemberCall->getSourceRange(),
+ "!" + ReplacementText);
+ }
+
+ if (MemberCall) {
+ diag(MemberCall->getLocStart(),
+ "the 'empty' method should be used to check "
+ "for emptiness instead of 'size'")
+ << Hint;
+ } else {
+ diag(BinCmp->getLocStart(),
+ "the 'empty' method should be used to check "
+ "for emptiness instead of comparing to an empty object")
+ << Hint;
+ }
+
+ const auto *Container = Result.Nodes.getNodeAs<NamedDecl>("container");
+ const auto *Empty = Result.Nodes.getNodeAs<FunctionDecl>("empty");
+
+ diag(Empty->getLocation(), "method %0::empty() defined here",
+ DiagnosticIDs::Note)
+ << Container;
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.h
new file mode 100644
index 0000000..bde83f8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.h
@@ -0,0 +1,40 @@
+//===--- ContainerSizeEmptyCheck.h - clang-tidy -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_CONTAINERSIZEEMPTYCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_CONTAINERSIZEEMPTYCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Checks whether a call to the `size()` method can be replaced with a call to
+/// `empty()`.
+///
+/// The emptiness of a container should be checked using the `empty()` method
+/// instead of the `size()` method. It is not guaranteed that `size()` is a
+/// constant-time function, and it is generally more efficient and also shows
+/// clearer intent to use `empty()`. Furthermore some containers may implement
+/// the `empty()` method but not implement the `size()` method. Using `empty()`
+/// whenever possible makes it easier to switch to another container in the
+/// future.
+class ContainerSizeEmptyCheck : public ClangTidyCheck {
+public:
+ ContainerSizeEmptyCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_CONTAINERSIZEEMPTYCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp
new file mode 100644
index 0000000..766dfda
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp
@@ -0,0 +1,79 @@
+//===--- DeleteNullPointerCheck.cpp - clang-tidy---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DeleteNullPointerCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+void DeleteNullPointerCheck::registerMatchers(MatchFinder *Finder) {
+ const auto DeleteExpr =
+ cxxDeleteExpr(has(castExpr(has(declRefExpr(
+ to(decl(equalsBoundNode("deletedPointer"))))))))
+ .bind("deleteExpr");
+
+ const auto DeleteMemberExpr =
+ cxxDeleteExpr(has(castExpr(has(memberExpr(hasDeclaration(
+ fieldDecl(equalsBoundNode("deletedMemberPointer"))))))))
+ .bind("deleteMemberExpr");
+
+ const auto PointerExpr = ignoringImpCasts(anyOf(
+ declRefExpr(to(decl().bind("deletedPointer"))),
+ memberExpr(hasDeclaration(fieldDecl().bind("deletedMemberPointer")))));
+
+ const auto PointerCondition = castExpr(hasCastKind(CK_PointerToBoolean),
+ hasSourceExpression(PointerExpr));
+ const auto BinaryPointerCheckCondition =
+ binaryOperator(hasEitherOperand(castExpr(hasCastKind(CK_NullToPointer))),
+ hasEitherOperand(PointerExpr));
+
+ Finder->addMatcher(
+ ifStmt(hasCondition(anyOf(PointerCondition, BinaryPointerCheckCondition)),
+ hasThen(anyOf(
+ DeleteExpr, DeleteMemberExpr,
+ compoundStmt(anyOf(has(DeleteExpr), has(DeleteMemberExpr)),
+ statementCountIs(1))
+ .bind("compound"))))
+ .bind("ifWithDelete"),
+ this);
+}
+
+void DeleteNullPointerCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *IfWithDelete = Result.Nodes.getNodeAs<IfStmt>("ifWithDelete");
+ const auto *Compound = Result.Nodes.getNodeAs<CompoundStmt>("compound");
+
+ auto Diag = diag(
+ IfWithDelete->getLocStart(),
+ "'if' statement is unnecessary; deleting null pointer has no effect");
+ if (IfWithDelete->getElse())
+ return;
+ // FIXME: generate fixit for this case.
+
+ Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
+ IfWithDelete->getLocStart(),
+ Lexer::getLocForEndOfToken(IfWithDelete->getCond()->getLocEnd(), 0,
+ *Result.SourceManager,
+ Result.Context->getLangOpts())));
+ if (Compound) {
+ Diag << FixItHint::CreateRemoval(
+ CharSourceRange::getTokenRange(Compound->getLBracLoc()));
+ Diag << FixItHint::CreateRemoval(
+ CharSourceRange::getTokenRange(Compound->getRBracLoc()));
+ }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.h
new file mode 100644
index 0000000..501f6f7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.h
@@ -0,0 +1,36 @@
+//===--- DeleteNullPointerCheck.h - clang-tidy-------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DELETE_NULL_POINTER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DELETE_NULL_POINTER_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Check whether the 'if' statement is unnecessary before calling 'delete' on a
+/// pointer.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-delete-null-pointer.html
+class DeleteNullPointerCheck : public ClangTidyCheck {
+public:
+ DeleteNullPointerCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DELETE_NULL_POINTER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/DeletedDefaultCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/DeletedDefaultCheck.cpp
new file mode 100644
index 0000000..a197e8d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/DeletedDefaultCheck.cpp
@@ -0,0 +1,69 @@
+//===--- DeletedDefaultCheck.cpp - clang-tidy------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DeletedDefaultCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+void DeletedDefaultCheck::registerMatchers(MatchFinder *Finder) {
+ // We match constructors/assignment operators that are:
+ // - explicitly marked '= default'
+ // - actually deleted
+ // - not in template instantiation.
+ // We bind the declaration to "method-decl" and also to "constructor" when
+ // it is a constructor.
+
+ Finder->addMatcher(
+ cxxMethodDecl(anyOf(cxxConstructorDecl().bind("constructor"),
+ isCopyAssignmentOperator(),
+ isMoveAssignmentOperator()),
+ isDefaulted(), unless(isImplicit()), isDeleted(),
+ unless(isInstantiated()))
+ .bind("method-decl"),
+ this);
+}
+
+void DeletedDefaultCheck::check(const MatchFinder::MatchResult &Result) {
+ const StringRef Message = "%0 is explicitly defaulted but implicitly "
+ "deleted, probably because %1; definition can "
+ "either be removed or explicitly deleted";
+ if (const auto *Constructor =
+ Result.Nodes.getNodeAs<CXXConstructorDecl>("constructor")) {
+ auto Diag = diag(Constructor->getLocStart(), Message);
+ if (Constructor->isDefaultConstructor()) {
+ Diag << "default constructor"
+ << "a non-static data member or a base class is lacking a default "
+ "constructor";
+ } else if (Constructor->isCopyConstructor()) {
+ Diag << "copy constructor"
+ << "a non-static data member or a base class is not copyable";
+ } else if (Constructor->isMoveConstructor()) {
+ Diag << "move constructor"
+ << "a non-static data member or a base class is neither copyable "
+ "nor movable";
+ }
+ } else if (const auto *Assignment =
+ Result.Nodes.getNodeAs<CXXMethodDecl>("method-decl")) {
+ diag(Assignment->getLocStart(), Message)
+ << (Assignment->isCopyAssignmentOperator() ? "copy assignment operator"
+ : "move assignment operator")
+ << "a base class or a non-static data member is not assignable, e.g. "
+ "because the latter is marked 'const'";
+ }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/DeletedDefaultCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/DeletedDefaultCheck.h
new file mode 100644
index 0000000..0608b07
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/DeletedDefaultCheck.h
@@ -0,0 +1,36 @@
+//===--- DeletedDefaultCheck.h - clang-tidy----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DELETED_DEFAULT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DELETED_DEFAULT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Checks when a constructor or an assignment operator is marked as '= default'
+/// but is actually deleted by the compiler.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-deleted-default.html
+class DeletedDefaultCheck : public ClangTidyCheck {
+public:
+ DeletedDefaultCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DELETED_DEFAULT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp
new file mode 100644
index 0000000..8b5526c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp
@@ -0,0 +1,57 @@
+//===--- ElseAfterReturnCheck.cpp - clang-tidy-----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ElseAfterReturnCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+void ElseAfterReturnCheck::registerMatchers(MatchFinder *Finder) {
+ const auto ControlFlowInterruptorMatcher =
+ stmt(anyOf(returnStmt().bind("return"), continueStmt().bind("continue"),
+ breakStmt().bind("break"),
+ expr(ignoringImplicit(cxxThrowExpr().bind("throw")))));
+ Finder->addMatcher(
+ compoundStmt(forEach(
+ ifStmt(hasThen(stmt(
+ anyOf(ControlFlowInterruptorMatcher,
+ compoundStmt(has(ControlFlowInterruptorMatcher))))),
+ hasElse(stmt().bind("else")))
+ .bind("if"))),
+ this);
+}
+
+void ElseAfterReturnCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *If = Result.Nodes.getNodeAs<IfStmt>("if");
+ SourceLocation ElseLoc = If->getElseLoc();
+ std::string ControlFlowInterruptor;
+ for (const auto *BindingName : {"return", "continue", "break", "throw"})
+ if (Result.Nodes.getNodeAs<Stmt>(BindingName))
+ ControlFlowInterruptor = BindingName;
+
+ DiagnosticBuilder Diag = diag(ElseLoc, "do not use 'else' after '%0'")
+ << ControlFlowInterruptor;
+ Diag << tooling::fixit::createRemoval(ElseLoc);
+
+ // FIXME: Removing the braces isn't always safe. Do a more careful analysis.
+ // FIXME: Change clang-format to correctly un-indent the code.
+ if (const auto *CS = Result.Nodes.getNodeAs<CompoundStmt>("else"))
+ Diag << tooling::fixit::createRemoval(CS->getLBracLoc())
+ << tooling::fixit::createRemoval(CS->getRBracLoc());
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.h
new file mode 100644
index 0000000..8479ab5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.h
@@ -0,0 +1,34 @@
+//===--- ElseAfterReturnCheck.h - clang-tidy---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ELSEAFTERRETURNCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ELSEAFTERRETURNCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Flags the usages of `else` after `return`.
+///
+/// http://llvm.org/docs/CodingStandards.html#don-t-use-else-after-a-return
+class ElseAfterReturnCheck : public ClangTidyCheck {
+public:
+ ElseAfterReturnCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ELSEAFTERRETURNCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.cpp
new file mode 100644
index 0000000..8ed6b90
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.cpp
@@ -0,0 +1,221 @@
+//===--- FunctionSize.cpp - clang-tidy ------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FunctionSizeCheck.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+namespace {
+
+class FunctionASTVisitor : public RecursiveASTVisitor<FunctionASTVisitor> {
+ using Base = RecursiveASTVisitor<FunctionASTVisitor>;
+
+public:
+ bool VisitVarDecl(VarDecl *VD) {
+ // Do not count function params.
+ // Do not count decomposition declarations (C++17's structured bindings).
+ if (StructNesting == 0 &&
+ !(isa<ParmVarDecl>(VD) || isa<DecompositionDecl>(VD)))
+ ++Info.Variables;
+ return true;
+ }
+ bool VisitBindingDecl(BindingDecl *BD) {
+ // Do count each of the bindings (in the decomposition declaration).
+ if (StructNesting == 0)
+ ++Info.Variables;
+ return true;
+ }
+
+ bool TraverseStmt(Stmt *Node) {
+ if (!Node)
+ return Base::TraverseStmt(Node);
+
+ if (TrackedParent.back() && !isa<CompoundStmt>(Node))
+ ++Info.Statements;
+
+ switch (Node->getStmtClass()) {
+ case Stmt::IfStmtClass:
+ case Stmt::WhileStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::CXXForRangeStmtClass:
+ case Stmt::ForStmtClass:
+ case Stmt::SwitchStmtClass:
+ ++Info.Branches;
+ LLVM_FALLTHROUGH;
+ case Stmt::CompoundStmtClass:
+ TrackedParent.push_back(true);
+ break;
+ default:
+ TrackedParent.push_back(false);
+ break;
+ }
+
+ Base::TraverseStmt(Node);
+
+ TrackedParent.pop_back();
+
+ return true;
+ }
+
+ bool TraverseCompoundStmt(CompoundStmt *Node) {
+ // If this new compound statement is located in a compound statement, which
+ // is already nested NestingThreshold levels deep, record the start location
+ // of this new compound statement.
+ if (CurrentNestingLevel == Info.NestingThreshold)
+ Info.NestingThresholders.push_back(Node->getLocStart());
+
+ ++CurrentNestingLevel;
+ Base::TraverseCompoundStmt(Node);
+ --CurrentNestingLevel;
+
+ return true;
+ }
+
+ bool TraverseDecl(Decl *Node) {
+ TrackedParent.push_back(false);
+ Base::TraverseDecl(Node);
+ TrackedParent.pop_back();
+ return true;
+ }
+
+ bool TraverseLambdaExpr(LambdaExpr *Node) {
+ ++StructNesting;
+ Base::TraverseLambdaExpr(Node);
+ --StructNesting;
+ return true;
+ }
+
+ bool TraverseCXXRecordDecl(CXXRecordDecl *Node) {
+ ++StructNesting;
+ Base::TraverseCXXRecordDecl(Node);
+ --StructNesting;
+ return true;
+ }
+
+ bool TraverseStmtExpr(StmtExpr *SE) {
+ ++StructNesting;
+ Base::TraverseStmtExpr(SE);
+ --StructNesting;
+ return true;
+ }
+
+ struct FunctionInfo {
+ unsigned Lines = 0;
+ unsigned Statements = 0;
+ unsigned Branches = 0;
+ unsigned NestingThreshold = 0;
+ unsigned Variables = 0;
+ std::vector<SourceLocation> NestingThresholders;
+ };
+ FunctionInfo Info;
+ std::vector<bool> TrackedParent;
+ unsigned StructNesting = 0;
+ unsigned CurrentNestingLevel = 0;
+};
+
+} // namespace
+
+FunctionSizeCheck::FunctionSizeCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ LineThreshold(Options.get("LineThreshold", -1U)),
+ StatementThreshold(Options.get("StatementThreshold", 800U)),
+ BranchThreshold(Options.get("BranchThreshold", -1U)),
+ ParameterThreshold(Options.get("ParameterThreshold", -1U)),
+ NestingThreshold(Options.get("NestingThreshold", -1U)),
+ VariableThreshold(Options.get("VariableThreshold", -1U)) {}
+
+void FunctionSizeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "LineThreshold", LineThreshold);
+ Options.store(Opts, "StatementThreshold", StatementThreshold);
+ Options.store(Opts, "BranchThreshold", BranchThreshold);
+ Options.store(Opts, "ParameterThreshold", ParameterThreshold);
+ Options.store(Opts, "NestingThreshold", NestingThreshold);
+ Options.store(Opts, "VariableThreshold", VariableThreshold);
+}
+
+void FunctionSizeCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(functionDecl(unless(isInstantiated())).bind("func"), this);
+}
+
+void FunctionSizeCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
+
+ FunctionASTVisitor Visitor;
+ Visitor.Info.NestingThreshold = NestingThreshold;
+ Visitor.TraverseDecl(const_cast<FunctionDecl *>(Func));
+ auto &FI = Visitor.Info;
+
+ if (FI.Statements == 0)
+ return;
+
+ // Count the lines including whitespace and comments. Really simple.
+ if (const Stmt *Body = Func->getBody()) {
+ SourceManager *SM = Result.SourceManager;
+ if (SM->isWrittenInSameFile(Body->getLocStart(), Body->getLocEnd())) {
+ FI.Lines = SM->getSpellingLineNumber(Body->getLocEnd()) -
+ SM->getSpellingLineNumber(Body->getLocStart());
+ }
+ }
+
+ unsigned ActualNumberParameters = Func->getNumParams();
+
+ if (FI.Lines > LineThreshold || FI.Statements > StatementThreshold ||
+ FI.Branches > BranchThreshold ||
+ ActualNumberParameters > ParameterThreshold ||
+ !FI.NestingThresholders.empty() || FI.Variables > VariableThreshold) {
+ diag(Func->getLocation(),
+ "function %0 exceeds recommended size/complexity thresholds")
+ << Func;
+ }
+
+ if (FI.Lines > LineThreshold) {
+ diag(Func->getLocation(),
+ "%0 lines including whitespace and comments (threshold %1)",
+ DiagnosticIDs::Note)
+ << FI.Lines << LineThreshold;
+ }
+
+ if (FI.Statements > StatementThreshold) {
+ diag(Func->getLocation(), "%0 statements (threshold %1)",
+ DiagnosticIDs::Note)
+ << FI.Statements << StatementThreshold;
+ }
+
+ if (FI.Branches > BranchThreshold) {
+ diag(Func->getLocation(), "%0 branches (threshold %1)", DiagnosticIDs::Note)
+ << FI.Branches << BranchThreshold;
+ }
+
+ if (ActualNumberParameters > ParameterThreshold) {
+ diag(Func->getLocation(), "%0 parameters (threshold %1)",
+ DiagnosticIDs::Note)
+ << ActualNumberParameters << ParameterThreshold;
+ }
+
+ for (const auto &CSPos : FI.NestingThresholders) {
+ diag(CSPos, "nesting level %0 starts here (threshold %1)",
+ DiagnosticIDs::Note)
+ << NestingThreshold + 1 << NestingThreshold;
+ }
+
+ if (FI.Variables > VariableThreshold) {
+ diag(Func->getLocation(), "%0 variables (threshold %1)",
+ DiagnosticIDs::Note)
+ << FI.Variables << VariableThreshold;
+ }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.h
new file mode 100644
index 0000000..7defccd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/FunctionSizeCheck.h
@@ -0,0 +1,59 @@
+//===--- FunctionSizeCheck.h - clang-tidy -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_FUNCTIONSIZECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_FUNCTIONSIZECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Checks for large functions based on various metrics.
+///
+/// These options are supported:
+///
+/// * `LineThreshold` - flag functions exceeding this number of lines. The
+/// default is `-1` (ignore the number of lines).
+/// * `StatementThreshold` - flag functions exceeding this number of
+/// statements. This may differ significantly from the number of lines for
+/// macro-heavy code. The default is `800`.
+/// * `BranchThreshold` - flag functions exceeding this number of control
+/// statements. The default is `-1` (ignore the number of branches).
+/// * `ParameterThreshold` - flag functions having a high number of
+/// parameters. The default is `-1` (ignore the number of parameters).
+/// * `NestingThreshold` - flag compound statements which create next nesting
+/// level after `NestingThreshold`. This may differ significantly from the
+/// expected value for macro-heavy code. The default is `-1` (ignore the
+/// nesting level).
+/// * `VariableThreshold` - flag functions having a high number of variable
+/// declarations. The default is `-1` (ignore the number of variables).
+class FunctionSizeCheck : public ClangTidyCheck {
+public:
+ FunctionSizeCheck(StringRef Name, ClangTidyContext *Context);
+
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const unsigned LineThreshold;
+ const unsigned StatementThreshold;
+ const unsigned BranchThreshold;
+ const unsigned ParameterThreshold;
+ const unsigned NestingThreshold;
+ const unsigned VariableThreshold;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_FUNCTIONSIZECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
new file mode 100644
index 0000000..46919d3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -0,0 +1,942 @@
+//===--- IdentifierNamingCheck.cpp - clang-tidy ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IdentifierNamingCheck.h"
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
+
+#define DEBUG_TYPE "clang-tidy"
+
+using namespace clang::ast_matchers;
+
+namespace llvm {
+/// Specialisation of DenseMapInfo to allow NamingCheckId objects in DenseMaps
+template <>
+struct DenseMapInfo<
+ clang::tidy::readability::IdentifierNamingCheck::NamingCheckId> {
+ using NamingCheckId =
+ clang::tidy::readability::IdentifierNamingCheck::NamingCheckId;
+
+ static inline NamingCheckId getEmptyKey() {
+ return NamingCheckId(
+ clang::SourceLocation::getFromRawEncoding(static_cast<unsigned>(-1)),
+ "EMPTY");
+ }
+
+ static inline NamingCheckId getTombstoneKey() {
+ return NamingCheckId(
+ clang::SourceLocation::getFromRawEncoding(static_cast<unsigned>(-2)),
+ "TOMBSTONE");
+ }
+
+ static unsigned getHashValue(NamingCheckId Val) {
+ assert(Val != getEmptyKey() && "Cannot hash the empty key!");
+ assert(Val != getTombstoneKey() && "Cannot hash the tombstone key!");
+
+ std::hash<NamingCheckId::second_type> SecondHash;
+ return Val.first.getRawEncoding() + SecondHash(Val.second);
+ }
+
+ static bool isEqual(const NamingCheckId &LHS, const NamingCheckId &RHS) {
+ if (RHS == getEmptyKey())
+ return LHS == getEmptyKey();
+ if (RHS == getTombstoneKey())
+ return LHS == getTombstoneKey();
+ return LHS == RHS;
+ }
+};
+} // namespace llvm
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+// clang-format off
+#define NAMING_KEYS(m) \
+ m(Namespace) \
+ m(InlineNamespace) \
+ m(EnumConstant) \
+ m(ConstexprVariable) \
+ m(ConstantMember) \
+ m(PrivateMember) \
+ m(ProtectedMember) \
+ m(PublicMember) \
+ m(Member) \
+ m(ClassConstant) \
+ m(ClassMember) \
+ m(GlobalConstant) \
+ m(GlobalVariable) \
+ m(LocalConstant) \
+ m(LocalVariable) \
+ m(StaticConstant) \
+ m(StaticVariable) \
+ m(Constant) \
+ m(Variable) \
+ m(ConstantParameter) \
+ m(ParameterPack) \
+ m(Parameter) \
+ m(AbstractClass) \
+ m(Struct) \
+ m(Class) \
+ m(Union) \
+ m(Enum) \
+ m(GlobalFunction) \
+ m(ConstexprFunction) \
+ m(Function) \
+ m(ConstexprMethod) \
+ m(VirtualMethod) \
+ m(ClassMethod) \
+ m(PrivateMethod) \
+ m(ProtectedMethod) \
+ m(PublicMethod) \
+ m(Method) \
+ m(Typedef) \
+ m(TypeTemplateParameter) \
+ m(ValueTemplateParameter) \
+ m(TemplateTemplateParameter) \
+ m(TemplateParameter) \
+ m(TypeAlias) \
+ m(MacroDefinition) \
+ m(ObjcIvar) \
+
+enum StyleKind {
+#define ENUMERATE(v) SK_ ## v,
+ NAMING_KEYS(ENUMERATE)
+#undef ENUMERATE
+ SK_Count,
+ SK_Invalid
+};
+
+static StringRef const StyleNames[] = {
+#define STRINGIZE(v) #v,
+ NAMING_KEYS(STRINGIZE)
+#undef STRINGIZE
+};
+
+#undef NAMING_KEYS
+// clang-format on
+
+namespace {
+/// Callback supplies macros to IdentifierNamingCheck::checkMacro
+class IdentifierNamingCheckPPCallbacks : public PPCallbacks {
+public:
+ IdentifierNamingCheckPPCallbacks(Preprocessor *PP,
+ IdentifierNamingCheck *Check)
+ : PP(PP), Check(Check) {}
+
+ /// MacroDefined calls checkMacro for macros in the main file
+ void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
+ Check->checkMacro(PP->getSourceManager(), MacroNameTok, MD->getMacroInfo());
+ }
+
+ /// MacroExpands calls expandMacro for macros in the main file
+ void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
+ SourceRange /*Range*/,
+ const MacroArgs * /*Args*/) override {
+ Check->expandMacro(MacroNameTok, MD.getMacroInfo());
+ }
+
+private:
+ Preprocessor *PP;
+ IdentifierNamingCheck *Check;
+};
+} // namespace
+
+IdentifierNamingCheck::IdentifierNamingCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {
+ auto const fromString = [](StringRef Str) {
+ return llvm::StringSwitch<llvm::Optional<CaseType>>(Str)
+ .Case("aNy_CasE", CT_AnyCase)
+ .Case("lower_case", CT_LowerCase)
+ .Case("UPPER_CASE", CT_UpperCase)
+ .Case("camelBack", CT_CamelBack)
+ .Case("CamelCase", CT_CamelCase)
+ .Case("Camel_Snake_Case", CT_CamelSnakeCase)
+ .Case("camel_Snake_Back", CT_CamelSnakeBack)
+ .Default(llvm::None);
+ };
+
+ for (auto const &Name : StyleNames) {
+ auto const caseOptional =
+ fromString(Options.get((Name + "Case").str(), ""));
+ auto prefix = Options.get((Name + "Prefix").str(), "");
+ auto postfix = Options.get((Name + "Suffix").str(), "");
+
+ if (caseOptional || !prefix.empty() || !postfix.empty()) {
+ NamingStyles.push_back(NamingStyle(caseOptional, prefix, postfix));
+ } else {
+ NamingStyles.push_back(llvm::None);
+ }
+ }
+
+ IgnoreFailedSplit = Options.get("IgnoreFailedSplit", 0);
+}
+
+void IdentifierNamingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ auto const toString = [](CaseType Type) {
+ switch (Type) {
+ case CT_AnyCase:
+ return "aNy_CasE";
+ case CT_LowerCase:
+ return "lower_case";
+ case CT_CamelBack:
+ return "camelBack";
+ case CT_UpperCase:
+ return "UPPER_CASE";
+ case CT_CamelCase:
+ return "CamelCase";
+ case CT_CamelSnakeCase:
+ return "Camel_Snake_Case";
+ case CT_CamelSnakeBack:
+ return "camel_Snake_Back";
+ }
+
+ llvm_unreachable("Unknown Case Type");
+ };
+
+ for (size_t i = 0; i < SK_Count; ++i) {
+ if (NamingStyles[i]) {
+ if (NamingStyles[i]->Case) {
+ Options.store(Opts, (StyleNames[i] + "Case").str(),
+ toString(*NamingStyles[i]->Case));
+ }
+ Options.store(Opts, (StyleNames[i] + "Prefix").str(),
+ NamingStyles[i]->Prefix);
+ Options.store(Opts, (StyleNames[i] + "Suffix").str(),
+ NamingStyles[i]->Suffix);
+ }
+ }
+
+ Options.store(Opts, "IgnoreFailedSplit", IgnoreFailedSplit);
+}
+
+void IdentifierNamingCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(namedDecl().bind("decl"), this);
+ Finder->addMatcher(usingDecl().bind("using"), this);
+ Finder->addMatcher(declRefExpr().bind("declRef"), this);
+ Finder->addMatcher(cxxConstructorDecl().bind("classRef"), this);
+ Finder->addMatcher(cxxDestructorDecl().bind("classRef"), this);
+ Finder->addMatcher(typeLoc().bind("typeLoc"), this);
+ Finder->addMatcher(nestedNameSpecifierLoc().bind("nestedNameLoc"), this);
+}
+
+void IdentifierNamingCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+ Compiler.getPreprocessor().addPPCallbacks(
+ llvm::make_unique<IdentifierNamingCheckPPCallbacks>(
+ &Compiler.getPreprocessor(), this));
+}
+
+static bool matchesStyle(StringRef Name,
+ IdentifierNamingCheck::NamingStyle Style) {
+ static llvm::Regex Matchers[] = {
+ llvm::Regex("^.*$"),
+ llvm::Regex("^[a-z][a-z0-9_]*$"),
+ llvm::Regex("^[a-z][a-zA-Z0-9]*$"),
+ llvm::Regex("^[A-Z][A-Z0-9_]*$"),
+ llvm::Regex("^[A-Z][a-zA-Z0-9]*$"),
+ llvm::Regex("^[A-Z]([a-z0-9]*(_[A-Z])?)*"),
+ llvm::Regex("^[a-z]([a-z0-9]*(_[A-Z])?)*"),
+ };
+
+ bool Matches = true;
+ if (Name.startswith(Style.Prefix))
+ Name = Name.drop_front(Style.Prefix.size());
+ else
+ Matches = false;
+
+ if (Name.endswith(Style.Suffix))
+ Name = Name.drop_back(Style.Suffix.size());
+ else
+ Matches = false;
+
+ // Ensure the name doesn't have any extra underscores beyond those specified
+ // in the prefix and suffix.
+ if (Name.startswith("_") || Name.endswith("_"))
+ Matches = false;
+
+ if (Style.Case && !Matchers[static_cast<size_t>(*Style.Case)].match(Name))
+ Matches = false;
+
+ return Matches;
+}
+
+static std::string fixupWithCase(StringRef Name,
+ IdentifierNamingCheck::CaseType Case) {
+ static llvm::Regex Splitter(
+ "([a-z0-9A-Z]*)(_+)|([A-Z]?[a-z0-9]+)([A-Z]|$)|([A-Z]+)([A-Z]|$)");
+
+ SmallVector<StringRef, 8> Substrs;
+ Name.split(Substrs, "_", -1, false);
+
+ SmallVector<StringRef, 8> Words;
+ for (auto Substr : Substrs) {
+ while (!Substr.empty()) {
+ SmallVector<StringRef, 8> Groups;
+ if (!Splitter.match(Substr, &Groups))
+ break;
+
+ if (Groups[2].size() > 0) {
+ Words.push_back(Groups[1]);
+ Substr = Substr.substr(Groups[0].size());
+ } else if (Groups[3].size() > 0) {
+ Words.push_back(Groups[3]);
+ Substr = Substr.substr(Groups[0].size() - Groups[4].size());
+ } else if (Groups[5].size() > 0) {
+ Words.push_back(Groups[5]);
+ Substr = Substr.substr(Groups[0].size() - Groups[6].size());
+ }
+ }
+ }
+
+ if (Words.empty())
+ return Name;
+
+ std::string Fixup;
+ switch (Case) {
+ case IdentifierNamingCheck::CT_AnyCase:
+ Fixup += Name;
+ break;
+
+ case IdentifierNamingCheck::CT_LowerCase:
+ for (auto const &Word : Words) {
+ if (&Word != &Words.front())
+ Fixup += "_";
+ Fixup += Word.lower();
+ }
+ break;
+
+ case IdentifierNamingCheck::CT_UpperCase:
+ for (auto const &Word : Words) {
+ if (&Word != &Words.front())
+ Fixup += "_";
+ Fixup += Word.upper();
+ }
+ break;
+
+ case IdentifierNamingCheck::CT_CamelCase:
+ for (auto const &Word : Words) {
+ Fixup += Word.substr(0, 1).upper();
+ Fixup += Word.substr(1).lower();
+ }
+ break;
+
+ case IdentifierNamingCheck::CT_CamelBack:
+ for (auto const &Word : Words) {
+ if (&Word == &Words.front()) {
+ Fixup += Word.lower();
+ } else {
+ Fixup += Word.substr(0, 1).upper();
+ Fixup += Word.substr(1).lower();
+ }
+ }
+ break;
+
+ case IdentifierNamingCheck::CT_CamelSnakeCase:
+ for (auto const &Word : Words) {
+ if (&Word != &Words.front())
+ Fixup += "_";
+ Fixup += Word.substr(0, 1).upper();
+ Fixup += Word.substr(1).lower();
+ }
+ break;
+
+ case IdentifierNamingCheck::CT_CamelSnakeBack:
+ for (auto const &Word : Words) {
+ if (&Word != &Words.front()) {
+ Fixup += "_";
+ Fixup += Word.substr(0, 1).upper();
+ } else {
+ Fixup += Word.substr(0, 1).lower();
+ }
+ Fixup += Word.substr(1).lower();
+ }
+ break;
+ }
+
+ return Fixup;
+}
+
+static std::string
+fixupWithStyle(StringRef Name,
+ const IdentifierNamingCheck::NamingStyle &Style) {
+ const std::string Fixed = fixupWithCase(
+ Name, Style.Case.getValueOr(IdentifierNamingCheck::CaseType::CT_AnyCase));
+ StringRef Mid = StringRef(Fixed).trim("_");
+ if (Mid.empty())
+ Mid = "_";
+ return (Style.Prefix + Mid + Style.Suffix).str();
+}
+
+static StyleKind findStyleKind(
+ const NamedDecl *D,
+ const std::vector<llvm::Optional<IdentifierNamingCheck::NamingStyle>>
+ &NamingStyles) {
+ if (isa<ObjCIvarDecl>(D) && NamingStyles[SK_ObjcIvar])
+ return SK_ObjcIvar;
+
+ if (isa<TypedefDecl>(D) && NamingStyles[SK_Typedef])
+ return SK_Typedef;
+
+ if (isa<TypeAliasDecl>(D) && NamingStyles[SK_TypeAlias])
+ return SK_TypeAlias;
+
+ if (const auto *Decl = dyn_cast<NamespaceDecl>(D)) {
+ if (Decl->isAnonymousNamespace())
+ return SK_Invalid;
+
+ if (Decl->isInline() && NamingStyles[SK_InlineNamespace])
+ return SK_InlineNamespace;
+
+ if (NamingStyles[SK_Namespace])
+ return SK_Namespace;
+ }
+
+ if (isa<EnumDecl>(D) && NamingStyles[SK_Enum])
+ return SK_Enum;
+
+ if (isa<EnumConstantDecl>(D)) {
+ if (NamingStyles[SK_EnumConstant])
+ return SK_EnumConstant;
+
+ if (NamingStyles[SK_Constant])
+ return SK_Constant;
+
+ return SK_Invalid;
+ }
+
+ if (const auto *Decl = dyn_cast<CXXRecordDecl>(D)) {
+ if (Decl->isAnonymousStructOrUnion())
+ return SK_Invalid;
+
+ if (!Decl->getCanonicalDecl()->isThisDeclarationADefinition())
+ return SK_Invalid;
+
+ if (Decl->hasDefinition() && Decl->isAbstract() &&
+ NamingStyles[SK_AbstractClass])
+ return SK_AbstractClass;
+
+ if (Decl->isStruct() && NamingStyles[SK_Struct])
+ return SK_Struct;
+
+ if (Decl->isStruct() && NamingStyles[SK_Class])
+ return SK_Class;
+
+ if (Decl->isClass() && NamingStyles[SK_Class])
+ return SK_Class;
+
+ if (Decl->isClass() && NamingStyles[SK_Struct])
+ return SK_Struct;
+
+ if (Decl->isUnion() && NamingStyles[SK_Union])
+ return SK_Union;
+
+ if (Decl->isEnum() && NamingStyles[SK_Enum])
+ return SK_Enum;
+
+ return SK_Invalid;
+ }
+
+ if (const auto *Decl = dyn_cast<FieldDecl>(D)) {
+ QualType Type = Decl->getType();
+
+ if (!Type.isNull() && Type.isConstQualified()) {
+ if (NamingStyles[SK_ConstantMember])
+ return SK_ConstantMember;
+
+ if (NamingStyles[SK_Constant])
+ return SK_Constant;
+ }
+
+ if (Decl->getAccess() == AS_private && NamingStyles[SK_PrivateMember])
+ return SK_PrivateMember;
+
+ if (Decl->getAccess() == AS_protected && NamingStyles[SK_ProtectedMember])
+ return SK_ProtectedMember;
+
+ if (Decl->getAccess() == AS_public && NamingStyles[SK_PublicMember])
+ return SK_PublicMember;
+
+ if (NamingStyles[SK_Member])
+ return SK_Member;
+
+ return SK_Invalid;
+ }
+
+ if (const auto *Decl = dyn_cast<ParmVarDecl>(D)) {
+ QualType Type = Decl->getType();
+
+ if (Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable])
+ return SK_ConstexprVariable;
+
+ if (!Type.isNull() && Type.isConstQualified()) {
+ if (NamingStyles[SK_ConstantParameter])
+ return SK_ConstantParameter;
+
+ if (NamingStyles[SK_Constant])
+ return SK_Constant;
+ }
+
+ if (Decl->isParameterPack() && NamingStyles[SK_ParameterPack])
+ return SK_ParameterPack;
+
+ if (NamingStyles[SK_Parameter])
+ return SK_Parameter;
+
+ return SK_Invalid;
+ }
+
+ if (const auto *Decl = dyn_cast<VarDecl>(D)) {
+ QualType Type = Decl->getType();
+
+ if (Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable])
+ return SK_ConstexprVariable;
+
+ if (!Type.isNull() && Type.isConstQualified()) {
+ if (Decl->isStaticDataMember() && NamingStyles[SK_ClassConstant])
+ return SK_ClassConstant;
+
+ if (Decl->isFileVarDecl() && NamingStyles[SK_GlobalConstant])
+ return SK_GlobalConstant;
+
+ if (Decl->isStaticLocal() && NamingStyles[SK_StaticConstant])
+ return SK_StaticConstant;
+
+ if (Decl->isLocalVarDecl() && NamingStyles[SK_LocalConstant])
+ return SK_LocalConstant;
+
+ if (Decl->isFunctionOrMethodVarDecl() && NamingStyles[SK_LocalConstant])
+ return SK_LocalConstant;
+
+ if (NamingStyles[SK_Constant])
+ return SK_Constant;
+ }
+
+ if (Decl->isStaticDataMember() && NamingStyles[SK_ClassMember])
+ return SK_ClassMember;
+
+ if (Decl->isFileVarDecl() && NamingStyles[SK_GlobalVariable])
+ return SK_GlobalVariable;
+
+ if (Decl->isStaticLocal() && NamingStyles[SK_StaticVariable])
+ return SK_StaticVariable;
+
+ if (Decl->isLocalVarDecl() && NamingStyles[SK_LocalVariable])
+ return SK_LocalVariable;
+
+ if (Decl->isFunctionOrMethodVarDecl() && NamingStyles[SK_LocalVariable])
+ return SK_LocalVariable;
+
+ if (NamingStyles[SK_Variable])
+ return SK_Variable;
+
+ return SK_Invalid;
+ }
+
+ if (const auto *Decl = dyn_cast<CXXMethodDecl>(D)) {
+ if (Decl->isMain() || !Decl->isUserProvided() ||
+ Decl->isUsualDeallocationFunction() ||
+ Decl->isCopyAssignmentOperator() || Decl->isMoveAssignmentOperator() ||
+ Decl->size_overridden_methods() > 0)
+ return SK_Invalid;
+
+ if (Decl->isConstexpr() && NamingStyles[SK_ConstexprMethod])
+ return SK_ConstexprMethod;
+
+ if (Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction])
+ return SK_ConstexprFunction;
+
+ if (Decl->isStatic() && NamingStyles[SK_ClassMethod])
+ return SK_ClassMethod;
+
+ if (Decl->isVirtual() && NamingStyles[SK_VirtualMethod])
+ return SK_VirtualMethod;
+
+ if (Decl->getAccess() == AS_private && NamingStyles[SK_PrivateMethod])
+ return SK_PrivateMethod;
+
+ if (Decl->getAccess() == AS_protected && NamingStyles[SK_ProtectedMethod])
+ return SK_ProtectedMethod;
+
+ if (Decl->getAccess() == AS_public && NamingStyles[SK_PublicMethod])
+ return SK_PublicMethod;
+
+ if (NamingStyles[SK_Method])
+ return SK_Method;
+
+ if (NamingStyles[SK_Function])
+ return SK_Function;
+
+ return SK_Invalid;
+ }
+
+ if (const auto *Decl = dyn_cast<FunctionDecl>(D)) {
+ if (Decl->isMain())
+ return SK_Invalid;
+
+ if (Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction])
+ return SK_ConstexprFunction;
+
+ if (Decl->isGlobal() && NamingStyles[SK_GlobalFunction])
+ return SK_GlobalFunction;
+
+ if (NamingStyles[SK_Function])
+ return SK_Function;
+ }
+
+ if (isa<TemplateTypeParmDecl>(D)) {
+ if (NamingStyles[SK_TypeTemplateParameter])
+ return SK_TypeTemplateParameter;
+
+ if (NamingStyles[SK_TemplateParameter])
+ return SK_TemplateParameter;
+
+ return SK_Invalid;
+ }
+
+ if (isa<NonTypeTemplateParmDecl>(D)) {
+ if (NamingStyles[SK_ValueTemplateParameter])
+ return SK_ValueTemplateParameter;
+
+ if (NamingStyles[SK_TemplateParameter])
+ return SK_TemplateParameter;
+
+ return SK_Invalid;
+ }
+
+ if (isa<TemplateTemplateParmDecl>(D)) {
+ if (NamingStyles[SK_TemplateTemplateParameter])
+ return SK_TemplateTemplateParameter;
+
+ if (NamingStyles[SK_TemplateParameter])
+ return SK_TemplateParameter;
+
+ return SK_Invalid;
+ }
+
+ return SK_Invalid;
+}
+
+static void addUsage(IdentifierNamingCheck::NamingCheckFailureMap &Failures,
+ const IdentifierNamingCheck::NamingCheckId &Decl,
+ SourceRange Range, SourceManager *SourceMgr = nullptr) {
+ // Do nothing if the provided range is invalid.
+ if (Range.getBegin().isInvalid() || Range.getEnd().isInvalid())
+ return;
+
+ // If we have a source manager, use it to convert to the spelling location for
+ // performing the fix. This is necessary because macros can map the same
+ // spelling location to different source locations, and we only want to fix
+ // the token once, before it is expanded by the macro.
+ SourceLocation FixLocation = Range.getBegin();
+ if (SourceMgr)
+ FixLocation = SourceMgr->getSpellingLoc(FixLocation);
+ if (FixLocation.isInvalid())
+ return;
+
+ // Try to insert the identifier location in the Usages map, and bail out if it
+ // is already in there
+ auto &Failure = Failures[Decl];
+ if (!Failure.RawUsageLocs.insert(FixLocation.getRawEncoding()).second)
+ return;
+
+ if (!Failure.ShouldFix)
+ return;
+
+ // Check if the range is entirely contained within a macro argument.
+ SourceLocation MacroArgExpansionStartForRangeBegin;
+ SourceLocation MacroArgExpansionStartForRangeEnd;
+ bool RangeIsEntirelyWithinMacroArgument =
+ SourceMgr &&
+ SourceMgr->isMacroArgExpansion(Range.getBegin(),
+ &MacroArgExpansionStartForRangeBegin) &&
+ SourceMgr->isMacroArgExpansion(Range.getEnd(),
+ &MacroArgExpansionStartForRangeEnd) &&
+ MacroArgExpansionStartForRangeBegin == MacroArgExpansionStartForRangeEnd;
+
+ // Check if the range contains any locations from a macro expansion.
+ bool RangeContainsMacroExpansion = RangeIsEntirelyWithinMacroArgument ||
+ Range.getBegin().isMacroID() ||
+ Range.getEnd().isMacroID();
+
+ bool RangeCanBeFixed =
+ RangeIsEntirelyWithinMacroArgument || !RangeContainsMacroExpansion;
+ Failure.ShouldFix = RangeCanBeFixed;
+}
+
+/// Convenience method when the usage to be added is a NamedDecl
+static void addUsage(IdentifierNamingCheck::NamingCheckFailureMap &Failures,
+ const NamedDecl *Decl, SourceRange Range,
+ SourceManager *SourceMgr = nullptr) {
+ return addUsage(Failures,
+ IdentifierNamingCheck::NamingCheckId(Decl->getLocation(),
+ Decl->getNameAsString()),
+ Range, SourceMgr);
+}
+
+void IdentifierNamingCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *Decl =
+ Result.Nodes.getNodeAs<CXXConstructorDecl>("classRef")) {
+ if (Decl->isImplicit())
+ return;
+
+ addUsage(NamingCheckFailures, Decl->getParent(),
+ Decl->getNameInfo().getSourceRange());
+
+ for (const auto *Init : Decl->inits()) {
+ if (!Init->isWritten() || Init->isInClassMemberInitializer())
+ continue;
+ if (const auto *FD = Init->getAnyMember())
+ addUsage(NamingCheckFailures, FD,
+ SourceRange(Init->getMemberLocation()));
+ // Note: delegating constructors and base class initializers are handled
+ // via the "typeLoc" matcher.
+ }
+ return;
+ }
+
+ if (const auto *Decl =
+ Result.Nodes.getNodeAs<CXXDestructorDecl>("classRef")) {
+ if (Decl->isImplicit())
+ return;
+
+ SourceRange Range = Decl->getNameInfo().getSourceRange();
+ if (Range.getBegin().isInvalid())
+ return;
+ // The first token that will be found is the ~ (or the equivalent trigraph),
+ // we want instead to replace the next token, that will be the identifier.
+ Range.setBegin(CharSourceRange::getTokenRange(Range).getEnd());
+
+ addUsage(NamingCheckFailures, Decl->getParent(), Range);
+ return;
+ }
+
+ if (const auto *Loc = Result.Nodes.getNodeAs<TypeLoc>("typeLoc")) {
+ NamedDecl *Decl = nullptr;
+ if (const auto &Ref = Loc->getAs<TagTypeLoc>()) {
+ Decl = Ref.getDecl();
+ } else if (const auto &Ref = Loc->getAs<InjectedClassNameTypeLoc>()) {
+ Decl = Ref.getDecl();
+ } else if (const auto &Ref = Loc->getAs<UnresolvedUsingTypeLoc>()) {
+ Decl = Ref.getDecl();
+ } else if (const auto &Ref = Loc->getAs<TemplateTypeParmTypeLoc>()) {
+ Decl = Ref.getDecl();
+ }
+
+ if (Decl) {
+ addUsage(NamingCheckFailures, Decl, Loc->getSourceRange());
+ return;
+ }
+
+ if (const auto &Ref = Loc->getAs<TemplateSpecializationTypeLoc>()) {
+ const auto *Decl =
+ Ref.getTypePtr()->getTemplateName().getAsTemplateDecl();
+
+ SourceRange Range(Ref.getTemplateNameLoc(), Ref.getTemplateNameLoc());
+ if (const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl)) {
+ if (const auto *TemplDecl = ClassDecl->getTemplatedDecl())
+ addUsage(NamingCheckFailures, TemplDecl, Range);
+ return;
+ }
+ }
+
+ if (const auto &Ref =
+ Loc->getAs<DependentTemplateSpecializationTypeLoc>()) {
+ if (const auto *Decl = Ref.getTypePtr()->getAsTagDecl())
+ addUsage(NamingCheckFailures, Decl, Loc->getSourceRange());
+ return;
+ }
+ }
+
+ if (const auto *Loc =
+ Result.Nodes.getNodeAs<NestedNameSpecifierLoc>("nestedNameLoc")) {
+ if (NestedNameSpecifier *Spec = Loc->getNestedNameSpecifier()) {
+ if (NamespaceDecl *Decl = Spec->getAsNamespace()) {
+ addUsage(NamingCheckFailures, Decl, Loc->getLocalSourceRange());
+ return;
+ }
+ }
+ }
+
+ if (const auto *Decl = Result.Nodes.getNodeAs<UsingDecl>("using")) {
+ for (const auto &Shadow : Decl->shadows()) {
+ addUsage(NamingCheckFailures, Shadow->getTargetDecl(),
+ Decl->getNameInfo().getSourceRange());
+ }
+ return;
+ }
+
+ if (const auto *DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>("declRef")) {
+ SourceRange Range = DeclRef->getNameInfo().getSourceRange();
+ addUsage(NamingCheckFailures, DeclRef->getDecl(), Range,
+ Result.SourceManager);
+ return;
+ }
+
+ if (const auto *Decl = Result.Nodes.getNodeAs<NamedDecl>("decl")) {
+ if (!Decl->getIdentifier() || Decl->getName().empty() || Decl->isImplicit())
+ return;
+
+ // Fix type aliases in value declarations
+ if (const auto *Value = Result.Nodes.getNodeAs<ValueDecl>("decl")) {
+ if (const auto *Typedef =
+ Value->getType().getTypePtr()->getAs<TypedefType>()) {
+ addUsage(NamingCheckFailures, Typedef->getDecl(),
+ Value->getSourceRange());
+ }
+ }
+
+ // Fix type aliases in function declarations
+ if (const auto *Value = Result.Nodes.getNodeAs<FunctionDecl>("decl")) {
+ if (const auto *Typedef =
+ Value->getReturnType().getTypePtr()->getAs<TypedefType>()) {
+ addUsage(NamingCheckFailures, Typedef->getDecl(),
+ Value->getSourceRange());
+ }
+ for (unsigned i = 0; i < Value->getNumParams(); ++i) {
+ if (const auto *Typedef = Value->parameters()[i]
+ ->getType()
+ .getTypePtr()
+ ->getAs<TypedefType>()) {
+ addUsage(NamingCheckFailures, Typedef->getDecl(),
+ Value->getSourceRange());
+ }
+ }
+ }
+
+ // Ignore ClassTemplateSpecializationDecl which are creating duplicate
+ // replacements with CXXRecordDecl
+ if (isa<ClassTemplateSpecializationDecl>(Decl))
+ return;
+
+ StyleKind SK = findStyleKind(Decl, NamingStyles);
+ if (SK == SK_Invalid)
+ return;
+
+ if (!NamingStyles[SK])
+ return;
+
+ const NamingStyle &Style = *NamingStyles[SK];
+ StringRef Name = Decl->getName();
+ if (matchesStyle(Name, Style))
+ return;
+
+ std::string KindName = fixupWithCase(StyleNames[SK], CT_LowerCase);
+ std::replace(KindName.begin(), KindName.end(), '_', ' ');
+
+ std::string Fixup = fixupWithStyle(Name, Style);
+ if (StringRef(Fixup).equals(Name)) {
+ if (!IgnoreFailedSplit) {
+ LLVM_DEBUG(llvm::dbgs()
+ << Decl->getLocStart().printToString(*Result.SourceManager)
+ << llvm::format(": unable to split words for %s '%s'\n",
+ KindName.c_str(), Name.str().c_str()));
+ }
+ } else {
+ NamingCheckFailure &Failure = NamingCheckFailures[NamingCheckId(
+ Decl->getLocation(), Decl->getNameAsString())];
+ SourceRange Range =
+ DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
+ .getSourceRange();
+
+ Failure.Fixup = std::move(Fixup);
+ Failure.KindName = std::move(KindName);
+ addUsage(NamingCheckFailures, Decl, Range);
+ }
+ }
+}
+
+void IdentifierNamingCheck::checkMacro(SourceManager &SourceMgr,
+ const Token &MacroNameTok,
+ const MacroInfo *MI) {
+ if (!NamingStyles[SK_MacroDefinition])
+ return;
+
+ StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
+ const NamingStyle &Style = *NamingStyles[SK_MacroDefinition];
+ if (matchesStyle(Name, Style))
+ return;
+
+ std::string KindName =
+ fixupWithCase(StyleNames[SK_MacroDefinition], CT_LowerCase);
+ std::replace(KindName.begin(), KindName.end(), '_', ' ');
+
+ std::string Fixup = fixupWithStyle(Name, Style);
+ if (StringRef(Fixup).equals(Name)) {
+ if (!IgnoreFailedSplit) {
+ LLVM_DEBUG(llvm::dbgs()
+ << MacroNameTok.getLocation().printToString(SourceMgr)
+ << llvm::format(": unable to split words for %s '%s'\n",
+ KindName.c_str(), Name.str().c_str()));
+ }
+ } else {
+ NamingCheckId ID(MI->getDefinitionLoc(), Name);
+ NamingCheckFailure &Failure = NamingCheckFailures[ID];
+ SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
+
+ Failure.Fixup = std::move(Fixup);
+ Failure.KindName = std::move(KindName);
+ addUsage(NamingCheckFailures, ID, Range);
+ }
+}
+
+void IdentifierNamingCheck::expandMacro(const Token &MacroNameTok,
+ const MacroInfo *MI) {
+ StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
+ NamingCheckId ID(MI->getDefinitionLoc(), Name);
+
+ auto Failure = NamingCheckFailures.find(ID);
+ if (Failure == NamingCheckFailures.end())
+ return;
+
+ SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
+ addUsage(NamingCheckFailures, ID, Range);
+}
+
+void IdentifierNamingCheck::onEndOfTranslationUnit() {
+ for (const auto &Pair : NamingCheckFailures) {
+ const NamingCheckId &Decl = Pair.first;
+ const NamingCheckFailure &Failure = Pair.second;
+
+ if (Failure.KindName.empty())
+ continue;
+
+ if (Failure.ShouldFix) {
+ auto Diag = diag(Decl.first, "invalid case style for %0 '%1'")
+ << Failure.KindName << Decl.second;
+
+ for (const auto &Loc : Failure.RawUsageLocs) {
+ // We assume that the identifier name is made of one token only. This is
+ // always the case as we ignore usages in macros that could build
+ // identifier names by combining multiple tokens.
+ //
+ // For destructors, we alread take care of it by remembering the
+ // location of the start of the identifier and not the start of the
+ // tilde.
+ //
+ // Other multi-token identifiers, such as operators are not checked at
+ // all.
+ Diag << FixItHint::CreateReplacement(
+ SourceRange(SourceLocation::getFromRawEncoding(Loc)),
+ Failure.Fixup);
+ }
+ }
+ }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
new file mode 100644
index 0000000..c236ad5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
@@ -0,0 +1,109 @@
+//===--- IdentifierNamingCheck.h - clang-tidy -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+
+class MacroInfo;
+
+namespace tidy {
+namespace readability {
+
+/// Checks for identifiers naming style mismatch.
+///
+/// This check will try to enforce coding guidelines on the identifiers naming.
+/// It supports `lower_case`, `UPPER_CASE`, `camelBack` and `CamelCase` casing
+/// and tries to convert from one to another if a mismatch is detected.
+///
+/// It also supports a fixed prefix and suffix that will be prepended or
+/// appended to the identifiers, regardless of the casing.
+///
+/// Many configuration options are available, in order to be able to create
+/// different rules for different kind of identifier. In general, the
+/// rules are falling back to a more generic rule if the specific case is not
+/// configured.
+class IdentifierNamingCheck : public ClangTidyCheck {
+public:
+ IdentifierNamingCheck(StringRef Name, ClangTidyContext *Context);
+
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+ void onEndOfTranslationUnit() override;
+
+ enum CaseType {
+ CT_AnyCase = 0,
+ CT_LowerCase,
+ CT_CamelBack,
+ CT_UpperCase,
+ CT_CamelCase,
+ CT_CamelSnakeCase,
+ CT_CamelSnakeBack
+ };
+
+ struct NamingStyle {
+ NamingStyle() = default;
+
+ NamingStyle(llvm::Optional<CaseType> Case, const std::string &Prefix,
+ const std::string &Suffix)
+ : Case(Case), Prefix(Prefix), Suffix(Suffix) {}
+
+ llvm::Optional<CaseType> Case;
+ std::string Prefix;
+ std::string Suffix;
+ };
+
+ /// \brief Holds an identifier name check failure, tracking the kind of the
+ /// identifer, its possible fixup and the starting locations of all the
+ /// identifier usages.
+ struct NamingCheckFailure {
+ std::string KindName;
+ std::string Fixup;
+
+ /// \brief Whether the failure should be fixed or not.
+ ///
+ /// ie: if the identifier was used or declared within a macro we won't offer
+ /// a fixup for safety reasons.
+ bool ShouldFix;
+
+ /// \brief A set of all the identifier usages starting SourceLocation, in
+ /// their encoded form.
+ llvm::DenseSet<unsigned> RawUsageLocs;
+
+ NamingCheckFailure() : ShouldFix(true) {}
+ };
+
+ typedef std::pair<SourceLocation, std::string> NamingCheckId;
+
+ typedef llvm::DenseMap<NamingCheckId, NamingCheckFailure>
+ NamingCheckFailureMap;
+
+ /// Check Macros for style violations.
+ void checkMacro(SourceManager &sourceMgr, const Token &MacroNameTok,
+ const MacroInfo *MI);
+
+ /// Add a usage of a macro if it already has a violation.
+ void expandMacro(const Token &MacroNameTok, const MacroInfo *MI);
+
+private:
+ std::vector<llvm::Optional<NamingStyle>> NamingStyles;
+ bool IgnoreFailedSplit;
+ NamingCheckFailureMap NamingCheckFailures;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
new file mode 100644
index 0000000..79022d4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp
@@ -0,0 +1,388 @@
+//===--- ImplicitBoolConversionCheck.cpp - clang-tidy----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ImplicitBoolConversionCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/FixIt.h"
+#include <queue>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+namespace {
+
+AST_MATCHER(Stmt, isMacroExpansion) {
+ SourceManager &SM = Finder->getASTContext().getSourceManager();
+ SourceLocation Loc = Node.getLocStart();
+ return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
+}
+
+bool isNULLMacroExpansion(const Stmt *Statement, ASTContext &Context) {
+ SourceManager &SM = Context.getSourceManager();
+ const LangOptions &LO = Context.getLangOpts();
+ SourceLocation Loc = Statement->getLocStart();
+ return SM.isMacroBodyExpansion(Loc) &&
+ Lexer::getImmediateMacroName(Loc, SM, LO) == "NULL";
+}
+
+AST_MATCHER(Stmt, isNULLMacroExpansion) {
+ return isNULLMacroExpansion(&Node, Finder->getASTContext());
+}
+
+StringRef getZeroLiteralToCompareWithForType(CastKind CastExprKind,
+ QualType Type,
+ ASTContext &Context) {
+ switch (CastExprKind) {
+ case CK_IntegralToBoolean:
+ return Type->isUnsignedIntegerType() ? "0u" : "0";
+
+ case CK_FloatingToBoolean:
+ return Context.hasSameType(Type, Context.FloatTy) ? "0.0f" : "0.0";
+
+ case CK_PointerToBoolean:
+ case CK_MemberPointerToBoolean: // Fall-through on purpose.
+ return Context.getLangOpts().CPlusPlus11 ? "nullptr" : "0";
+
+ default:
+ llvm_unreachable("Unexpected cast kind");
+ }
+}
+
+bool isUnaryLogicalNotOperator(const Stmt *Statement) {
+ const auto *UnaryOperatorExpr = dyn_cast<UnaryOperator>(Statement);
+ return UnaryOperatorExpr && UnaryOperatorExpr->getOpcode() == UO_LNot;
+}
+
+bool areParensNeededForOverloadedOperator(OverloadedOperatorKind OperatorKind) {
+ switch (OperatorKind) {
+ case OO_New:
+ case OO_Delete: // Fall-through on purpose.
+ case OO_Array_New:
+ case OO_Array_Delete:
+ case OO_ArrowStar:
+ case OO_Arrow:
+ case OO_Call:
+ case OO_Subscript:
+ return false;
+
+ default:
+ return true;
+ }
+}
+
+bool areParensNeededForStatement(const Stmt *Statement) {
+ if (const auto *OperatorCall = dyn_cast<CXXOperatorCallExpr>(Statement)) {
+ return areParensNeededForOverloadedOperator(OperatorCall->getOperator());
+ }
+
+ return isa<BinaryOperator>(Statement) || isa<UnaryOperator>(Statement);
+}
+
+void fixGenericExprCastToBool(DiagnosticBuilder &Diag,
+ const ImplicitCastExpr *Cast, const Stmt *Parent,
+ ASTContext &Context) {
+ // In case of expressions like (! integer), we should remove the redundant not
+ // operator and use inverted comparison (integer == 0).
+ bool InvertComparison =
+ Parent != nullptr && isUnaryLogicalNotOperator(Parent);
+ if (InvertComparison) {
+ SourceLocation ParentStartLoc = Parent->getLocStart();
+ SourceLocation ParentEndLoc =
+ cast<UnaryOperator>(Parent)->getSubExpr()->getLocStart();
+ Diag << FixItHint::CreateRemoval(
+ CharSourceRange::getCharRange(ParentStartLoc, ParentEndLoc));
+
+ Parent = Context.getParents(*Parent)[0].get<Stmt>();
+ }
+
+ const Expr *SubExpr = Cast->getSubExpr();
+
+ bool NeedInnerParens = areParensNeededForStatement(SubExpr);
+ bool NeedOuterParens =
+ Parent != nullptr && areParensNeededForStatement(Parent);
+
+ std::string StartLocInsertion;
+
+ if (NeedOuterParens) {
+ StartLocInsertion += "(";
+ }
+ if (NeedInnerParens) {
+ StartLocInsertion += "(";
+ }
+
+ if (!StartLocInsertion.empty()) {
+ Diag << FixItHint::CreateInsertion(Cast->getLocStart(), StartLocInsertion);
+ }
+
+ std::string EndLocInsertion;
+
+ if (NeedInnerParens) {
+ EndLocInsertion += ")";
+ }
+
+ if (InvertComparison) {
+ EndLocInsertion += " == ";
+ } else {
+ EndLocInsertion += " != ";
+ }
+
+ EndLocInsertion += getZeroLiteralToCompareWithForType(
+ Cast->getCastKind(), SubExpr->getType(), Context);
+
+ if (NeedOuterParens) {
+ EndLocInsertion += ")";
+ }
+
+ SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ Cast->getLocEnd(), 0, Context.getSourceManager(), Context.getLangOpts());
+ Diag << FixItHint::CreateInsertion(EndLoc, EndLocInsertion);
+}
+
+StringRef getEquivalentBoolLiteralForExpr(const Expr *Expression,
+ ASTContext &Context) {
+ if (isNULLMacroExpansion(Expression, Context)) {
+ return "false";
+ }
+
+ if (const auto *IntLit = dyn_cast<IntegerLiteral>(Expression)) {
+ return (IntLit->getValue() == 0) ? "false" : "true";
+ }
+
+ if (const auto *FloatLit = dyn_cast<FloatingLiteral>(Expression)) {
+ llvm::APFloat FloatLitAbsValue = FloatLit->getValue();
+ FloatLitAbsValue.clearSign();
+ return (FloatLitAbsValue.bitcastToAPInt() == 0) ? "false" : "true";
+ }
+
+ if (const auto *CharLit = dyn_cast<CharacterLiteral>(Expression)) {
+ return (CharLit->getValue() == 0) ? "false" : "true";
+ }
+
+ if (isa<StringLiteral>(Expression->IgnoreCasts())) {
+ return "true";
+ }
+
+ return StringRef();
+}
+
+void fixGenericExprCastFromBool(DiagnosticBuilder &Diag,
+ const ImplicitCastExpr *Cast,
+ ASTContext &Context, StringRef OtherType) {
+ const Expr *SubExpr = Cast->getSubExpr();
+ bool NeedParens = !isa<ParenExpr>(SubExpr);
+
+ Diag << FixItHint::CreateInsertion(
+ Cast->getLocStart(),
+ (Twine("static_cast<") + OtherType + ">" + (NeedParens ? "(" : ""))
+ .str());
+
+ if (NeedParens) {
+ SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ Cast->getLocEnd(), 0, Context.getSourceManager(),
+ Context.getLangOpts());
+
+ Diag << FixItHint::CreateInsertion(EndLoc, ")");
+ }
+}
+
+StringRef getEquivalentForBoolLiteral(const CXXBoolLiteralExpr *BoolLiteral,
+ QualType DestType, ASTContext &Context) {
+ // Prior to C++11, false literal could be implicitly converted to pointer.
+ if (!Context.getLangOpts().CPlusPlus11 &&
+ (DestType->isPointerType() || DestType->isMemberPointerType()) &&
+ BoolLiteral->getValue() == false) {
+ return "0";
+ }
+
+ if (DestType->isFloatingType()) {
+ if (Context.hasSameType(DestType, Context.FloatTy)) {
+ return BoolLiteral->getValue() ? "1.0f" : "0.0f";
+ }
+ return BoolLiteral->getValue() ? "1.0" : "0.0";
+ }
+
+ if (DestType->isUnsignedIntegerType()) {
+ return BoolLiteral->getValue() ? "1u" : "0u";
+ }
+ return BoolLiteral->getValue() ? "1" : "0";
+}
+
+bool isCastAllowedInCondition(const ImplicitCastExpr *Cast,
+ ASTContext &Context) {
+ std::queue<const Stmt *> Q;
+ Q.push(Cast);
+ while (!Q.empty()) {
+ for (const auto &N : Context.getParents(*Q.front())) {
+ const Stmt *S = N.get<Stmt>();
+ if (!S)
+ return false;
+ if (isa<IfStmt>(S) || isa<ConditionalOperator>(S) || isa<ForStmt>(S) ||
+ isa<WhileStmt>(S) || isa<BinaryConditionalOperator>(S))
+ return true;
+ if (isa<ParenExpr>(S) || isa<ImplicitCastExpr>(S) ||
+ isUnaryLogicalNotOperator(S) ||
+ (isa<BinaryOperator>(S) && cast<BinaryOperator>(S)->isLogicalOp())) {
+ Q.push(S);
+ } else {
+ return false;
+ }
+ }
+ Q.pop();
+ }
+ return false;
+}
+
+} // anonymous namespace
+
+ImplicitBoolConversionCheck::ImplicitBoolConversionCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ AllowIntegerConditions(Options.get("AllowIntegerConditions", false)),
+ AllowPointerConditions(Options.get("AllowPointerConditions", false)) {}
+
+void ImplicitBoolConversionCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "AllowIntegerConditions", AllowIntegerConditions);
+ Options.store(Opts, "AllowPointerConditions", AllowPointerConditions);
+}
+
+void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) {
+ // This check doesn't make much sense if we run it on language without
+ // built-in bool support.
+ if (!getLangOpts().Bool) {
+ return;
+ }
+
+ auto exceptionCases =
+ expr(anyOf(allOf(isMacroExpansion(), unless(isNULLMacroExpansion())),
+ hasParent(explicitCastExpr())));
+ auto implicitCastFromBool = implicitCastExpr(
+ anyOf(hasCastKind(CK_IntegralCast), hasCastKind(CK_IntegralToFloating),
+ // Prior to C++11 cast from bool literal to pointer was allowed.
+ allOf(anyOf(hasCastKind(CK_NullToPointer),
+ hasCastKind(CK_NullToMemberPointer)),
+ hasSourceExpression(cxxBoolLiteral()))),
+ hasSourceExpression(expr(hasType(booleanType()))),
+ unless(exceptionCases));
+ auto boolXor =
+ binaryOperator(hasOperatorName("^"), hasLHS(implicitCastFromBool),
+ hasRHS(implicitCastFromBool));
+ Finder->addMatcher(
+ implicitCastExpr(
+ anyOf(hasCastKind(CK_IntegralToBoolean),
+ hasCastKind(CK_FloatingToBoolean),
+ hasCastKind(CK_PointerToBoolean),
+ hasCastKind(CK_MemberPointerToBoolean)),
+ // Exclude case of using if or while statements with variable
+ // declaration, e.g.:
+ // if (int var = functionCall()) {}
+ unless(
+ hasParent(stmt(anyOf(ifStmt(), whileStmt()), has(declStmt())))),
+ // Exclude cases common to implicit cast to and from bool.
+ unless(exceptionCases), unless(has(boolXor)),
+ // Retrive also parent statement, to check if we need additional
+ // parens in replacement.
+ anyOf(hasParent(stmt().bind("parentStmt")), anything()),
+ unless(isInTemplateInstantiation()),
+ unless(hasAncestor(functionTemplateDecl())))
+ .bind("implicitCastToBool"),
+ this);
+
+ auto boolComparison = binaryOperator(
+ anyOf(hasOperatorName("=="), hasOperatorName("!=")),
+ hasLHS(implicitCastFromBool), hasRHS(implicitCastFromBool));
+ auto boolOpAssignment =
+ binaryOperator(anyOf(hasOperatorName("|="), hasOperatorName("&=")),
+ hasLHS(expr(hasType(booleanType()))));
+ Finder->addMatcher(
+ implicitCastExpr(
+ implicitCastFromBool,
+ // Exclude comparisons of bools, as they are always cast to integers
+ // in such context:
+ // bool_expr_a == bool_expr_b
+ // bool_expr_a != bool_expr_b
+ unless(hasParent(binaryOperator(
+ anyOf(boolComparison, boolXor, boolOpAssignment)))),
+ // Check also for nested casts, for example: bool -> int -> float.
+ anyOf(hasParent(implicitCastExpr().bind("furtherImplicitCast")),
+ anything()),
+ unless(isInTemplateInstantiation()),
+ unless(hasAncestor(functionTemplateDecl())))
+ .bind("implicitCastFromBool"),
+ this);
+}
+
+void ImplicitBoolConversionCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ if (const auto *CastToBool =
+ Result.Nodes.getNodeAs<ImplicitCastExpr>("implicitCastToBool")) {
+ const auto *Parent = Result.Nodes.getNodeAs<Stmt>("parentStmt");
+ return handleCastToBool(CastToBool, Parent, *Result.Context);
+ }
+
+ if (const auto *CastFromBool =
+ Result.Nodes.getNodeAs<ImplicitCastExpr>("implicitCastFromBool")) {
+ const auto *NextImplicitCast =
+ Result.Nodes.getNodeAs<ImplicitCastExpr>("furtherImplicitCast");
+ return handleCastFromBool(CastFromBool, NextImplicitCast, *Result.Context);
+ }
+}
+
+void ImplicitBoolConversionCheck::handleCastToBool(const ImplicitCastExpr *Cast,
+ const Stmt *Parent,
+ ASTContext &Context) {
+ if (AllowPointerConditions &&
+ (Cast->getCastKind() == CK_PointerToBoolean ||
+ Cast->getCastKind() == CK_MemberPointerToBoolean) &&
+ isCastAllowedInCondition(Cast, Context)) {
+ return;
+ }
+
+ if (AllowIntegerConditions && Cast->getCastKind() == CK_IntegralToBoolean &&
+ isCastAllowedInCondition(Cast, Context)) {
+ return;
+ }
+
+ auto Diag = diag(Cast->getLocStart(), "implicit conversion %0 -> bool")
+ << Cast->getSubExpr()->getType();
+
+ StringRef EquivalentLiteral =
+ getEquivalentBoolLiteralForExpr(Cast->getSubExpr(), Context);
+ if (!EquivalentLiteral.empty()) {
+ Diag << tooling::fixit::createReplacement(*Cast, EquivalentLiteral);
+ } else {
+ fixGenericExprCastToBool(Diag, Cast, Parent, Context);
+ }
+}
+
+void ImplicitBoolConversionCheck::handleCastFromBool(
+ const ImplicitCastExpr *Cast, const ImplicitCastExpr *NextImplicitCast,
+ ASTContext &Context) {
+ QualType DestType =
+ NextImplicitCast ? NextImplicitCast->getType() : Cast->getType();
+ auto Diag = diag(Cast->getLocStart(), "implicit conversion bool -> %0")
+ << DestType;
+
+ if (const auto *BoolLiteral =
+ dyn_cast<CXXBoolLiteralExpr>(Cast->getSubExpr())) {
+ Diag << tooling::fixit::createReplacement(
+ *Cast, getEquivalentForBoolLiteral(BoolLiteral, DestType, Context));
+ } else {
+ fixGenericExprCastFromBool(Diag, Cast, Context, DestType.getAsString());
+ }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h
new file mode 100644
index 0000000..bb062e0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.h
@@ -0,0 +1,46 @@
+//===--- ImplicitBoolConversionCheck.h - clang-tidy--------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IMPLICIT_BOOL_CONVERSION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IMPLICIT_BOOL_CONVERSION_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// \brief Checks for use of implicit bool conversions in expressions.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-implicit-bool-conversion.html
+class ImplicitBoolConversionCheck : public ClangTidyCheck {
+public:
+ ImplicitBoolConversionCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void handleCastToBool(const ImplicitCastExpr *CastExpression,
+ const Stmt *ParentStatement, ASTContext &Context);
+ void handleCastFromBool(const ImplicitCastExpr *CastExpression,
+ const ImplicitCastExpr *FurtherImplicitCastExpression,
+ ASTContext &Context);
+
+ const bool AllowIntegerConditions;
+ const bool AllowPointerConditions;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IMPLICIT_BOOL_CONVERSION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.cpp
new file mode 100644
index 0000000..f1d0036
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.cpp
@@ -0,0 +1,360 @@
+//===--- InconsistentDeclarationParameterNameCheck.cpp - clang-tidy-------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InconsistentDeclarationParameterNameCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+#include <algorithm>
+#include <functional>
+#include <sstream>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+namespace {
+
+AST_MATCHER(FunctionDecl, hasOtherDeclarations) {
+ auto It = Node.redecls_begin();
+ auto EndIt = Node.redecls_end();
+
+ if (It == EndIt)
+ return false;
+
+ ++It;
+ return It != EndIt;
+}
+
+struct DifferingParamInfo {
+ DifferingParamInfo(StringRef SourceName, StringRef OtherName,
+ SourceRange OtherNameRange, bool GenerateFixItHint)
+ : SourceName(SourceName), OtherName(OtherName),
+ OtherNameRange(OtherNameRange), GenerateFixItHint(GenerateFixItHint) {}
+
+ StringRef SourceName;
+ StringRef OtherName;
+ SourceRange OtherNameRange;
+ bool GenerateFixItHint;
+};
+
+using DifferingParamsContainer = llvm::SmallVector<DifferingParamInfo, 10>;
+
+struct InconsistentDeclarationInfo {
+ InconsistentDeclarationInfo(SourceLocation DeclarationLocation,
+ DifferingParamsContainer &&DifferingParams)
+ : DeclarationLocation(DeclarationLocation),
+ DifferingParams(std::move(DifferingParams)) {}
+
+ SourceLocation DeclarationLocation;
+ DifferingParamsContainer DifferingParams;
+};
+
+using InconsistentDeclarationsContainer =
+ llvm::SmallVector<InconsistentDeclarationInfo, 2>;
+
+bool checkIfFixItHintIsApplicable(
+ const FunctionDecl *ParameterSourceDeclaration,
+ const ParmVarDecl *SourceParam, const FunctionDecl *OriginalDeclaration) {
+ // Assumptions with regard to function declarations/definition:
+ // * If both function declaration and definition are seen, assume that
+ // definition is most up-to-date, and use it to generate replacements.
+ // * If only function declarations are seen, there is no easy way to tell
+ // which is up-to-date and which is not, so don't do anything.
+ // TODO: This may be changed later, but for now it seems the reasonable
+ // solution.
+ if (!ParameterSourceDeclaration->isThisDeclarationADefinition())
+ return false;
+
+ // Assumption: if parameter is not referenced in function defintion body, it
+ // may indicate that it's outdated, so don't touch it.
+ if (!SourceParam->isReferenced())
+ return false;
+
+ // In case there is the primary template definition and (possibly several)
+ // template specializations (and each with possibly several redeclarations),
+ // it is not at all clear what to change.
+ if (OriginalDeclaration->getTemplatedKind() ==
+ FunctionDecl::TK_FunctionTemplateSpecialization)
+ return false;
+
+ // Other cases seem OK to allow replacements.
+ return true;
+}
+
+bool nameMatch(StringRef L, StringRef R, bool Strict) {
+ if (Strict)
+ return L.empty() || R.empty() || L == R;
+ // We allow two names if one is a prefix/suffix of the other, ignoring case.
+ // Important special case: this is true if either parameter has no name!
+ return L.startswith_lower(R) || R.startswith_lower(L) ||
+ L.endswith_lower(R) || R.endswith_lower(L);
+}
+
+DifferingParamsContainer
+findDifferingParamsInDeclaration(const FunctionDecl *ParameterSourceDeclaration,
+ const FunctionDecl *OtherDeclaration,
+ const FunctionDecl *OriginalDeclaration,
+ bool Strict) {
+ DifferingParamsContainer DifferingParams;
+
+ auto SourceParamIt = ParameterSourceDeclaration->param_begin();
+ auto OtherParamIt = OtherDeclaration->param_begin();
+
+ while (SourceParamIt != ParameterSourceDeclaration->param_end() &&
+ OtherParamIt != OtherDeclaration->param_end()) {
+ auto SourceParamName = (*SourceParamIt)->getName();
+ auto OtherParamName = (*OtherParamIt)->getName();
+
+ // FIXME: Provide a way to extract commented out parameter name from comment
+ // next to it.
+ if (!nameMatch(SourceParamName, OtherParamName, Strict)) {
+ SourceRange OtherParamNameRange =
+ DeclarationNameInfo((*OtherParamIt)->getDeclName(),
+ (*OtherParamIt)->getLocation())
+ .getSourceRange();
+
+ bool GenerateFixItHint = checkIfFixItHintIsApplicable(
+ ParameterSourceDeclaration, *SourceParamIt, OriginalDeclaration);
+
+ DifferingParams.emplace_back(SourceParamName, OtherParamName,
+ OtherParamNameRange, GenerateFixItHint);
+ }
+
+ ++SourceParamIt;
+ ++OtherParamIt;
+ }
+
+ return DifferingParams;
+}
+
+InconsistentDeclarationsContainer
+findInconsistentDeclarations(const FunctionDecl *OriginalDeclaration,
+ const FunctionDecl *ParameterSourceDeclaration,
+ SourceManager &SM, bool Strict) {
+ InconsistentDeclarationsContainer InconsistentDeclarations;
+ SourceLocation ParameterSourceLocation =
+ ParameterSourceDeclaration->getLocation();
+
+ for (const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls()) {
+ SourceLocation OtherLocation = OtherDeclaration->getLocation();
+ if (OtherLocation != ParameterSourceLocation) { // Skip self.
+ DifferingParamsContainer DifferingParams =
+ findDifferingParamsInDeclaration(ParameterSourceDeclaration,
+ OtherDeclaration,
+ OriginalDeclaration, Strict);
+ if (!DifferingParams.empty()) {
+ InconsistentDeclarations.emplace_back(OtherDeclaration->getLocation(),
+ std::move(DifferingParams));
+ }
+ }
+ }
+
+ // Sort in order of appearance in translation unit to generate clear
+ // diagnostics.
+ std::sort(InconsistentDeclarations.begin(), InconsistentDeclarations.end(),
+ [&SM](const InconsistentDeclarationInfo &Info1,
+ const InconsistentDeclarationInfo &Info2) {
+ return SM.isBeforeInTranslationUnit(Info1.DeclarationLocation,
+ Info2.DeclarationLocation);
+ });
+ return InconsistentDeclarations;
+}
+
+const FunctionDecl *
+getParameterSourceDeclaration(const FunctionDecl *OriginalDeclaration) {
+ const FunctionTemplateDecl *PrimaryTemplate =
+ OriginalDeclaration->getPrimaryTemplate();
+ if (PrimaryTemplate != nullptr) {
+ // In case of template specializations, use primary template declaration as
+ // the source of parameter names.
+ return PrimaryTemplate->getTemplatedDecl();
+ }
+
+ // In other cases, try to change to function definition, if available.
+
+ if (OriginalDeclaration->isThisDeclarationADefinition())
+ return OriginalDeclaration;
+
+ for (const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls()) {
+ if (OtherDeclaration->isThisDeclarationADefinition()) {
+ return OtherDeclaration;
+ }
+ }
+
+ // No definition found, so return original declaration.
+ return OriginalDeclaration;
+}
+
+std::string joinParameterNames(
+ const DifferingParamsContainer &DifferingParams,
+ llvm::function_ref<StringRef(const DifferingParamInfo &)> ChooseParamName) {
+ llvm::SmallVector<char, 40> Buffer;
+ llvm::raw_svector_ostream Str(Buffer);
+ bool First = true;
+ for (const DifferingParamInfo &ParamInfo : DifferingParams) {
+ if (First)
+ First = false;
+ else
+ Str << ", ";
+
+ Str << "'" << ChooseParamName(ParamInfo).str() << "'";
+ }
+ return Str.str().str();
+}
+
+void formatDifferingParamsDiagnostic(
+ InconsistentDeclarationParameterNameCheck *Check, SourceLocation Location,
+ StringRef OtherDeclarationDescription,
+ const DifferingParamsContainer &DifferingParams) {
+ auto ChooseOtherName = [](const DifferingParamInfo &ParamInfo) {
+ return ParamInfo.OtherName;
+ };
+ auto ChooseSourceName = [](const DifferingParamInfo &ParamInfo) {
+ return ParamInfo.SourceName;
+ };
+
+ auto ParamDiag =
+ Check->diag(Location,
+ "differing parameters are named here: (%0), in %1: (%2)",
+ DiagnosticIDs::Level::Note)
+ << joinParameterNames(DifferingParams, ChooseOtherName)
+ << OtherDeclarationDescription
+ << joinParameterNames(DifferingParams, ChooseSourceName);
+
+ for (const DifferingParamInfo &ParamInfo : DifferingParams) {
+ if (ParamInfo.GenerateFixItHint) {
+ ParamDiag << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(ParamInfo.OtherNameRange),
+ ParamInfo.SourceName);
+ }
+ }
+}
+
+void formatDiagnosticsForDeclarations(
+ InconsistentDeclarationParameterNameCheck *Check,
+ const FunctionDecl *ParameterSourceDeclaration,
+ const FunctionDecl *OriginalDeclaration,
+ const InconsistentDeclarationsContainer &InconsistentDeclarations) {
+ Check->diag(
+ OriginalDeclaration->getLocation(),
+ "function %q0 has %1 other declaration%s1 with different parameter names")
+ << OriginalDeclaration
+ << static_cast<int>(InconsistentDeclarations.size());
+ int Count = 1;
+ for (const InconsistentDeclarationInfo &InconsistentDeclaration :
+ InconsistentDeclarations) {
+ Check->diag(InconsistentDeclaration.DeclarationLocation,
+ "the %ordinal0 inconsistent declaration seen here",
+ DiagnosticIDs::Level::Note)
+ << Count;
+
+ formatDifferingParamsDiagnostic(
+ Check, InconsistentDeclaration.DeclarationLocation,
+ "the other declaration", InconsistentDeclaration.DifferingParams);
+
+ ++Count;
+ }
+}
+
+void formatDiagnostics(
+ InconsistentDeclarationParameterNameCheck *Check,
+ const FunctionDecl *ParameterSourceDeclaration,
+ const FunctionDecl *OriginalDeclaration,
+ const InconsistentDeclarationsContainer &InconsistentDeclarations,
+ StringRef FunctionDescription, StringRef ParameterSourceDescription) {
+ for (const InconsistentDeclarationInfo &InconsistentDeclaration :
+ InconsistentDeclarations) {
+ Check->diag(InconsistentDeclaration.DeclarationLocation,
+ "%0 %q1 has a %2 with different parameter names")
+ << FunctionDescription << OriginalDeclaration
+ << ParameterSourceDescription;
+
+ Check->diag(ParameterSourceDeclaration->getLocation(), "the %0 seen here",
+ DiagnosticIDs::Level::Note)
+ << ParameterSourceDescription;
+
+ formatDifferingParamsDiagnostic(
+ Check, InconsistentDeclaration.DeclarationLocation,
+ ParameterSourceDescription, InconsistentDeclaration.DifferingParams);
+ }
+}
+
+} // anonymous namespace
+
+void InconsistentDeclarationParameterNameCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IgnoreMacros", IgnoreMacros);
+ Options.store(Opts, "Strict", Strict);
+}
+
+void InconsistentDeclarationParameterNameCheck::registerMatchers(
+ MatchFinder *Finder) {
+ Finder->addMatcher(functionDecl(unless(isImplicit()), hasOtherDeclarations())
+ .bind("functionDecl"),
+ this);
+}
+
+void InconsistentDeclarationParameterNameCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *OriginalDeclaration =
+ Result.Nodes.getNodeAs<FunctionDecl>("functionDecl");
+
+ if (VisitedDeclarations.count(OriginalDeclaration) > 0)
+ return; // Avoid multiple warnings.
+
+ const FunctionDecl *ParameterSourceDeclaration =
+ getParameterSourceDeclaration(OriginalDeclaration);
+
+ InconsistentDeclarationsContainer InconsistentDeclarations =
+ findInconsistentDeclarations(OriginalDeclaration,
+ ParameterSourceDeclaration,
+ *Result.SourceManager, Strict);
+ if (InconsistentDeclarations.empty()) {
+ // Avoid unnecessary further visits.
+ markRedeclarationsAsVisited(OriginalDeclaration);
+ return;
+ }
+
+ SourceLocation StartLoc = OriginalDeclaration->getLocStart();
+ if (StartLoc.isMacroID() && IgnoreMacros) {
+ markRedeclarationsAsVisited(OriginalDeclaration);
+ return;
+ }
+
+ if (OriginalDeclaration->getTemplatedKind() ==
+ FunctionDecl::TK_FunctionTemplateSpecialization) {
+ formatDiagnostics(this, ParameterSourceDeclaration, OriginalDeclaration,
+ InconsistentDeclarations,
+ "function template specialization",
+ "primary template declaration");
+ } else if (ParameterSourceDeclaration->isThisDeclarationADefinition()) {
+ formatDiagnostics(this, ParameterSourceDeclaration, OriginalDeclaration,
+ InconsistentDeclarations, "function", "definition");
+ } else {
+ formatDiagnosticsForDeclarations(this, ParameterSourceDeclaration,
+ OriginalDeclaration,
+ InconsistentDeclarations);
+ }
+
+ markRedeclarationsAsVisited(OriginalDeclaration);
+}
+
+void InconsistentDeclarationParameterNameCheck::markRedeclarationsAsVisited(
+ const FunctionDecl *OriginalDeclaration) {
+ for (const FunctionDecl *Redecl : OriginalDeclaration->redecls()) {
+ VisitedDeclarations.insert(Redecl);
+ }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.h
new file mode 100644
index 0000000..602856f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.h
@@ -0,0 +1,50 @@
+//===- InconsistentDeclarationParameterNameCheck.h - clang-tidy-*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_INCONSISTENT_DECLARATION_PARAMETER_NAME_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_INCONSISTENT_DECLARATION_PARAMETER_NAME_H
+
+#include "../ClangTidy.h"
+
+#include "llvm/ADT/DenseSet.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// \brief Checks for declarations of functions which differ in parameter names.
+///
+/// For detailed documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-inconsistent-declaration-parameter-name.html
+///
+class InconsistentDeclarationParameterNameCheck : public ClangTidyCheck {
+public:
+ InconsistentDeclarationParameterNameCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", 1) != 0),
+ Strict(Options.getLocalOrGlobal("Strict", 0) != 0) {}
+
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void markRedeclarationsAsVisited(const FunctionDecl *FunctionDeclaration);
+
+ llvm::DenseSet<const FunctionDecl *> VisitedDeclarations;
+ const bool IgnoreMacros;
+ const bool Strict;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_INCONSISTENT_DECLARATION_PARAMETER_NAME_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/MisleadingIndentationCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/MisleadingIndentationCheck.cpp
new file mode 100644
index 0000000..8a6c8c4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/MisleadingIndentationCheck.cpp
@@ -0,0 +1,123 @@
+//===--- MisleadingIndentationCheck.cpp - clang-tidy-----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MisleadingIndentationCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+static const IfStmt *getPrecedingIf(const SourceManager &SM,
+ ASTContext *Context, const IfStmt *If) {
+ auto parents = Context->getParents(*If);
+ if (parents.size() != 1)
+ return nullptr;
+ if (const auto *PrecedingIf = parents[0].get<IfStmt>()) {
+ SourceLocation PreviousElseLoc = PrecedingIf->getElseLoc();
+ if (SM.getExpansionLineNumber(PreviousElseLoc) ==
+ SM.getExpansionLineNumber(If->getIfLoc()))
+ return PrecedingIf;
+ }
+ return nullptr;
+}
+
+void MisleadingIndentationCheck::danglingElseCheck(const SourceManager &SM,
+ ASTContext *Context,
+ const IfStmt *If) {
+ SourceLocation IfLoc = If->getIfLoc();
+ SourceLocation ElseLoc = If->getElseLoc();
+
+ if (IfLoc.isMacroID() || ElseLoc.isMacroID())
+ return;
+
+ if (SM.getExpansionLineNumber(If->getThen()->getLocEnd()) ==
+ SM.getExpansionLineNumber(ElseLoc))
+ return;
+
+ // Find location of first 'if' in a 'if else if' chain.
+ for (auto PrecedingIf = getPrecedingIf(SM, Context, If); PrecedingIf;
+ PrecedingIf = getPrecedingIf(SM, Context, PrecedingIf))
+ IfLoc = PrecedingIf->getIfLoc();
+
+ if (SM.getExpansionColumnNumber(IfLoc) !=
+ SM.getExpansionColumnNumber(ElseLoc))
+ diag(ElseLoc, "different indentation for 'if' and corresponding 'else'");
+}
+
+void MisleadingIndentationCheck::missingBracesCheck(const SourceManager &SM,
+ const CompoundStmt *CStmt) {
+ const static StringRef StmtNames[] = {"if", "for", "while"};
+ for (unsigned int i = 0; i < CStmt->size() - 1; i++) {
+ const Stmt *CurrentStmt = CStmt->body_begin()[i];
+ const Stmt *Inner = nullptr;
+ int StmtKind = 0;
+
+ if (const auto *CurrentIf = dyn_cast<IfStmt>(CurrentStmt)) {
+ StmtKind = 0;
+ Inner =
+ CurrentIf->getElse() ? CurrentIf->getElse() : CurrentIf->getThen();
+ } else if (const auto *CurrentFor = dyn_cast<ForStmt>(CurrentStmt)) {
+ StmtKind = 1;
+ Inner = CurrentFor->getBody();
+ } else if (const auto *CurrentWhile = dyn_cast<WhileStmt>(CurrentStmt)) {
+ StmtKind = 2;
+ Inner = CurrentWhile->getBody();
+ } else {
+ continue;
+ }
+
+ if (isa<CompoundStmt>(Inner))
+ continue;
+
+ SourceLocation InnerLoc = Inner->getLocStart();
+ SourceLocation OuterLoc = CurrentStmt->getLocStart();
+
+ if (SM.getExpansionLineNumber(InnerLoc) ==
+ SM.getExpansionLineNumber(OuterLoc))
+ continue;
+
+ const Stmt *NextStmt = CStmt->body_begin()[i + 1];
+ SourceLocation NextLoc = NextStmt->getLocStart();
+
+ if (InnerLoc.isMacroID() || OuterLoc.isMacroID() || NextLoc.isMacroID())
+ continue;
+
+ if (SM.getExpansionColumnNumber(InnerLoc) ==
+ SM.getExpansionColumnNumber(NextLoc)) {
+ diag(NextLoc, "misleading indentation: statement is indented too deeply");
+ diag(OuterLoc, "did you mean this line to be inside this '%0'",
+ DiagnosticIDs::Note)
+ << StmtNames[StmtKind];
+ }
+ }
+}
+
+void MisleadingIndentationCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(ifStmt(hasElse(stmt())).bind("if"), this);
+ Finder->addMatcher(
+ compoundStmt(has(stmt(anyOf(ifStmt(), forStmt(), whileStmt()))))
+ .bind("compound"),
+ this);
+}
+
+void MisleadingIndentationCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *If = Result.Nodes.getNodeAs<IfStmt>("if"))
+ danglingElseCheck(*Result.SourceManager, Result.Context, If);
+
+ if (const auto *CStmt = Result.Nodes.getNodeAs<CompoundStmt>("compound"))
+ missingBracesCheck(*Result.SourceManager, CStmt);
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/MisleadingIndentationCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/MisleadingIndentationCheck.h
new file mode 100644
index 0000000..0ca50bb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/MisleadingIndentationCheck.h
@@ -0,0 +1,42 @@
+//===--- MisleadingIndentationCheck.h - clang-tidy---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MISLEADING_INDENTATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MISLEADING_INDENTATION_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Checks the code for dangling else, and possible misleading indentations due
+/// to missing braces. Note that this check only works as expected when the tabs
+/// or spaces are used consistently and not mixed.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-misleading-indentation.html
+class MisleadingIndentationCheck : public ClangTidyCheck {
+public:
+ MisleadingIndentationCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void danglingElseCheck(const SourceManager &SM, ASTContext *Context,
+ const IfStmt *If);
+ void missingBracesCheck(const SourceManager &SM, const CompoundStmt *CStmt);
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MISLEADING_INDENTATION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/MisplacedArrayIndexCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/MisplacedArrayIndexCheck.cpp
new file mode 100644
index 0000000..f5e09fa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/MisplacedArrayIndexCheck.cpp
@@ -0,0 +1,57 @@
+//===--- MisplacedArrayIndexCheck.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MisplacedArrayIndexCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+void MisplacedArrayIndexCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(arraySubscriptExpr(hasLHS(hasType(isInteger())),
+ hasRHS(hasType(isAnyPointer())))
+ .bind("expr"),
+ this);
+}
+
+void MisplacedArrayIndexCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *ArraySubscriptE =
+ Result.Nodes.getNodeAs<ArraySubscriptExpr>("expr");
+
+ auto Diag = diag(ArraySubscriptE->getLocStart(), "confusing array subscript "
+ "expression, usually the "
+ "index is inside the []");
+
+ // Only try to fixit when LHS and RHS can be swapped directly without changing
+ // the logic.
+ const Expr *RHSE = ArraySubscriptE->getRHS()->IgnoreParenImpCasts();
+ if (!isa<StringLiteral>(RHSE) && !isa<DeclRefExpr>(RHSE) &&
+ !isa<MemberExpr>(RHSE))
+ return;
+
+ const StringRef LText = tooling::fixit::getText(
+ ArraySubscriptE->getLHS()->getSourceRange(), *Result.Context);
+ const StringRef RText = tooling::fixit::getText(
+ ArraySubscriptE->getRHS()->getSourceRange(), *Result.Context);
+
+ Diag << FixItHint::CreateReplacement(
+ ArraySubscriptE->getLHS()->getSourceRange(), RText);
+ Diag << FixItHint::CreateReplacement(
+ ArraySubscriptE->getRHS()->getSourceRange(), LText);
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/MisplacedArrayIndexCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/MisplacedArrayIndexCheck.h
new file mode 100644
index 0000000..e9a2231
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/MisplacedArrayIndexCheck.h
@@ -0,0 +1,36 @@
+//===--- MisplacedArrayIndexCheck.h - clang-tidy-----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MISPLACED_ARRAY_INDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MISPLACED_ARRAY_INDEX_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Warn about unusual array index syntax (`index[array]` instead of
+/// `array[index]`).
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-misplaced-array-index.html
+class MisplacedArrayIndexCheck : public ClangTidyCheck {
+public:
+ MisplacedArrayIndexCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_MISPLACED_ARRAY_INDEX_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NamedParameterCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NamedParameterCheck.cpp
new file mode 100644
index 0000000..ffdc813
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NamedParameterCheck.cpp
@@ -0,0 +1,127 @@
+//===--- NamedParameterCheck.cpp - clang-tidy -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NamedParameterCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+void NamedParameterCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
+ Finder->addMatcher(functionDecl(unless(isInstantiated())).bind("decl"), this);
+}
+
+void NamedParameterCheck::check(const MatchFinder::MatchResult &Result) {
+ const SourceManager &SM = *Result.SourceManager;
+ const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>("decl");
+ SmallVector<std::pair<const FunctionDecl *, unsigned>, 4> UnnamedParams;
+
+ // Ignore implicitly generated members.
+ if (Function->isImplicit())
+ return;
+
+ // Ignore declarations without a definition if we're not dealing with an
+ // overriden method.
+ const FunctionDecl *Definition = nullptr;
+ if ((!Function->isDefined(Definition) || Function->isDefaulted() ||
+ Function->isDeleted()) &&
+ (!isa<CXXMethodDecl>(Function) ||
+ cast<CXXMethodDecl>(Function)->size_overridden_methods() == 0))
+ return;
+
+ // TODO: Handle overloads.
+ // TODO: We could check that all redeclarations use the same name for
+ // arguments in the same position.
+ for (unsigned I = 0, E = Function->getNumParams(); I != E; ++I) {
+ const ParmVarDecl *Parm = Function->getParamDecl(I);
+ if (Parm->isImplicit())
+ continue;
+ // Look for unnamed parameters.
+ if (!Parm->getName().empty())
+ continue;
+
+ // Don't warn on the dummy argument on post-inc and post-dec operators.
+ if ((Function->getOverloadedOperator() == OO_PlusPlus ||
+ Function->getOverloadedOperator() == OO_MinusMinus) &&
+ Parm->getType()->isSpecificBuiltinType(BuiltinType::Int))
+ continue;
+
+ // Sanity check the source locations.
+ if (!Parm->getLocation().isValid() || Parm->getLocation().isMacroID() ||
+ !SM.isWrittenInSameFile(Parm->getLocStart(), Parm->getLocation()))
+ continue;
+
+ // Skip gmock testing::Unused parameters.
+ if (auto Typedef = Parm->getType()->getAs<clang::TypedefType>())
+ if (Typedef->getDecl()->getQualifiedNameAsString() == "testing::Unused")
+ continue;
+
+ // Skip std::nullptr_t.
+ if (Parm->getType().getCanonicalType()->isNullPtrType())
+ continue;
+
+ // Look for comments. We explicitly want to allow idioms like
+ // void foo(int /*unused*/)
+ const char *Begin = SM.getCharacterData(Parm->getLocStart());
+ const char *End = SM.getCharacterData(Parm->getLocation());
+ StringRef Data(Begin, End - Begin);
+ if (Data.find("/*") != StringRef::npos)
+ continue;
+
+ UnnamedParams.push_back(std::make_pair(Function, I));
+ }
+
+ // Emit only one warning per function but fixits for all unnamed parameters.
+ if (!UnnamedParams.empty()) {
+ const ParmVarDecl *FirstParm =
+ UnnamedParams.front().first->getParamDecl(UnnamedParams.front().second);
+ auto D = diag(FirstParm->getLocation(),
+ "all parameters should be named in a function");
+
+ for (auto P : UnnamedParams) {
+ // Fallback to an unused marker.
+ StringRef NewName = "unused";
+
+ // If the method is overridden, try to copy the name from the base method
+ // into the overrider.
+ const auto *M = dyn_cast<CXXMethodDecl>(P.first);
+ if (M && M->size_overridden_methods() > 0) {
+ const ParmVarDecl *OtherParm =
+ (*M->begin_overridden_methods())->getParamDecl(P.second);
+ StringRef Name = OtherParm->getName();
+ if (!Name.empty())
+ NewName = Name;
+ }
+
+ // If the definition has a named parameter use that name.
+ if (Definition) {
+ const ParmVarDecl *DefParm = Definition->getParamDecl(P.second);
+ StringRef Name = DefParm->getName();
+ if (!Name.empty())
+ NewName = Name;
+ }
+
+ // Now insert the comment. Note that getLocation() points to the place
+ // where the name would be, this allows us to also get complex cases like
+ // function pointers right.
+ const ParmVarDecl *Parm = P.first->getParamDecl(P.second);
+ D << FixItHint::CreateInsertion(Parm->getLocation(),
+ " /*" + NewName.str() + "*/");
+ }
+ }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NamedParameterCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NamedParameterCheck.h
new file mode 100644
index 0000000..bd38ad2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NamedParameterCheck.h
@@ -0,0 +1,42 @@
+//===--- NamedParameterCheck.h - clang-tidy ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_NAMEDPARAMETERCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_NAMEDPARAMETERCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Find functions with unnamed arguments.
+///
+/// The check implements the following rule originating in the Google C++ Style
+/// Guide:
+///
+/// https://google.github.io/styleguide/cppguide.html#Function_Declarations_and_Definitions
+///
+/// All parameters should be named, with identical names in the declaration and
+/// implementation.
+///
+/// Corresponding cpplint.py check name: 'readability/function'.
+class NamedParameterCheck : public ClangTidyCheck {
+public:
+ NamedParameterCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_NAMEDPARAMETERCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.cpp
new file mode 100644
index 0000000..409aba9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.cpp
@@ -0,0 +1,196 @@
+//===--- NamespaceCommentCheck.cpp - clang-tidy ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NamespaceCommentCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+NamespaceCommentCheck::NamespaceCommentCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ NamespaceCommentPattern("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *"
+ "namespace( +([a-zA-Z0-9_:]+))?\\.? *(\\*/)?$",
+ llvm::Regex::IgnoreCase),
+ ShortNamespaceLines(Options.get("ShortNamespaceLines", 1u)),
+ SpacesBeforeComments(Options.get("SpacesBeforeComments", 1u)) {}
+
+void NamespaceCommentCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "ShortNamespaceLines", ShortNamespaceLines);
+ Options.store(Opts, "SpacesBeforeComments", SpacesBeforeComments);
+}
+
+void NamespaceCommentCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (getLangOpts().CPlusPlus)
+ Finder->addMatcher(namespaceDecl().bind("namespace"), this);
+}
+
+static bool locationsInSameFile(const SourceManager &Sources,
+ SourceLocation Loc1, SourceLocation Loc2) {
+ return Loc1.isFileID() && Loc2.isFileID() &&
+ Sources.getFileID(Loc1) == Sources.getFileID(Loc2);
+}
+
+static std::string getNamespaceComment(const NamespaceDecl *ND,
+ bool InsertLineBreak) {
+ std::string Fix = "// namespace";
+ if (!ND->isAnonymousNamespace())
+ Fix.append(" ").append(ND->getNameAsString());
+ if (InsertLineBreak)
+ Fix.append("\n");
+ return Fix;
+}
+
+static std::string getNamespaceComment(const std::string &NameSpaceName,
+ bool InsertLineBreak) {
+ std::string Fix = "// namespace ";
+ Fix.append(NameSpaceName);
+ if (InsertLineBreak)
+ Fix.append("\n");
+ return Fix;
+}
+
+void NamespaceCommentCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *ND = Result.Nodes.getNodeAs<NamespaceDecl>("namespace");
+ const SourceManager &Sources = *Result.SourceManager;
+
+ if (!locationsInSameFile(Sources, ND->getLocStart(), ND->getRBraceLoc()))
+ return;
+
+ // Don't require closing comments for namespaces spanning less than certain
+ // number of lines.
+ unsigned StartLine = Sources.getSpellingLineNumber(ND->getLocStart());
+ unsigned EndLine = Sources.getSpellingLineNumber(ND->getRBraceLoc());
+ if (EndLine - StartLine + 1 <= ShortNamespaceLines)
+ return;
+
+ // Find next token after the namespace closing brace.
+ SourceLocation AfterRBrace = ND->getRBraceLoc().getLocWithOffset(1);
+ SourceLocation Loc = AfterRBrace;
+ Token Tok;
+ SourceLocation LBracketLocation = ND->getLocation();
+ SourceLocation NestedNamespaceBegin = LBracketLocation;
+
+ // Currently for nested namepsace (n1::n2::...) the AST matcher will match foo
+ // then bar instead of a single match. So if we got a nested namespace we have
+ // to skip the next ones.
+ for (const auto &EndOfNameLocation : Ends) {
+ if (Sources.isBeforeInTranslationUnit(NestedNamespaceBegin,
+ EndOfNameLocation))
+ return;
+ }
+
+ // Ignore macros
+ if (!ND->getLocation().isMacroID()) {
+ while (Lexer::getRawToken(LBracketLocation, Tok, Sources, getLangOpts()) ||
+ !Tok.is(tok::l_brace)) {
+ LBracketLocation = LBracketLocation.getLocWithOffset(1);
+ }
+ }
+
+ auto TextRange =
+ Lexer::getAsCharRange(SourceRange(NestedNamespaceBegin, LBracketLocation),
+ Sources, getLangOpts());
+ StringRef NestedNamespaceName =
+ Lexer::getSourceText(TextRange, Sources, getLangOpts()).rtrim();
+ bool IsNested = NestedNamespaceName.contains(':');
+
+ if (IsNested)
+ Ends.push_back(LBracketLocation);
+ else
+ NestedNamespaceName = ND->getName();
+
+ // Skip whitespace until we find the next token.
+ while (Lexer::getRawToken(Loc, Tok, Sources, getLangOpts()) ||
+ Tok.is(tok::semi)) {
+ Loc = Loc.getLocWithOffset(1);
+ }
+
+ if (!locationsInSameFile(Sources, ND->getRBraceLoc(), Loc))
+ return;
+
+ bool NextTokenIsOnSameLine = Sources.getSpellingLineNumber(Loc) == EndLine;
+ // If we insert a line comment before the token in the same line, we need
+ // to insert a line break.
+ bool NeedLineBreak = NextTokenIsOnSameLine && Tok.isNot(tok::eof);
+
+ SourceRange OldCommentRange(AfterRBrace, AfterRBrace);
+ std::string Message = "%0 not terminated with a closing comment";
+
+ // Try to find existing namespace closing comment on the same line.
+ if (Tok.is(tok::comment) && NextTokenIsOnSameLine) {
+ StringRef Comment(Sources.getCharacterData(Loc), Tok.getLength());
+ SmallVector<StringRef, 7> Groups;
+ if (NamespaceCommentPattern.match(Comment, &Groups)) {
+ StringRef NamespaceNameInComment = Groups.size() > 5 ? Groups[5] : "";
+ StringRef Anonymous = Groups.size() > 3 ? Groups[3] : "";
+
+ if (IsNested && NestedNamespaceName == NamespaceNameInComment) {
+ // C++17 nested namespace.
+ return;
+ } else if ((ND->isAnonymousNamespace() &&
+ NamespaceNameInComment.empty()) ||
+ (ND->getNameAsString() == NamespaceNameInComment &&
+ Anonymous.empty())) {
+ // Check if the namespace in the comment is the same.
+ // FIXME: Maybe we need a strict mode, where we always fix namespace
+ // comments with different format.
+ return;
+ }
+
+ // Otherwise we need to fix the comment.
+ NeedLineBreak = Comment.startswith("/*");
+ OldCommentRange =
+ SourceRange(AfterRBrace, Loc.getLocWithOffset(Tok.getLength()));
+ Message =
+ (llvm::Twine(
+ "%0 ends with a comment that refers to a wrong namespace '") +
+ NamespaceNameInComment + "'")
+ .str();
+ } else if (Comment.startswith("//")) {
+ // Assume that this is an unrecognized form of a namespace closing line
+ // comment. Replace it.
+ NeedLineBreak = false;
+ OldCommentRange =
+ SourceRange(AfterRBrace, Loc.getLocWithOffset(Tok.getLength()));
+ Message = "%0 ends with an unrecognized comment";
+ }
+ // If it's a block comment, just move it to the next line, as it can be
+ // multi-line or there may be other tokens behind it.
+ }
+
+ std::string NamespaceName =
+ ND->isAnonymousNamespace()
+ ? "anonymous namespace"
+ : ("namespace '" + NestedNamespaceName.str() + "'");
+
+ diag(AfterRBrace, Message)
+ << NamespaceName
+ << FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(OldCommentRange),
+ std::string(SpacesBeforeComments, ' ') +
+ (IsNested
+ ? getNamespaceComment(NestedNamespaceName, NeedLineBreak)
+ : getNamespaceComment(ND, NeedLineBreak)));
+ diag(ND->getLocation(), "%0 starts here", DiagnosticIDs::Note)
+ << NamespaceName;
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.h
new file mode 100644
index 0000000..1b1a231
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NamespaceCommentCheck.h
@@ -0,0 +1,44 @@
+//===--- NamespaceCommentCheck.h - clang-tidy -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_NAMESPACECOMMENTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_NAMESPACECOMMENTCHECK_H
+
+#include "../ClangTidy.h"
+#include "llvm/Support/Regex.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Checks that long namespaces have a closing comment.
+///
+/// http://llvm.org/docs/CodingStandards.html#namespace-indentation
+///
+/// https://google.github.io/styleguide/cppguide.html#Namespaces
+class NamespaceCommentCheck : public ClangTidyCheck {
+public:
+ NamespaceCommentCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void storeOptions(ClangTidyOptions::OptionMap &Options) override;
+
+ llvm::Regex NamespaceCommentPattern;
+ const unsigned ShortNamespaceLines;
+ const unsigned SpacesBeforeComments;
+ llvm::SmallVector<SourceLocation, 4> Ends;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_NAMESPACECOMMENTCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp
new file mode 100644
index 0000000..bc6507c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp
@@ -0,0 +1,223 @@
+//===--- NonConstParameterCheck.cpp - clang-tidy---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NonConstParameterCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+void NonConstParameterCheck::registerMatchers(MatchFinder *Finder) {
+ // Add parameters to Parameters.
+ Finder->addMatcher(parmVarDecl(unless(isInstantiated())).bind("Parm"), this);
+
+ // C++ constructor.
+ Finder->addMatcher(cxxConstructorDecl().bind("Ctor"), this);
+
+ // Track unused parameters, there is Wunused-parameter about unused
+ // parameters.
+ Finder->addMatcher(declRefExpr().bind("Ref"), this);
+
+ // Analyse parameter usage in function.
+ Finder->addMatcher(stmt(anyOf(unaryOperator(anyOf(hasOperatorName("++"),
+ hasOperatorName("--"))),
+ binaryOperator(), callExpr(), returnStmt(),
+ cxxConstructExpr()))
+ .bind("Mark"),
+ this);
+ Finder->addMatcher(varDecl(hasInitializer(anything())).bind("Mark"), this);
+}
+
+void NonConstParameterCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *Parm = Result.Nodes.getNodeAs<ParmVarDecl>("Parm")) {
+ if (const DeclContext *D = Parm->getParentFunctionOrMethod()) {
+ if (const auto *M = dyn_cast<CXXMethodDecl>(D)) {
+ if (M->isVirtual() || M->size_overridden_methods() != 0)
+ return;
+ }
+ }
+ addParm(Parm);
+ } else if (const auto *Ctor =
+ Result.Nodes.getNodeAs<CXXConstructorDecl>("Ctor")) {
+ for (const auto *Parm : Ctor->parameters())
+ addParm(Parm);
+ for (const auto *Init : Ctor->inits())
+ markCanNotBeConst(Init->getInit(), true);
+ } else if (const auto *Ref = Result.Nodes.getNodeAs<DeclRefExpr>("Ref")) {
+ setReferenced(Ref);
+ } else if (const auto *S = Result.Nodes.getNodeAs<Stmt>("Mark")) {
+ if (const auto *B = dyn_cast<BinaryOperator>(S)) {
+ if (B->isAssignmentOp())
+ markCanNotBeConst(B, false);
+ } else if (const auto *CE = dyn_cast<CallExpr>(S)) {
+ // Typically, if a parameter is const then it is fine to make the data
+ // const. But sometimes the data is written even though the parameter
+ // is const. Mark all data passed by address to the function.
+ for (const auto *Arg : CE->arguments()) {
+ markCanNotBeConst(Arg->IgnoreParenCasts(), true);
+ }
+
+ // Data passed by nonconst reference should not be made const.
+ if (const FunctionDecl *FD = CE->getDirectCallee()) {
+ unsigned ArgNr = 0U;
+ for (const auto *Par : FD->parameters()) {
+ if (ArgNr >= CE->getNumArgs())
+ break;
+ const Expr *Arg = CE->getArg(ArgNr++);
+ // Is this a non constant reference parameter?
+ const Type *ParType = Par->getType().getTypePtr();
+ if (!ParType->isReferenceType() || Par->getType().isConstQualified())
+ continue;
+ markCanNotBeConst(Arg->IgnoreParenCasts(), false);
+ }
+ }
+ } else if (const auto *CE = dyn_cast<CXXConstructExpr>(S)) {
+ for (const auto *Arg : CE->arguments()) {
+ markCanNotBeConst(Arg->IgnoreParenCasts(), true);
+ }
+ } else if (const auto *R = dyn_cast<ReturnStmt>(S)) {
+ markCanNotBeConst(R->getRetValue(), true);
+ } else if (const auto *U = dyn_cast<UnaryOperator>(S)) {
+ markCanNotBeConst(U, true);
+ }
+ } else if (const auto *VD = Result.Nodes.getNodeAs<VarDecl>("Mark")) {
+ const QualType T = VD->getType();
+ if ((T->isPointerType() && !T->getPointeeType().isConstQualified()) ||
+ T->isArrayType())
+ markCanNotBeConst(VD->getInit(), true);
+ }
+}
+
+void NonConstParameterCheck::addParm(const ParmVarDecl *Parm) {
+ // Only add nonconst integer/float pointer parameters.
+ const QualType T = Parm->getType();
+ if (!T->isPointerType() || T->getPointeeType().isConstQualified() ||
+ !(T->getPointeeType()->isIntegerType() ||
+ T->getPointeeType()->isFloatingType()))
+ return;
+
+ if (Parameters.find(Parm) != Parameters.end())
+ return;
+
+ ParmInfo PI;
+ PI.IsReferenced = false;
+ PI.CanBeConst = true;
+ Parameters[Parm] = PI;
+}
+
+void NonConstParameterCheck::setReferenced(const DeclRefExpr *Ref) {
+ auto It = Parameters.find(dyn_cast<ParmVarDecl>(Ref->getDecl()));
+ if (It != Parameters.end())
+ It->second.IsReferenced = true;
+}
+
+void NonConstParameterCheck::onEndOfTranslationUnit() {
+ diagnoseNonConstParameters();
+}
+
+void NonConstParameterCheck::diagnoseNonConstParameters() {
+ for (const auto &It : Parameters) {
+ const ParmVarDecl *Par = It.first;
+ const ParmInfo &ParamInfo = It.second;
+
+ // Unused parameter => there are other warnings about this.
+ if (!ParamInfo.IsReferenced)
+ continue;
+
+ // Parameter can't be const.
+ if (!ParamInfo.CanBeConst)
+ continue;
+
+ SmallVector<FixItHint, 8> Fixes;
+ auto *Function =
+ dyn_cast_or_null<const FunctionDecl>(Par->getParentFunctionOrMethod());
+ if (!Function)
+ continue;
+ unsigned Index = Par->getFunctionScopeIndex();
+ for (FunctionDecl *FnDecl : Function->redecls())
+ Fixes.push_back(FixItHint::CreateInsertion(
+ FnDecl->getParamDecl(Index)->getLocStart(), "const "));
+
+ diag(Par->getLocation(), "pointer parameter '%0' can be pointer to const")
+ << Par->getName() << Fixes;
+ }
+}
+
+void NonConstParameterCheck::markCanNotBeConst(const Expr *E,
+ bool CanNotBeConst) {
+ if (!E)
+ return;
+
+ if (const auto *Cast = dyn_cast<ImplicitCastExpr>(E)) {
+ // If expression is const then ignore usage.
+ const QualType T = Cast->getType();
+ if (T->isPointerType() && T->getPointeeType().isConstQualified())
+ return;
+ }
+
+ E = E->IgnoreParenCasts();
+
+ if (const auto *B = dyn_cast<BinaryOperator>(E)) {
+ if (B->isAdditiveOp()) {
+ // p + 2
+ markCanNotBeConst(B->getLHS(), CanNotBeConst);
+ markCanNotBeConst(B->getRHS(), CanNotBeConst);
+ } else if (B->isAssignmentOp()) {
+ markCanNotBeConst(B->getLHS(), false);
+
+ // If LHS is not const then RHS can't be const.
+ const QualType T = B->getLHS()->getType();
+ if (T->isPointerType() && !T->getPointeeType().isConstQualified())
+ markCanNotBeConst(B->getRHS(), true);
+ }
+ } else if (const auto *C = dyn_cast<ConditionalOperator>(E)) {
+ markCanNotBeConst(C->getTrueExpr(), CanNotBeConst);
+ markCanNotBeConst(C->getFalseExpr(), CanNotBeConst);
+ } else if (const auto *U = dyn_cast<UnaryOperator>(E)) {
+ if (U->getOpcode() == UO_PreInc || U->getOpcode() == UO_PreDec ||
+ U->getOpcode() == UO_PostInc || U->getOpcode() == UO_PostDec) {
+ if (const auto *SubU =
+ dyn_cast<UnaryOperator>(U->getSubExpr()->IgnoreParenCasts()))
+ markCanNotBeConst(SubU->getSubExpr(), true);
+ markCanNotBeConst(U->getSubExpr(), CanNotBeConst);
+ } else if (U->getOpcode() == UO_Deref) {
+ if (!CanNotBeConst)
+ markCanNotBeConst(U->getSubExpr(), true);
+ } else {
+ markCanNotBeConst(U->getSubExpr(), CanNotBeConst);
+ }
+ } else if (const auto *A = dyn_cast<ArraySubscriptExpr>(E)) {
+ markCanNotBeConst(A->getBase(), true);
+ } else if (const auto *CLE = dyn_cast<CompoundLiteralExpr>(E)) {
+ markCanNotBeConst(CLE->getInitializer(), true);
+ } else if (const auto *Constr = dyn_cast<CXXConstructExpr>(E)) {
+ for (const auto *Arg : Constr->arguments()) {
+ if (const auto *M = dyn_cast<MaterializeTemporaryExpr>(Arg))
+ markCanNotBeConst(cast<Expr>(M->getTemporary()), CanNotBeConst);
+ }
+ } else if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
+ for (unsigned I = 0U; I < ILE->getNumInits(); ++I)
+ markCanNotBeConst(ILE->getInit(I), true);
+ } else if (CanNotBeConst) {
+ // Referencing parameter.
+ if (const auto *D = dyn_cast<DeclRefExpr>(E)) {
+ auto It = Parameters.find(dyn_cast<ParmVarDecl>(D->getDecl()));
+ if (It != Parameters.end())
+ It->second.CanBeConst = false;
+ }
+ }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.h
new file mode 100644
index 0000000..3cc73e9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.h
@@ -0,0 +1,64 @@
+//===--- NonConstParameterCheck.h - clang-tidy-------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_NON_CONST_PARAMETER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_NON_CONST_PARAMETER_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Warn when a pointer function parameter can be const.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-non-const-parameter.html
+class NonConstParameterCheck : public ClangTidyCheck {
+public:
+ NonConstParameterCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void onEndOfTranslationUnit() override;
+
+private:
+ /// Parameter info.
+ struct ParmInfo {
+ /// Is function parameter referenced?
+ bool IsReferenced;
+
+ /// Can function parameter be const?
+ bool CanBeConst;
+ };
+
+ /// Track all nonconst integer/float parameters.
+ std::map<const ParmVarDecl *, ParmInfo> Parameters;
+
+ /// Add function parameter.
+ void addParm(const ParmVarDecl *Parm);
+
+ /// Set IsReferenced.
+ void setReferenced(const DeclRefExpr *Ref);
+
+ /// Set CanNotBeConst.
+ /// Visits sub expressions recursively. If a DeclRefExpr is found
+ /// and CanNotBeConst is true the Parameter is marked as not-const.
+ /// The CanNotBeConst is updated as sub expressions are visited.
+ void markCanNotBeConst(const Expr *E, bool CanNotBeConst);
+
+ /// Diagnose non const parameters.
+ void diagnoseNonConstParameters();
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_NON_CONST_PARAMETER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
new file mode 100644
index 0000000..be1ae43
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -0,0 +1,116 @@
+//===--- ReadabilityTidyModule.cpp - clang-tidy ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "AvoidConstParamsInDecls.h"
+#include "BracesAroundStatementsCheck.h"
+#include "ContainerSizeEmptyCheck.h"
+#include "DeleteNullPointerCheck.h"
+#include "DeletedDefaultCheck.h"
+#include "ElseAfterReturnCheck.h"
+#include "FunctionSizeCheck.h"
+#include "IdentifierNamingCheck.h"
+#include "ImplicitBoolConversionCheck.h"
+#include "InconsistentDeclarationParameterNameCheck.h"
+#include "MisleadingIndentationCheck.h"
+#include "MisplacedArrayIndexCheck.h"
+#include "NamedParameterCheck.h"
+#include "NonConstParameterCheck.h"
+#include "RedundantControlFlowCheck.h"
+#include "RedundantDeclarationCheck.h"
+#include "RedundantFunctionPtrDereferenceCheck.h"
+#include "RedundantMemberInitCheck.h"
+#include "RedundantSmartptrGetCheck.h"
+#include "RedundantStringCStrCheck.h"
+#include "RedundantStringInitCheck.h"
+#include "SimplifyBooleanExprCheck.h"
+#include "SimplifySubscriptExprCheck.h"
+#include "StaticAccessedThroughInstanceCheck.h"
+#include "StaticDefinitionInAnonymousNamespaceCheck.h"
+#include "StringCompareCheck.h"
+#include "UniqueptrDeleteReleaseCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+class ReadabilityModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<AvoidConstParamsInDecls>(
+ "readability-avoid-const-params-in-decls");
+ CheckFactories.registerCheck<BracesAroundStatementsCheck>(
+ "readability-braces-around-statements");
+ CheckFactories.registerCheck<ContainerSizeEmptyCheck>(
+ "readability-container-size-empty");
+ CheckFactories.registerCheck<DeleteNullPointerCheck>(
+ "readability-delete-null-pointer");
+ CheckFactories.registerCheck<DeletedDefaultCheck>(
+ "readability-deleted-default");
+ CheckFactories.registerCheck<ElseAfterReturnCheck>(
+ "readability-else-after-return");
+ CheckFactories.registerCheck<FunctionSizeCheck>(
+ "readability-function-size");
+ CheckFactories.registerCheck<IdentifierNamingCheck>(
+ "readability-identifier-naming");
+ CheckFactories.registerCheck<ImplicitBoolConversionCheck>(
+ "readability-implicit-bool-conversion");
+ CheckFactories.registerCheck<InconsistentDeclarationParameterNameCheck>(
+ "readability-inconsistent-declaration-parameter-name");
+ CheckFactories.registerCheck<MisleadingIndentationCheck>(
+ "readability-misleading-indentation");
+ CheckFactories.registerCheck<MisplacedArrayIndexCheck>(
+ "readability-misplaced-array-index");
+ CheckFactories.registerCheck<RedundantFunctionPtrDereferenceCheck>(
+ "readability-redundant-function-ptr-dereference");
+ CheckFactories.registerCheck<RedundantMemberInitCheck>(
+ "readability-redundant-member-init");
+ CheckFactories.registerCheck<SimplifySubscriptExprCheck>(
+ "readability-simplify-subscript-expr");
+ CheckFactories.registerCheck<StaticAccessedThroughInstanceCheck>(
+ "readability-static-accessed-through-instance");
+ CheckFactories.registerCheck<StaticDefinitionInAnonymousNamespaceCheck>(
+ "readability-static-definition-in-anonymous-namespace");
+ CheckFactories.registerCheck<StringCompareCheck>(
+ "readability-string-compare");
+ CheckFactories.registerCheck<readability::NamedParameterCheck>(
+ "readability-named-parameter");
+ CheckFactories.registerCheck<NonConstParameterCheck>(
+ "readability-non-const-parameter");
+ CheckFactories.registerCheck<RedundantControlFlowCheck>(
+ "readability-redundant-control-flow");
+ CheckFactories.registerCheck<RedundantDeclarationCheck>(
+ "readability-redundant-declaration");
+ CheckFactories.registerCheck<RedundantSmartptrGetCheck>(
+ "readability-redundant-smartptr-get");
+ CheckFactories.registerCheck<RedundantStringCStrCheck>(
+ "readability-redundant-string-cstr");
+ CheckFactories.registerCheck<RedundantStringInitCheck>(
+ "readability-redundant-string-init");
+ CheckFactories.registerCheck<SimplifyBooleanExprCheck>(
+ "readability-simplify-boolean-expr");
+ CheckFactories.registerCheck<UniqueptrDeleteReleaseCheck>(
+ "readability-uniqueptr-delete-release");
+ }
+};
+
+// Register the ReadabilityModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<ReadabilityModule>
+ X("readability-module", "Adds readability-related checks.");
+
+} // namespace readability
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the ReadabilityModule.
+volatile int ReadabilityModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
new file mode 100644
index 0000000..0788c42
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
@@ -0,0 +1,98 @@
+//===--- RedundantControlFlowCheck.cpp - clang-tidy------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RedundantControlFlowCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+namespace {
+
+const char *const RedundantReturnDiag = "redundant return statement at the end "
+ "of a function with a void return type";
+const char *const RedundantContinueDiag = "redundant continue statement at the "
+ "end of loop statement";
+
+bool isLocationInMacroExpansion(const SourceManager &SM, SourceLocation Loc) {
+ return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
+}
+
+} // namespace
+
+void RedundantControlFlowCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ functionDecl(
+ isDefinition(), returns(voidType()),
+ has(compoundStmt(hasAnySubstatement(returnStmt(unless(has(expr())))))
+ .bind("return"))),
+ this);
+ auto CompoundContinue =
+ has(compoundStmt(hasAnySubstatement(continueStmt())).bind("continue"));
+ Finder->addMatcher(
+ stmt(anyOf(forStmt(), cxxForRangeStmt(), whileStmt(), doStmt()),
+ CompoundContinue),
+ this);
+}
+
+void RedundantControlFlowCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *Return = Result.Nodes.getNodeAs<CompoundStmt>("return"))
+ checkRedundantReturn(Result, Return);
+ else if (const auto *Continue =
+ Result.Nodes.getNodeAs<CompoundStmt>("continue"))
+ checkRedundantContinue(Result, Continue);
+}
+
+void RedundantControlFlowCheck::checkRedundantReturn(
+ const MatchFinder::MatchResult &Result, const CompoundStmt *Block) {
+ CompoundStmt::const_reverse_body_iterator last = Block->body_rbegin();
+ if (const auto *Return = dyn_cast<ReturnStmt>(*last))
+ issueDiagnostic(Result, Block, Return->getSourceRange(),
+ RedundantReturnDiag);
+}
+
+void RedundantControlFlowCheck::checkRedundantContinue(
+ const MatchFinder::MatchResult &Result, const CompoundStmt *Block) {
+ CompoundStmt::const_reverse_body_iterator last = Block->body_rbegin();
+ if (const auto *Continue = dyn_cast<ContinueStmt>(*last))
+ issueDiagnostic(Result, Block, Continue->getSourceRange(),
+ RedundantContinueDiag);
+}
+
+void RedundantControlFlowCheck::issueDiagnostic(
+ const MatchFinder::MatchResult &Result, const CompoundStmt *const Block,
+ const SourceRange &StmtRange, const char *const Diag) {
+ SourceManager &SM = *Result.SourceManager;
+ if (isLocationInMacroExpansion(SM, StmtRange.getBegin()))
+ return;
+
+ CompoundStmt::const_reverse_body_iterator Previous = ++Block->body_rbegin();
+ SourceLocation Start;
+ if (Previous != Block->body_rend())
+ Start = Lexer::findLocationAfterToken(
+ dyn_cast<Stmt>(*Previous)->getLocEnd(), tok::semi, SM, getLangOpts(),
+ /*SkipTrailingWhitespaceAndNewLine=*/true);
+ if (!Start.isValid())
+ Start = StmtRange.getBegin();
+ auto RemovedRange = CharSourceRange::getCharRange(
+ Start, Lexer::findLocationAfterToken(
+ StmtRange.getEnd(), tok::semi, SM, getLangOpts(),
+ /*SkipTrailingWhitespaceAndNewLine=*/true));
+
+ diag(StmtRange.getBegin(), Diag) << FixItHint::CreateRemoval(RemovedRange);
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.h
new file mode 100644
index 0000000..4b8b6fb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.h
@@ -0,0 +1,51 @@
+//===--- RedundantControlFlowCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_CONTROL_FLOW_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_CONTROL_FLOW_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Eliminates redundant `return` statements at the end of a function that
+/// returns `void`.
+///
+/// Eliminates redundant `continue` statements at the end of a loop body.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-redundant-control-flow.html
+class RedundantControlFlowCheck : public ClangTidyCheck {
+public:
+ RedundantControlFlowCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ void
+ checkRedundantReturn(const ast_matchers::MatchFinder::MatchResult &Result,
+ const CompoundStmt *Block);
+
+ void
+ checkRedundantContinue(const ast_matchers::MatchFinder::MatchResult &Result,
+ const CompoundStmt *Block);
+
+ void issueDiagnostic(const ast_matchers::MatchFinder::MatchResult &Result,
+ const CompoundStmt *Block, const SourceRange &StmtRange,
+ const char *Diag);
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_CONTROL_FLOW_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
new file mode 100644
index 0000000..1df3f05
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.cpp
@@ -0,0 +1,82 @@
+//===--- RedundantDeclarationCheck.cpp - clang-tidy------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RedundantDeclarationCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+RedundantDeclarationCheck::RedundantDeclarationCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {}
+
+void RedundantDeclarationCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ namedDecl(anyOf(varDecl(unless(isDefinition())),
+ functionDecl(unless(anyOf(isDefinition(), isDefaulted(),
+ hasParent(friendDecl()))))))
+ .bind("Decl"),
+ this);
+}
+
+void RedundantDeclarationCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *D = Result.Nodes.getNodeAs<NamedDecl>("Decl");
+ const auto *Prev = D->getPreviousDecl();
+ if (!Prev)
+ return;
+ if (!Prev->getLocation().isValid())
+ return;
+ if (Prev->getLocation() == D->getLocation())
+ return;
+ if (IgnoreMacros &&
+ (D->getLocation().isMacroID() || Prev->getLocation().isMacroID()))
+ return;
+ // Don't complain when the previous declaration is a friend declaration.
+ for (const auto &Parent : Result.Context->getParents(*Prev))
+ if (Parent.get<FriendDecl>())
+ return;
+
+ const SourceManager &SM = *Result.SourceManager;
+
+ const bool DifferentHeaders =
+ !SM.isInMainFile(D->getLocation()) &&
+ !SM.isWrittenInSameFile(Prev->getLocation(), D->getLocation());
+
+ bool MultiVar = false;
+ if (const auto *VD = dyn_cast<VarDecl>(D)) {
+ // Is this a multivariable declaration?
+ for (const auto Other : VD->getDeclContext()->decls()) {
+ if (Other != D && Other->getLocStart() == VD->getLocStart()) {
+ MultiVar = true;
+ break;
+ }
+ }
+ }
+
+ SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+ D->getSourceRange().getEnd(), 0, SM, Result.Context->getLangOpts());
+ {
+ auto Diag = diag(D->getLocation(), "redundant %0 declaration") << D;
+ if (!MultiVar && !DifferentHeaders)
+ Diag << FixItHint::CreateRemoval(
+ SourceRange(D->getSourceRange().getBegin(), EndLoc));
+ }
+ diag(Prev->getLocation(), "previously declared here", DiagnosticIDs::Note);
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.h
new file mode 100644
index 0000000..9be79b8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantDeclarationCheck.h
@@ -0,0 +1,37 @@
+//===--- RedundantDeclarationCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_DECLARATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_DECLARATION_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Find redundant variable declarations.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-redundant-declaration.html
+class RedundantDeclarationCheck : public ClangTidyCheck {
+public:
+ RedundantDeclarationCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const bool IgnoreMacros;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_DECLARATION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantFunctionPtrDereferenceCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantFunctionPtrDereferenceCheck.cpp
new file mode 100644
index 0000000..fa503c5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantFunctionPtrDereferenceCheck.cpp
@@ -0,0 +1,37 @@
+//===--- RedundantFunctionPtrDereferenceCheck.cpp - clang-tidy-------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RedundantFunctionPtrDereferenceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+void RedundantFunctionPtrDereferenceCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(unaryOperator(hasOperatorName("*"),
+ has(implicitCastExpr(
+ hasCastKind(CK_FunctionToPointerDecay))))
+ .bind("op"),
+ this);
+}
+
+void RedundantFunctionPtrDereferenceCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Operator = Result.Nodes.getNodeAs<UnaryOperator>("op");
+ diag(Operator->getOperatorLoc(),
+ "redundant repeated dereference of function pointer")
+ << FixItHint::CreateRemoval(Operator->getOperatorLoc());
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantFunctionPtrDereferenceCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantFunctionPtrDereferenceCheck.h
new file mode 100644
index 0000000..4cf6d11
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantFunctionPtrDereferenceCheck.h
@@ -0,0 +1,35 @@
+//===--- RedundantFunctionPtrDereferenceCheck.h - clang-tidy-----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_FUNCTION_PTR_DEREFERENCE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_FUNCTION_PTR_DEREFERENCE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Eliminate redundant dereferences of a function pointer.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-redundant-function-ptr-dereference.html
+class RedundantFunctionPtrDereferenceCheck : public ClangTidyCheck {
+public:
+ RedundantFunctionPtrDereferenceCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_FUNCTION_PTR_DEREFERENCE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
new file mode 100644
index 0000000..8409f9f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp
@@ -0,0 +1,69 @@
+//===--- RedundantMemberInitCheck.cpp - clang-tidy-------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RedundantMemberInitCheck.h"
+#include "../utils/Matchers.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include <algorithm>
+
+using namespace clang::ast_matchers;
+using namespace clang::tidy::matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ auto Construct =
+ cxxConstructExpr(
+ hasDeclaration(cxxConstructorDecl(hasParent(
+ cxxRecordDecl(unless(isTriviallyDefaultConstructible()))))))
+ .bind("construct");
+
+ Finder->addMatcher(
+ cxxConstructorDecl(
+ unless(isDelegatingConstructor()),
+ ofClass(unless(
+ anyOf(isUnion(), ast_matchers::isTemplateInstantiation()))),
+ forEachConstructorInitializer(
+ cxxCtorInitializer(isWritten(),
+ withInitializer(ignoringImplicit(Construct)),
+ unless(forField(hasType(isConstQualified()))),
+ unless(forField(hasParent(recordDecl(isUnion())))))
+ .bind("init"))),
+ this);
+}
+
+void RedundantMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Init = Result.Nodes.getNodeAs<CXXCtorInitializer>("init");
+ const auto *Construct = Result.Nodes.getNodeAs<CXXConstructExpr>("construct");
+
+ if (Construct->getNumArgs() == 0 ||
+ Construct->getArg(0)->isDefaultArgument()) {
+ if (Init->isAnyMemberInitializer()) {
+ diag(Init->getSourceLocation(), "initializer for member %0 is redundant")
+ << Init->getAnyMember()
+ << FixItHint::CreateRemoval(Init->getSourceRange());
+ } else {
+ diag(Init->getSourceLocation(),
+ "initializer for base class %0 is redundant")
+ << Construct->getType()
+ << FixItHint::CreateRemoval(Init->getSourceRange());
+ }
+ }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
new file mode 100644
index 0000000..13cc9d3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.h
@@ -0,0 +1,36 @@
+//===--- RedundantMemberInitCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_MEMBER_INIT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_MEMBER_INIT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Finds member initializations that are unnecessary because the same default
+/// constructor would be called if they were not present.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-redundant-member-init.html
+class RedundantMemberInitCheck : public ClangTidyCheck {
+public:
+ RedundantMemberInitCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_MEMBER_INIT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.cpp
new file mode 100644
index 0000000..1abd70b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.cpp
@@ -0,0 +1,147 @@
+//===--- RedundantSmartptrGetCheck.cpp - clang-tidy -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RedundantSmartptrGetCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+namespace {
+internal::Matcher<Expr> callToGet(const internal::Matcher<Decl> &OnClass) {
+ return cxxMemberCallExpr(
+ on(expr(anyOf(hasType(OnClass),
+ hasType(qualType(
+ pointsTo(decl(OnClass).bind("ptr_to_ptr"))))))
+ .bind("smart_pointer")),
+ unless(callee(memberExpr(hasObjectExpression(cxxThisExpr())))),
+ callee(cxxMethodDecl(
+ hasName("get"),
+ returns(qualType(pointsTo(type().bind("getType")))))))
+ .bind("redundant_get");
+}
+
+void registerMatchersForGetArrowStart(MatchFinder *Finder,
+ MatchFinder::MatchCallback *Callback) {
+ const auto QuacksLikeASmartptr = recordDecl(
+ recordDecl().bind("duck_typing"),
+ has(cxxMethodDecl(hasName("operator->"),
+ returns(qualType(pointsTo(type().bind("op->Type")))))),
+ has(cxxMethodDecl(hasName("operator*"), returns(qualType(references(
+ type().bind("op*Type")))))));
+
+ // Catch 'ptr.get()->Foo()'
+ Finder->addMatcher(memberExpr(expr().bind("memberExpr"), isArrow(),
+ hasObjectExpression(ignoringImpCasts(
+ callToGet(QuacksLikeASmartptr)))),
+ Callback);
+
+ // Catch '*ptr.get()' or '*ptr->get()'
+ Finder->addMatcher(
+ unaryOperator(hasOperatorName("*"),
+ hasUnaryOperand(callToGet(QuacksLikeASmartptr))),
+ Callback);
+
+ // Catch '!ptr.get()'
+ const auto CallToGetAsBool = ignoringParenImpCasts(callToGet(recordDecl(
+ QuacksLikeASmartptr, has(cxxConversionDecl(returns(booleanType()))))));
+ Finder->addMatcher(
+ unaryOperator(hasOperatorName("!"), hasUnaryOperand(CallToGetAsBool)),
+ Callback);
+
+ // Catch 'if(ptr.get())'
+ Finder->addMatcher(ifStmt(hasCondition(CallToGetAsBool)), Callback);
+
+ // Catch 'ptr.get() ? X : Y'
+ Finder->addMatcher(conditionalOperator(hasCondition(CallToGetAsBool)),
+ Callback);
+}
+
+void registerMatchersForGetEquals(MatchFinder *Finder,
+ MatchFinder::MatchCallback *Callback) {
+ // This one is harder to do with duck typing.
+ // The operator==/!= that we are looking for might be member or non-member,
+ // might be on global namespace or found by ADL, might be a template, etc.
+ // For now, lets keep a list of known standard types.
+
+ const auto IsAKnownSmartptr =
+ recordDecl(hasAnyName("::std::unique_ptr", "::std::shared_ptr"));
+
+ // Matches against nullptr.
+ Finder->addMatcher(
+ binaryOperator(anyOf(hasOperatorName("=="), hasOperatorName("!=")),
+ hasEitherOperand(ignoringImpCasts(
+ anyOf(cxxNullPtrLiteralExpr(), gnuNullExpr(),
+ integerLiteral(equals(0))))),
+ hasEitherOperand(callToGet(IsAKnownSmartptr))),
+ Callback);
+
+ // FIXME: Match and fix if (l.get() == r.get()).
+}
+
+} // namespace
+
+void RedundantSmartptrGetCheck::registerMatchers(MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ registerMatchersForGetArrowStart(Finder, this);
+ registerMatchersForGetEquals(Finder, this);
+}
+
+namespace {
+bool allReturnTypesMatch(const MatchFinder::MatchResult &Result) {
+ if (Result.Nodes.getNodeAs<Decl>("duck_typing") == nullptr)
+ return true;
+ // Verify that the types match.
+ // We can't do this on the matcher because the type nodes can be different,
+ // even though they represent the same type. This difference comes from how
+ // the type is referenced (eg. through a typedef, a type trait, etc).
+ const Type *OpArrowType =
+ Result.Nodes.getNodeAs<Type>("op->Type")->getUnqualifiedDesugaredType();
+ const Type *OpStarType =
+ Result.Nodes.getNodeAs<Type>("op*Type")->getUnqualifiedDesugaredType();
+ const Type *GetType =
+ Result.Nodes.getNodeAs<Type>("getType")->getUnqualifiedDesugaredType();
+ return OpArrowType == OpStarType && OpArrowType == GetType;
+}
+} // namespace
+
+void RedundantSmartptrGetCheck::check(const MatchFinder::MatchResult &Result) {
+ if (!allReturnTypesMatch(Result))
+ return;
+
+ bool IsPtrToPtr = Result.Nodes.getNodeAs<Decl>("ptr_to_ptr") != nullptr;
+ bool IsMemberExpr = Result.Nodes.getNodeAs<Expr>("memberExpr") != nullptr;
+ const auto *GetCall = Result.Nodes.getNodeAs<Expr>("redundant_get");
+ const auto *Smartptr = Result.Nodes.getNodeAs<Expr>("smart_pointer");
+
+ if (IsPtrToPtr && IsMemberExpr) {
+ // Ignore this case (eg. Foo->get()->DoSomething());
+ return;
+ }
+
+ StringRef SmartptrText = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(Smartptr->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ // Replace foo->get() with *foo, and foo.get() with foo.
+ std::string Replacement = Twine(IsPtrToPtr ? "*" : "", SmartptrText).str();
+ diag(GetCall->getLocStart(), "redundant get() call on smart pointer")
+ << FixItHint::CreateReplacement(GetCall->getSourceRange(), Replacement);
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.h
new file mode 100644
index 0000000..1da6195
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantSmartptrGetCheck.h
@@ -0,0 +1,40 @@
+//===--- RedundantSmartptrGetCheck.h - clang-tidy ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTSMARTPTRGETCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTSMARTPTRGETCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Find and remove redundant calls to smart pointer's `.get()` method.
+///
+/// Examples:
+///
+/// \code
+/// ptr.get()->Foo() ==> ptr->Foo()
+/// *ptr.get() ==> *ptr
+/// *ptr->get() ==> **ptr
+/// \endcode
+class RedundantSmartptrGetCheck : public ClangTidyCheck {
+public:
+ RedundantSmartptrGetCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTSMARTPTRGETCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
new file mode 100644
index 0000000..21f4a8a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp
@@ -0,0 +1,199 @@
+//===- RedundantStringCStrCheck.cpp - Check for redundant c_str calls -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a check for redundant calls of c_str() on strings.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RedundantStringCStrCheck.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+namespace {
+
+template <typename T>
+StringRef getText(const ast_matchers::MatchFinder::MatchResult &Result,
+ T const &Node) {
+ return Lexer::getSourceText(
+ CharSourceRange::getTokenRange(Node.getSourceRange()),
+ *Result.SourceManager, Result.Context->getLangOpts());
+}
+
+// Return true if expr needs to be put in parens when it is an argument of a
+// prefix unary operator, e.g. when it is a binary or ternary operator
+// syntactically.
+bool needParensAfterUnaryOperator(const Expr &ExprNode) {
+ if (isa<clang::BinaryOperator>(&ExprNode) ||
+ isa<clang::ConditionalOperator>(&ExprNode)) {
+ return true;
+ }
+ if (const auto *Op = dyn_cast<CXXOperatorCallExpr>(&ExprNode)) {
+ return Op->getNumArgs() == 2 && Op->getOperator() != OO_PlusPlus &&
+ Op->getOperator() != OO_MinusMinus && Op->getOperator() != OO_Call &&
+ Op->getOperator() != OO_Subscript;
+ }
+ return false;
+}
+
+// Format a pointer to an expression: prefix with '*' but simplify
+// when it already begins with '&'. Return empty string on failure.
+std::string
+formatDereference(const ast_matchers::MatchFinder::MatchResult &Result,
+ const Expr &ExprNode) {
+ if (const auto *Op = dyn_cast<clang::UnaryOperator>(&ExprNode)) {
+ if (Op->getOpcode() == UO_AddrOf) {
+ // Strip leading '&'.
+ return getText(Result, *Op->getSubExpr()->IgnoreParens());
+ }
+ }
+ StringRef Text = getText(Result, ExprNode);
+ if (Text.empty())
+ return std::string();
+ // Add leading '*'.
+ if (needParensAfterUnaryOperator(ExprNode)) {
+ return (llvm::Twine("*(") + Text + ")").str();
+ }
+ return (llvm::Twine("*") + Text).str();
+}
+
+} // end namespace
+
+void RedundantStringCStrCheck::registerMatchers(
+ ast_matchers::MatchFinder *Finder) {
+ // Only register the matchers for C++; the functionality currently does not
+ // provide any benefit to other languages, despite being benign.
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // Match expressions of type 'string' or 'string*'.
+ const auto StringDecl = type(hasUnqualifiedDesugaredType(recordType(
+ hasDeclaration(cxxRecordDecl(hasName("::std::basic_string"))))));
+ const auto StringExpr =
+ expr(anyOf(hasType(StringDecl), hasType(qualType(pointsTo(StringDecl)))));
+
+ // Match string constructor.
+ const auto StringConstructorExpr = expr(anyOf(
+ cxxConstructExpr(argumentCountIs(1),
+ hasDeclaration(cxxMethodDecl(hasName("basic_string")))),
+ cxxConstructExpr(
+ argumentCountIs(2),
+ hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+ // If present, the second argument is the alloc object which must not
+ // be present explicitly.
+ hasArgument(1, cxxDefaultArgExpr()))));
+
+ // Match a call to the string 'c_str()' method.
+ const auto StringCStrCallExpr =
+ cxxMemberCallExpr(on(StringExpr.bind("arg")),
+ callee(memberExpr().bind("member")),
+ callee(cxxMethodDecl(hasAnyName("c_str", "data"))))
+ .bind("call");
+
+ // Detect redundant 'c_str()' calls through a string constructor.
+ Finder->addMatcher(cxxConstructExpr(StringConstructorExpr,
+ hasArgument(0, StringCStrCallExpr)),
+ this);
+
+ // Detect: 's == str.c_str()' -> 's == str'
+ Finder->addMatcher(
+ cxxOperatorCallExpr(
+ anyOf(
+ hasOverloadedOperatorName("<"), hasOverloadedOperatorName(">"),
+ hasOverloadedOperatorName(">="), hasOverloadedOperatorName("<="),
+ hasOverloadedOperatorName("!="), hasOverloadedOperatorName("=="),
+ hasOverloadedOperatorName("+")),
+ anyOf(allOf(hasArgument(0, StringExpr),
+ hasArgument(1, StringCStrCallExpr)),
+ allOf(hasArgument(0, StringCStrCallExpr),
+ hasArgument(1, StringExpr)))),
+ this);
+
+ // Detect: 'dst += str.c_str()' -> 'dst += str'
+ // Detect: 's = str.c_str()' -> 's = str'
+ Finder->addMatcher(cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("="),
+ hasOverloadedOperatorName("+=")),
+ hasArgument(0, StringExpr),
+ hasArgument(1, StringCStrCallExpr)),
+ this);
+
+ // Detect: 'dst.append(str.c_str())' -> 'dst.append(str)'
+ Finder->addMatcher(
+ cxxMemberCallExpr(on(StringExpr), callee(decl(cxxMethodDecl(hasAnyName(
+ "append", "assign", "compare")))),
+ argumentCountIs(1), hasArgument(0, StringCStrCallExpr)),
+ this);
+
+ // Detect: 'dst.compare(p, n, str.c_str())' -> 'dst.compare(p, n, str)'
+ Finder->addMatcher(
+ cxxMemberCallExpr(on(StringExpr),
+ callee(decl(cxxMethodDecl(hasName("compare")))),
+ argumentCountIs(3), hasArgument(2, StringCStrCallExpr)),
+ this);
+
+ // Detect: 'dst.find(str.c_str())' -> 'dst.find(str)'
+ Finder->addMatcher(
+ cxxMemberCallExpr(on(StringExpr),
+ callee(decl(cxxMethodDecl(hasAnyName(
+ "find", "find_first_not_of", "find_first_of",
+ "find_last_not_of", "find_last_of", "rfind")))),
+ anyOf(argumentCountIs(1), argumentCountIs(2)),
+ hasArgument(0, StringCStrCallExpr)),
+ this);
+
+ // Detect: 'dst.insert(pos, str.c_str())' -> 'dst.insert(pos, str)'
+ Finder->addMatcher(
+ cxxMemberCallExpr(on(StringExpr),
+ callee(decl(cxxMethodDecl(hasName("insert")))),
+ argumentCountIs(2), hasArgument(1, StringCStrCallExpr)),
+ this);
+
+ // Detect redundant 'c_str()' calls through a StringRef constructor.
+ Finder->addMatcher(
+ cxxConstructExpr(
+ // Implicit constructors of these classes are overloaded
+ // wrt. string types and they internally make a StringRef
+ // referring to the argument. Passing a string directly to
+ // them is preferred to passing a char pointer.
+ hasDeclaration(cxxMethodDecl(hasAnyName(
+ "::llvm::StringRef::StringRef", "::llvm::Twine::Twine"))),
+ argumentCountIs(1),
+ // The only argument must have the form x.c_str() or p->c_str()
+ // where the method is string::c_str(). StringRef also has
+ // a constructor from string which is more efficient (avoids
+ // strlen), so we can construct StringRef from the string
+ // directly.
+ hasArgument(0, StringCStrCallExpr)),
+ this);
+}
+
+void RedundantStringCStrCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+ const auto *Arg = Result.Nodes.getNodeAs<Expr>("arg");
+ const auto *Member = Result.Nodes.getNodeAs<MemberExpr>("member");
+ bool Arrow = Member->isArrow();
+ // Replace the "call" node with the "arg" node, prefixed with '*'
+ // if the call was using '->' rather than '.'.
+ std::string ArgText =
+ Arrow ? formatDereference(Result, *Arg) : getText(Result, *Arg).str();
+ if (ArgText.empty())
+ return;
+
+ diag(Call->getLocStart(), "redundant call to %0")
+ << Member->getMemberDecl()
+ << FixItHint::CreateReplacement(Call->getSourceRange(), ArgText);
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.h
new file mode 100644
index 0000000..9406f8e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.h
@@ -0,0 +1,32 @@
+//===--- RedundantStringCStrCheck.h - clang-tidy ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTSTRINGCSTRCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTSTRINGCSTRCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Finds unnecessary calls to `std::string::c_str()`.
+class RedundantStringCStrCheck : public ClangTidyCheck {
+public:
+ RedundantStringCStrCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTSTRINGCSTRCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
new file mode 100644
index 0000000..46ce2a4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp
@@ -0,0 +1,71 @@
+//===- RedundantStringInitCheck.cpp - clang-tidy ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RedundantStringInitCheck.h"
+#include "../utils/Matchers.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::tidy::matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+void RedundantStringInitCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // Match string constructor.
+ const auto StringConstructorExpr = expr(anyOf(
+ cxxConstructExpr(argumentCountIs(1),
+ hasDeclaration(cxxMethodDecl(hasName("basic_string")))),
+ // If present, the second argument is the alloc object which must not
+ // be present explicitly.
+ cxxConstructExpr(argumentCountIs(2),
+ hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+ hasArgument(1, cxxDefaultArgExpr()))));
+
+ // Match a string constructor expression with an empty string literal.
+ const auto EmptyStringCtorExpr = cxxConstructExpr(
+ StringConstructorExpr,
+ hasArgument(0, ignoringParenImpCasts(stringLiteral(hasSize(0)))));
+
+ const auto EmptyStringCtorExprWithTemporaries =
+ cxxConstructExpr(StringConstructorExpr,
+ hasArgument(0, ignoringImplicit(EmptyStringCtorExpr)));
+
+ // Match a variable declaration with an empty string literal as initializer.
+ // Examples:
+ // string foo = "";
+ // string bar("");
+ Finder->addMatcher(
+ namedDecl(
+ varDecl(hasType(hasUnqualifiedDesugaredType(recordType(
+ hasDeclaration(cxxRecordDecl(hasName("basic_string")))))),
+ hasInitializer(expr(ignoringImplicit(anyOf(
+ EmptyStringCtorExpr,
+ EmptyStringCtorExprWithTemporaries)))
+ .bind("expr"))),
+ unless(parmVarDecl()))
+ .bind("decl"),
+ this);
+}
+
+void RedundantStringInitCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *CtorExpr = Result.Nodes.getNodeAs<Expr>("expr");
+ const auto *Decl = Result.Nodes.getNodeAs<NamedDecl>("decl");
+ diag(CtorExpr->getExprLoc(), "redundant string initialization")
+ << FixItHint::CreateReplacement(CtorExpr->getSourceRange(),
+ Decl->getName());
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
new file mode 100644
index 0000000..0a32eb6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.h
@@ -0,0 +1,32 @@
+//===- RedundantStringInitCheck.h - clang-tidy ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_STRING_INIT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_STRING_INIT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Finds unnecessary string initializations.
+class RedundantStringInitCheck : public ClangTidyCheck {
+public:
+ RedundantStringInitCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_STRING_INIT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
new file mode 100644
index 0000000..ba8e5b4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp
@@ -0,0 +1,676 @@
+//===--- SimplifyBooleanExpr.cpp clang-tidy ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SimplifyBooleanExprCheck.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Lex/Lexer.h"
+
+#include <cassert>
+#include <string>
+#include <utility>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+namespace {
+
+StringRef getText(const MatchFinder::MatchResult &Result, SourceRange Range) {
+ return Lexer::getSourceText(CharSourceRange::getTokenRange(Range),
+ *Result.SourceManager,
+ Result.Context->getLangOpts());
+}
+
+template <typename T>
+StringRef getText(const MatchFinder::MatchResult &Result, T &Node) {
+ return getText(Result, Node.getSourceRange());
+}
+
+const char ConditionThenStmtId[] = "if-bool-yields-then";
+const char ConditionElseStmtId[] = "if-bool-yields-else";
+const char TernaryId[] = "ternary-bool-yields-condition";
+const char TernaryNegatedId[] = "ternary-bool-yields-not-condition";
+const char IfReturnsBoolId[] = "if-return";
+const char IfReturnsNotBoolId[] = "if-not-return";
+const char ThenLiteralId[] = "then-literal";
+const char IfAssignVariableId[] = "if-assign-lvalue";
+const char IfAssignLocId[] = "if-assign-loc";
+const char IfAssignBoolId[] = "if-assign";
+const char IfAssignNotBoolId[] = "if-assign-not";
+const char IfAssignObjId[] = "if-assign-obj";
+const char CompoundReturnId[] = "compound-return";
+const char CompoundBoolId[] = "compound-bool";
+const char CompoundNotBoolId[] = "compound-bool-not";
+
+const char IfStmtId[] = "if";
+
+const char SimplifyOperatorDiagnostic[] =
+ "redundant boolean literal supplied to boolean operator";
+const char SimplifyConditionDiagnostic[] =
+ "redundant boolean literal in if statement condition";
+const char SimplifyConditionalReturnDiagnostic[] =
+ "redundant boolean literal in conditional return statement";
+
+const CXXBoolLiteralExpr *getBoolLiteral(const MatchFinder::MatchResult &Result,
+ StringRef Id) {
+ const auto *Literal = Result.Nodes.getNodeAs<CXXBoolLiteralExpr>(Id);
+ return (Literal && Literal->getLocStart().isMacroID()) ? nullptr : Literal;
+}
+
+internal::Matcher<Stmt> returnsBool(bool Value, StringRef Id = "ignored") {
+ auto SimpleReturnsBool =
+ returnStmt(has(cxxBoolLiteral(equals(Value)).bind(Id)))
+ .bind("returns-bool");
+ return anyOf(SimpleReturnsBool,
+ compoundStmt(statementCountIs(1), has(SimpleReturnsBool)));
+}
+
+bool needsParensAfterUnaryNegation(const Expr *E) {
+ E = E->IgnoreImpCasts();
+ if (isa<BinaryOperator>(E) || isa<ConditionalOperator>(E))
+ return true;
+
+ if (const auto *Op = dyn_cast<CXXOperatorCallExpr>(E))
+ return Op->getNumArgs() == 2 && Op->getOperator() != OO_Call &&
+ Op->getOperator() != OO_Subscript;
+
+ return false;
+}
+
+std::pair<BinaryOperatorKind, BinaryOperatorKind> Opposites[] = {
+ {BO_LT, BO_GE}, {BO_GT, BO_LE}, {BO_EQ, BO_NE}};
+
+StringRef negatedOperator(const BinaryOperator *BinOp) {
+ const BinaryOperatorKind Opcode = BinOp->getOpcode();
+ for (auto NegatableOp : Opposites) {
+ if (Opcode == NegatableOp.first)
+ return BinOp->getOpcodeStr(NegatableOp.second);
+ if (Opcode == NegatableOp.second)
+ return BinOp->getOpcodeStr(NegatableOp.first);
+ }
+ return StringRef();
+}
+
+std::pair<OverloadedOperatorKind, StringRef> OperatorNames[] = {
+ {OO_EqualEqual, "=="}, {OO_ExclaimEqual, "!="}, {OO_Less, "<"},
+ {OO_GreaterEqual, ">="}, {OO_Greater, ">"}, {OO_LessEqual, "<="}};
+
+StringRef getOperatorName(OverloadedOperatorKind OpKind) {
+ for (auto Name : OperatorNames) {
+ if (Name.first == OpKind)
+ return Name.second;
+ }
+
+ return StringRef();
+}
+
+std::pair<OverloadedOperatorKind, OverloadedOperatorKind> OppositeOverloads[] =
+ {{OO_EqualEqual, OO_ExclaimEqual},
+ {OO_Less, OO_GreaterEqual},
+ {OO_Greater, OO_LessEqual}};
+
+StringRef negatedOperator(const CXXOperatorCallExpr *OpCall) {
+ const OverloadedOperatorKind Opcode = OpCall->getOperator();
+ for (auto NegatableOp : OppositeOverloads) {
+ if (Opcode == NegatableOp.first)
+ return getOperatorName(NegatableOp.second);
+ if (Opcode == NegatableOp.second)
+ return getOperatorName(NegatableOp.first);
+ }
+ return StringRef();
+}
+
+std::string asBool(StringRef text, bool NeedsStaticCast) {
+ if (NeedsStaticCast)
+ return ("static_cast<bool>(" + text + ")").str();
+
+ return text;
+}
+
+bool needsNullPtrComparison(const Expr *E) {
+ if (const auto *ImpCast = dyn_cast<ImplicitCastExpr>(E))
+ return ImpCast->getCastKind() == CK_PointerToBoolean ||
+ ImpCast->getCastKind() == CK_MemberPointerToBoolean;
+
+ return false;
+}
+
+bool needsZeroComparison(const Expr *E) {
+ if (const auto *ImpCast = dyn_cast<ImplicitCastExpr>(E))
+ return ImpCast->getCastKind() == CK_IntegralToBoolean;
+
+ return false;
+}
+
+bool needsStaticCast(const Expr *E) {
+ if (const auto *ImpCast = dyn_cast<ImplicitCastExpr>(E)) {
+ if (ImpCast->getCastKind() == CK_UserDefinedConversion &&
+ ImpCast->getSubExpr()->getType()->isBooleanType()) {
+ if (const auto *MemCall =
+ dyn_cast<CXXMemberCallExpr>(ImpCast->getSubExpr())) {
+ if (const auto *MemDecl =
+ dyn_cast<CXXConversionDecl>(MemCall->getMethodDecl())) {
+ if (MemDecl->isExplicit())
+ return true;
+ }
+ }
+ }
+ }
+
+ E = E->IgnoreImpCasts();
+ return !E->getType()->isBooleanType();
+}
+
+std::string compareExpressionToConstant(const MatchFinder::MatchResult &Result,
+ const Expr *E, bool Negated,
+ const char *Constant) {
+ E = E->IgnoreImpCasts();
+ const std::string ExprText =
+ (isa<BinaryOperator>(E) ? ("(" + getText(Result, *E) + ")")
+ : getText(Result, *E))
+ .str();
+ return ExprText + " " + (Negated ? "!=" : "==") + " " + Constant;
+}
+
+std::string compareExpressionToNullPtr(const MatchFinder::MatchResult &Result,
+ const Expr *E, bool Negated) {
+ const char *NullPtr =
+ Result.Context->getLangOpts().CPlusPlus11 ? "nullptr" : "NULL";
+ return compareExpressionToConstant(Result, E, Negated, NullPtr);
+}
+
+std::string compareExpressionToZero(const MatchFinder::MatchResult &Result,
+ const Expr *E, bool Negated) {
+ return compareExpressionToConstant(Result, E, Negated, "0");
+}
+
+std::string replacementExpression(const MatchFinder::MatchResult &Result,
+ bool Negated, const Expr *E) {
+ E = E->ignoreParenBaseCasts();
+ if (const auto *EC = dyn_cast<ExprWithCleanups>(E))
+ E = EC->getSubExpr();
+
+ const bool NeedsStaticCast = needsStaticCast(E);
+ if (Negated) {
+ if (const auto *UnOp = dyn_cast<UnaryOperator>(E)) {
+ if (UnOp->getOpcode() == UO_LNot) {
+ if (needsNullPtrComparison(UnOp->getSubExpr()))
+ return compareExpressionToNullPtr(Result, UnOp->getSubExpr(), true);
+
+ if (needsZeroComparison(UnOp->getSubExpr()))
+ return compareExpressionToZero(Result, UnOp->getSubExpr(), true);
+
+ return replacementExpression(Result, false, UnOp->getSubExpr());
+ }
+ }
+
+ if (needsNullPtrComparison(E))
+ return compareExpressionToNullPtr(Result, E, false);
+
+ if (needsZeroComparison(E))
+ return compareExpressionToZero(Result, E, false);
+
+ StringRef NegatedOperator;
+ const Expr *LHS = nullptr;
+ const Expr *RHS = nullptr;
+ if (const auto *BinOp = dyn_cast<BinaryOperator>(E)) {
+ NegatedOperator = negatedOperator(BinOp);
+ LHS = BinOp->getLHS();
+ RHS = BinOp->getRHS();
+ } else if (const auto *OpExpr = dyn_cast<CXXOperatorCallExpr>(E)) {
+ if (OpExpr->getNumArgs() == 2) {
+ NegatedOperator = negatedOperator(OpExpr);
+ LHS = OpExpr->getArg(0);
+ RHS = OpExpr->getArg(1);
+ }
+ }
+ if (!NegatedOperator.empty() && LHS && RHS)
+ return (asBool((getText(Result, *LHS) + " " + NegatedOperator + " " +
+ getText(Result, *RHS))
+ .str(),
+ NeedsStaticCast));
+
+ StringRef Text = getText(Result, *E);
+ if (!NeedsStaticCast && needsParensAfterUnaryNegation(E))
+ return ("!(" + Text + ")").str();
+
+ if (needsNullPtrComparison(E))
+ return compareExpressionToNullPtr(Result, E, false);
+
+ if (needsZeroComparison(E))
+ return compareExpressionToZero(Result, E, false);
+
+ return ("!" + asBool(Text, NeedsStaticCast));
+ }
+
+ if (const auto *UnOp = dyn_cast<UnaryOperator>(E)) {
+ if (UnOp->getOpcode() == UO_LNot) {
+ if (needsNullPtrComparison(UnOp->getSubExpr()))
+ return compareExpressionToNullPtr(Result, UnOp->getSubExpr(), false);
+
+ if (needsZeroComparison(UnOp->getSubExpr()))
+ return compareExpressionToZero(Result, UnOp->getSubExpr(), false);
+ }
+ }
+
+ if (needsNullPtrComparison(E))
+ return compareExpressionToNullPtr(Result, E, true);
+
+ if (needsZeroComparison(E))
+ return compareExpressionToZero(Result, E, true);
+
+ return asBool(getText(Result, *E), NeedsStaticCast);
+}
+
+const CXXBoolLiteralExpr *stmtReturnsBool(const ReturnStmt *Ret, bool Negated) {
+ if (const auto *Bool = dyn_cast<CXXBoolLiteralExpr>(Ret->getRetValue())) {
+ if (Bool->getValue() == !Negated)
+ return Bool;
+ }
+
+ return nullptr;
+}
+
+const CXXBoolLiteralExpr *stmtReturnsBool(const IfStmt *IfRet, bool Negated) {
+ if (IfRet->getElse() != nullptr)
+ return nullptr;
+
+ if (const auto *Ret = dyn_cast<ReturnStmt>(IfRet->getThen()))
+ return stmtReturnsBool(Ret, Negated);
+
+ if (const auto *Compound = dyn_cast<CompoundStmt>(IfRet->getThen())) {
+ if (Compound->size() == 1) {
+ if (const auto *CompoundRet = dyn_cast<ReturnStmt>(Compound->body_back()))
+ return stmtReturnsBool(CompoundRet, Negated);
+ }
+ }
+
+ return nullptr;
+}
+
+bool containsDiscardedTokens(const MatchFinder::MatchResult &Result,
+ CharSourceRange CharRange) {
+ std::string ReplacementText =
+ Lexer::getSourceText(CharRange, *Result.SourceManager,
+ Result.Context->getLangOpts())
+ .str();
+ Lexer Lex(CharRange.getBegin(), Result.Context->getLangOpts(),
+ ReplacementText.data(), ReplacementText.data(),
+ ReplacementText.data() + ReplacementText.size());
+ Lex.SetCommentRetentionState(true);
+
+ Token Tok;
+ while (!Lex.LexFromRawLexer(Tok)) {
+ if (Tok.is(tok::TokenKind::comment) || Tok.is(tok::TokenKind::hash))
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
+
+class SimplifyBooleanExprCheck::Visitor : public RecursiveASTVisitor<Visitor> {
+ using Base = RecursiveASTVisitor<Visitor>;
+
+ public:
+ Visitor(SimplifyBooleanExprCheck *Check,
+ const MatchFinder::MatchResult &Result)
+ : Check(Check), Result(Result) {}
+
+ bool VisitBinaryOperator(BinaryOperator *Op) {
+ Check->reportBinOp(Result, Op);
+ return true;
+ }
+
+ private:
+ SimplifyBooleanExprCheck *Check;
+ const MatchFinder::MatchResult &Result;
+};
+
+
+SimplifyBooleanExprCheck::SimplifyBooleanExprCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ ChainedConditionalReturn(Options.get("ChainedConditionalReturn", 0U)),
+ ChainedConditionalAssignment(
+ Options.get("ChainedConditionalAssignment", 0U)) {}
+
+bool containsBoolLiteral(const Expr *E) {
+ if (!E)
+ return false;
+ E = E->IgnoreParenImpCasts();
+ if (isa<CXXBoolLiteralExpr>(E))
+ return true;
+ if (const auto *BinOp = dyn_cast<BinaryOperator>(E))
+ return containsBoolLiteral(BinOp->getLHS()) ||
+ containsBoolLiteral(BinOp->getRHS());
+ if (const auto *UnaryOp = dyn_cast<UnaryOperator>(E))
+ return containsBoolLiteral(UnaryOp->getSubExpr());
+ return false;
+}
+
+void SimplifyBooleanExprCheck::reportBinOp(
+ const MatchFinder::MatchResult &Result, const BinaryOperator *Op) {
+ const auto *LHS = Op->getLHS()->IgnoreParenImpCasts();
+ const auto *RHS = Op->getRHS()->IgnoreParenImpCasts();
+
+ const CXXBoolLiteralExpr *Bool = nullptr;
+ const Expr *Other = nullptr;
+ if ((Bool = dyn_cast<CXXBoolLiteralExpr>(LHS)))
+ Other = RHS;
+ else if ((Bool = dyn_cast<CXXBoolLiteralExpr>(RHS)))
+ Other = LHS;
+ else
+ return;
+
+ if (Bool->getLocStart().isMacroID())
+ return;
+
+ // FIXME: why do we need this?
+ if (!isa<CXXBoolLiteralExpr>(Other) && containsBoolLiteral(Other))
+ return;
+
+ bool BoolValue = Bool->getValue();
+
+ auto replaceWithExpression = [this, &Result, LHS, RHS, Bool](
+ const Expr *ReplaceWith, bool Negated) {
+ std::string Replacement =
+ replacementExpression(Result, Negated, ReplaceWith);
+ SourceRange Range(LHS->getLocStart(), RHS->getLocEnd());
+ issueDiag(Result, Bool->getLocStart(), SimplifyOperatorDiagnostic, Range,
+ Replacement);
+ };
+
+ switch (Op->getOpcode()) {
+ case BO_LAnd:
+ if (BoolValue) {
+ // expr && true -> expr
+ replaceWithExpression(Other, /*Negated=*/false);
+ } else {
+ // expr && false -> false
+ replaceWithExpression(Bool, /*Negated=*/false);
+ }
+ break;
+ case BO_LOr:
+ if (BoolValue) {
+ // expr || true -> true
+ replaceWithExpression(Bool, /*Negated=*/false);
+ } else {
+ // expr || false -> expr
+ replaceWithExpression(Other, /*Negated=*/false);
+ }
+ break;
+ case BO_EQ:
+ // expr == true -> expr, expr == false -> !expr
+ replaceWithExpression(Other, /*Negated=*/!BoolValue);
+ break;
+ case BO_NE:
+ // expr != true -> !expr, expr != false -> expr
+ replaceWithExpression(Other, /*Negated=*/BoolValue);
+ break;
+ default:
+ break;
+ }
+}
+
+void SimplifyBooleanExprCheck::matchBoolCondition(MatchFinder *Finder,
+ bool Value,
+ StringRef BooleanId) {
+ Finder->addMatcher(
+ ifStmt(isExpansionInMainFile(),
+ hasCondition(cxxBoolLiteral(equals(Value)).bind(BooleanId)))
+ .bind(IfStmtId),
+ this);
+}
+
+void SimplifyBooleanExprCheck::matchTernaryResult(MatchFinder *Finder,
+ bool Value,
+ StringRef TernaryId) {
+ Finder->addMatcher(
+ conditionalOperator(isExpansionInMainFile(),
+ hasTrueExpression(cxxBoolLiteral(equals(Value))),
+ hasFalseExpression(cxxBoolLiteral(equals(!Value))))
+ .bind(TernaryId),
+ this);
+}
+
+void SimplifyBooleanExprCheck::matchIfReturnsBool(MatchFinder *Finder,
+ bool Value, StringRef Id) {
+ if (ChainedConditionalReturn)
+ Finder->addMatcher(ifStmt(isExpansionInMainFile(),
+ hasThen(returnsBool(Value, ThenLiteralId)),
+ hasElse(returnsBool(!Value)))
+ .bind(Id),
+ this);
+ else
+ Finder->addMatcher(ifStmt(isExpansionInMainFile(),
+ unless(hasParent(ifStmt())),
+ hasThen(returnsBool(Value, ThenLiteralId)),
+ hasElse(returnsBool(!Value)))
+ .bind(Id),
+ this);
+}
+
+void SimplifyBooleanExprCheck::matchIfAssignsBool(MatchFinder *Finder,
+ bool Value, StringRef Id) {
+ auto SimpleThen = binaryOperator(
+ hasOperatorName("="),
+ hasLHS(declRefExpr(hasDeclaration(decl().bind(IfAssignObjId)))),
+ hasLHS(expr().bind(IfAssignVariableId)),
+ hasRHS(cxxBoolLiteral(equals(Value)).bind(IfAssignLocId)));
+ auto Then = anyOf(SimpleThen, compoundStmt(statementCountIs(1),
+ hasAnySubstatement(SimpleThen)));
+ auto SimpleElse = binaryOperator(
+ hasOperatorName("="),
+ hasLHS(declRefExpr(hasDeclaration(equalsBoundNode(IfAssignObjId)))),
+ hasRHS(cxxBoolLiteral(equals(!Value))));
+ auto Else = anyOf(SimpleElse, compoundStmt(statementCountIs(1),
+ hasAnySubstatement(SimpleElse)));
+ if (ChainedConditionalAssignment)
+ Finder->addMatcher(
+ ifStmt(isExpansionInMainFile(), hasThen(Then), hasElse(Else)).bind(Id),
+ this);
+ else
+ Finder->addMatcher(ifStmt(isExpansionInMainFile(),
+ unless(hasParent(ifStmt())), hasThen(Then),
+ hasElse(Else))
+ .bind(Id),
+ this);
+}
+
+void SimplifyBooleanExprCheck::matchCompoundIfReturnsBool(MatchFinder *Finder,
+ bool Value,
+ StringRef Id) {
+ Finder->addMatcher(
+ compoundStmt(allOf(hasAnySubstatement(ifStmt(hasThen(returnsBool(Value)),
+ unless(hasElse(stmt())))),
+ hasAnySubstatement(
+ returnStmt(has(ignoringParenImpCasts(
+ cxxBoolLiteral(equals(!Value)))))
+ .bind(CompoundReturnId))))
+ .bind(Id),
+ this);
+}
+
+void SimplifyBooleanExprCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "ChainedConditionalReturn", ChainedConditionalReturn);
+ Options.store(Opts, "ChainedConditionalAssignment",
+ ChainedConditionalAssignment);
+}
+
+void SimplifyBooleanExprCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(translationUnitDecl().bind("top"), this);
+
+ matchBoolCondition(Finder, true, ConditionThenStmtId);
+ matchBoolCondition(Finder, false, ConditionElseStmtId);
+
+ matchTernaryResult(Finder, true, TernaryId);
+ matchTernaryResult(Finder, false, TernaryNegatedId);
+
+ matchIfReturnsBool(Finder, true, IfReturnsBoolId);
+ matchIfReturnsBool(Finder, false, IfReturnsNotBoolId);
+
+ matchIfAssignsBool(Finder, true, IfAssignBoolId);
+ matchIfAssignsBool(Finder, false, IfAssignNotBoolId);
+
+ matchCompoundIfReturnsBool(Finder, true, CompoundBoolId);
+ matchCompoundIfReturnsBool(Finder, false, CompoundNotBoolId);
+}
+
+void SimplifyBooleanExprCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const CXXBoolLiteralExpr *TrueConditionRemoved =
+ getBoolLiteral(Result, ConditionThenStmtId))
+ replaceWithThenStatement(Result, TrueConditionRemoved);
+ else if (const CXXBoolLiteralExpr *FalseConditionRemoved =
+ getBoolLiteral(Result, ConditionElseStmtId))
+ replaceWithElseStatement(Result, FalseConditionRemoved);
+ else if (const auto *Ternary =
+ Result.Nodes.getNodeAs<ConditionalOperator>(TernaryId))
+ replaceWithCondition(Result, Ternary);
+ else if (const auto *TernaryNegated =
+ Result.Nodes.getNodeAs<ConditionalOperator>(TernaryNegatedId))
+ replaceWithCondition(Result, TernaryNegated, true);
+ else if (const auto *If = Result.Nodes.getNodeAs<IfStmt>(IfReturnsBoolId))
+ replaceWithReturnCondition(Result, If);
+ else if (const auto *IfNot =
+ Result.Nodes.getNodeAs<IfStmt>(IfReturnsNotBoolId))
+ replaceWithReturnCondition(Result, IfNot, true);
+ else if (const auto *IfAssign =
+ Result.Nodes.getNodeAs<IfStmt>(IfAssignBoolId))
+ replaceWithAssignment(Result, IfAssign);
+ else if (const auto *IfAssignNot =
+ Result.Nodes.getNodeAs<IfStmt>(IfAssignNotBoolId))
+ replaceWithAssignment(Result, IfAssignNot, true);
+ else if (const auto *Compound =
+ Result.Nodes.getNodeAs<CompoundStmt>(CompoundBoolId))
+ replaceCompoundReturnWithCondition(Result, Compound);
+ else if (const auto *Compound =
+ Result.Nodes.getNodeAs<CompoundStmt>(CompoundNotBoolId))
+ replaceCompoundReturnWithCondition(Result, Compound, true);
+ else if (const auto TU = Result.Nodes.getNodeAs<Decl>("top"))
+ Visitor(this, Result).TraverseDecl(const_cast<Decl*>(TU));
+}
+
+void SimplifyBooleanExprCheck::issueDiag(
+ const ast_matchers::MatchFinder::MatchResult &Result, SourceLocation Loc,
+ StringRef Description, SourceRange ReplacementRange,
+ StringRef Replacement) {
+ CharSourceRange CharRange =
+ Lexer::makeFileCharRange(CharSourceRange::getTokenRange(ReplacementRange),
+ *Result.SourceManager, getLangOpts());
+
+ DiagnosticBuilder Diag = diag(Loc, Description);
+ if (!containsDiscardedTokens(Result, CharRange))
+ Diag << FixItHint::CreateReplacement(CharRange, Replacement);
+}
+
+void SimplifyBooleanExprCheck::replaceWithThenStatement(
+ const MatchFinder::MatchResult &Result,
+ const CXXBoolLiteralExpr *TrueConditionRemoved) {
+ const auto *IfStatement = Result.Nodes.getNodeAs<IfStmt>(IfStmtId);
+ issueDiag(Result, TrueConditionRemoved->getLocStart(),
+ SimplifyConditionDiagnostic, IfStatement->getSourceRange(),
+ getText(Result, *IfStatement->getThen()));
+}
+
+void SimplifyBooleanExprCheck::replaceWithElseStatement(
+ const MatchFinder::MatchResult &Result,
+ const CXXBoolLiteralExpr *FalseConditionRemoved) {
+ const auto *IfStatement = Result.Nodes.getNodeAs<IfStmt>(IfStmtId);
+ const Stmt *ElseStatement = IfStatement->getElse();
+ issueDiag(Result, FalseConditionRemoved->getLocStart(),
+ SimplifyConditionDiagnostic, IfStatement->getSourceRange(),
+ ElseStatement ? getText(Result, *ElseStatement) : "");
+}
+
+void SimplifyBooleanExprCheck::replaceWithCondition(
+ const MatchFinder::MatchResult &Result, const ConditionalOperator *Ternary,
+ bool Negated) {
+ std::string Replacement =
+ replacementExpression(Result, Negated, Ternary->getCond());
+ issueDiag(Result, Ternary->getTrueExpr()->getLocStart(),
+ "redundant boolean literal in ternary expression result",
+ Ternary->getSourceRange(), Replacement);
+}
+
+void SimplifyBooleanExprCheck::replaceWithReturnCondition(
+ const MatchFinder::MatchResult &Result, const IfStmt *If, bool Negated) {
+ StringRef Terminator = isa<CompoundStmt>(If->getElse()) ? ";" : "";
+ std::string Condition = replacementExpression(Result, Negated, If->getCond());
+ std::string Replacement = ("return " + Condition + Terminator).str();
+ SourceLocation Start =
+ Result.Nodes.getNodeAs<CXXBoolLiteralExpr>(ThenLiteralId)->getLocStart();
+ issueDiag(Result, Start, SimplifyConditionalReturnDiagnostic,
+ If->getSourceRange(), Replacement);
+}
+
+void SimplifyBooleanExprCheck::replaceCompoundReturnWithCondition(
+ const MatchFinder::MatchResult &Result, const CompoundStmt *Compound,
+ bool Negated) {
+ const auto *Ret = Result.Nodes.getNodeAs<ReturnStmt>(CompoundReturnId);
+
+ // The body shouldn't be empty because the matcher ensures that it must
+ // contain at least two statements:
+ // 1) A `return` statement returning a boolean literal `false` or `true`
+ // 2) An `if` statement with no `else` clause that consists of a single
+ // `return` statement returning the opposite boolean literal `true` or
+ // `false`.
+ assert(Compound->size() >= 2);
+ const IfStmt *BeforeIf = nullptr;
+ CompoundStmt::const_body_iterator Current = Compound->body_begin();
+ CompoundStmt::const_body_iterator After = Compound->body_begin();
+ for (++After; After != Compound->body_end() && *Current != Ret;
+ ++Current, ++After) {
+ if (const auto *If = dyn_cast<IfStmt>(*Current)) {
+ if (const CXXBoolLiteralExpr *Lit = stmtReturnsBool(If, Negated)) {
+ if (*After == Ret) {
+ if (!ChainedConditionalReturn && BeforeIf)
+ continue;
+
+ const Expr *Condition = If->getCond();
+ std::string Replacement =
+ "return " + replacementExpression(Result, Negated, Condition);
+ issueDiag(
+ Result, Lit->getLocStart(), SimplifyConditionalReturnDiagnostic,
+ SourceRange(If->getLocStart(), Ret->getLocEnd()), Replacement);
+ return;
+ }
+
+ BeforeIf = If;
+ }
+ } else {
+ BeforeIf = nullptr;
+ }
+ }
+}
+
+void SimplifyBooleanExprCheck::replaceWithAssignment(
+ const MatchFinder::MatchResult &Result, const IfStmt *IfAssign,
+ bool Negated) {
+ SourceRange Range = IfAssign->getSourceRange();
+ StringRef VariableName =
+ getText(Result, *Result.Nodes.getNodeAs<Expr>(IfAssignVariableId));
+ StringRef Terminator = isa<CompoundStmt>(IfAssign->getElse()) ? ";" : "";
+ std::string Condition =
+ replacementExpression(Result, Negated, IfAssign->getCond());
+ std::string Replacement =
+ (VariableName + " = " + Condition + Terminator).str();
+ SourceLocation Location =
+ Result.Nodes.getNodeAs<CXXBoolLiteralExpr>(IfAssignLocId)->getLocStart();
+ issueDiag(Result, Location,
+ "redundant boolean literal in conditional assignment", Range,
+ Replacement);
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h
new file mode 100644
index 0000000..af47453
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h
@@ -0,0 +1,90 @@
+//===--- SimplifyBooleanExpr.h clang-tidy -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFY_BOOLEAN_EXPR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFY_BOOLEAN_EXPR_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Looks for boolean expressions involving boolean constants and simplifies
+/// them to use the appropriate boolean expression directly.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-simplify-boolean-expr.html
+class SimplifyBooleanExprCheck : public ClangTidyCheck {
+public:
+ SimplifyBooleanExprCheck(StringRef Name, ClangTidyContext *Context);
+
+ void storeOptions(ClangTidyOptions::OptionMap &Options) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ class Visitor;
+
+ void reportBinOp(const ast_matchers::MatchFinder::MatchResult &Result,
+ const BinaryOperator *Op);
+
+ void matchBoolCondition(ast_matchers::MatchFinder *Finder, bool Value,
+ StringRef BooleanId);
+
+ void matchTernaryResult(ast_matchers::MatchFinder *Finder, bool Value,
+ StringRef TernaryId);
+
+ void matchIfReturnsBool(ast_matchers::MatchFinder *Finder, bool Value,
+ StringRef Id);
+
+ void matchIfAssignsBool(ast_matchers::MatchFinder *Finder, bool Value,
+ StringRef Id);
+
+ void matchCompoundIfReturnsBool(ast_matchers::MatchFinder *Finder, bool Value,
+ StringRef Id);
+
+ void
+ replaceWithThenStatement(const ast_matchers::MatchFinder::MatchResult &Result,
+ const CXXBoolLiteralExpr *BoolLiteral);
+
+ void
+ replaceWithElseStatement(const ast_matchers::MatchFinder::MatchResult &Result,
+ const CXXBoolLiteralExpr *FalseConditionRemoved);
+
+ void
+ replaceWithCondition(const ast_matchers::MatchFinder::MatchResult &Result,
+ const ConditionalOperator *Ternary,
+ bool Negated = false);
+
+ void replaceWithReturnCondition(
+ const ast_matchers::MatchFinder::MatchResult &Result, const IfStmt *If,
+ bool Negated = false);
+
+ void
+ replaceWithAssignment(const ast_matchers::MatchFinder::MatchResult &Result,
+ const IfStmt *If, bool Negated = false);
+
+ void replaceCompoundReturnWithCondition(
+ const ast_matchers::MatchFinder::MatchResult &Result,
+ const CompoundStmt *Compound, bool Negated = false);
+
+ void issueDiag(const ast_matchers::MatchFinder::MatchResult &Result,
+ SourceLocation Loc, StringRef Description,
+ SourceRange ReplacementRange, StringRef Replacement);
+
+ const bool ChainedConditionalReturn;
+ const bool ChainedConditionalAssignment;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFY_BOOLEAN_EXPR_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/SimplifySubscriptExprCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/SimplifySubscriptExprCheck.cpp
new file mode 100644
index 0000000..28cc576
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/SimplifySubscriptExprCheck.cpp
@@ -0,0 +1,76 @@
+//===--- SimplifySubscriptExprCheck.cpp - clang-tidy-----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SimplifySubscriptExprCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+static const char kDefaultTypes[] =
+ "::std::basic_string;::std::basic_string_view;::std::vector;::std::array";
+
+SimplifySubscriptExprCheck::SimplifySubscriptExprCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context), Types(utils::options::parseStringList(
+ Options.get("Types", kDefaultTypes))) {
+}
+
+void SimplifySubscriptExprCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ const auto TypesMatcher = hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(cxxRecordDecl(hasAnyName(
+ llvm::SmallVector<StringRef, 8>(Types.begin(), Types.end()))))));
+
+ Finder->addMatcher(
+ arraySubscriptExpr(hasBase(ignoringParenImpCasts(
+ cxxMemberCallExpr(
+ has(memberExpr().bind("member")),
+ on(hasType(qualType(
+ unless(anyOf(substTemplateTypeParmType(),
+ hasDescendant(substTemplateTypeParmType()))),
+ anyOf(TypesMatcher, pointerType(pointee(TypesMatcher)))))),
+ callee(namedDecl(hasName("data"))))
+ .bind("call")))),
+ this);
+}
+
+void SimplifySubscriptExprCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Call = Result.Nodes.getNodeAs<CXXMemberCallExpr>("call");
+ if (Result.Context->getSourceManager().isMacroBodyExpansion(
+ Call->getExprLoc()))
+ return;
+
+ const auto *Member = Result.Nodes.getNodeAs<MemberExpr>("member");
+ auto DiagBuilder =
+ diag(Member->getMemberLoc(),
+ "accessing an element of the container does not require a call to "
+ "'data()'; did you mean to use 'operator[]'?");
+ if (Member->isArrow())
+ DiagBuilder << FixItHint::CreateInsertion(Member->getLocStart(), "(*")
+ << FixItHint::CreateInsertion(Member->getOperatorLoc(), ")");
+ DiagBuilder << FixItHint::CreateRemoval(
+ {Member->getOperatorLoc(), Call->getLocEnd()});
+}
+
+void SimplifySubscriptExprCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "Types", utils::options::serializeStringList(Types));
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/SimplifySubscriptExprCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/SimplifySubscriptExprCheck.h
new file mode 100644
index 0000000..86a21b9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/SimplifySubscriptExprCheck.h
@@ -0,0 +1,38 @@
+//===--- SimplifySubscriptExprCheck.h - clang-tidy---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFYSUBSCRIPTEXPRCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFYSUBSCRIPTEXPRCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Simplifies subscript expressions.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-simplify-subscript-expr.html
+class SimplifySubscriptExprCheck : public ClangTidyCheck {
+public:
+ SimplifySubscriptExprCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap& Opts) override;
+
+private:
+ const std::vector<std::string> Types;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_SIMPLIFYSUBSCRIPTEXPRCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
new file mode 100644
index 0000000..b136577
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp
@@ -0,0 +1,90 @@
+//===--- StaticAccessedThroughInstanceCheck.cpp - clang-tidy---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StaticAccessedThroughInstanceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+static unsigned getNameSpecifierNestingLevel(const QualType &QType) {
+ if (const ElaboratedType *ElType = QType->getAs<ElaboratedType>()) {
+ const NestedNameSpecifier *NestedSpecifiers = ElType->getQualifier();
+ unsigned NameSpecifierNestingLevel = 1;
+ do {
+ NameSpecifierNestingLevel++;
+ NestedSpecifiers = NestedSpecifiers->getPrefix();
+ } while (NestedSpecifiers);
+
+ return NameSpecifierNestingLevel;
+ }
+ return 0;
+}
+
+void StaticAccessedThroughInstanceCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "NameSpecifierNestingThreshold",
+ NameSpecifierNestingThreshold);
+}
+
+void StaticAccessedThroughInstanceCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ memberExpr(hasDeclaration(anyOf(cxxMethodDecl(isStaticStorageClass()),
+ varDecl(hasStaticStorageDuration()))),
+ unless(isInTemplateInstantiation()))
+ .bind("memberExpression"),
+ this);
+}
+
+void StaticAccessedThroughInstanceCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *MemberExpression =
+ Result.Nodes.getNodeAs<MemberExpr>("memberExpression");
+
+ if (MemberExpression->getLocStart().isMacroID())
+ return;
+
+ const Expr *BaseExpr = MemberExpression->getBase();
+
+ // Do not warn for overlaoded -> operators.
+ if (isa<CXXOperatorCallExpr>(BaseExpr))
+ return;
+
+ QualType BaseType =
+ BaseExpr->getType()->isPointerType()
+ ? BaseExpr->getType()->getPointeeType().getUnqualifiedType()
+ : BaseExpr->getType().getUnqualifiedType();
+
+ const ASTContext *AstContext = Result.Context;
+ PrintingPolicy PrintingPolicyWithSupressedTag(AstContext->getLangOpts());
+ PrintingPolicyWithSupressedTag.SuppressTagKeyword = true;
+ std::string BaseTypeName =
+ BaseType.getAsString(PrintingPolicyWithSupressedTag);
+
+ SourceLocation MemberExprStartLoc = MemberExpression->getLocStart();
+ auto Diag =
+ diag(MemberExprStartLoc, "static member accessed through instance");
+
+ if (BaseExpr->HasSideEffects(*AstContext) ||
+ getNameSpecifierNestingLevel(BaseType) > NameSpecifierNestingThreshold)
+ return;
+
+ Diag << FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(MemberExprStartLoc,
+ MemberExpression->getMemberLoc()),
+ BaseTypeName + "::");
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.h
new file mode 100644
index 0000000..c2eebab
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.h
@@ -0,0 +1,43 @@
+//===--- StaticAccessedThroughInstanceCheck.h - clang-tidy-------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STATIC_ACCESSED_THROUGH_INSTANCE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STATIC_ACCESSED_THROUGH_INSTANCE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// \@brief Checks for member expressions that access static members through
+/// instances and replaces them with uses of the appropriate qualified-id.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-static-accessed-through-instance.html
+class StaticAccessedThroughInstanceCheck : public ClangTidyCheck {
+public:
+ StaticAccessedThroughInstanceCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ NameSpecifierNestingThreshold(
+ Options.get("NameSpecifierNestingThreshold", 3)) {}
+
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const unsigned NameSpecifierNestingThreshold;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STATIC_ACCESSED_THROUGH_INSTANCE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.cpp
new file mode 100644
index 0000000..0554605
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.cpp
@@ -0,0 +1,66 @@
+//===--- StaticDefinitionInAnonymousNamespaceCheck.cpp - clang-tidy--------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StaticDefinitionInAnonymousNamespaceCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+void StaticDefinitionInAnonymousNamespaceCheck::registerMatchers(
+ MatchFinder *Finder) {
+ Finder->addMatcher(
+ namedDecl(anyOf(functionDecl(isDefinition(), isStaticStorageClass()),
+ varDecl(isDefinition(), isStaticStorageClass())),
+ hasParent(namespaceDecl(isAnonymous())))
+ .bind("static-def"),
+ this);
+}
+
+void StaticDefinitionInAnonymousNamespaceCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *Def = Result.Nodes.getNodeAs<NamedDecl>("static-def");
+ // Skips all static definitions defined in Macro.
+ if (Def->getLocation().isMacroID())
+ return;
+
+ // Skips all static definitions in function scope.
+ const DeclContext *DC = Def->getDeclContext();
+ if (DC->getDeclKind() != Decl::Namespace)
+ return;
+
+ auto Diag =
+ diag(Def->getLocation(), "%0 is a static definition in "
+ "anonymous namespace; static is redundant here")
+ << Def;
+ Token Tok;
+ SourceLocation Loc = Def->getSourceRange().getBegin();
+ while (Loc < Def->getSourceRange().getEnd() &&
+ !Lexer::getRawToken(Loc, Tok, *Result.SourceManager, getLangOpts(),
+ true)) {
+ SourceRange TokenRange(Tok.getLocation(), Tok.getEndLoc());
+ StringRef SourceText =
+ Lexer::getSourceText(CharSourceRange::getTokenRange(TokenRange),
+ *Result.SourceManager, getLangOpts());
+ if (SourceText == "static") {
+ Diag << FixItHint::CreateRemoval(TokenRange);
+ break;
+ }
+ Loc = Tok.getEndLoc();
+ }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.h
new file mode 100644
index 0000000..03e99fd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.h
@@ -0,0 +1,36 @@
+//===--- StaticDefinitionInAnonymousNamespaceCheck.h - clang-tidy*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STATIC_DEFINITION_IN_ANONYMOUS_NAMESPACE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STATIC_DEFINITION_IN_ANONYMOUS_NAMESPACE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Finds static function and variable definitions in anonymous namespace.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-static-definition-in-anonymous-namespace.html
+class StaticDefinitionInAnonymousNamespaceCheck : public ClangTidyCheck {
+public:
+ StaticDefinitionInAnonymousNamespaceCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STATIC_DEFINITION_IN_ANONYMOUS_NAMESPACE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp
new file mode 100644
index 0000000..e75e80b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp
@@ -0,0 +1,82 @@
+//===--- MiscStringCompare.cpp - clang-tidy--------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StringCompareCheck.h"
+#include "../utils/FixItHintUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+static const StringRef CompareMessage = "do not use 'compare' to test equality "
+ "of strings; use the string equality "
+ "operator instead";
+
+void StringCompareCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ const auto StrCompare = cxxMemberCallExpr(
+ callee(cxxMethodDecl(hasName("compare"),
+ ofClass(classTemplateSpecializationDecl(
+ hasName("::std::basic_string"))))),
+ hasArgument(0, expr().bind("str2")), argumentCountIs(1),
+ callee(memberExpr().bind("str1")));
+
+ // First and second case: cast str.compare(str) to boolean.
+ Finder->addMatcher(implicitCastExpr(hasImplicitDestinationType(booleanType()),
+ has(StrCompare))
+ .bind("match1"),
+ this);
+
+ // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0.
+ Finder->addMatcher(
+ binaryOperator(anyOf(hasOperatorName("=="), hasOperatorName("!=")),
+ hasEitherOperand(StrCompare.bind("compare")),
+ hasEitherOperand(integerLiteral(equals(0)).bind("zero")))
+ .bind("match2"),
+ this);
+}
+
+void StringCompareCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *Matched = Result.Nodes.getNodeAs<Stmt>("match1")) {
+ diag(Matched->getLocStart(), CompareMessage);
+ return;
+ }
+
+ if (const auto *Matched = Result.Nodes.getNodeAs<Stmt>("match2")) {
+ const ASTContext &Ctx = *Result.Context;
+
+ if (const auto *Zero = Result.Nodes.getNodeAs<Stmt>("zero")) {
+ const auto *Str1 = Result.Nodes.getNodeAs<MemberExpr>("str1");
+ const auto *Str2 = Result.Nodes.getNodeAs<Stmt>("str2");
+ const auto *Compare = Result.Nodes.getNodeAs<Stmt>("compare");
+
+ auto Diag = diag(Matched->getLocStart(), CompareMessage);
+
+ if (Str1->isArrow())
+ Diag << FixItHint::CreateInsertion(Str1->getLocStart(), "*");
+
+ Diag << tooling::fixit::createReplacement(*Zero, *Str2, Ctx)
+ << tooling::fixit::createReplacement(*Compare, *Str1->getBase(),
+ Ctx);
+ }
+ }
+
+ // FIXME: Add fixit to fix the code for case one and two (match1).
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h
new file mode 100644
index 0000000..248d2ee
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h
@@ -0,0 +1,36 @@
+//===--- StringCompareCheck.h - clang-tidy-----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRINGCOMPARECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRINGCOMPARECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// This check flags all calls compare when used to check for string
+/// equality or inequality.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-string-compare.html
+class StringCompareCheck : public ClangTidyCheck {
+public:
+ StringCompareCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRINGCOMPARECHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.cpp
new file mode 100644
index 0000000..3ad346c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.cpp
@@ -0,0 +1,69 @@
+//===--- UniqueptrDeleteReleaseCheck.cpp - clang-tidy----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UniqueptrDeleteReleaseCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+void UniqueptrDeleteReleaseCheck::registerMatchers(MatchFinder *Finder) {
+ auto IsSusbstituted = qualType(anyOf(
+ substTemplateTypeParmType(), hasDescendant(substTemplateTypeParmType())));
+
+ auto UniquePtrWithDefaultDelete = classTemplateSpecializationDecl(
+ hasName("std::unique_ptr"),
+ hasTemplateArgument(1, refersToType(qualType(hasDeclaration(cxxRecordDecl(
+ hasName("std::default_delete")))))));
+
+ Finder->addMatcher(
+ cxxDeleteExpr(has(ignoringParenImpCasts(cxxMemberCallExpr(
+ on(expr(hasType(UniquePtrWithDefaultDelete),
+ unless(hasType(IsSusbstituted)))
+ .bind("uptr")),
+ callee(cxxMethodDecl(hasName("release")))))))
+ .bind("delete"),
+ this);
+}
+
+void UniqueptrDeleteReleaseCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const auto *PtrExpr = Result.Nodes.getNodeAs<Expr>("uptr");
+ const auto *DeleteExpr = Result.Nodes.getNodeAs<Expr>("delete");
+
+ if (PtrExpr->getLocStart().isMacroID())
+ return;
+
+ // Ignore dependent types.
+ // It can give us false positives, so we go with false negatives instead to
+ // be safe.
+ if (PtrExpr->getType()->isDependentType())
+ return;
+
+ SourceLocation AfterPtr = Lexer::getLocForEndOfToken(
+ PtrExpr->getLocEnd(), 0, *Result.SourceManager, getLangOpts());
+
+ diag(DeleteExpr->getLocStart(),
+ "prefer '= nullptr' to 'delete x.release()' to reset unique_ptr<> "
+ "objects")
+ << FixItHint::CreateRemoval(CharSourceRange::getCharRange(
+ DeleteExpr->getLocStart(), PtrExpr->getLocStart()))
+ << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(AfterPtr, DeleteExpr->getLocEnd()),
+ " = nullptr");
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.h
new file mode 100644
index 0000000..fd86bdb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.h
@@ -0,0 +1,36 @@
+//===--- UniqueptrDeleteReleaseCheck.h - clang-tidy--------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_UNIQUEPTR_DELETE_RELEASE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_UNIQUEPTR_DELETE_RELEASE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// Flags statements of the form ``delete <unique_ptr expr>.release();`` and
+/// replaces them with: ``<unique_ptr expr> = nullptr;``
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability-uniqueptr-delete-release.html
+class UniqueptrDeleteReleaseCheck : public ClangTidyCheck {
+public:
+ UniqueptrDeleteReleaseCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_UNIQUEPTR_DELETE_RELEASE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/rename_check.py b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/rename_check.py
new file mode 100755
index 0000000..53a5ff9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/rename_check.py
@@ -0,0 +1,272 @@
+#!/usr/bin/env python
+#
+#===- rename_check.py - clang-tidy check renamer -------------*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+import argparse
+import glob
+import os
+import re
+
+
+def replaceInFile(fileName, sFrom, sTo):
+ if sFrom == sTo:
+ return
+ txt = None
+ with open(fileName, "r") as f:
+ txt = f.read()
+
+ if sFrom not in txt:
+ return
+
+ txt = txt.replace(sFrom, sTo)
+ print("Replacing '%s' -> '%s' in '%s'..." % (sFrom, sTo, fileName))
+ with open(fileName, "w") as f:
+ f.write(txt)
+
+
+def generateCommentLineHeader(filename):
+ return ''.join(['//===--- ',
+ os.path.basename(filename),
+ ' - clang-tidy ',
+ '-' * max(0, 42 - len(os.path.basename(filename))),
+ '*- C++ -*-===//'])
+
+
+def generateCommentLineSource(filename):
+ return ''.join(['//===--- ',
+ os.path.basename(filename),
+ ' - clang-tidy',
+ '-' * max(0, 52 - len(os.path.basename(filename))),
+ '-===//'])
+
+
+def fileRename(fileName, sFrom, sTo):
+ if sFrom not in fileName or sFrom == sTo:
+ return fileName
+ newFileName = fileName.replace(sFrom, sTo)
+ print("Renaming '%s' -> '%s'..." % (fileName, newFileName))
+ os.rename(fileName, newFileName)
+ return newFileName
+
+def deleteMatchingLines(fileName, pattern):
+ lines = None
+ with open(fileName, "r") as f:
+ lines = f.readlines()
+
+ not_matching_lines = [l for l in lines if not re.search(pattern, l)]
+ if len(not_matching_lines) == len(lines):
+ return False
+
+ print("Removing lines matching '%s' in '%s'..." % (pattern, fileName))
+ print(' ' + ' '.join([l for l in lines if re.search(pattern, l)]))
+ with open(fileName, "w") as f:
+ f.writelines(not_matching_lines)
+
+ return True
+
+def getListOfFiles(clang_tidy_path):
+ files = glob.glob(os.path.join(clang_tidy_path, '*'))
+ for dirname in files:
+ if os.path.isdir(dirname):
+ files += glob.glob(os.path.join(dirname, '*'))
+ files += glob.glob(os.path.join(clang_tidy_path, '..', 'test',
+ 'clang-tidy', '*'))
+ files += glob.glob(os.path.join(clang_tidy_path, '..', 'docs',
+ 'clang-tidy', 'checks', '*'))
+ return [filename for filename in files if os.path.isfile(filename)]
+
+# Adapts the module's CMakelist file. Returns 'True' if it could add a new entry
+# and 'False' if the entry already existed.
+def adapt_cmake(module_path, check_name_camel):
+ filename = os.path.join(module_path, 'CMakeLists.txt')
+ with open(filename, 'r') as f:
+ lines = f.readlines()
+
+ cpp_file = check_name_camel + '.cpp'
+
+ # Figure out whether this check already exists.
+ for line in lines:
+ if line.strip() == cpp_file:
+ return False
+
+ print('Updating %s...' % filename)
+ with open(filename, 'wb') as f:
+ cpp_found = False
+ file_added = False
+ for line in lines:
+ cpp_line = line.strip().endswith('.cpp')
+ if (not file_added) and (cpp_line or cpp_found):
+ cpp_found = True
+ if (line.strip() > cpp_file) or (not cpp_line):
+ f.write(' ' + cpp_file + '\n')
+ file_added = True
+ f.write(line)
+
+ return True
+
+# Modifies the module to include the new check.
+def adapt_module(module_path, module, check_name, check_name_camel):
+ modulecpp = filter(lambda p: p.lower() == module.lower() + 'tidymodule.cpp',
+ os.listdir(module_path))[0]
+ filename = os.path.join(module_path, modulecpp)
+ with open(filename, 'r') as f:
+ lines = f.readlines()
+
+ print('Updating %s...' % filename)
+ with open(filename, 'wb') as f:
+ header_added = False
+ header_found = False
+ check_added = False
+ check_decl = (' CheckFactories.registerCheck<' + check_name_camel +
+ '>(\n "' + check_name + '");\n')
+
+ for line in lines:
+ if not header_added:
+ match = re.search('#include "(.*)"', line)
+ if match:
+ header_found = True
+ if match.group(1) > check_name_camel:
+ header_added = True
+ f.write('#include "' + check_name_camel + '.h"\n')
+ elif header_found:
+ header_added = True
+ f.write('#include "' + check_name_camel + '.h"\n')
+
+ if not check_added:
+ if line.strip() == '}':
+ check_added = True
+ f.write(check_decl)
+ else:
+ match = re.search('registerCheck<(.*)>', line)
+ if match and match.group(1) > check_name_camel:
+ check_added = True
+ f.write(check_decl)
+ f.write(line)
+
+
+# Adds a release notes entry.
+def add_release_notes(clang_tidy_path, old_check_name, new_check_name):
+ filename = os.path.normpath(os.path.join(clang_tidy_path,
+ '../docs/ReleaseNotes.rst'))
+ with open(filename, 'r') as f:
+ lines = f.readlines()
+
+ print('Updating %s...' % filename)
+ with open(filename, 'wb') as f:
+ note_added = False
+ header_found = False
+
+ for line in lines:
+ if not note_added:
+ match = re.search('Improvements to clang-tidy', line)
+ if match:
+ header_found = True
+ elif header_found:
+ if not line.startswith('----'):
+ f.write("""
+- The '%s' check was renamed to :doc:`%s
+ <clang-tidy/checks/%s>`
+""" % (old_check_name, new_check_name, new_check_name))
+ note_added = True
+
+ f.write(line)
+
+def main():
+ parser = argparse.ArgumentParser(description='Rename clang-tidy check.')
+ parser.add_argument('old_check_name', type=str,
+ help='Old check name.')
+ parser.add_argument('new_check_name', type=str,
+ help='New check name.')
+ parser.add_argument('--check_class_name', type=str,
+ help='Old name of the class implementing the check.')
+ args = parser.parse_args()
+
+ old_module = args.old_check_name.split('-')[0]
+ new_module = args.new_check_name.split('-')[0]
+ if args.check_class_name:
+ check_name_camel = args.check_class_name
+ else:
+ check_name_camel = (''.join(map(lambda elem: elem.capitalize(),
+ args.old_check_name.split('-')[1:])) +
+ 'Check')
+
+ new_check_name_camel = (''.join(map(lambda elem: elem.capitalize(),
+ args.new_check_name.split('-')[1:])) +
+ 'Check')
+
+ clang_tidy_path = os.path.dirname(__file__)
+
+ header_guard_variants = [
+ (old_module + '_' + new_check_name_camel).upper(),
+ args.old_check_name.replace('-', '_').upper()]
+ header_guard_new = (new_module + '_' + new_check_name_camel).upper()
+
+ old_module_path = os.path.join(clang_tidy_path, old_module)
+ new_module_path = os.path.join(clang_tidy_path, new_module)
+
+ # Remove the check from the old module.
+ cmake_lists = os.path.join(old_module_path, 'CMakeLists.txt')
+ check_found = deleteMatchingLines(cmake_lists, '\\b' + check_name_camel)
+ if not check_found:
+ print("Check name '%s' not found in %s. Exiting." %
+ (check_name_camel, cmake_lists))
+ return 1
+
+ modulecpp = filter(
+ lambda p: p.lower() == old_module.lower() + 'tidymodule.cpp',
+ os.listdir(old_module_path))[0]
+ deleteMatchingLines(os.path.join(old_module_path, modulecpp),
+ '\\b' + check_name_camel + '|\\b' + args.old_check_name)
+
+ for filename in getListOfFiles(clang_tidy_path):
+ originalName = filename
+ filename = fileRename(filename, args.old_check_name,
+ args.new_check_name)
+ filename = fileRename(filename, check_name_camel, new_check_name_camel)
+ replaceInFile(filename, generateCommentLineHeader(originalName),
+ generateCommentLineHeader(filename))
+ replaceInFile(filename, generateCommentLineSource(originalName),
+ generateCommentLineSource(filename))
+ for header_guard in header_guard_variants:
+ replaceInFile(filename, header_guard, header_guard_new)
+
+ if args.new_check_name + '.rst' in filename:
+ replaceInFile(
+ filename,
+ args.old_check_name + '\n' + '=' * len(args.old_check_name) + '\n',
+ args.new_check_name + '\n' + '=' * len(args.new_check_name) + '\n')
+
+ replaceInFile(filename, args.old_check_name, args.new_check_name)
+ replaceInFile(filename, old_module + '::' + check_name_camel,
+ new_module + '::' + new_check_name_camel)
+ replaceInFile(filename, old_module + '/' + check_name_camel,
+ new_module + '/' + new_check_name_camel)
+ replaceInFile(filename, check_name_camel, new_check_name_camel)
+
+ if old_module != new_module:
+ check_implementation_files = glob.glob(
+ os.path.join(old_module_path, new_check_name_camel + '*'))
+ for filename in check_implementation_files:
+ # Move check implementation to the directory of the new module.
+ filename = fileRename(filename, old_module_path, new_module_path)
+ replaceInFile(filename, 'namespace ' + old_module,
+ 'namespace ' + new_module)
+
+ # Add check to the new module.
+ adapt_cmake(new_module_path, new_check_name_camel)
+ adapt_module(new_module_path, new_module, args.new_check_name,
+ new_check_name_camel)
+
+ os.system(os.path.join(clang_tidy_path, 'add_new_check.py')
+ + ' --update-docs')
+ add_release_notes(clang_tidy_path, args.old_check_name, args.new_check_name)
+
+if __name__ == '__main__':
+ main()
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/tool/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/tool/CMakeLists.txt
new file mode 100644
index 0000000..a3ec4ae
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/tool/CMakeLists.txt
@@ -0,0 +1,47 @@
+set(LLVM_LINK_COMPONENTS
+ AllTargetsAsmParsers
+ AllTargetsDescs
+ AllTargetsInfos
+ support
+ )
+
+add_clang_tool(clang-tidy
+ ClangTidyMain.cpp
+ )
+add_dependencies(clang-tidy
+ clang-headers
+ )
+target_link_libraries(clang-tidy
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangTidy
+ clangTidyAndroidModule
+ clangTidyAbseilModule
+ clangTidyBoostModule
+ clangTidyBugproneModule
+ clangTidyCERTModule
+ clangTidyCppCoreGuidelinesModule
+ clangTidyFuchsiaModule
+ clangTidyGoogleModule
+ clangTidyHICPPModule
+ clangTidyLLVMModule
+ clangTidyMiscModule
+ clangTidyModernizeModule
+ clangTidyMPIModule
+ clangTidyObjCModule
+ clangTidyPerformanceModule
+ clangTidyPortabilityModule
+ clangTidyReadabilityModule
+ clangTidyZirconModule
+ clangTooling
+ clangToolingCore
+ )
+
+install(PROGRAMS clang-tidy-diff.py
+ DESTINATION share/clang
+ COMPONENT clang-tidy)
+install(PROGRAMS run-clang-tidy.py
+ DESTINATION share/clang
+ COMPONENT clang-tidy)
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
new file mode 100644
index 0000000..b458b29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -0,0 +1,577 @@
+//===--- tools/extra/clang-tidy/ClangTidyMain.cpp - Clang tidy tool -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file implements a clang-tidy tool.
+///
+/// This tool uses the Clang Tooling infrastructure, see
+/// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+/// for details on setting it up with LLVM source tree.
+///
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/TargetSelect.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::driver;
+using namespace clang::tooling;
+using namespace llvm;
+
+static cl::OptionCategory ClangTidyCategory("clang-tidy options");
+
+static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+static cl::extrahelp ClangTidyHelp(R"(
+Configuration files:
+ clang-tidy attempts to read configuration for each source file from a
+ .clang-tidy file located in the closest parent directory of the source
+ file. If any configuration options have a corresponding command-line
+ option, command-line option takes precedence. The effective
+ configuration can be inspected using -dump-config:
+
+ $ clang-tidy -dump-config
+ ---
+ Checks: '-*,some-check'
+ WarningsAsErrors: ''
+ HeaderFilterRegex: ''
+ FormatStyle: none
+ User: user
+ CheckOptions:
+ - key: some-check.SomeOption
+ value: 'some value'
+ ...
+
+)");
+
+const char DefaultChecks[] = // Enable these checks by default:
+ "clang-diagnostic-*," // * compiler diagnostics
+ "clang-analyzer-*"; // * Static Analyzer checks
+
+static cl::opt<std::string> Checks("checks", cl::desc(R"(
+Comma-separated list of globs with optional '-'
+prefix. Globs are processed in order of
+appearance in the list. Globs without '-'
+prefix add checks with matching names to the
+set, globs with the '-' prefix remove checks
+with matching names from the set of enabled
+checks. This option's value is appended to the
+value of the 'Checks' option in .clang-tidy
+file, if any.
+)"),
+ cl::init(""), cl::cat(ClangTidyCategory));
+
+static cl::opt<std::string> WarningsAsErrors("warnings-as-errors", cl::desc(R"(
+Upgrades warnings to errors. Same format as
+'-checks'.
+This option's value is appended to the value of
+the 'WarningsAsErrors' option in .clang-tidy
+file, if any.
+)"),
+ cl::init(""),
+ cl::cat(ClangTidyCategory));
+
+static cl::opt<std::string> HeaderFilter("header-filter", cl::desc(R"(
+Regular expression matching the names of the
+headers to output diagnostics from. Diagnostics
+from the main file of each translation unit are
+always displayed.
+Can be used together with -line-filter.
+This option overrides the 'HeaderFilter' option
+in .clang-tidy file, if any.
+)"),
+ cl::init(""),
+ cl::cat(ClangTidyCategory));
+
+static cl::opt<bool>
+ SystemHeaders("system-headers",
+ cl::desc("Display the errors from system headers."),
+ cl::init(false), cl::cat(ClangTidyCategory));
+static cl::opt<std::string> LineFilter("line-filter", cl::desc(R"(
+List of files with line ranges to filter the
+warnings. Can be used together with
+-header-filter. The format of the list is a
+JSON array of objects:
+ [
+ {"name":"file1.cpp","lines":[[1,3],[5,7]]},
+ {"name":"file2.h"}
+ ]
+)"),
+ cl::init(""),
+ cl::cat(ClangTidyCategory));
+
+static cl::opt<bool> Fix("fix", cl::desc(R"(
+Apply suggested fixes. Without -fix-errors
+clang-tidy will bail out if any compilation
+errors were found.
+)"),
+ cl::init(false), cl::cat(ClangTidyCategory));
+
+static cl::opt<bool> FixErrors("fix-errors", cl::desc(R"(
+Apply suggested fixes even if compilation
+errors were found. If compiler errors have
+attached fix-its, clang-tidy will apply them as
+well.
+)"),
+ cl::init(false), cl::cat(ClangTidyCategory));
+
+static cl::opt<std::string> FormatStyle("format-style", cl::desc(R"(
+Style for formatting code around applied fixes:
+ - 'none' (default) turns off formatting
+ - 'file' (literally 'file', not a placeholder)
+ uses .clang-format file in the closest parent
+ directory
+ - '{ <json> }' specifies options inline, e.g.
+ -format-style='{BasedOnStyle: llvm, IndentWidth: 8}'
+ - 'llvm', 'google', 'webkit', 'mozilla'
+See clang-format documentation for the up-to-date
+information about formatting styles and options.
+This option overrides the 'FormatStyle` option in
+.clang-tidy file, if any.
+)"),
+ cl::init("none"),
+ cl::cat(ClangTidyCategory));
+
+static cl::opt<bool> ListChecks("list-checks", cl::desc(R"(
+List all enabled checks and exit. Use with
+-checks=* to list all available checks.
+)"),
+ cl::init(false), cl::cat(ClangTidyCategory));
+
+static cl::opt<bool> ExplainConfig("explain-config", cl::desc(R"(
+For each enabled check explains, where it is
+enabled, i.e. in clang-tidy binary, command
+line or a specific configuration file.
+)"),
+ cl::init(false), cl::cat(ClangTidyCategory));
+
+static cl::opt<std::string> Config("config", cl::desc(R"(
+Specifies a configuration in YAML/JSON format:
+ -config="{Checks: '*',
+ CheckOptions: [{key: x,
+ value: y}]}"
+When the value is empty, clang-tidy will
+attempt to find a file named .clang-tidy for
+each source file in its parent directories.
+)"),
+ cl::init(""), cl::cat(ClangTidyCategory));
+
+static cl::opt<bool> DumpConfig("dump-config", cl::desc(R"(
+Dumps configuration in the YAML format to
+stdout. This option can be used along with a
+file name (and '--' if the file is outside of a
+project with configured compilation database).
+The configuration used for this file will be
+printed.
+Use along with -checks=* to include
+configuration of all checks.
+)"),
+ cl::init(false), cl::cat(ClangTidyCategory));
+
+static cl::opt<bool> EnableCheckProfile("enable-check-profile", cl::desc(R"(
+Enable per-check timing profiles, and print a
+report to stderr.
+)"),
+ cl::init(false),
+ cl::cat(ClangTidyCategory));
+
+static cl::opt<std::string> StoreCheckProfile("store-check-profile",
+ cl::desc(R"(
+By default reports are printed in tabulated
+format to stderr. When this option is passed,
+these per-TU profiles are instead stored as JSON.
+)"),
+ cl::value_desc("prefix"),
+ cl::cat(ClangTidyCategory));
+
+/// This option allows enabling the experimental alpha checkers from the static
+/// analyzer. This option is set to false and not visible in help, because it is
+/// highly not recommended for users.
+static cl::opt<bool>
+ AllowEnablingAnalyzerAlphaCheckers("allow-enabling-analyzer-alpha-checkers",
+ cl::init(false), cl::Hidden,
+ cl::cat(ClangTidyCategory));
+
+static cl::opt<std::string> ExportFixes("export-fixes", cl::desc(R"(
+YAML file to store suggested fixes in. The
+stored fixes can be applied to the input source
+code with clang-apply-replacements.
+)"),
+ cl::value_desc("filename"),
+ cl::cat(ClangTidyCategory));
+
+static cl::opt<bool> Quiet("quiet", cl::desc(R"(
+Run clang-tidy in quiet mode. This suppresses
+printing statistics about ignored warnings and
+warnings treated as errors if the respective
+options are specified.
+)"),
+ cl::init(false),
+ cl::cat(ClangTidyCategory));
+
+static cl::opt<std::string> VfsOverlay("vfsoverlay", cl::desc(R"(
+Overlay the virtual filesystem described by file
+over the real file system.
+)"),
+ cl::value_desc("filename"),
+ cl::cat(ClangTidyCategory));
+
+namespace clang {
+namespace tidy {
+
+static void printStats(const ClangTidyStats &Stats) {
+ if (Stats.errorsIgnored()) {
+ llvm::errs() << "Suppressed " << Stats.errorsIgnored() << " warnings (";
+ StringRef Separator = "";
+ if (Stats.ErrorsIgnoredNonUserCode) {
+ llvm::errs() << Stats.ErrorsIgnoredNonUserCode << " in non-user code";
+ Separator = ", ";
+ }
+ if (Stats.ErrorsIgnoredLineFilter) {
+ llvm::errs() << Separator << Stats.ErrorsIgnoredLineFilter
+ << " due to line filter";
+ Separator = ", ";
+ }
+ if (Stats.ErrorsIgnoredNOLINT) {
+ llvm::errs() << Separator << Stats.ErrorsIgnoredNOLINT << " NOLINT";
+ Separator = ", ";
+ }
+ if (Stats.ErrorsIgnoredCheckFilter)
+ llvm::errs() << Separator << Stats.ErrorsIgnoredCheckFilter
+ << " with check filters";
+ llvm::errs() << ").\n";
+ if (Stats.ErrorsIgnoredNonUserCode)
+ llvm::errs() << "Use -header-filter=.* to display errors from all "
+ "non-system headers. Use -system-headers to display "
+ "errors from system headers as well.\n";
+ }
+}
+
+static std::unique_ptr<ClangTidyOptionsProvider> createOptionsProvider(
+ llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS) {
+ ClangTidyGlobalOptions GlobalOptions;
+ if (std::error_code Err = parseLineFilter(LineFilter, GlobalOptions)) {
+ llvm::errs() << "Invalid LineFilter: " << Err.message() << "\n\nUsage:\n";
+ llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
+ return nullptr;
+ }
+
+ ClangTidyOptions DefaultOptions;
+ DefaultOptions.Checks = DefaultChecks;
+ DefaultOptions.WarningsAsErrors = "";
+ DefaultOptions.HeaderFilterRegex = HeaderFilter;
+ DefaultOptions.SystemHeaders = SystemHeaders;
+ DefaultOptions.FormatStyle = FormatStyle;
+ DefaultOptions.User = llvm::sys::Process::GetEnv("USER");
+ // USERNAME is used on Windows.
+ if (!DefaultOptions.User)
+ DefaultOptions.User = llvm::sys::Process::GetEnv("USERNAME");
+
+ ClangTidyOptions OverrideOptions;
+ if (Checks.getNumOccurrences() > 0)
+ OverrideOptions.Checks = Checks;
+ if (WarningsAsErrors.getNumOccurrences() > 0)
+ OverrideOptions.WarningsAsErrors = WarningsAsErrors;
+ if (HeaderFilter.getNumOccurrences() > 0)
+ OverrideOptions.HeaderFilterRegex = HeaderFilter;
+ if (SystemHeaders.getNumOccurrences() > 0)
+ OverrideOptions.SystemHeaders = SystemHeaders;
+ if (FormatStyle.getNumOccurrences() > 0)
+ OverrideOptions.FormatStyle = FormatStyle;
+
+ if (!Config.empty()) {
+ if (llvm::ErrorOr<ClangTidyOptions> ParsedConfig =
+ parseConfiguration(Config)) {
+ return llvm::make_unique<ConfigOptionsProvider>(
+ GlobalOptions,
+ ClangTidyOptions::getDefaults().mergeWith(DefaultOptions),
+ *ParsedConfig, OverrideOptions);
+ } else {
+ llvm::errs() << "Error: invalid configuration specified.\n"
+ << ParsedConfig.getError().message() << "\n";
+ return nullptr;
+ }
+ }
+ return llvm::make_unique<FileOptionsProvider>(GlobalOptions, DefaultOptions,
+ OverrideOptions, std::move(FS));
+}
+
+llvm::IntrusiveRefCntPtr<vfs::FileSystem>
+getVfsOverlayFromFile(const std::string &OverlayFile) {
+ llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFS(
+ new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
+ OverlayFS->getBufferForFile(OverlayFile);
+ if (!Buffer) {
+ llvm::errs() << "Can't load virtual filesystem overlay file '"
+ << OverlayFile << "': " << Buffer.getError().message()
+ << ".\n";
+ return nullptr;
+ }
+
+ IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getVFSFromYAML(
+ std::move(Buffer.get()), /*DiagHandler*/ nullptr, OverlayFile);
+ if (!FS) {
+ llvm::errs() << "Error: invalid virtual filesystem overlay file '"
+ << OverlayFile << "'.\n";
+ return nullptr;
+ }
+ OverlayFS->pushOverlay(FS);
+ return OverlayFS;
+}
+
+static int clangTidyMain(int argc, const char **argv) {
+ CommonOptionsParser OptionsParser(argc, argv, ClangTidyCategory,
+ cl::ZeroOrMore);
+ llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS(
+ VfsOverlay.empty() ? vfs::getRealFileSystem()
+ : getVfsOverlayFromFile(VfsOverlay));
+ if (!BaseFS)
+ return 1;
+
+ auto OwningOptionsProvider = createOptionsProvider(BaseFS);
+ auto *OptionsProvider = OwningOptionsProvider.get();
+ if (!OptionsProvider)
+ return 1;
+
+ auto MakeAbsolute = [](const std::string &Input) -> SmallString<256> {
+ if (Input.empty())
+ return {};
+ SmallString<256> AbsolutePath(Input);
+ if (std::error_code EC = llvm::sys::fs::make_absolute(AbsolutePath)) {
+ llvm::errs() << "Can't make absolute path from " << Input << ": "
+ << EC.message() << "\n";
+ }
+ return AbsolutePath;
+ };
+
+ SmallString<256> ProfilePrefix = MakeAbsolute(StoreCheckProfile);
+
+ StringRef FileName("dummy");
+ auto PathList = OptionsParser.getSourcePathList();
+ if (!PathList.empty()) {
+ FileName = PathList.front();
+ }
+
+ SmallString<256> FilePath = MakeAbsolute(FileName);
+
+ ClangTidyOptions EffectiveOptions = OptionsProvider->getOptions(FilePath);
+ std::vector<std::string> EnabledChecks =
+ getCheckNames(EffectiveOptions, AllowEnablingAnalyzerAlphaCheckers);
+
+ if (ExplainConfig) {
+ // FIXME: Show other ClangTidyOptions' fields, like ExtraArg.
+ std::vector<clang::tidy::ClangTidyOptionsProvider::OptionsSource>
+ RawOptions = OptionsProvider->getRawOptions(FilePath);
+ for (const std::string &Check : EnabledChecks) {
+ for (auto It = RawOptions.rbegin(); It != RawOptions.rend(); ++It) {
+ if (It->first.Checks && GlobList(*It->first.Checks).contains(Check)) {
+ llvm::outs() << "'" << Check << "' is enabled in the " << It->second
+ << ".\n";
+ break;
+ }
+ }
+ }
+ return 0;
+ }
+
+ if (ListChecks) {
+ if (EnabledChecks.empty()) {
+ llvm::errs() << "No checks enabled.\n";
+ return 1;
+ }
+ llvm::outs() << "Enabled checks:";
+ for (const auto &CheckName : EnabledChecks)
+ llvm::outs() << "\n " << CheckName;
+ llvm::outs() << "\n\n";
+ return 0;
+ }
+
+ if (DumpConfig) {
+ EffectiveOptions.CheckOptions =
+ getCheckOptions(EffectiveOptions, AllowEnablingAnalyzerAlphaCheckers);
+ llvm::outs() << configurationAsText(
+ ClangTidyOptions::getDefaults().mergeWith(
+ EffectiveOptions))
+ << "\n";
+ return 0;
+ }
+
+ if (EnabledChecks.empty()) {
+ llvm::errs() << "Error: no checks enabled.\n";
+ llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
+ return 1;
+ }
+
+ if (PathList.empty()) {
+ llvm::errs() << "Error: no input files specified.\n";
+ llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
+ return 1;
+ }
+
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmParsers();
+
+ ClangTidyContext Context(std::move(OwningOptionsProvider),
+ AllowEnablingAnalyzerAlphaCheckers);
+ runClangTidy(Context, OptionsParser.getCompilations(), PathList, BaseFS,
+ EnableCheckProfile, ProfilePrefix);
+ ArrayRef<ClangTidyError> Errors = Context.getErrors();
+ bool FoundErrors = llvm::find_if(Errors, [](const ClangTidyError &E) {
+ return E.DiagLevel == ClangTidyError::Error;
+ }) != Errors.end();
+
+ const bool DisableFixes = Fix && FoundErrors && !FixErrors;
+
+ unsigned WErrorCount = 0;
+
+ // -fix-errors implies -fix.
+ handleErrors(Context, (FixErrors || Fix) && !DisableFixes, WErrorCount,
+ BaseFS);
+
+ if (!ExportFixes.empty() && !Errors.empty()) {
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(ExportFixes, EC, llvm::sys::fs::F_None);
+ if (EC) {
+ llvm::errs() << "Error opening output file: " << EC.message() << '\n';
+ return 1;
+ }
+ exportReplacements(FilePath.str(), Errors, OS);
+ }
+
+ if (!Quiet) {
+ printStats(Context.getStats());
+ if (DisableFixes)
+ llvm::errs()
+ << "Found compiler errors, but -fix-errors was not specified.\n"
+ "Fixes have NOT been applied.\n\n";
+ }
+
+ if (WErrorCount) {
+ if (!Quiet) {
+ StringRef Plural = WErrorCount == 1 ? "" : "s";
+ llvm::errs() << WErrorCount << " warning" << Plural << " treated as error"
+ << Plural << "\n";
+ }
+ return WErrorCount;
+ }
+
+ if (FoundErrors) {
+ // TODO: Figure out when zero exit code should be used with -fix-errors:
+ // a. when a fix has been applied for an error
+ // b. when a fix has been applied for all errors
+ // c. some other condition.
+ // For now always returning zero when -fix-errors is used.
+ if (FixErrors)
+ return 0;
+ if (!Quiet)
+ llvm::errs() << "Found compiler error(s).\n";
+ return 1;
+ }
+
+ return 0;
+}
+
+// This anchor is used to force the linker to link the CERTModule.
+extern volatile int CERTModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED CERTModuleAnchorDestination =
+ CERTModuleAnchorSource;
+
+// This anchor is used to force the linker to link the AbseilModule.
+extern volatile int AbseilModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED AbseilModuleAnchorDestination =
+ AbseilModuleAnchorSource;
+
+// This anchor is used to force the linker to link the BoostModule.
+extern volatile int BoostModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED BoostModuleAnchorDestination =
+ BoostModuleAnchorSource;
+
+// This anchor is used to force the linker to link the BugproneModule.
+extern volatile int BugproneModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED BugproneModuleAnchorDestination =
+ BugproneModuleAnchorSource;
+
+// This anchor is used to force the linker to link the LLVMModule.
+extern volatile int LLVMModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED LLVMModuleAnchorDestination =
+ LLVMModuleAnchorSource;
+
+// This anchor is used to force the linker to link the CppCoreGuidelinesModule.
+extern volatile int CppCoreGuidelinesModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED CppCoreGuidelinesModuleAnchorDestination =
+ CppCoreGuidelinesModuleAnchorSource;
+
+// This anchor is used to force the linker to link the FuchsiaModule.
+extern volatile int FuchsiaModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED FuchsiaModuleAnchorDestination =
+ FuchsiaModuleAnchorSource;
+
+// This anchor is used to force the linker to link the GoogleModule.
+extern volatile int GoogleModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED GoogleModuleAnchorDestination =
+ GoogleModuleAnchorSource;
+
+// This anchor is used to force the linker to link the AndroidModule.
+extern volatile int AndroidModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED AndroidModuleAnchorDestination =
+ AndroidModuleAnchorSource;
+
+// This anchor is used to force the linker to link the MiscModule.
+extern volatile int MiscModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED MiscModuleAnchorDestination =
+ MiscModuleAnchorSource;
+
+// This anchor is used to force the linker to link the ModernizeModule.
+extern volatile int ModernizeModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED ModernizeModuleAnchorDestination =
+ ModernizeModuleAnchorSource;
+
+// This anchor is used to force the linker to link the MPIModule.
+extern volatile int MPIModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED MPIModuleAnchorDestination =
+ MPIModuleAnchorSource;
+
+// This anchor is used to force the linker to link the PerformanceModule.
+extern volatile int PerformanceModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED PerformanceModuleAnchorDestination =
+ PerformanceModuleAnchorSource;
+
+// This anchor is used to force the linker to link the PortabilityModule.
+extern volatile int PortabilityModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED PortabilityModuleAnchorDestination =
+ PortabilityModuleAnchorSource;
+
+// This anchor is used to force the linker to link the ReadabilityModule.
+extern volatile int ReadabilityModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED ReadabilityModuleAnchorDestination =
+ ReadabilityModuleAnchorSource;
+
+// This anchor is used to force the linker to link the ObjCModule.
+extern volatile int ObjCModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED ObjCModuleAnchorDestination =
+ ObjCModuleAnchorSource;
+
+// This anchor is used to force the linker to link the HICPPModule.
+extern volatile int HICPPModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED HICPPModuleAnchorDestination =
+ HICPPModuleAnchorSource;
+
+// This anchor is used to force the linker to link the ZirconModule.
+extern volatile int ZirconModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED ZirconModuleAnchorDestination =
+ ZirconModuleAnchorSource;
+
+} // namespace tidy
+} // namespace clang
+
+int main(int argc, const char **argv) {
+ return clang::tidy::clangTidyMain(argc, argv);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py
new file mode 100755
index 0000000..f2c15e5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python
+#
+#===- clang-tidy-diff.py - ClangTidy Diff Checker ------------*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+r"""
+ClangTidy Diff Checker
+======================
+
+This script reads input from a unified diff, runs clang-tidy on all changed
+files and outputs clang-tidy warnings in changed lines only. This is useful to
+detect clang-tidy regressions in the lines touched by a specific patch.
+Example usage for git/svn users:
+
+ git diff -U0 HEAD^ | clang-tidy-diff.py -p1
+ svn diff --diff-cmd=diff -x-U0 | \
+ clang-tidy-diff.py -fix -checks=-*,modernize-use-override
+
+"""
+
+import argparse
+import json
+import re
+import subprocess
+import sys
+
+
+def main():
+ parser = argparse.ArgumentParser(description=
+ 'Run clang-tidy against changed files, and '
+ 'output diagnostics only for modified '
+ 'lines.')
+ parser.add_argument('-clang-tidy-binary', metavar='PATH',
+ default='clang-tidy',
+ help='path to clang-tidy binary')
+ parser.add_argument('-p', metavar='NUM', default=0,
+ help='strip the smallest prefix containing P slashes')
+ parser.add_argument('-regex', metavar='PATTERN', default=None,
+ help='custom pattern selecting file paths to check '
+ '(case sensitive, overrides -iregex)')
+ parser.add_argument('-iregex', metavar='PATTERN', default=
+ r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)',
+ help='custom pattern selecting file paths to check '
+ '(case insensitive, overridden by -regex)')
+
+ parser.add_argument('-fix', action='store_true', default=False,
+ help='apply suggested fixes')
+ parser.add_argument('-checks',
+ help='checks filter, when not specified, use clang-tidy '
+ 'default',
+ default='')
+ parser.add_argument('-path', dest='build_path',
+ help='Path used to read a compile command database.')
+ parser.add_argument('-extra-arg', dest='extra_arg',
+ action='append', default=[],
+ help='Additional argument to append to the compiler '
+ 'command line.')
+ parser.add_argument('-extra-arg-before', dest='extra_arg_before',
+ action='append', default=[],
+ help='Additional argument to prepend to the compiler '
+ 'command line.')
+ parser.add_argument('-quiet', action='store_true', default=False,
+ help='Run clang-tidy in quiet mode')
+ clang_tidy_args = []
+ argv = sys.argv[1:]
+ if '--' in argv:
+ clang_tidy_args.extend(argv[argv.index('--'):])
+ argv = argv[:argv.index('--')]
+
+ args = parser.parse_args(argv)
+
+ # Extract changed lines for each file.
+ filename = None
+ lines_by_file = {}
+ for line in sys.stdin:
+ match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
+ if match:
+ filename = match.group(2)
+ if filename == None:
+ continue
+
+ if args.regex is not None:
+ if not re.match('^%s$' % args.regex, filename):
+ continue
+ else:
+ if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
+ continue
+
+ match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
+ if match:
+ start_line = int(match.group(1))
+ line_count = 1
+ if match.group(3):
+ line_count = int(match.group(3))
+ if line_count == 0:
+ continue
+ end_line = start_line + line_count - 1;
+ lines_by_file.setdefault(filename, []).append([start_line, end_line])
+
+ if len(lines_by_file) == 0:
+ print("No relevant changes found.")
+ sys.exit(0)
+
+ line_filter_json = json.dumps(
+ [{"name" : name, "lines" : lines_by_file[name]} for name in lines_by_file],
+ separators = (',', ':'))
+
+ quote = "";
+ if sys.platform == 'win32':
+ line_filter_json=re.sub(r'"', r'"""', line_filter_json)
+ else:
+ quote = "'";
+
+ # Run clang-tidy on files containing changes.
+ command = [args.clang_tidy_binary]
+ command.append('-line-filter=' + quote + line_filter_json + quote)
+ if args.fix:
+ command.append('-fix')
+ if args.checks != '':
+ command.append('-checks=' + quote + args.checks + quote)
+ if args.quiet:
+ command.append('-quiet')
+ if args.build_path is not None:
+ command.append('-p=%s' % args.build_path)
+ command.extend(lines_by_file.keys())
+ for arg in args.extra_arg:
+ command.append('-extra-arg=%s' % arg)
+ for arg in args.extra_arg_before:
+ command.append('-extra-arg-before=%s' % arg)
+ command.extend(clang_tidy_args)
+
+ sys.exit(subprocess.call(' '.join(command), shell=True))
+
+if __name__ == '__main__':
+ main()
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py
new file mode 100755
index 0000000..ce46c0e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py
@@ -0,0 +1,313 @@
+#!/usr/bin/env python
+#
+#===- run-clang-tidy.py - Parallel clang-tidy runner ---------*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+# FIXME: Integrate with clang-tidy-diff.py
+
+"""
+Parallel clang-tidy runner
+==========================
+
+Runs clang-tidy over all files in a compilation database. Requires clang-tidy
+and clang-apply-replacements in $PATH.
+
+Example invocations.
+- Run clang-tidy on all files in the current working directory with a default
+ set of checks and show warnings in the cpp files and all project headers.
+ run-clang-tidy.py $PWD
+
+- Fix all header guards.
+ run-clang-tidy.py -fix -checks=-*,llvm-header-guard
+
+- Fix all header guards included from clang-tidy and header guards
+ for clang-tidy headers.
+ run-clang-tidy.py -fix -checks=-*,llvm-header-guard extra/clang-tidy \
+ -header-filter=extra/clang-tidy
+
+Compilation database setup:
+http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+"""
+
+from __future__ import print_function
+
+import argparse
+import glob
+import json
+import multiprocessing
+import os
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+import threading
+import traceback
+import yaml
+
+is_py2 = sys.version[0] == '2'
+
+if is_py2:
+ import Queue as queue
+else:
+ import queue as queue
+
+def find_compilation_database(path):
+ """Adjusts the directory until a compilation database is found."""
+ result = './'
+ while not os.path.isfile(os.path.join(result, path)):
+ if os.path.realpath(result) == '/':
+ print('Error: could not find compilation database.')
+ sys.exit(1)
+ result += '../'
+ return os.path.realpath(result)
+
+
+def make_absolute(f, directory):
+ if os.path.isabs(f):
+ return f
+ return os.path.normpath(os.path.join(directory, f))
+
+
+def get_tidy_invocation(f, clang_tidy_binary, checks, tmpdir, build_path,
+ header_filter, extra_arg, extra_arg_before, quiet,
+ config):
+ """Gets a command line for clang-tidy."""
+ start = [clang_tidy_binary]
+ if header_filter is not None:
+ start.append('-header-filter=' + header_filter)
+ else:
+ # Show warnings in all in-project headers by default.
+ start.append('-header-filter=^' + build_path + '/.*')
+ if checks:
+ start.append('-checks=' + checks)
+ if tmpdir is not None:
+ start.append('-export-fixes')
+ # Get a temporary file. We immediately close the handle so clang-tidy can
+ # overwrite it.
+ (handle, name) = tempfile.mkstemp(suffix='.yaml', dir=tmpdir)
+ os.close(handle)
+ start.append(name)
+ for arg in extra_arg:
+ start.append('-extra-arg=%s' % arg)
+ for arg in extra_arg_before:
+ start.append('-extra-arg-before=%s' % arg)
+ start.append('-p=' + build_path)
+ if quiet:
+ start.append('-quiet')
+ if config:
+ start.append('-config=' + config)
+ start.append(f)
+ return start
+
+
+def merge_replacement_files(tmpdir, mergefile):
+ """Merge all replacement files in a directory into a single file"""
+ # The fixes suggested by clang-tidy >= 4.0.0 are given under
+ # the top level key 'Diagnostics' in the output yaml files
+ mergekey="Diagnostics"
+ merged=[]
+ for replacefile in glob.iglob(os.path.join(tmpdir, '*.yaml')):
+ content = yaml.safe_load(open(replacefile, 'r'))
+ if not content:
+ continue # Skip empty files.
+ merged.extend(content.get(mergekey, []))
+
+ if merged:
+ # MainSourceFile: The key is required by the definition inside
+ # include/clang/Tooling/ReplacementsYaml.h, but the value
+ # is actually never used inside clang-apply-replacements,
+ # so we set it to '' here.
+ output = { 'MainSourceFile': '', mergekey: merged }
+ with open(mergefile, 'w') as out:
+ yaml.safe_dump(output, out)
+ else:
+ # Empty the file:
+ open(mergefile, 'w').close()
+
+
+def check_clang_apply_replacements_binary(args):
+ """Checks if invoking supplied clang-apply-replacements binary works."""
+ try:
+ subprocess.check_call([args.clang_apply_replacements_binary, '--version'])
+ except:
+ print('Unable to run clang-apply-replacements. Is clang-apply-replacements '
+ 'binary correctly specified?', file=sys.stderr)
+ traceback.print_exc()
+ sys.exit(1)
+
+
+def apply_fixes(args, tmpdir):
+ """Calls clang-apply-fixes on a given directory."""
+ invocation = [args.clang_apply_replacements_binary]
+ if args.format:
+ invocation.append('-format')
+ if args.style:
+ invocation.append('-style=' + args.style)
+ invocation.append(tmpdir)
+ subprocess.call(invocation)
+
+
+def run_tidy(args, tmpdir, build_path, queue, failed_files):
+ """Takes filenames out of queue and runs clang-tidy on them."""
+ while True:
+ name = queue.get()
+ invocation = get_tidy_invocation(name, args.clang_tidy_binary, args.checks,
+ tmpdir, build_path, args.header_filter,
+ args.extra_arg, args.extra_arg_before,
+ args.quiet, args.config)
+ sys.stdout.write(' '.join(invocation) + '\n')
+ return_code = subprocess.call(invocation)
+ if return_code != 0:
+ failed_files.append(name)
+ queue.task_done()
+
+
+def main():
+ parser = argparse.ArgumentParser(description='Runs clang-tidy over all files '
+ 'in a compilation database. Requires '
+ 'clang-tidy and clang-apply-replacements in '
+ '$PATH.')
+ parser.add_argument('-clang-tidy-binary', metavar='PATH',
+ default='clang-tidy',
+ help='path to clang-tidy binary')
+ parser.add_argument('-clang-apply-replacements-binary', metavar='PATH',
+ default='clang-apply-replacements',
+ help='path to clang-apply-replacements binary')
+ parser.add_argument('-checks', default=None,
+ help='checks filter, when not specified, use clang-tidy '
+ 'default')
+ parser.add_argument('-config', default=None,
+ help='Specifies a configuration in YAML/JSON format: '
+ ' -config="{Checks: \'*\', '
+ ' CheckOptions: [{key: x, '
+ ' value: y}]}" '
+ 'When the value is empty, clang-tidy will '
+ 'attempt to find a file named .clang-tidy for '
+ 'each source file in its parent directories.')
+ parser.add_argument('-header-filter', default=None,
+ help='regular expression matching the names of the '
+ 'headers to output diagnostics from. Diagnostics from '
+ 'the main file of each translation unit are always '
+ 'displayed.')
+ parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
+ help='Create a yaml file to store suggested fixes in, '
+ 'which can be applied with clang-apply-replacements.')
+ parser.add_argument('-j', type=int, default=0,
+ help='number of tidy instances to be run in parallel.')
+ parser.add_argument('files', nargs='*', default=['.*'],
+ help='files to be processed (regex on path)')
+ parser.add_argument('-fix', action='store_true', help='apply fix-its')
+ parser.add_argument('-format', action='store_true', help='Reformat code '
+ 'after applying fixes')
+ parser.add_argument('-style', default='file', help='The style of reformat '
+ 'code after applying fixes')
+ parser.add_argument('-p', dest='build_path',
+ help='Path used to read a compile command database.')
+ parser.add_argument('-extra-arg', dest='extra_arg',
+ action='append', default=[],
+ help='Additional argument to append to the compiler '
+ 'command line.')
+ parser.add_argument('-extra-arg-before', dest='extra_arg_before',
+ action='append', default=[],
+ help='Additional argument to prepend to the compiler '
+ 'command line.')
+ parser.add_argument('-quiet', action='store_true',
+ help='Run clang-tidy in quiet mode')
+ args = parser.parse_args()
+
+ db_path = 'compile_commands.json'
+
+ if args.build_path is not None:
+ build_path = args.build_path
+ else:
+ # Find our database
+ build_path = find_compilation_database(db_path)
+
+ try:
+ invocation = [args.clang_tidy_binary, '-list-checks']
+ invocation.append('-p=' + build_path)
+ if args.checks:
+ invocation.append('-checks=' + args.checks)
+ invocation.append('-')
+ subprocess.check_call(invocation)
+ except:
+ print("Unable to run clang-tidy.", file=sys.stderr)
+ sys.exit(1)
+
+ # Load the database and extract all files.
+ database = json.load(open(os.path.join(build_path, db_path)))
+ files = [make_absolute(entry['file'], entry['directory'])
+ for entry in database]
+
+ max_task = args.j
+ if max_task == 0:
+ max_task = multiprocessing.cpu_count()
+
+ tmpdir = None
+ if args.fix or args.export_fixes:
+ check_clang_apply_replacements_binary(args)
+ tmpdir = tempfile.mkdtemp()
+
+ # Build up a big regexy filter from all command line arguments.
+ file_name_re = re.compile('|'.join(args.files))
+
+ return_code = 0
+ try:
+ # Spin up a bunch of tidy-launching threads.
+ task_queue = queue.Queue(max_task)
+ # List of files with a non-zero return code.
+ failed_files = []
+ for _ in range(max_task):
+ t = threading.Thread(target=run_tidy,
+ args=(args, tmpdir, build_path, task_queue, failed_files))
+ t.daemon = True
+ t.start()
+
+ # Fill the queue with files.
+ for name in files:
+ if file_name_re.search(name):
+ task_queue.put(name)
+
+ # Wait for all threads to be done.
+ task_queue.join()
+ if len(failed_files):
+ return_code = 1
+
+ except KeyboardInterrupt:
+ # This is a sad hack. Unfortunately subprocess goes
+ # bonkers with ctrl-c and we start forking merrily.
+ print('\nCtrl-C detected, goodbye.')
+ if tmpdir:
+ shutil.rmtree(tmpdir)
+ os.kill(0, 9)
+
+ if args.export_fixes:
+ print('Writing fixes to ' + args.export_fixes + ' ...')
+ try:
+ merge_replacement_files(tmpdir, args.export_fixes)
+ except:
+ print('Error exporting fixes.\n', file=sys.stderr)
+ traceback.print_exc()
+ return_code=1
+
+ if args.fix:
+ print('Applying fixes ...')
+ try:
+ apply_fixes(args, tmpdir)
+ except:
+ print('Error applying fixes.\n', file=sys.stderr)
+ traceback.print_exc()
+ return_code=1
+
+ if tmpdir:
+ shutil.rmtree(tmpdir)
+ sys.exit(return_code)
+
+if __name__ == '__main__':
+ main()
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ASTUtils.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ASTUtils.cpp
new file mode 100644
index 0000000..ab6077a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ASTUtils.cpp
@@ -0,0 +1,72 @@
+//===---------- ASTUtils.cpp - clang-tidy ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTUtils.h"
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+using namespace ast_matchers;
+
+const FunctionDecl *getSurroundingFunction(ASTContext &Context,
+ const Stmt &Statement) {
+ return selectFirst<const FunctionDecl>(
+ "function", match(stmt(hasAncestor(functionDecl().bind("function"))),
+ Statement, Context));
+}
+
+bool IsBinaryOrTernary(const Expr *E) {
+ const Expr *E_base = E->IgnoreImpCasts();
+ if (clang::isa<clang::BinaryOperator>(E_base) ||
+ clang::isa<clang::ConditionalOperator>(E_base)) {
+ return true;
+ }
+
+ if (const auto *Operator =
+ clang::dyn_cast<clang::CXXOperatorCallExpr>(E_base)) {
+ return Operator->isInfixBinaryOp();
+ }
+
+ return false;
+}
+
+bool exprHasBitFlagWithSpelling(const Expr *Flags, const SourceManager &SM,
+ const LangOptions &LangOpts,
+ StringRef FlagName) {
+ // If the Flag is an integer constant, check it.
+ if (isa<IntegerLiteral>(Flags)) {
+ if (!SM.isMacroBodyExpansion(Flags->getLocStart()) &&
+ !SM.isMacroArgExpansion(Flags->getLocStart()))
+ return false;
+
+ // Get the macro name.
+ auto MacroName = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(Flags->getSourceRange()), SM, LangOpts);
+
+ return MacroName == FlagName;
+ }
+ // If it's a binary OR operation.
+ if (const auto *BO = dyn_cast<BinaryOperator>(Flags))
+ if (BO->getOpcode() == clang::BinaryOperatorKind::BO_Or)
+ return exprHasBitFlagWithSpelling(BO->getLHS()->IgnoreParenCasts(), SM,
+ LangOpts, FlagName) ||
+ exprHasBitFlagWithSpelling(BO->getRHS()->IgnoreParenCasts(), SM,
+ LangOpts, FlagName);
+
+ // Otherwise, assume it has the flag.
+ return true;
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ASTUtils.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ASTUtils.h
new file mode 100644
index 0000000..ccff000
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ASTUtils.h
@@ -0,0 +1,34 @@
+//===---------- ASTUtils.h - clang-tidy -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ASTUTILS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ASTUTILS_H
+
+#include "clang/AST/AST.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+// Returns the (closest) Function declaration surrounding |Statement| or NULL.
+const FunctionDecl *getSurroundingFunction(ASTContext &Context,
+ const Stmt &Statement);
+// Determine whether Expr is a Binary or Ternary expression.
+bool IsBinaryOrTernary(const Expr *E);
+
+/// Checks whether a macro flag is present in the given argument. Only considers
+/// cases of single match or match in a binary OR expression. For example,
+/// <needed-flag> or <flag> | <needed-flag> | ...
+bool exprHasBitFlagWithSpelling(const Expr *Flags, const SourceManager &SM,
+ const LangOptions &LangOpts,
+ StringRef FlagName);
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ASTUTILS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/CMakeLists.txt
new file mode 100644
index 0000000..487b09a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/CMakeLists.txt
@@ -0,0 +1,25 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyUtils
+ ASTUtils.cpp
+ DeclRefExprUtils.cpp
+ ExprMutationAnalyzer.cpp
+ ExprSequence.cpp
+ FixItHintUtils.cpp
+ HeaderFileExtensionsUtils.cpp
+ HeaderGuard.cpp
+ IncludeInserter.cpp
+ IncludeSorter.cpp
+ LexerUtils.cpp
+ NamespaceAliaser.cpp
+ OptionsUtils.cpp
+ TypeTraits.cpp
+ UsingInserter.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
new file mode 100644
index 0000000..06acd31
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -0,0 +1,172 @@
+//===--- DeclRefExprUtils.cpp - clang-tidy---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DeclRefExprUtils.h"
+#include "Matchers.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+namespace decl_ref_expr {
+
+using namespace ::clang::ast_matchers;
+using llvm::SmallPtrSet;
+
+namespace {
+
+template <typename S> bool isSetDifferenceEmpty(const S &S1, const S &S2) {
+ for (const auto &E : S1)
+ if (S2.count(E) == 0)
+ return false;
+ return true;
+}
+
+// Extracts all Nodes keyed by ID from Matches and inserts them into Nodes.
+template <typename Node>
+void extractNodesByIdTo(ArrayRef<BoundNodes> Matches, StringRef ID,
+ SmallPtrSet<const Node *, 16> &Nodes) {
+ for (const auto &Match : Matches)
+ Nodes.insert(Match.getNodeAs<Node>(ID));
+}
+
+} // namespace
+
+// Finds all DeclRefExprs where a const method is called on VarDecl or VarDecl
+// is the a const reference or value argument to a CallExpr or CXXConstructExpr.
+SmallPtrSet<const DeclRefExpr *, 16>
+constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt,
+ ASTContext &Context) {
+ auto DeclRefToVar =
+ declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef");
+ auto ConstMethodCallee = callee(cxxMethodDecl(isConst()));
+ // Match method call expressions where the variable is referenced as the this
+ // implicit object argument and opertor call expression for member operators
+ // where the variable is the 0-th argument.
+ auto Matches = match(
+ findAll(expr(anyOf(cxxMemberCallExpr(ConstMethodCallee, on(DeclRefToVar)),
+ cxxOperatorCallExpr(ConstMethodCallee,
+ hasArgument(0, DeclRefToVar))))),
+ Stmt, Context);
+ SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
+ extractNodesByIdTo(Matches, "declRef", DeclRefs);
+ auto ConstReferenceOrValue =
+ qualType(anyOf(referenceType(pointee(qualType(isConstQualified()))),
+ unless(anyOf(referenceType(), pointerType()))));
+ auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
+ DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
+ Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
+ extractNodesByIdTo(Matches, "declRef", DeclRefs);
+ Matches =
+ match(findAll(cxxConstructExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
+ extractNodesByIdTo(Matches, "declRef", DeclRefs);
+ return DeclRefs;
+}
+
+// Finds all DeclRefExprs where a const method is called on VarDecl or VarDecl
+// is the a const reference or value argument to a CallExpr or CXXConstructExpr.
+SmallPtrSet<const DeclRefExpr *, 16>
+constReferenceDeclRefExprs(const VarDecl &VarDecl, const Decl &Decl,
+ ASTContext &Context) {
+ auto DeclRefToVar =
+ declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef");
+ auto ConstMethodCallee = callee(cxxMethodDecl(isConst()));
+ // Match method call expressions where the variable is referenced as the this
+ // implicit object argument and opertor call expression for member operators
+ // where the variable is the 0-th argument.
+ auto Matches =
+ match(decl(forEachDescendant(expr(
+ anyOf(cxxMemberCallExpr(ConstMethodCallee, on(DeclRefToVar)),
+ cxxOperatorCallExpr(ConstMethodCallee,
+ hasArgument(0, DeclRefToVar)))))),
+ Decl, Context);
+ SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
+ extractNodesByIdTo(Matches, "declRef", DeclRefs);
+ auto ConstReferenceOrValue =
+ qualType(anyOf(referenceType(pointee(qualType(isConstQualified()))),
+ unless(anyOf(referenceType(), pointerType()))));
+ auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
+ DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue)));
+ Matches = match(decl(forEachDescendant(callExpr(UsedAsConstRefOrValueArg))),
+ Decl, Context);
+ extractNodesByIdTo(Matches, "declRef", DeclRefs);
+ Matches =
+ match(decl(forEachDescendant(cxxConstructExpr(UsedAsConstRefOrValueArg))),
+ Decl, Context);
+ extractNodesByIdTo(Matches, "declRef", DeclRefs);
+ return DeclRefs;
+}
+
+bool isOnlyUsedAsConst(const VarDecl &Var, const Stmt &Stmt,
+ ASTContext &Context) {
+ // Collect all DeclRefExprs to the loop variable and all CallExprs and
+ // CXXConstructExprs where the loop variable is used as argument to a const
+ // reference parameter.
+ // If the difference is empty it is safe for the loop variable to be a const
+ // reference.
+ auto AllDeclRefs = allDeclRefExprs(Var, Stmt, Context);
+ auto ConstReferenceDeclRefs = constReferenceDeclRefExprs(Var, Stmt, Context);
+ return isSetDifferenceEmpty(AllDeclRefs, ConstReferenceDeclRefs);
+}
+
+SmallPtrSet<const DeclRefExpr *, 16>
+allDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context) {
+ auto Matches = match(
+ findAll(declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef")),
+ Stmt, Context);
+ SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
+ extractNodesByIdTo(Matches, "declRef", DeclRefs);
+ return DeclRefs;
+}
+
+SmallPtrSet<const DeclRefExpr *, 16>
+allDeclRefExprs(const VarDecl &VarDecl, const Decl &Decl, ASTContext &Context) {
+ auto Matches = match(
+ decl(forEachDescendant(
+ declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef"))),
+ Decl, Context);
+ SmallPtrSet<const DeclRefExpr *, 16> DeclRefs;
+ extractNodesByIdTo(Matches, "declRef", DeclRefs);
+ return DeclRefs;
+}
+
+bool isCopyConstructorArgument(const DeclRefExpr &DeclRef, const Decl &Decl,
+ ASTContext &Context) {
+ auto UsedAsConstRefArg = forEachArgumentWithParam(
+ declRefExpr(equalsNode(&DeclRef)),
+ parmVarDecl(hasType(matchers::isReferenceToConst())));
+ auto Matches = match(
+ decl(hasDescendant(
+ cxxConstructExpr(UsedAsConstRefArg, hasDeclaration(cxxConstructorDecl(
+ isCopyConstructor())))
+ .bind("constructExpr"))),
+ Decl, Context);
+ return !Matches.empty();
+}
+
+bool isCopyAssignmentArgument(const DeclRefExpr &DeclRef, const Decl &Decl,
+ ASTContext &Context) {
+ auto UsedAsConstRefArg = forEachArgumentWithParam(
+ declRefExpr(equalsNode(&DeclRef)),
+ parmVarDecl(hasType(matchers::isReferenceToConst())));
+ auto Matches = match(
+ decl(hasDescendant(
+ cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName("="),
+ callee(cxxMethodDecl(isCopyAssignmentOperator())))
+ .bind("operatorCallExpr"))),
+ Decl, Context);
+ return !Matches.empty();
+}
+
+} // namespace decl_ref_expr
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.h
new file mode 100644
index 0000000..c25102f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.h
@@ -0,0 +1,66 @@
+//===--- DeclRefExprUtils.h - clang-tidy-------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_DECLREFEXPRUTILS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_DECLREFEXPRUTILS_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+namespace decl_ref_expr {
+
+/// \brief Returns true if all ``DeclRefExpr`` to the variable within ``Stmt``
+/// do not modify it.
+///
+/// Returns ``true`` if only const methods or operators are called on the
+/// variable or the variable is a const reference or value argument to a
+/// ``callExpr()``.
+bool isOnlyUsedAsConst(const VarDecl &Var, const Stmt &Stmt,
+ ASTContext &Context);
+
+/// Returns set of all ``DeclRefExprs`` to ``VarDecl`` within ``Stmt``.
+llvm::SmallPtrSet<const DeclRefExpr *, 16>
+allDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context);
+
+/// Returns set of all ``DeclRefExprs`` to ``VarDecl`` within ``Decl``.
+llvm::SmallPtrSet<const DeclRefExpr *, 16>
+allDeclRefExprs(const VarDecl &VarDecl, const Decl &Decl, ASTContext &Context);
+
+/// Returns set of all ``DeclRefExprs`` to ``VarDecl`` within ``Stmt`` where
+/// ``VarDecl`` is guaranteed to be accessed in a const fashion.
+llvm::SmallPtrSet<const DeclRefExpr *, 16>
+constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt,
+ ASTContext &Context);
+
+/// Returns set of all ``DeclRefExprs`` to ``VarDecl`` within ``Decl`` where
+/// ``VarDecl`` is guaranteed to be accessed in a const fashion.
+llvm::SmallPtrSet<const DeclRefExpr *, 16>
+constReferenceDeclRefExprs(const VarDecl &VarDecl, const Decl &Decl,
+ ASTContext &Context);
+
+/// Returns ``true`` if ``DeclRefExpr`` is the argument of a copy-constructor
+/// call expression within ``Decl``.
+bool isCopyConstructorArgument(const DeclRefExpr &DeclRef, const Decl &Decl,
+ ASTContext &Context);
+
+/// Returns ``true`` if ``DeclRefExpr`` is the argument of a copy-assignment
+/// operator CallExpr within ``Decl``.
+bool isCopyAssignmentArgument(const DeclRefExpr &DeclRef, const Decl &Decl,
+ ASTContext &Context);
+
+} // namespace decl_ref_expr
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_DECLREFEXPRUTILS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ExprMutationAnalyzer.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ExprMutationAnalyzer.cpp
new file mode 100644
index 0000000..424fa8f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ExprMutationAnalyzer.cpp
@@ -0,0 +1,260 @@
+//===---------- ExprMutationAnalyzer.cpp - clang-tidy ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "ExprMutationAnalyzer.h"
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+using namespace ast_matchers;
+
+namespace {
+
+AST_MATCHER_P(LambdaExpr, hasCaptureInit, const Expr *, E) {
+ return llvm::is_contained(Node.capture_inits(), E);
+}
+
+AST_MATCHER_P(CXXForRangeStmt, hasRangeStmt,
+ ast_matchers::internal::Matcher<DeclStmt>, InnerMatcher) {
+ const DeclStmt *const Range = Node.getRangeStmt();
+ return InnerMatcher.matches(*Range, Finder, Builder);
+}
+
+const ast_matchers::internal::VariadicDynCastAllOfMatcher<Stmt, CXXTypeidExpr>
+ cxxTypeidExpr;
+
+AST_MATCHER(CXXTypeidExpr, isPotentiallyEvaluated) {
+ return Node.isPotentiallyEvaluated();
+}
+
+const ast_matchers::internal::VariadicDynCastAllOfMatcher<Stmt, CXXNoexceptExpr>
+ cxxNoexceptExpr;
+
+const ast_matchers::internal::VariadicDynCastAllOfMatcher<Stmt,
+ GenericSelectionExpr>
+ genericSelectionExpr;
+
+AST_MATCHER_P(GenericSelectionExpr, hasControllingExpr,
+ ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
+ return InnerMatcher.matches(*Node.getControllingExpr(), Finder, Builder);
+}
+
+const auto nonConstReferenceType = [] {
+ return referenceType(pointee(unless(isConstQualified())));
+};
+
+} // namespace
+
+const Stmt *ExprMutationAnalyzer::findMutation(const Expr *Exp) {
+ const auto Memoized = Results.find(Exp);
+ if (Memoized != Results.end())
+ return Memoized->second;
+
+ if (isUnevaluated(Exp))
+ return Results[Exp] = nullptr;
+
+ for (const auto &Finder : {&ExprMutationAnalyzer::findDirectMutation,
+ &ExprMutationAnalyzer::findMemberMutation,
+ &ExprMutationAnalyzer::findArrayElementMutation,
+ &ExprMutationAnalyzer::findCastMutation,
+ &ExprMutationAnalyzer::findRangeLoopMutation,
+ &ExprMutationAnalyzer::findReferenceMutation}) {
+ if (const Stmt *S = (this->*Finder)(Exp))
+ return Results[Exp] = S;
+ }
+
+ return Results[Exp] = nullptr;
+}
+
+bool ExprMutationAnalyzer::isUnevaluated(const Expr *Exp) {
+ return selectFirst<Expr>(
+ "expr",
+ match(
+ findAll(
+ expr(equalsNode(Exp),
+ anyOf(
+ // `Exp` is part of the underlying expression of
+ // decltype/typeof if it has an ancestor of
+ // typeLoc.
+ hasAncestor(typeLoc(unless(
+ hasAncestor(unaryExprOrTypeTraitExpr())))),
+ hasAncestor(expr(anyOf(
+ // `UnaryExprOrTypeTraitExpr` is unevaluated
+ // unless it's sizeof on VLA.
+ unaryExprOrTypeTraitExpr(unless(sizeOfExpr(
+ hasArgumentOfType(variableArrayType())))),
+ // `CXXTypeidExpr` is unevaluated unless it's
+ // applied to an expression of glvalue of
+ // polymorphic class type.
+ cxxTypeidExpr(
+ unless(isPotentiallyEvaluated())),
+ // The controlling expression of
+ // `GenericSelectionExpr` is unevaluated.
+ genericSelectionExpr(hasControllingExpr(
+ hasDescendant(equalsNode(Exp)))),
+ cxxNoexceptExpr())))))
+ .bind("expr")),
+ *Stm, *Context)) != nullptr;
+}
+
+const Stmt *
+ExprMutationAnalyzer::findExprMutation(ArrayRef<BoundNodes> Matches) {
+ for (const auto &Nodes : Matches) {
+ if (const Stmt *S = findMutation(Nodes.getNodeAs<Expr>("expr")))
+ return S;
+ }
+ return nullptr;
+}
+
+const Stmt *
+ExprMutationAnalyzer::findDeclMutation(ArrayRef<BoundNodes> Matches) {
+ for (const auto &DeclNodes : Matches) {
+ if (const Stmt *S = findDeclMutation(DeclNodes.getNodeAs<Decl>("decl")))
+ return S;
+ }
+ return nullptr;
+}
+
+const Stmt *ExprMutationAnalyzer::findDeclMutation(const Decl *Dec) {
+ const auto Refs = match(
+ findAll(declRefExpr(to(equalsNode(Dec))).bind("expr")), *Stm, *Context);
+ for (const auto &RefNodes : Refs) {
+ const auto *E = RefNodes.getNodeAs<Expr>("expr");
+ if (findMutation(E))
+ return E;
+ }
+ return nullptr;
+}
+
+const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) {
+ // LHS of any assignment operators.
+ const auto AsAssignmentLhs =
+ binaryOperator(isAssignmentOperator(), hasLHS(equalsNode(Exp)));
+
+ // Operand of increment/decrement operators.
+ const auto AsIncDecOperand =
+ unaryOperator(anyOf(hasOperatorName("++"), hasOperatorName("--")),
+ hasUnaryOperand(equalsNode(Exp)));
+
+ // Invoking non-const member function.
+ const auto NonConstMethod = cxxMethodDecl(unless(isConst()));
+ const auto AsNonConstThis =
+ expr(anyOf(cxxMemberCallExpr(callee(NonConstMethod), on(equalsNode(Exp))),
+ cxxOperatorCallExpr(callee(NonConstMethod),
+ hasArgument(0, equalsNode(Exp)))));
+
+ // Taking address of 'Exp'.
+ // We're assuming 'Exp' is mutated as soon as its address is taken, though in
+ // theory we can follow the pointer and see whether it escaped `Stm` or is
+ // dereferenced and then mutated. This is left for future improvements.
+ const auto AsAmpersandOperand =
+ unaryOperator(hasOperatorName("&"),
+ // A NoOp implicit cast is adding const.
+ unless(hasParent(implicitCastExpr(hasCastKind(CK_NoOp)))),
+ hasUnaryOperand(equalsNode(Exp)));
+ const auto AsPointerFromArrayDecay =
+ castExpr(hasCastKind(CK_ArrayToPointerDecay),
+ unless(hasParent(arraySubscriptExpr())), has(equalsNode(Exp)));
+
+ // Used as non-const-ref argument when calling a function.
+ const auto NonConstRefParam = forEachArgumentWithParam(
+ equalsNode(Exp), parmVarDecl(hasType(nonConstReferenceType())));
+ const auto AsNonConstRefArg =
+ anyOf(callExpr(NonConstRefParam), cxxConstructExpr(NonConstRefParam));
+
+ // Captured by a lambda by reference.
+ // If we're initializing a capture with 'Exp' directly then we're initializing
+ // a reference capture.
+ // For value captures there will be an ImplicitCastExpr <LValueToRValue>.
+ const auto AsLambdaRefCaptureInit = lambdaExpr(hasCaptureInit(Exp));
+
+ // Returned as non-const-ref.
+ // If we're returning 'Exp' directly then it's returned as non-const-ref.
+ // For returning by value there will be an ImplicitCastExpr <LValueToRValue>.
+ // For returning by const-ref there will be an ImplicitCastExpr <NoOp> (for
+ // adding const.)
+ const auto AsNonConstRefReturn = returnStmt(hasReturnValue(equalsNode(Exp)));
+
+ const auto Matches =
+ match(findAll(stmt(anyOf(AsAssignmentLhs, AsIncDecOperand, AsNonConstThis,
+ AsAmpersandOperand, AsPointerFromArrayDecay,
+ AsNonConstRefArg, AsLambdaRefCaptureInit,
+ AsNonConstRefReturn))
+ .bind("stmt")),
+ *Stm, *Context);
+ return selectFirst<Stmt>("stmt", Matches);
+}
+
+const Stmt *ExprMutationAnalyzer::findMemberMutation(const Expr *Exp) {
+ // Check whether any member of 'Exp' is mutated.
+ const auto MemberExprs = match(
+ findAll(memberExpr(hasObjectExpression(equalsNode(Exp))).bind("expr")),
+ *Stm, *Context);
+ return findExprMutation(MemberExprs);
+}
+
+const Stmt *ExprMutationAnalyzer::findArrayElementMutation(const Expr *Exp) {
+ // Check whether any element of an array is mutated.
+ const auto SubscriptExprs = match(
+ findAll(arraySubscriptExpr(hasBase(ignoringImpCasts(equalsNode(Exp))))
+ .bind("expr")),
+ *Stm, *Context);
+ return findExprMutation(SubscriptExprs);
+}
+
+const Stmt *ExprMutationAnalyzer::findCastMutation(const Expr *Exp) {
+ // If 'Exp' is casted to any non-const reference type, check the castExpr.
+ const auto Casts =
+ match(findAll(castExpr(hasSourceExpression(equalsNode(Exp)),
+ anyOf(explicitCastExpr(hasDestinationType(
+ nonConstReferenceType())),
+ implicitCastExpr(hasImplicitDestinationType(
+ nonConstReferenceType()))))
+ .bind("expr")),
+ *Stm, *Context);
+ return findExprMutation(Casts);
+}
+
+const Stmt *ExprMutationAnalyzer::findRangeLoopMutation(const Expr *Exp) {
+ // If range for looping over 'Exp' with a non-const reference loop variable,
+ // check all declRefExpr of the loop variable.
+ const auto LoopVars =
+ match(findAll(cxxForRangeStmt(
+ hasLoopVariable(
+ varDecl(hasType(nonConstReferenceType())).bind("decl")),
+ hasRangeInit(equalsNode(Exp)))),
+ *Stm, *Context);
+ return findDeclMutation(LoopVars);
+}
+
+const Stmt *ExprMutationAnalyzer::findReferenceMutation(const Expr *Exp) {
+ // If 'Exp' is bound to a non-const reference, check all declRefExpr to that.
+ const auto Refs = match(
+ stmt(forEachDescendant(
+ varDecl(
+ hasType(nonConstReferenceType()),
+ hasInitializer(anyOf(equalsNode(Exp),
+ conditionalOperator(anyOf(
+ hasTrueExpression(equalsNode(Exp)),
+ hasFalseExpression(equalsNode(Exp)))))),
+ hasParent(declStmt().bind("stmt")),
+ // Don't follow the reference in range statement, we've handled
+ // that separately.
+ unless(hasParent(declStmt(hasParent(
+ cxxForRangeStmt(hasRangeStmt(equalsBoundNode("stmt"))))))))
+ .bind("decl"))),
+ *Stm, *Context);
+ return findDeclMutation(Refs);
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ExprMutationAnalyzer.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ExprMutationAnalyzer.h
new file mode 100644
index 0000000..256bb71
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ExprMutationAnalyzer.h
@@ -0,0 +1,56 @@
+//===---------- ExprMutationAnalyzer.h - clang-tidy -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_EXPRMUTATIONANALYZER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_EXPRMUTATIONANALYZER_H
+
+#include <type_traits>
+
+#include "clang/AST/AST.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+/// Analyzes whether any mutative operations are applied to an expression within
+/// a given statement.
+class ExprMutationAnalyzer {
+public:
+ ExprMutationAnalyzer(const Stmt *Stm, ASTContext *Context)
+ : Stm(Stm), Context(Context) {}
+
+ bool isMutated(const Decl *Dec) { return findDeclMutation(Dec) != nullptr; }
+ bool isMutated(const Expr *Exp) { return findMutation(Exp) != nullptr; }
+ const Stmt *findMutation(const Expr *Exp);
+
+private:
+ bool isUnevaluated(const Expr *Exp);
+
+ const Stmt *findExprMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
+ const Stmt *findDeclMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
+ const Stmt *findDeclMutation(const Decl *Dec);
+
+ const Stmt *findDirectMutation(const Expr *Exp);
+ const Stmt *findMemberMutation(const Expr *Exp);
+ const Stmt *findArrayElementMutation(const Expr *Exp);
+ const Stmt *findCastMutation(const Expr *Exp);
+ const Stmt *findRangeLoopMutation(const Expr *Exp);
+ const Stmt *findReferenceMutation(const Expr *Exp);
+
+ const Stmt *const Stm;
+ ASTContext *const Context;
+ llvm::DenseMap<const Expr *, const Stmt *> Results;
+};
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_EXPRMUTATIONANALYZER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp
new file mode 100644
index 0000000..02d4a0b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp
@@ -0,0 +1,182 @@
+//===---------- ExprSequence.cpp - clang-tidy -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprSequence.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+// Returns the Stmt nodes that are parents of 'S', skipping any potential
+// intermediate non-Stmt nodes.
+//
+// In almost all cases, this function returns a single parent or no parents at
+// all.
+//
+// The case that a Stmt has multiple parents is rare but does actually occur in
+// the parts of the AST that we're interested in. Specifically, InitListExpr
+// nodes cause ASTContext::getParent() to return multiple parents for certain
+// nodes in their subtree because RecursiveASTVisitor visits both the syntactic
+// and semantic forms of InitListExpr, and the parent-child relationships are
+// different between the two forms.
+static SmallVector<const Stmt *, 1> getParentStmts(const Stmt *S,
+ ASTContext *Context) {
+ SmallVector<const Stmt *, 1> Result;
+
+ ASTContext::DynTypedNodeList Parents = Context->getParents(*S);
+
+ SmallVector<ast_type_traits::DynTypedNode, 1> NodesToProcess(Parents.begin(),
+ Parents.end());
+
+ while (!NodesToProcess.empty()) {
+ ast_type_traits::DynTypedNode Node = NodesToProcess.back();
+ NodesToProcess.pop_back();
+
+ if (const auto *S = Node.get<Stmt>()) {
+ Result.push_back(S);
+ } else {
+ Parents = Context->getParents(Node);
+ NodesToProcess.append(Parents.begin(), Parents.end());
+ }
+ }
+
+ return Result;
+}
+
+namespace {
+bool isDescendantOrEqual(const Stmt *Descendant, const Stmt *Ancestor,
+ ASTContext *Context) {
+ if (Descendant == Ancestor)
+ return true;
+ for (const Stmt *Parent : getParentStmts(Descendant, Context)) {
+ if (isDescendantOrEqual(Parent, Ancestor, Context))
+ return true;
+ }
+
+ return false;
+}
+}
+
+ExprSequence::ExprSequence(const CFG *TheCFG, ASTContext *TheContext)
+ : Context(TheContext) {
+ for (const auto &SyntheticStmt : TheCFG->synthetic_stmts()) {
+ SyntheticStmtSourceMap[SyntheticStmt.first] = SyntheticStmt.second;
+ }
+}
+
+bool ExprSequence::inSequence(const Stmt *Before, const Stmt *After) const {
+ Before = resolveSyntheticStmt(Before);
+ After = resolveSyntheticStmt(After);
+
+ // If 'After' is in the subtree of the siblings that follow 'Before' in the
+ // chain of successors, we know that 'After' is sequenced after 'Before'.
+ for (const Stmt *Successor = getSequenceSuccessor(Before); Successor;
+ Successor = getSequenceSuccessor(Successor)) {
+ if (isDescendantOrEqual(After, Successor, Context))
+ return true;
+ }
+
+ // If 'After' is a parent of 'Before' or is sequenced after one of these
+ // parents, we know that it is sequenced after 'Before'.
+ for (const Stmt *Parent : getParentStmts(Before, Context)) {
+ if (Parent == After || inSequence(Parent, After))
+ return true;
+ }
+
+ return false;
+}
+
+bool ExprSequence::potentiallyAfter(const Stmt *After,
+ const Stmt *Before) const {
+ return !inSequence(After, Before);
+}
+
+const Stmt *ExprSequence::getSequenceSuccessor(const Stmt *S) const {
+ for (const Stmt *Parent : getParentStmts(S, Context)) {
+ if (const auto *BO = dyn_cast<BinaryOperator>(Parent)) {
+ // Comma operator: Right-hand side is sequenced after the left-hand side.
+ if (BO->getLHS() == S && BO->getOpcode() == BO_Comma)
+ return BO->getRHS();
+ } else if (const auto *InitList = dyn_cast<InitListExpr>(Parent)) {
+ // Initializer list: Each initializer clause is sequenced after the
+ // clauses that precede it.
+ for (unsigned I = 1; I < InitList->getNumInits(); ++I) {
+ if (InitList->getInit(I - 1) == S)
+ return InitList->getInit(I);
+ }
+ } else if (const auto *Compound = dyn_cast<CompoundStmt>(Parent)) {
+ // Compound statement: Each sub-statement is sequenced after the
+ // statements that precede it.
+ const Stmt *Previous = nullptr;
+ for (const auto *Child : Compound->body()) {
+ if (Previous == S)
+ return Child;
+ Previous = Child;
+ }
+ } else if (const auto *TheDeclStmt = dyn_cast<DeclStmt>(Parent)) {
+ // Declaration: Every initializer expression is sequenced after the
+ // initializer expressions that precede it.
+ const Expr *PreviousInit = nullptr;
+ for (const Decl *TheDecl : TheDeclStmt->decls()) {
+ if (const auto *TheVarDecl = dyn_cast<VarDecl>(TheDecl)) {
+ if (const Expr *Init = TheVarDecl->getInit()) {
+ if (PreviousInit == S)
+ return Init;
+ PreviousInit = Init;
+ }
+ }
+ }
+ } else if (const auto *ForRange = dyn_cast<CXXForRangeStmt>(Parent)) {
+ // Range-based for: Loop variable declaration is sequenced before the
+ // body. (We need this rule because these get placed in the same
+ // CFGBlock.)
+ if (S == ForRange->getLoopVarStmt())
+ return ForRange->getBody();
+ } else if (const auto *TheIfStmt = dyn_cast<IfStmt>(Parent)) {
+ // If statement: If a variable is declared inside the condition, the
+ // expression used to initialize the variable is sequenced before the
+ // evaluation of the condition.
+ if (S == TheIfStmt->getConditionVariableDeclStmt())
+ return TheIfStmt->getCond();
+ }
+ }
+
+ return nullptr;
+}
+
+const Stmt *ExprSequence::resolveSyntheticStmt(const Stmt *S) const {
+ if (SyntheticStmtSourceMap.count(S))
+ return SyntheticStmtSourceMap.lookup(S);
+ return S;
+}
+
+StmtToBlockMap::StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext)
+ : Context(TheContext) {
+ for (const auto *B : *TheCFG) {
+ for (const auto &Elem : *B) {
+ if (Optional<CFGStmt> S = Elem.getAs<CFGStmt>())
+ Map[S->getStmt()] = B;
+ }
+ }
+}
+
+const CFGBlock *StmtToBlockMap::blockContainingStmt(const Stmt *S) const {
+ while (!Map.count(S)) {
+ SmallVector<const Stmt *, 1> Parents = getParentStmts(S, Context);
+ if (Parents.empty())
+ return nullptr;
+ S = Parents[0];
+ }
+
+ return Map.lookup(S);
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ExprSequence.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ExprSequence.h
new file mode 100644
index 0000000..2b355d9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/ExprSequence.h
@@ -0,0 +1,124 @@
+//===------------- ExprSequence.h - clang-tidy ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_EXPRSEQUENCE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_EXPRSEQUENCE_H
+
+#include "clang/Analysis/CFG.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+/// Provides information about the evaluation order of (sub-)expressions within
+/// a `CFGBlock`.
+///
+/// While a `CFGBlock` does contain individual `CFGElement`s for some
+/// sub-expressions, the order in which those `CFGElement`s appear reflects
+/// only one possible order in which the sub-expressions may be evaluated.
+/// However, we want to warn if any of the potential evaluation orders can lead
+/// to a use-after-move, not just the one contained in the `CFGBlock`.
+///
+/// This class implements only a simplified version of the C++ sequencing
+/// rules. The main limitation is that we do not distinguish between value
+/// computation and side effect -- see the "Implementation" section for more
+/// details.
+///
+/// Note: `SequenceChecker` from SemaChecking.cpp does a similar job (and much
+/// more thoroughly), but using it would require
+/// - Pulling `SequenceChecker` out into a header file (i.e. making it part of
+/// the API),
+/// - Removing the dependency of `SequenceChecker` on `Sema`, and
+/// - (Probably) modifying `SequenceChecker` to make it suitable to be used in
+/// this context.
+/// For the moment, it seems preferable to re-implement our own version of
+/// sequence checking that is special-cased to what we need here.
+///
+/// Implementation
+/// --------------
+///
+/// `ExprSequence` uses two types of sequencing edges between nodes in the AST:
+///
+/// - Every `Stmt` is assumed to be sequenced after its children. This is
+/// overly optimistic because the standard only states that value computations
+/// of operands are sequenced before the value computation of the operator,
+/// making no guarantees about side effects (in general).
+///
+/// For our purposes, this rule is sufficient, however, because this check is
+/// interested in operations on objects, which are generally performed through
+/// function calls (whether explicit and implicit). Function calls guarantee
+/// that the value computations and side effects for all function arguments
+/// are sequenced before the execution of the function.
+///
+/// - In addition, some `Stmt`s are known to be sequenced before or after
+/// their siblings. For example, the `Stmt`s that make up a `CompoundStmt`are
+/// all sequenced relative to each other. The function
+/// `getSequenceSuccessor()` implements these sequencing rules.
+class ExprSequence {
+public:
+ /// Initializes this `ExprSequence` with sequence information for the given
+ /// `CFG`.
+ ExprSequence(const CFG *TheCFG, ASTContext *TheContext);
+
+ /// Returns whether \p Before is sequenced before \p After.
+ bool inSequence(const Stmt *Before, const Stmt *After) const;
+
+ /// Returns whether \p After can potentially be evaluated after \p Before.
+ /// This is exactly equivalent to `!inSequence(After, Before)` but makes some
+ /// conditions read more naturally.
+ bool potentiallyAfter(const Stmt *After, const Stmt *Before) const;
+
+private:
+ // Returns the sibling of \p S (if any) that is directly sequenced after \p S,
+ // or nullptr if no such sibling exists. For example, if \p S is the child of
+ // a `CompoundStmt`, this would return the Stmt that directly follows \p S in
+ // the `CompoundStmt`.
+ //
+ // As the sequencing of many constructs that change control flow is already
+ // encoded in the `CFG`, this function only implements the sequencing rules
+ // for those constructs where sequencing cannot be inferred from the `CFG`.
+ const Stmt *getSequenceSuccessor(const Stmt *S) const;
+
+ const Stmt *resolveSyntheticStmt(const Stmt *S) const;
+
+ ASTContext *Context;
+
+ llvm::DenseMap<const Stmt *, const Stmt *> SyntheticStmtSourceMap;
+};
+
+/// Maps `Stmt`s to the `CFGBlock` that contains them. Some `Stmt`s may be
+/// contained in more than one `CFGBlock`; in this case, they are mapped to the
+/// innermost block (i.e. the one that is furthest from the root of the tree).
+class StmtToBlockMap {
+public:
+ /// Initializes the map for the given `CFG`.
+ StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext);
+
+ /// Returns the block that \p S is contained in. Some `Stmt`s may be contained
+ /// in more than one `CFGBlock`; in this case, this function returns the
+ /// innermost block (i.e. the one that is furthest from the root of the tree).
+ const CFGBlock *blockContainingStmt(const Stmt *S) const;
+
+private:
+ ASTContext *Context;
+
+ llvm::DenseMap<const Stmt *, const CFGBlock *> Map;
+};
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_EXPRSEQUENCE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp
new file mode 100644
index 0000000..0627e51
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/FixItHintUtils.cpp
@@ -0,0 +1,36 @@
+//===--- FixItHintUtils.cpp - clang-tidy-----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FixItHintUtils.h"
+#include "LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+namespace fixit {
+
+FixItHint changeVarDeclToReference(const VarDecl &Var, ASTContext &Context) {
+ SourceLocation AmpLocation = Var.getLocation();
+ auto Token = utils::lexer::getPreviousToken(Context, AmpLocation);
+ if (!Token.is(tok::unknown))
+ AmpLocation = Lexer::getLocForEndOfToken(Token.getLocation(), 0,
+ Context.getSourceManager(),
+ Context.getLangOpts());
+ return FixItHint::CreateInsertion(AmpLocation, "&");
+}
+
+FixItHint changeVarDeclToConst(const VarDecl &Var) {
+ return FixItHint::CreateInsertion(Var.getTypeSpecStartLoc(), "const ");
+}
+
+} // namespace fixit
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/FixItHintUtils.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/FixItHintUtils.h
new file mode 100644
index 0000000..e64a6e4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/FixItHintUtils.h
@@ -0,0 +1,32 @@
+//===--- FixItHintUtils.h - clang-tidy---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_FIXITHINTUTILS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_FIXITHINTUTILS_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+namespace fixit {
+
+/// \brief Creates fix to make ``VarDecl`` a reference by adding ``&``.
+FixItHint changeVarDeclToReference(const VarDecl &Var, ASTContext &Context);
+
+/// \brief Creates fix to make ``VarDecl`` const qualified.
+FixItHint changeVarDeclToConst(const VarDecl &Var);
+
+} // namespace fixit
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_FIXITHINTUTILS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/HeaderFileExtensionsUtils.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/HeaderFileExtensionsUtils.cpp
new file mode 100644
index 0000000..b734b89
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/HeaderFileExtensionsUtils.cpp
@@ -0,0 +1,71 @@
+//===--- HeaderFileExtensionsUtils.cpp - clang-tidy--------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HeaderFileExtensionsUtils.h"
+#include "clang/Basic/CharInfo.h"
+#include "llvm/Support/Path.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+bool isExpansionLocInHeaderFile(
+ SourceLocation Loc, const SourceManager &SM,
+ const HeaderFileExtensionsSet &HeaderFileExtensions) {
+ SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
+ return isHeaderFileExtension(SM.getFilename(ExpansionLoc),
+ HeaderFileExtensions);
+}
+
+bool isPresumedLocInHeaderFile(
+ SourceLocation Loc, SourceManager &SM,
+ const HeaderFileExtensionsSet &HeaderFileExtensions) {
+ PresumedLoc PresumedLocation = SM.getPresumedLoc(Loc);
+ return isHeaderFileExtension(PresumedLocation.getFilename(),
+ HeaderFileExtensions);
+}
+
+bool isSpellingLocInHeaderFile(
+ SourceLocation Loc, SourceManager &SM,
+ const HeaderFileExtensionsSet &HeaderFileExtensions) {
+ SourceLocation SpellingLoc = SM.getSpellingLoc(Loc);
+ return isHeaderFileExtension(SM.getFilename(SpellingLoc),
+ HeaderFileExtensions);
+}
+
+bool parseHeaderFileExtensions(StringRef AllHeaderFileExtensions,
+ HeaderFileExtensionsSet &HeaderFileExtensions,
+ char delimiter) {
+ SmallVector<StringRef, 5> Suffixes;
+ AllHeaderFileExtensions.split(Suffixes, delimiter);
+ HeaderFileExtensions.clear();
+ for (StringRef Suffix : Suffixes) {
+ StringRef Extension = Suffix.trim();
+ for (StringRef::const_iterator it = Extension.begin();
+ it != Extension.end(); ++it) {
+ if (!isAlphanumeric(*it))
+ return false;
+ }
+ HeaderFileExtensions.insert(Extension);
+ }
+ return true;
+}
+
+bool isHeaderFileExtension(
+ StringRef FileName, const HeaderFileExtensionsSet &HeaderFileExtensions) {
+ StringRef extension = llvm::sys::path::extension(FileName);
+ if (extension.empty())
+ return false;
+ // Skip "." prefix.
+ return HeaderFileExtensions.count(extension.substr(1)) > 0;
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/HeaderFileExtensionsUtils.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/HeaderFileExtensionsUtils.h
new file mode 100644
index 0000000..2012017
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/HeaderFileExtensionsUtils.h
@@ -0,0 +1,56 @@
+//===--- HeaderFileExtensionsUtils.h - clang-tidy----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADER_FILE_EXTENSIONS_UTILS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADER_FILE_EXTENSIONS_UTILS_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+typedef llvm::SmallSet<llvm::StringRef, 5> HeaderFileExtensionsSet;
+
+/// \brief Checks whether expansion location of \p Loc is in header file.
+bool isExpansionLocInHeaderFile(
+ SourceLocation Loc, const SourceManager &SM,
+ const HeaderFileExtensionsSet &HeaderFileExtensions);
+
+/// \brief Checks whether presumed location of \p Loc is in header file.
+bool isPresumedLocInHeaderFile(
+ SourceLocation Loc, SourceManager &SM,
+ const HeaderFileExtensionsSet &HeaderFileExtensions);
+
+/// \brief Checks whether spelling location of \p Loc is in header file.
+bool isSpellingLocInHeaderFile(
+ SourceLocation Loc, SourceManager &SM,
+ const HeaderFileExtensionsSet &HeaderFileExtensions);
+
+/// \brief Returns recommended default value for the list of header file
+/// extensions.
+inline StringRef defaultHeaderFileExtensions() { return ",h,hh,hpp,hxx"; }
+
+/// \brief Parses header file extensions from a semicolon-separated list.
+bool parseHeaderFileExtensions(StringRef AllHeaderFileExtensions,
+ HeaderFileExtensionsSet &HeaderFileExtensions,
+ char delimiter);
+
+/// \brief Decides whether a file has a header file extension.
+bool isHeaderFileExtension(StringRef FileName,
+ const HeaderFileExtensionsSet &HeaderFileExtensions);
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADER_FILE_EXTENSIONS_UTILS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp
new file mode 100644
index 0000000..515f882
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp
@@ -0,0 +1,292 @@
+//===--- HeaderGuard.cpp - clang-tidy -------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HeaderGuard.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/Path.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+/// \brief canonicalize a path by removing ./ and ../ components.
+static std::string cleanPath(StringRef Path) {
+ SmallString<256> Result = Path;
+ llvm::sys::path::remove_dots(Result, true);
+ return Result.str();
+}
+
+namespace {
+class HeaderGuardPPCallbacks : public PPCallbacks {
+public:
+ HeaderGuardPPCallbacks(Preprocessor *PP, HeaderGuardCheck *Check)
+ : PP(PP), Check(Check) {}
+
+ void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) override {
+ // Record all files we enter. We'll need them to diagnose headers without
+ // guards.
+ SourceManager &SM = PP->getSourceManager();
+ if (Reason == EnterFile && FileType == SrcMgr::C_User) {
+ if (const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Loc))) {
+ std::string FileName = cleanPath(FE->getName());
+ Files[FileName] = FE;
+ }
+ }
+ }
+
+ void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDefinition &MD) override {
+ if (MD)
+ return;
+
+ // Record #ifndefs that succeeded. We also need the Location of the Name.
+ Ifndefs[MacroNameTok.getIdentifierInfo()] =
+ std::make_pair(Loc, MacroNameTok.getLocation());
+ }
+
+ void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
+ // Record all defined macros. We store the whole token to get info on the
+ // name later.
+ Macros.emplace_back(MacroNameTok, MD->getMacroInfo());
+ }
+
+ void Endif(SourceLocation Loc, SourceLocation IfLoc) override {
+ // Record all #endif and the corresponding #ifs (including #ifndefs).
+ EndIfs[IfLoc] = Loc;
+ }
+
+ void EndOfMainFile() override {
+ // Now that we have all this information from the preprocessor, use it!
+ SourceManager &SM = PP->getSourceManager();
+
+ for (const auto &MacroEntry : Macros) {
+ const MacroInfo *MI = MacroEntry.second;
+
+ // We use clang's header guard detection. This has the advantage of also
+ // emitting a warning for cases where a pseudo header guard is found but
+ // preceded by something blocking the header guard optimization.
+ if (!MI->isUsedForHeaderGuard())
+ continue;
+
+ const FileEntry *FE =
+ SM.getFileEntryForID(SM.getFileID(MI->getDefinitionLoc()));
+ std::string FileName = cleanPath(FE->getName());
+ Files.erase(FileName);
+
+ // See if we should check and fix this header guard.
+ if (!Check->shouldFixHeaderGuard(FileName))
+ continue;
+
+ // Look up Locations for this guard.
+ SourceLocation Ifndef =
+ Ifndefs[MacroEntry.first.getIdentifierInfo()].second;
+ SourceLocation Define = MacroEntry.first.getLocation();
+ SourceLocation EndIf =
+ EndIfs[Ifndefs[MacroEntry.first.getIdentifierInfo()].first];
+
+ // If the macro Name is not equal to what we can compute, correct it in
+ // the #ifndef and #define.
+ StringRef CurHeaderGuard =
+ MacroEntry.first.getIdentifierInfo()->getName();
+ std::vector<FixItHint> FixIts;
+ std::string NewGuard = checkHeaderGuardDefinition(
+ Ifndef, Define, EndIf, FileName, CurHeaderGuard, FixIts);
+
+ // Now look at the #endif. We want a comment with the header guard. Fix it
+ // at the slightest deviation.
+ checkEndifComment(FileName, EndIf, NewGuard, FixIts);
+
+ // Bundle all fix-its into one warning. The message depends on whether we
+ // changed the header guard or not.
+ if (!FixIts.empty()) {
+ if (CurHeaderGuard != NewGuard) {
+ Check->diag(Ifndef, "header guard does not follow preferred style")
+ << FixIts;
+ } else {
+ Check->diag(EndIf, "#endif for a header guard should reference the "
+ "guard macro in a comment")
+ << FixIts;
+ }
+ }
+ }
+
+ // Emit warnings for headers that are missing guards.
+ checkGuardlessHeaders();
+
+ // Clear all state.
+ Macros.clear();
+ Files.clear();
+ Ifndefs.clear();
+ EndIfs.clear();
+ }
+
+ bool wouldFixEndifComment(StringRef FileName, SourceLocation EndIf,
+ StringRef HeaderGuard,
+ size_t *EndIfLenPtr = nullptr) {
+ if (!EndIf.isValid())
+ return false;
+ const char *EndIfData = PP->getSourceManager().getCharacterData(EndIf);
+ size_t EndIfLen = std::strcspn(EndIfData, "\r\n");
+ if (EndIfLenPtr)
+ *EndIfLenPtr = EndIfLen;
+
+ StringRef EndIfStr(EndIfData, EndIfLen);
+ EndIfStr = EndIfStr.substr(EndIfStr.find_first_not_of("#endif \t"));
+
+ // Give up if there's an escaped newline.
+ size_t FindEscapedNewline = EndIfStr.find_last_not_of(' ');
+ if (FindEscapedNewline != StringRef::npos &&
+ EndIfStr[FindEscapedNewline] == '\\')
+ return false;
+
+ if (!Check->shouldSuggestEndifComment(FileName) &&
+ !(EndIfStr.startswith("//") ||
+ (EndIfStr.startswith("/*") && EndIfStr.endswith("*/"))))
+ return false;
+
+ return (EndIfStr != "// " + HeaderGuard.str()) &&
+ (EndIfStr != "/* " + HeaderGuard.str() + " */");
+ }
+
+ /// \brief Look for header guards that don't match the preferred style. Emit
+ /// fix-its and return the suggested header guard (or the original if no
+ /// change was made.
+ std::string checkHeaderGuardDefinition(SourceLocation Ifndef,
+ SourceLocation Define,
+ SourceLocation EndIf,
+ StringRef FileName,
+ StringRef CurHeaderGuard,
+ std::vector<FixItHint> &FixIts) {
+ std::string CPPVar = Check->getHeaderGuard(FileName, CurHeaderGuard);
+ std::string CPPVarUnder = CPPVar + '_';
+
+ // Allow a trailing underscore iff we don't have to change the endif comment
+ // too.
+ if (Ifndef.isValid() && CurHeaderGuard != CPPVar &&
+ (CurHeaderGuard != CPPVarUnder ||
+ wouldFixEndifComment(FileName, EndIf, CurHeaderGuard))) {
+ FixIts.push_back(FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(
+ Ifndef, Ifndef.getLocWithOffset(CurHeaderGuard.size())),
+ CPPVar));
+ FixIts.push_back(FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(
+ Define, Define.getLocWithOffset(CurHeaderGuard.size())),
+ CPPVar));
+ return CPPVar;
+ }
+ return CurHeaderGuard;
+ }
+
+ /// \brief Checks the comment after the #endif of a header guard and fixes it
+ /// if it doesn't match \c HeaderGuard.
+ void checkEndifComment(StringRef FileName, SourceLocation EndIf,
+ StringRef HeaderGuard,
+ std::vector<FixItHint> &FixIts) {
+ size_t EndIfLen;
+ if (wouldFixEndifComment(FileName, EndIf, HeaderGuard, &EndIfLen)) {
+ FixIts.push_back(FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(EndIf,
+ EndIf.getLocWithOffset(EndIfLen)),
+ Check->formatEndIf(HeaderGuard)));
+ }
+ }
+
+ /// \brief Looks for files that were visited but didn't have a header guard.
+ /// Emits a warning with fixits suggesting adding one.
+ void checkGuardlessHeaders() {
+ // Look for header files that didn't have a header guard. Emit a warning and
+ // fix-its to add the guard.
+ // TODO: Insert the guard after top comments.
+ for (const auto &FE : Files) {
+ StringRef FileName = FE.getKey();
+ if (!Check->shouldSuggestToAddHeaderGuard(FileName))
+ continue;
+
+ SourceManager &SM = PP->getSourceManager();
+ FileID FID = SM.translateFile(FE.getValue());
+ SourceLocation StartLoc = SM.getLocForStartOfFile(FID);
+ if (StartLoc.isInvalid())
+ continue;
+
+ std::string CPPVar = Check->getHeaderGuard(FileName);
+ std::string CPPVarUnder = CPPVar + '_'; // Allow a trailing underscore.
+ // If there's a macro with a name that follows the header guard convention
+ // but was not recognized by the preprocessor as a header guard there must
+ // be code outside of the guarded area. Emit a plain warning without
+ // fix-its.
+ // FIXME: Can we move it into the right spot?
+ bool SeenMacro = false;
+ for (const auto &MacroEntry : Macros) {
+ StringRef Name = MacroEntry.first.getIdentifierInfo()->getName();
+ SourceLocation DefineLoc = MacroEntry.first.getLocation();
+ if ((Name == CPPVar || Name == CPPVarUnder) &&
+ SM.isWrittenInSameFile(StartLoc, DefineLoc)) {
+ Check->diag(DefineLoc, "code/includes outside of area guarded by "
+ "header guard; consider moving it");
+ SeenMacro = true;
+ break;
+ }
+ }
+
+ if (SeenMacro)
+ continue;
+
+ Check->diag(StartLoc, "header is missing header guard")
+ << FixItHint::CreateInsertion(
+ StartLoc, "#ifndef " + CPPVar + "\n#define " + CPPVar + "\n\n")
+ << FixItHint::CreateInsertion(
+ SM.getLocForEndOfFile(FID),
+ Check->shouldSuggestEndifComment(FileName)
+ ? "\n#" + Check->formatEndIf(CPPVar) + "\n"
+ : "\n#endif\n");
+ }
+ }
+
+private:
+ std::vector<std::pair<Token, const MacroInfo *>> Macros;
+ llvm::StringMap<const FileEntry *> Files;
+ std::map<const IdentifierInfo *, std::pair<SourceLocation, SourceLocation>>
+ Ifndefs;
+ std::map<SourceLocation, SourceLocation> EndIfs;
+
+ Preprocessor *PP;
+ HeaderGuardCheck *Check;
+};
+} // namespace
+
+void HeaderGuardCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+ Compiler.getPreprocessor().addPPCallbacks(
+ llvm::make_unique<HeaderGuardPPCallbacks>(&Compiler.getPreprocessor(),
+ this));
+}
+
+bool HeaderGuardCheck::shouldSuggestEndifComment(StringRef FileName) {
+ return utils::isHeaderFileExtension(FileName, HeaderFileExtensions);
+}
+
+bool HeaderGuardCheck::shouldFixHeaderGuard(StringRef FileName) { return true; }
+
+bool HeaderGuardCheck::shouldSuggestToAddHeaderGuard(StringRef FileName) {
+ return utils::isHeaderFileExtension(FileName, HeaderFileExtensions);
+}
+
+std::string HeaderGuardCheck::formatEndIf(StringRef HeaderGuard) {
+ return "endif // " + HeaderGuard.str();
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/HeaderGuard.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/HeaderGuard.h
new file mode 100644
index 0000000..a2d8288
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/HeaderGuard.h
@@ -0,0 +1,64 @@
+//===--- HeaderGuard.h - clang-tidy -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADERGUARD_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADERGUARD_H
+
+#include "../ClangTidy.h"
+#include "../utils/HeaderFileExtensionsUtils.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+/// Finds and fixes header guards.
+/// The check supports these options:
+/// - `HeaderFileExtensions`: a comma-separated list of filename extensions of
+/// header files (The filename extension should not contain "." prefix).
+/// ",h,hh,hpp,hxx" by default.
+/// For extension-less header files, using an empty string or leaving an
+/// empty string between "," if there are other filename extensions.
+class HeaderGuardCheck : public ClangTidyCheck {
+public:
+ HeaderGuardCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
+ "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
+ utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions,
+ HeaderFileExtensions, ',');
+ }
+ void registerPPCallbacks(CompilerInstance &Compiler) override;
+
+ /// Returns ``true`` if the check should suggest inserting a trailing comment
+ /// on the ``#endif`` of the header guard. It will use the same name as
+ /// returned by ``HeaderGuardCheck::getHeaderGuard``.
+ virtual bool shouldSuggestEndifComment(StringRef Filename);
+ /// Returns ``true`` if the check should suggest changing an existing header
+ /// guard to the string returned by ``HeaderGuardCheck::getHeaderGuard``.
+ virtual bool shouldFixHeaderGuard(StringRef Filename);
+ /// Returns ``true`` if the check should add a header guard to the file
+ /// if it has none.
+ virtual bool shouldSuggestToAddHeaderGuard(StringRef Filename);
+ /// Returns a replacement for the ``#endif`` line with a comment mentioning
+ /// \p HeaderGuard. The replacement should start with ``endif``.
+ virtual std::string formatEndIf(StringRef HeaderGuard);
+ /// Gets the canonical header guard for a file.
+ virtual std::string getHeaderGuard(StringRef Filename,
+ StringRef OldGuard = StringRef()) = 0;
+
+private:
+ std::string RawStringHeaderFileExtensions;
+ utils::HeaderFileExtensionsSet HeaderFileExtensions;
+};
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_HEADERGUARD_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/IncludeInserter.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/IncludeInserter.cpp
new file mode 100644
index 0000000..64e4213
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/IncludeInserter.cpp
@@ -0,0 +1,86 @@
+//===-------- IncludeInserter.cpp - clang-tidy ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IncludeInserter.h"
+#include "clang/Lex/Token.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+class IncludeInserterCallback : public PPCallbacks {
+public:
+ explicit IncludeInserterCallback(IncludeInserter *Inserter)
+ : Inserter(Inserter) {}
+ // Implements PPCallbacks::InclusionDerective(). Records the names and source
+ // locations of the inclusions in the main source file being processed.
+ void InclusionDirective(SourceLocation HashLocation,
+ const Token &IncludeToken, StringRef FileNameRef,
+ bool IsAngled, CharSourceRange FileNameRange,
+ const FileEntry * /*IncludedFile*/,
+ StringRef /*SearchPath*/, StringRef /*RelativePath*/,
+ const Module * /*ImportedModule*/,
+ SrcMgr::CharacteristicKind /*FileType*/) override {
+ Inserter->AddInclude(FileNameRef, IsAngled, HashLocation,
+ IncludeToken.getEndLoc());
+ }
+
+private:
+ IncludeInserter *Inserter;
+};
+
+IncludeInserter::IncludeInserter(const SourceManager &SourceMgr,
+ const LangOptions &LangOpts,
+ IncludeSorter::IncludeStyle Style)
+ : SourceMgr(SourceMgr), LangOpts(LangOpts), Style(Style) {}
+
+IncludeInserter::~IncludeInserter() {}
+
+std::unique_ptr<PPCallbacks> IncludeInserter::CreatePPCallbacks() {
+ return llvm::make_unique<IncludeInserterCallback>(this);
+}
+
+llvm::Optional<FixItHint>
+IncludeInserter::CreateIncludeInsertion(FileID FileID, StringRef Header,
+ bool IsAngled) {
+ // We assume the same Header will never be included both angled and not
+ // angled.
+ if (!InsertedHeaders[FileID].insert(Header).second)
+ return llvm::None;
+
+ if (IncludeSorterByFile.find(FileID) == IncludeSorterByFile.end()) {
+ // This may happen if there have been no preprocessor directives in this
+ // file.
+ IncludeSorterByFile.insert(std::make_pair(
+ FileID,
+ llvm::make_unique<IncludeSorter>(
+ &SourceMgr, &LangOpts, FileID,
+ SourceMgr.getFilename(SourceMgr.getLocForStartOfFile(FileID)),
+ Style)));
+ }
+ return IncludeSorterByFile[FileID]->CreateIncludeInsertion(Header, IsAngled);
+}
+
+void IncludeInserter::AddInclude(StringRef FileName, bool IsAngled,
+ SourceLocation HashLocation,
+ SourceLocation EndLocation) {
+ FileID FileID = SourceMgr.getFileID(HashLocation);
+ if (IncludeSorterByFile.find(FileID) == IncludeSorterByFile.end()) {
+ IncludeSorterByFile.insert(std::make_pair(
+ FileID, llvm::make_unique<IncludeSorter>(
+ &SourceMgr, &LangOpts, FileID,
+ SourceMgr.getFilename(HashLocation), Style)));
+ }
+ IncludeSorterByFile[FileID]->AddInclude(FileName, IsAngled, HashLocation,
+ EndLocation);
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/IncludeInserter.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/IncludeInserter.h
new file mode 100644
index 0000000..75f2554
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/IncludeInserter.h
@@ -0,0 +1,84 @@
+//===---------- IncludeInserter.h - clang-tidy ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDEINSERTER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDEINSERTER_H
+
+#include "IncludeSorter.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/PPCallbacks.h"
+#include <memory>
+#include <string>
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+/// \brief Produces fixes to insert specified includes to source files, if not
+/// yet present.
+///
+/// ``IncludeInserter`` can be used by ``ClangTidyCheck`` in the following
+/// fashion:
+/// \code
+/// class MyCheck : public ClangTidyCheck {
+/// public:
+/// void registerPPCallbacks(CompilerInstance& Compiler) override {
+/// Inserter.reset(new IncludeInserter(&Compiler.getSourceManager(),
+/// &Compiler.getLangOpts()));
+/// Compiler.getPreprocessor().addPPCallbacks(
+/// Inserter->CreatePPCallback());
+/// }
+///
+/// void registerMatchers(ast_matchers::MatchFinder* Finder) override { ... }
+///
+/// void check(
+/// const ast_matchers::MatchFinder::MatchResult& Result) override {
+/// ...
+/// Inserter->CreateIncludeInsertion(
+/// Result.SourceManager->getMainFileID(), "path/to/Header.h",
+/// /*IsAngled=*/false);
+/// ...
+/// }
+///
+/// private:
+/// std::unique_ptr<IncludeInserter> Inserter;
+/// };
+/// \endcode
+class IncludeInserter {
+public:
+ IncludeInserter(const SourceManager &SourceMgr, const LangOptions &LangOpts,
+ IncludeSorter::IncludeStyle Style);
+ ~IncludeInserter();
+
+ /// Create ``PPCallbacks`` for registration with the compiler's preprocessor.
+ std::unique_ptr<PPCallbacks> CreatePPCallbacks();
+
+ /// Creates a \p Header inclusion directive fixit. Returns ``llvm::None`` on
+ /// error or if inclusion directive already exists.
+ llvm::Optional<FixItHint>
+ CreateIncludeInsertion(FileID FileID, llvm::StringRef Header, bool IsAngled);
+
+private:
+ void AddInclude(StringRef FileName, bool IsAngled,
+ SourceLocation HashLocation, SourceLocation EndLocation);
+
+ llvm::DenseMap<FileID, std::unique_ptr<IncludeSorter>> IncludeSorterByFile;
+ llvm::DenseMap<FileID, std::set<std::string>> InsertedHeaders;
+ const SourceManager &SourceMgr;
+ const LangOptions &LangOpts;
+ const IncludeSorter::IncludeStyle Style;
+ friend class IncludeInserterCallback;
+};
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDEINSERTER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp
new file mode 100644
index 0000000..1502da7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp
@@ -0,0 +1,290 @@
+//===---------- IncludeSorter.cpp - clang-tidy ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IncludeSorter.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+namespace {
+
+StringRef RemoveFirstSuffix(StringRef Str, ArrayRef<const char *> Suffixes) {
+ for (StringRef Suffix : Suffixes) {
+ if (Str.endswith(Suffix)) {
+ return Str.substr(0, Str.size() - Suffix.size());
+ }
+ }
+ return Str;
+}
+
+StringRef MakeCanonicalName(StringRef Str, IncludeSorter::IncludeStyle Style) {
+ // The list of suffixes to remove from source file names to get the
+ // "canonical" file names.
+ // E.g. tools/sort_includes.cc and tools/sort_includes_test.cc
+ // would both canonicalize to tools/sort_includes and tools/sort_includes.h
+ // (once canonicalized) will match as being the main include file associated
+ // with the source files.
+ if (Style == IncludeSorter::IS_LLVM) {
+ return RemoveFirstSuffix(
+ RemoveFirstSuffix(Str, {".cc", ".cpp", ".c", ".h", ".hpp"}), {"Test"});
+ }
+ return RemoveFirstSuffix(
+ RemoveFirstSuffix(Str, {".cc", ".cpp", ".c", ".h", ".hpp"}),
+ {"_unittest", "_regtest", "_test"});
+}
+
+// Scan to the end of the line and return the offset of the next line.
+size_t FindNextLine(const char *Text) {
+ size_t EOLIndex = std::strcspn(Text, "\n");
+ return Text[EOLIndex] == '\0' ? EOLIndex : EOLIndex + 1;
+}
+
+IncludeSorter::IncludeKinds
+DetermineIncludeKind(StringRef CanonicalFile, StringRef IncludeFile,
+ bool IsAngled, IncludeSorter::IncludeStyle Style) {
+ // Compute the two "canonical" forms of the include's filename sans extension.
+ // The first form is the include's filename without ".h" or "-inl.h" at the
+ // end. The second form is the first form with "/public/" in the file path
+ // replaced by "/internal/".
+ if (IsAngled) {
+ // If the system include (<foo>) ends with ".h", then it is a normal C-style
+ // include. Otherwise assume it is a C++-style extensionless include.
+ return IncludeFile.endswith(".h") ? IncludeSorter::IK_CSystemInclude
+ : IncludeSorter::IK_CXXSystemInclude;
+ }
+ StringRef CanonicalInclude = MakeCanonicalName(IncludeFile, Style);
+ if (CanonicalFile.endswith(CanonicalInclude)
+ || CanonicalInclude.endswith(CanonicalFile)) {
+ return IncludeSorter::IK_MainTUInclude;
+ }
+ if (Style == IncludeSorter::IS_Google) {
+ std::pair<StringRef, StringRef> Parts = CanonicalInclude.split("/public/");
+ std::string AltCanonicalInclude =
+ Parts.first.str() + "/internal/" + Parts.second.str();
+ std::string ProtoCanonicalInclude =
+ Parts.first.str() + "/proto/" + Parts.second.str();
+
+ // Determine the kind of this inclusion.
+ if (CanonicalFile.equals(AltCanonicalInclude) ||
+ CanonicalFile.equals(ProtoCanonicalInclude)) {
+ return IncludeSorter::IK_MainTUInclude;
+ }
+ }
+ return IncludeSorter::IK_NonSystemInclude;
+}
+
+} // namespace
+
+IncludeSorter::IncludeSorter(const SourceManager *SourceMgr,
+ const LangOptions *LangOpts, const FileID FileID,
+ StringRef FileName, IncludeStyle Style)
+ : SourceMgr(SourceMgr), LangOpts(LangOpts), Style(Style),
+ CurrentFileID(FileID), CanonicalFile(MakeCanonicalName(FileName, Style)) {
+}
+
+void IncludeSorter::AddInclude(StringRef FileName, bool IsAngled,
+ SourceLocation HashLocation,
+ SourceLocation EndLocation) {
+ int Offset = FindNextLine(SourceMgr->getCharacterData(EndLocation));
+
+ // Record the relevant location information for this inclusion directive.
+ IncludeLocations[FileName].push_back(
+ SourceRange(HashLocation, EndLocation.getLocWithOffset(Offset)));
+ SourceLocations.push_back(IncludeLocations[FileName].back());
+
+ // Stop if this inclusion is a duplicate.
+ if (IncludeLocations[FileName].size() > 1)
+ return;
+
+ // Add the included file's name to the appropriate bucket.
+ IncludeKinds Kind =
+ DetermineIncludeKind(CanonicalFile, FileName, IsAngled, Style);
+ if (Kind != IK_InvalidInclude)
+ IncludeBucket[Kind].push_back(FileName.str());
+}
+
+Optional<FixItHint> IncludeSorter::CreateIncludeInsertion(StringRef FileName,
+ bool IsAngled) {
+ std::string IncludeStmt =
+ IsAngled ? llvm::Twine("#include <" + FileName + ">\n").str()
+ : llvm::Twine("#include \"" + FileName + "\"\n").str();
+ if (SourceLocations.empty()) {
+ // If there are no includes in this file, add it in the first line.
+ // FIXME: insert after the file comment or the header guard, if present.
+ IncludeStmt.append("\n");
+ return FixItHint::CreateInsertion(
+ SourceMgr->getLocForStartOfFile(CurrentFileID), IncludeStmt);
+ }
+
+ auto IncludeKind =
+ DetermineIncludeKind(CanonicalFile, FileName, IsAngled, Style);
+
+ if (!IncludeBucket[IncludeKind].empty()) {
+ for (const std::string &IncludeEntry : IncludeBucket[IncludeKind]) {
+ if (FileName < IncludeEntry) {
+ const auto &Location = IncludeLocations[IncludeEntry][0];
+ return FixItHint::CreateInsertion(Location.getBegin(), IncludeStmt);
+ } else if (FileName == IncludeEntry) {
+ return llvm::None;
+ }
+ }
+ // FileName comes after all include entries in bucket, insert it after
+ // last.
+ const std::string &LastInclude = IncludeBucket[IncludeKind].back();
+ SourceRange LastIncludeLocation = IncludeLocations[LastInclude].back();
+ return FixItHint::CreateInsertion(LastIncludeLocation.getEnd(),
+ IncludeStmt);
+ }
+ // Find the non-empty include bucket to be sorted directly above
+ // 'IncludeKind'. If such a bucket exists, we'll want to sort the include
+ // after that bucket. If no such bucket exists, find the first non-empty
+ // include bucket in the file. In that case, we'll want to sort the include
+ // before that bucket.
+ IncludeKinds NonEmptyKind = IK_InvalidInclude;
+ for (int i = IK_InvalidInclude - 1; i >= 0; --i) {
+ if (!IncludeBucket[i].empty()) {
+ NonEmptyKind = static_cast<IncludeKinds>(i);
+ if (NonEmptyKind < IncludeKind)
+ break;
+ }
+ }
+ if (NonEmptyKind == IK_InvalidInclude) {
+ return llvm::None;
+ }
+
+ if (NonEmptyKind < IncludeKind) {
+ // Create a block after.
+ const std::string &LastInclude = IncludeBucket[NonEmptyKind].back();
+ SourceRange LastIncludeLocation = IncludeLocations[LastInclude].back();
+ IncludeStmt = '\n' + IncludeStmt;
+ return FixItHint::CreateInsertion(LastIncludeLocation.getEnd(),
+ IncludeStmt);
+ }
+ // Create a block before.
+ const std::string &FirstInclude = IncludeBucket[NonEmptyKind][0];
+ SourceRange FirstIncludeLocation = IncludeLocations[FirstInclude].back();
+ IncludeStmt.append("\n");
+ return FixItHint::CreateInsertion(FirstIncludeLocation.getBegin(),
+ IncludeStmt);
+}
+
+std::vector<FixItHint> IncludeSorter::GetEdits() {
+ if (SourceLocations.empty())
+ return {};
+
+ typedef std::map<int, std::pair<SourceRange, std::string>>
+ FileLineToSourceEditMap;
+ FileLineToSourceEditMap Edits;
+ auto SourceLocationIterator = SourceLocations.begin();
+ auto SourceLocationIteratorEnd = SourceLocations.end();
+
+ // Compute the Edits that need to be done to each line to add, replace, or
+ // delete inclusions.
+ for (int IncludeKind = 0; IncludeKind < IK_InvalidInclude; ++IncludeKind) {
+ std::sort(IncludeBucket[IncludeKind].begin(),
+ IncludeBucket[IncludeKind].end());
+ for (const auto &IncludeEntry : IncludeBucket[IncludeKind]) {
+ auto &Location = IncludeLocations[IncludeEntry];
+ SourceRangeVector::iterator LocationIterator = Location.begin();
+ SourceRangeVector::iterator LocationIteratorEnd = Location.end();
+ SourceRange FirstLocation = *LocationIterator;
+
+ // If the first occurrence of a particular include is on the current
+ // source line we are examining, leave it alone.
+ if (FirstLocation == *SourceLocationIterator)
+ ++LocationIterator;
+
+ // Add the deletion Edits for any (remaining) instances of this inclusion,
+ // and remove their Locations from the source Locations to be processed.
+ for (; LocationIterator != LocationIteratorEnd; ++LocationIterator) {
+ int LineNumber =
+ SourceMgr->getSpellingLineNumber(LocationIterator->getBegin());
+ Edits[LineNumber] = std::make_pair(*LocationIterator, "");
+ SourceLocationIteratorEnd =
+ std::remove(SourceLocationIterator, SourceLocationIteratorEnd,
+ *LocationIterator);
+ }
+
+ if (FirstLocation == *SourceLocationIterator) {
+ // Do nothing except move to the next source Location (Location of an
+ // inclusion in the original, unchanged source file).
+ ++SourceLocationIterator;
+ continue;
+ }
+
+ // Add (or append to) the replacement text for this line in source file.
+ int LineNumber =
+ SourceMgr->getSpellingLineNumber(SourceLocationIterator->getBegin());
+ if (Edits.find(LineNumber) == Edits.end()) {
+ Edits[LineNumber].first =
+ SourceRange(SourceLocationIterator->getBegin());
+ }
+ StringRef SourceText = Lexer::getSourceText(
+ CharSourceRange::getCharRange(FirstLocation), *SourceMgr, *LangOpts);
+ Edits[LineNumber].second.append(SourceText.data(), SourceText.size());
+ }
+
+ // Clear the bucket.
+ IncludeBucket[IncludeKind].clear();
+ }
+
+ // Go through the single-line Edits and combine them into blocks of Edits.
+ int CurrentEndLine = 0;
+ SourceRange CurrentRange;
+ std::string CurrentText;
+ std::vector<FixItHint> Fixes;
+ for (const auto &LineEdit : Edits) {
+ // If the current edit is on the next line after the previous edit, add it
+ // to the current block edit.
+ if (LineEdit.first == CurrentEndLine + 1 &&
+ CurrentRange.getBegin() != CurrentRange.getEnd()) {
+ SourceRange EditRange = LineEdit.second.first;
+ if (EditRange.getBegin() != EditRange.getEnd()) {
+ ++CurrentEndLine;
+ CurrentRange.setEnd(EditRange.getEnd());
+ }
+ CurrentText += LineEdit.second.second;
+ // Otherwise report the current block edit and start a new block.
+ } else {
+ if (CurrentEndLine) {
+ Fixes.push_back(FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(CurrentRange), CurrentText));
+ }
+
+ CurrentEndLine = LineEdit.first;
+ CurrentRange = LineEdit.second.first;
+ CurrentText = LineEdit.second.second;
+ }
+ }
+ // Finally, report the current block edit if there is one.
+ if (CurrentEndLine) {
+ Fixes.push_back(FixItHint::CreateReplacement(
+ CharSourceRange::getCharRange(CurrentRange), CurrentText));
+ }
+
+ // Reset the remaining internal state.
+ SourceLocations.clear();
+ IncludeLocations.clear();
+ return Fixes;
+}
+
+IncludeSorter::IncludeStyle
+IncludeSorter::parseIncludeStyle(const std::string &Value) {
+ return Value == "llvm" ? IS_LLVM : IS_Google;
+}
+
+StringRef IncludeSorter::toString(IncludeStyle Style) {
+ return Style == IS_LLVM ? "llvm" : "google";
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/IncludeSorter.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/IncludeSorter.h
new file mode 100644
index 0000000..07fa293
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/IncludeSorter.h
@@ -0,0 +1,86 @@
+//===------------ IncludeSorter.h - clang-tidy ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDESORTER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDESORTER_H
+
+#include "../ClangTidy.h"
+#include <string>
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+/// Class used by ``IncludeInserterCallback`` to record the names of the
+/// inclusions in a given source file being processed and generate the necessary
+/// commands to sort the inclusions according to the precedence encoded in
+/// ``IncludeKinds``.
+class IncludeSorter {
+public:
+ /// Supported include styles.
+ enum IncludeStyle { IS_LLVM = 0, IS_Google = 1 };
+
+ /// Converts "llvm" to ``IS_LLVM``, otherwise returns ``IS_Google``.
+ static IncludeStyle parseIncludeStyle(const std::string &Value);
+
+ /// Converts ``IncludeStyle`` to string representation.
+ static StringRef toString(IncludeStyle Style);
+
+ /// The classifications of inclusions, in the order they should be sorted.
+ enum IncludeKinds {
+ IK_MainTUInclude = 0, ///< e.g. ``#include "foo.h"`` when editing foo.cc
+ IK_CSystemInclude = 1, ///< e.g. ``#include <stdio.h>``
+ IK_CXXSystemInclude = 2, ///< e.g. ``#include <vector>``
+ IK_NonSystemInclude = 3, ///< e.g. ``#include "bar.h"``
+ IK_InvalidInclude = 4 ///< total number of valid ``IncludeKind``s
+ };
+
+ /// ``IncludeSorter`` constructor; takes the FileID and name of the file to be
+ /// processed by the sorter.
+ IncludeSorter(const SourceManager *SourceMgr, const LangOptions *LangOpts,
+ const FileID FileID, StringRef FileName, IncludeStyle Style);
+
+ /// Returns the ``SourceManager``-specific file ID for the file being handled
+ /// by the sorter.
+ const FileID current_FileID() const { return CurrentFileID; }
+
+ /// Adds the given include directive to the sorter.
+ void AddInclude(StringRef FileName, bool IsAngled,
+ SourceLocation HashLocation, SourceLocation EndLocation);
+
+ /// Returns the edits needed to sort the current set of includes and reset the
+ /// internal state (so that different blocks of includes are sorted separately
+ /// within the same file).
+ std::vector<FixItHint> GetEdits();
+
+ /// Creates a quoted inclusion directive in the right sort order. Returns None
+ /// on error or if header inclusion directive for header already exists.
+ Optional<FixItHint> CreateIncludeInsertion(StringRef FileName, bool IsAngled);
+
+private:
+ typedef SmallVector<SourceRange, 1> SourceRangeVector;
+
+ const SourceManager *SourceMgr;
+ const LangOptions *LangOpts;
+ const IncludeStyle Style;
+ FileID CurrentFileID;
+ /// The file name stripped of common suffixes.
+ StringRef CanonicalFile;
+ /// Locations of visited include directives.
+ SourceRangeVector SourceLocations;
+ /// Mapping from file name to #include locations.
+ llvm::StringMap<SourceRangeVector> IncludeLocations;
+ /// Includes sorted into buckets.
+ SmallVector<std::string, 1> IncludeBucket[IK_InvalidInclude];
+};
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDESORTER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
new file mode 100644
index 0000000..d027219
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
@@ -0,0 +1,41 @@
+//===--- LexerUtils.cpp - clang-tidy---------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LexerUtils.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+namespace lexer {
+
+Token getPreviousToken(const ASTContext &Context, SourceLocation Location,
+ bool SkipComments) {
+ const auto &SourceManager = Context.getSourceManager();
+ Token Token;
+ Token.setKind(tok::unknown);
+ Location = Location.getLocWithOffset(-1);
+ auto StartOfFile =
+ SourceManager.getLocForStartOfFile(SourceManager.getFileID(Location));
+ while (Location != StartOfFile) {
+ Location = Lexer::GetBeginningOfToken(Location, SourceManager,
+ Context.getLangOpts());
+ if (!Lexer::getRawToken(Location, Token, SourceManager,
+ Context.getLangOpts()) &&
+ (!SkipComments || !Token.is(tok::comment))) {
+ break;
+ }
+ Location = Location.getLocWithOffset(-1);
+ }
+ return Token;
+}
+
+} // namespace lexer
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/LexerUtils.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/LexerUtils.h
new file mode 100644
index 0000000..f7bcd6f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/LexerUtils.h
@@ -0,0 +1,30 @@
+//===--- LexerUtils.h - clang-tidy-------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_LEXER_UTILS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_LEXER_UTILS_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+namespace lexer {
+
+/// Returns previous token or ``tok::unknown`` if not found.
+Token getPreviousToken(const ASTContext &Context, SourceLocation Location,
+ bool SkipComments = true);
+
+} // namespace lexer
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_LEXER_UTILS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/Matchers.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/Matchers.h
new file mode 100644
index 0000000..aeb639f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/Matchers.h
@@ -0,0 +1,55 @@
+//===--- Matchers.h - clang-tidy-------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H
+
+#include "TypeTraits.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+namespace clang {
+namespace tidy {
+namespace matchers {
+
+AST_MATCHER(BinaryOperator, isAssignmentOperator) {
+ return Node.isAssignmentOp();
+}
+
+AST_MATCHER(BinaryOperator, isRelationalOperator) {
+ return Node.isRelationalOp();
+}
+
+AST_MATCHER(BinaryOperator, isEqualityOperator) { return Node.isEqualityOp(); }
+
+AST_MATCHER(BinaryOperator, isComparisonOperator) {
+ return Node.isComparisonOp();
+}
+
+AST_MATCHER(QualType, isExpensiveToCopy) {
+ llvm::Optional<bool> IsExpensive =
+ utils::type_traits::isExpensiveToCopy(Node, Finder->getASTContext());
+ return IsExpensive && *IsExpensive;
+}
+
+AST_MATCHER(RecordDecl, isTriviallyDefaultConstructible) {
+ return utils::type_traits::recordIsTriviallyDefaultConstructible(
+ Node, Finder->getASTContext());
+}
+
+// Returns QualType matcher for references to const.
+AST_MATCHER_FUNCTION(ast_matchers::TypeMatcher, isReferenceToConst) {
+ using namespace ast_matchers;
+ return referenceType(pointee(qualType(isConstQualified())));
+}
+
+} // namespace matchers
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_MATCHERS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/NamespaceAliaser.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/NamespaceAliaser.cpp
new file mode 100644
index 0000000..1a5120d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/NamespaceAliaser.cpp
@@ -0,0 +1,97 @@
+//===---------- NamespaceAliaser.cpp - clang-tidy -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NamespaceAliaser.h"
+
+#include "ASTUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+namespace clang {
+namespace tidy {
+namespace utils {
+
+using namespace ast_matchers;
+
+NamespaceAliaser::NamespaceAliaser(const SourceManager &SourceMgr)
+ : SourceMgr(SourceMgr) {}
+
+AST_MATCHER_P(NamespaceAliasDecl, hasTargetNamespace,
+ ast_matchers::internal::Matcher<NamespaceDecl>, innerMatcher) {
+ return innerMatcher.matches(*Node.getNamespace(), Finder, Builder);
+}
+
+Optional<FixItHint>
+NamespaceAliaser::createAlias(ASTContext &Context, const Stmt &Statement,
+ StringRef Namespace,
+ const std::vector<std::string> &Abbreviations) {
+ const FunctionDecl *Function = getSurroundingFunction(Context, Statement);
+ if (!Function || !Function->hasBody())
+ return None;
+
+ if (AddedAliases[Function].count(Namespace.str()) != 0)
+ return None;
+
+ // FIXME: Doesn't consider the order of declarations.
+ // If we accidentially pick an alias defined later in the function,
+ // the output won't compile.
+ // FIXME: Also doesn't consider file or class-scope aliases.
+
+ const auto *ExistingAlias = selectFirst<NamedDecl>(
+ "alias",
+ match(functionDecl(hasBody(compoundStmt(has(declStmt(
+ has(namespaceAliasDecl(hasTargetNamespace(hasName(Namespace)))
+ .bind("alias"))))))),
+ *Function, Context));
+
+ if (ExistingAlias != nullptr) {
+ AddedAliases[Function][Namespace.str()] = ExistingAlias->getName().str();
+ return None;
+ }
+
+ for (const auto &Abbreviation : Abbreviations) {
+ DeclarationMatcher ConflictMatcher = namedDecl(hasName(Abbreviation));
+ const auto HasConflictingChildren =
+ !match(findAll(ConflictMatcher), *Function, Context).empty();
+ const auto HasConflictingAncestors =
+ !match(functionDecl(hasAncestor(decl(has(ConflictMatcher)))), *Function,
+ Context)
+ .empty();
+ if (HasConflictingAncestors || HasConflictingChildren)
+ continue;
+
+ std::string Declaration =
+ (llvm::Twine("\nnamespace ") + Abbreviation + " = " + Namespace + ";")
+ .str();
+ SourceLocation Loc =
+ Lexer::getLocForEndOfToken(Function->getBody()->getLocStart(), 0,
+ SourceMgr, Context.getLangOpts());
+ AddedAliases[Function][Namespace.str()] = Abbreviation;
+ return FixItHint::CreateInsertion(Loc, Declaration);
+ }
+
+ return None;
+}
+
+std::string NamespaceAliaser::getNamespaceName(ASTContext &Context,
+ const Stmt &Statement,
+ StringRef Namespace) const {
+ const auto *Function = getSurroundingFunction(Context, Statement);
+ auto FunctionAliases = AddedAliases.find(Function);
+ if (FunctionAliases != AddedAliases.end()) {
+ if (FunctionAliases->second.count(Namespace) != 0) {
+ return FunctionAliases->second.find(Namespace)->getValue();
+ }
+ }
+ return Namespace.str();
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/NamespaceAliaser.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/NamespaceAliaser.h
new file mode 100644
index 0000000..e56d69d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/NamespaceAliaser.h
@@ -0,0 +1,52 @@
+//===---------- NamespaceAliaser.h - clang-tidy ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_NAMESPACEALIASER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_NAMESPACEALIASER_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include <map>
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+// This class creates function-level namespace aliases.
+class NamespaceAliaser {
+public:
+ explicit NamespaceAliaser(const SourceManager &SourceMgr);
+ // Adds a namespace alias for \p Namespace valid near \p
+ // Statement. Picks the first available name from \p Abbreviations.
+ // Returns ``llvm::None`` if an alias already exists or there is an error.
+ llvm::Optional<FixItHint>
+ createAlias(ASTContext &Context, const Stmt &Statement,
+ llvm::StringRef Namespace,
+ const std::vector<std::string> &Abbreviations);
+
+ // Get an alias name for \p Namespace valid at \p Statement. Returns \p
+ // Namespace if there is no alias.
+ std::string getNamespaceName(ASTContext &Context, const Stmt &Statement,
+ llvm::StringRef Namespace) const;
+
+private:
+ const SourceManager &SourceMgr;
+ llvm::DenseMap<const FunctionDecl *, llvm::StringMap<std::string>>
+ AddedAliases;
+};
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_NAMESPACEALIASER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/OptionsUtils.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/OptionsUtils.cpp
new file mode 100644
index 0000000..0b1d27d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/OptionsUtils.cpp
@@ -0,0 +1,38 @@
+//===--- DanglingHandleCheck.cpp - clang-tidy------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OptionsUtils.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+namespace options {
+
+static const char StringsDelimiter[] = ";";
+
+std::vector<std::string> parseStringList(StringRef Option) {
+ SmallVector<StringRef, 4> Names;
+ Option.split(Names, StringsDelimiter);
+ std::vector<std::string> Result;
+ for (StringRef &Name : Names) {
+ Name = Name.trim();
+ if (!Name.empty())
+ Result.push_back(Name);
+ }
+ return Result;
+}
+
+std::string serializeStringList(ArrayRef<std::string> Strings) {
+ return llvm::join(Strings.begin(), Strings.end(), StringsDelimiter);
+}
+
+} // namespace options
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/OptionsUtils.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/OptionsUtils.h
new file mode 100644
index 0000000..d822ac9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/OptionsUtils.h
@@ -0,0 +1,32 @@
+//===--- DanglingHandleCheck.h - clang-tidy----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_OPTIONUTILS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_OPTIONUTILS_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+namespace options {
+
+/// \brief Parse a semicolon separated list of strings.
+std::vector<std::string> parseStringList(StringRef Option);
+
+/// \brief Serialize a sequence of names that can be parsed by
+/// ``parseStringList``.
+std::string serializeStringList(ArrayRef<std::string> Strings);
+
+} // namespace options
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_OPTIONUTILS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp
new file mode 100644
index 0000000..2cdc506
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp
@@ -0,0 +1,150 @@
+//===--- TypeTraits.cpp - clang-tidy---------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TypeTraits.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+namespace type_traits {
+
+namespace {
+
+bool classHasTrivialCopyAndDestroy(QualType Type) {
+ auto *Record = Type->getAsCXXRecordDecl();
+ return Record && Record->hasDefinition() &&
+ !Record->hasNonTrivialCopyConstructor() &&
+ !Record->hasNonTrivialDestructor();
+}
+
+bool hasDeletedCopyConstructor(QualType Type) {
+ auto *Record = Type->getAsCXXRecordDecl();
+ if (!Record || !Record->hasDefinition())
+ return false;
+ for (const auto *Constructor : Record->ctors()) {
+ if (Constructor->isCopyConstructor() && Constructor->isDeleted())
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+llvm::Optional<bool> isExpensiveToCopy(QualType Type,
+ const ASTContext &Context) {
+ if (Type->isDependentType() || Type->isIncompleteType())
+ return llvm::None;
+ return !Type.isTriviallyCopyableType(Context) &&
+ !classHasTrivialCopyAndDestroy(Type) &&
+ !hasDeletedCopyConstructor(Type) &&
+ !Type->isObjCLifetimeType();
+}
+
+bool recordIsTriviallyDefaultConstructible(const RecordDecl &RecordDecl,
+ const ASTContext &Context) {
+ const auto *ClassDecl = dyn_cast<CXXRecordDecl>(&RecordDecl);
+ // Non-C++ records are always trivially constructible.
+ if (!ClassDecl)
+ return true;
+ // A class with a user-provided default constructor is not trivially
+ // constructible.
+ if (ClassDecl->hasUserProvidedDefaultConstructor())
+ return false;
+ // A polymorphic class is not trivially constructible
+ if (ClassDecl->isPolymorphic())
+ return false;
+ // A class is trivially constructible if it has a trivial default constructor.
+ if (ClassDecl->hasTrivialDefaultConstructor())
+ return true;
+
+ // If all its fields are trivially constructible and have no default
+ // initializers.
+ for (const FieldDecl *Field : ClassDecl->fields()) {
+ if (Field->hasInClassInitializer())
+ return false;
+ if (!isTriviallyDefaultConstructible(Field->getType(), Context))
+ return false;
+ }
+ // If all its direct bases are trivially constructible.
+ for (const CXXBaseSpecifier &Base : ClassDecl->bases()) {
+ if (!isTriviallyDefaultConstructible(Base.getType(), Context))
+ return false;
+ if (Base.isVirtual())
+ return false;
+ }
+
+ return true;
+}
+
+// Based on QualType::isTrivial.
+bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) {
+ if (Type.isNull())
+ return false;
+
+ if (Type->isArrayType())
+ return isTriviallyDefaultConstructible(Context.getBaseElementType(Type),
+ Context);
+
+ // Return false for incomplete types after skipping any incomplete array
+ // types which are expressly allowed by the standard and thus our API.
+ if (Type->isIncompleteType())
+ return false;
+
+ if (Context.getLangOpts().ObjCAutoRefCount) {
+ switch (Type.getObjCLifetime()) {
+ case Qualifiers::OCL_ExplicitNone:
+ return true;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Autoreleasing:
+ return false;
+
+ case Qualifiers::OCL_None:
+ if (Type->isObjCLifetimeType())
+ return false;
+ break;
+ }
+ }
+
+ QualType CanonicalType = Type.getCanonicalType();
+ if (CanonicalType->isDependentType())
+ return false;
+
+ // As an extension, Clang treats vector types as Scalar types.
+ if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
+ return true;
+
+ if (const auto *RT = CanonicalType->getAs<RecordType>()) {
+ return recordIsTriviallyDefaultConstructible(*RT->getDecl(), Context);
+ }
+
+ // No other types can match.
+ return false;
+}
+
+bool hasNonTrivialMoveConstructor(QualType Type) {
+ auto *Record = Type->getAsCXXRecordDecl();
+ return Record && Record->hasDefinition() &&
+ Record->hasNonTrivialMoveConstructor();
+}
+
+bool hasNonTrivialMoveAssignment(QualType Type) {
+ auto *Record = Type->getAsCXXRecordDecl();
+ return Record && Record->hasDefinition() &&
+ Record->hasNonTrivialMoveAssignment();
+}
+
+} // namespace type_traits
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/TypeTraits.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/TypeTraits.h
new file mode 100644
index 0000000..ae0b3f0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/TypeTraits.h
@@ -0,0 +1,43 @@
+//===--- TypeTraits.h - clang-tidy-------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_TYPETRAITS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_TYPETRAITS_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Type.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+namespace type_traits {
+
+/// Returns `true` if `Type` is expensive to copy.
+llvm::Optional<bool> isExpensiveToCopy(QualType Type,
+ const ASTContext &Context);
+
+/// Returns `true` if `Type` is trivially default constructible.
+bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context);
+
+/// Returns `true` if `RecordDecl` is trivially default constructible.
+bool recordIsTriviallyDefaultConstructible(const RecordDecl &RecordDecl,
+ const ASTContext &Context);
+
+/// Returns true if `Type` has a non-trivial move constructor.
+bool hasNonTrivialMoveConstructor(QualType Type);
+
+/// Return true if `Type` has a non-trivial move assignment operator.
+bool hasNonTrivialMoveAssignment(QualType Type);
+
+} // type_traits
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_TYPETRAITS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/UsingInserter.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/UsingInserter.cpp
new file mode 100644
index 0000000..e7200c9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/UsingInserter.cpp
@@ -0,0 +1,89 @@
+//===---------- UsingInserter.cpp - clang-tidy ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UsingInserter.h"
+
+#include "ASTUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+using namespace ast_matchers;
+
+static StringRef getUnqualifiedName(StringRef QualifiedName) {
+ size_t LastSeparatorPos = QualifiedName.rfind("::");
+ if (LastSeparatorPos == StringRef::npos)
+ return QualifiedName;
+ return QualifiedName.drop_front(LastSeparatorPos + 2);
+}
+
+UsingInserter::UsingInserter(const SourceManager &SourceMgr)
+ : SourceMgr(SourceMgr) {}
+
+Optional<FixItHint> UsingInserter::createUsingDeclaration(
+ ASTContext &Context, const Stmt &Statement, StringRef QualifiedName) {
+ StringRef UnqualifiedName = getUnqualifiedName(QualifiedName);
+ const FunctionDecl *Function = getSurroundingFunction(Context, Statement);
+ if (!Function)
+ return None;
+
+ if (AddedUsing.count(std::make_pair(Function, QualifiedName.str())) != 0)
+ return None;
+
+ SourceLocation InsertLoc = Lexer::getLocForEndOfToken(
+ Function->getBody()->getLocStart(), 0, SourceMgr, Context.getLangOpts());
+
+ // Only use using declarations in the main file, not in includes.
+ if (SourceMgr.getFileID(InsertLoc) != SourceMgr.getMainFileID())
+ return None;
+
+ // FIXME: This declaration could be masked. Investigate if
+ // there is a way to avoid using Sema.
+ bool AlreadyHasUsingDecl =
+ !match(stmt(hasAncestor(decl(has(usingDecl(hasAnyUsingShadowDecl(
+ hasTargetDecl(hasName(QualifiedName.str())))))))),
+ Statement, Context)
+ .empty();
+ if (AlreadyHasUsingDecl) {
+ AddedUsing.emplace(NameInFunction(Function, QualifiedName.str()));
+ return None;
+ }
+ // Find conflicting declarations and references.
+ auto ConflictingDecl = namedDecl(hasName(UnqualifiedName));
+ bool HasConflictingDeclaration =
+ !match(findAll(ConflictingDecl), *Function, Context).empty();
+ bool HasConflictingDeclRef =
+ !match(findAll(declRefExpr(to(ConflictingDecl))), *Function, Context)
+ .empty();
+ if (HasConflictingDeclaration || HasConflictingDeclRef)
+ return None;
+
+ std::string Declaration =
+ (llvm::Twine("\nusing ") + QualifiedName + ";").str();
+
+ AddedUsing.emplace(std::make_pair(Function, QualifiedName.str()));
+ return FixItHint::CreateInsertion(InsertLoc, Declaration);
+}
+
+StringRef UsingInserter::getShortName(ASTContext &Context,
+ const Stmt &Statement,
+ StringRef QualifiedName) {
+ const FunctionDecl *Function = getSurroundingFunction(Context, Statement);
+ if (AddedUsing.count(NameInFunction(Function, QualifiedName.str())) != 0)
+ return getUnqualifiedName(QualifiedName);
+ return QualifiedName;
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/UsingInserter.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/UsingInserter.h
new file mode 100644
index 0000000..62108e4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/utils/UsingInserter.h
@@ -0,0 +1,50 @@
+//===---------- UsingInserter.h - clang-tidy ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_USINGINSERTER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_USINGINSERTER_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include <set>
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+// UsingInserter adds using declarations for |QualifiedName| to the surrounding
+// function.
+// This allows using a shorter name without clobbering other scopes.
+class UsingInserter {
+public:
+ UsingInserter(const SourceManager &SourceMgr);
+
+ // Creates a \p using declaration fixit. Returns ``llvm::None`` on error
+ // or if the using declaration already exists.
+ llvm::Optional<FixItHint>
+ createUsingDeclaration(ASTContext &Context, const Stmt &Statement,
+ llvm::StringRef QualifiedName);
+
+ // Returns the unqualified version of the name if there is an
+ // appropriate using declaration and the qualified name otherwise.
+ llvm::StringRef getShortName(ASTContext &Context, const Stmt &Statement,
+ llvm::StringRef QualifiedName);
+
+private:
+ typedef std::pair<const FunctionDecl *, std::string> NameInFunction;
+ const SourceManager &SourceMgr;
+ std::set<NameInFunction> AddedUsing;
+};
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_USINGINSERTER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/zircon/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/zircon/CMakeLists.txt
new file mode 100644
index 0000000..7aa7cd3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/zircon/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyZirconModule
+ TemporaryObjectsCheck.cpp
+ ZirconTidyModule.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangTidy
+ clangTidyUtils
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.cpp
new file mode 100644
index 0000000..5fff67b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.cpp
@@ -0,0 +1,60 @@
+//===--- TemporaryObjectsCheck.cpp - clang-tidy----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TemporaryObjectsCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include <string>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace zircon {
+
+AST_MATCHER_P(CXXRecordDecl, matchesAnyName, ArrayRef<std::string>, Names) {
+ std::string QualifiedName = Node.getQualifiedNameAsString();
+ return llvm::any_of(Names,
+ [&](StringRef Name) { return QualifiedName == Name; });
+}
+
+void TemporaryObjectsCheck::registerMatchers(MatchFinder *Finder) {
+ // Matcher for default constructors.
+ Finder->addMatcher(
+ cxxTemporaryObjectExpr(hasDeclaration(cxxConstructorDecl(hasParent(
+ cxxRecordDecl(matchesAnyName(Names))))))
+ .bind("temps"),
+ this);
+
+ // Matcher for user-defined constructors.
+ Finder->addMatcher(
+ cxxConstructExpr(allOf(hasParent(cxxFunctionalCastExpr()),
+ hasDeclaration(cxxConstructorDecl(hasParent(
+ cxxRecordDecl(matchesAnyName(Names)))))))
+ .bind("temps"),
+ this);
+}
+
+void TemporaryObjectsCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *D = Result.Nodes.getNodeAs<CXXConstructExpr>("temps"))
+ diag(D->getLocation(),
+ "creating a temporary object of type %q0 is prohibited")
+ << D->getConstructor()->getParent();
+}
+
+void TemporaryObjectsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "Names", utils::options::serializeStringList(Names));
+}
+
+} // namespace zircon
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.h b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.h
new file mode 100644
index 0000000..302ef72
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.h
@@ -0,0 +1,42 @@
+//===--- TemporaryObjectsCheck.h - clang-tidy------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ZIRCON_TEMPORARYOBJECTSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ZIRCON_TEMPORARYOBJECTSCHECK_H
+
+#include "../ClangTidy.h"
+#include "../utils/OptionsUtils.h"
+
+namespace clang {
+namespace tidy {
+namespace zircon {
+
+/// Construction of specific temporary objects in the Zircon kernel is
+/// discouraged.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/zircon-temporary-objects.html
+class TemporaryObjectsCheck : public ClangTidyCheck {
+public:
+ TemporaryObjectsCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ Names(utils::options::parseStringList(Options.get("Names", ""))) {}
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ std::vector<std::string> Names;
+};
+
+} // namespace zircon
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ZIRCON_TEMPORARYOBJECTSCHECK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clang-tidy/zircon/ZirconTidyModule.cpp b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/zircon/ZirconTidyModule.cpp
new file mode 100644
index 0000000..3e53c23
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clang-tidy/zircon/ZirconTidyModule.cpp
@@ -0,0 +1,40 @@
+//===--- ZirconTidyModule.cpp - clang-tidy---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "TemporaryObjectsCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace zircon {
+
+/// This module is for Zircon-specific checks.
+class ZirconModule : public ClangTidyModule {
+public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<TemporaryObjectsCheck>(
+ "zircon-temporary-objects");
+ }
+};
+
+// Register the ZirconTidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<ZirconModule>
+ X("zircon-module", "Adds Zircon kernel checks.");
+} // namespace zircon
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the ZirconModule.
+volatile int ZirconModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/AST.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/AST.cpp
new file mode 100644
index 0000000..ec1862c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/AST.cpp
@@ -0,0 +1,57 @@
+//===--- AST.cpp - Utility AST functions -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AST.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/Basic/SourceManager.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+SourceLocation findNameLoc(const clang::Decl* D) {
+ const auto& SM = D->getASTContext().getSourceManager();
+ // FIXME: Revisit the strategy, the heuristic is limitted when handling
+ // macros, we should use the location where the whole definition occurs.
+ SourceLocation SpellingLoc = SM.getSpellingLoc(D->getLocation());
+ if (D->getLocation().isMacroID()) {
+ std::string PrintLoc = SpellingLoc.printToString(SM);
+ if (llvm::StringRef(PrintLoc).startswith("<scratch") ||
+ llvm::StringRef(PrintLoc).startswith("<command line>")) {
+ // We use the expansion location for the following symbols, as spelling
+ // locations of these symbols are not interesting to us:
+ // * symbols formed via macro concatenation, the spelling location will
+ // be "<scratch space>"
+ // * symbols controlled and defined by a compile command-line option
+ // `-DName=foo`, the spelling location will be "<command line>".
+ SpellingLoc = SM.getExpansionRange(D->getLocation()).getBegin();
+ }
+ }
+ return SpellingLoc;
+}
+
+std::string printQualifiedName(const NamedDecl &ND) {
+ std::string QName;
+ llvm::raw_string_ostream OS(QName);
+ PrintingPolicy Policy(ND.getASTContext().getLangOpts());
+ // Note that inline namespaces are treated as transparent scopes. This
+ // reflects the way they're most commonly used for lookup. Ideally we'd
+ // include them, but at query time it's hard to find all the inline
+ // namespaces to query: the preamble doesn't have a dedicated list.
+ Policy.SuppressUnwrittenScope = true;
+ ND.printQualifiedName(OS, Policy);
+ OS.flush();
+ assert(!StringRef(QName).startswith("::"));
+ return QName;
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/AST.h b/src/third_party/llvm-project/clang-tools-extra/clangd/AST.h
new file mode 100644
index 0000000..cb47c10
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/AST.h
@@ -0,0 +1,39 @@
+//===--- AST.h - Utility AST functions -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Various code that examines C++ source code using AST.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_AST_H_
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_AST_H_
+
+#include "clang/AST/Decl.h"
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+class SourceManager;
+class Decl;
+
+namespace clangd {
+
+/// Find the identifier source location of the given D.
+///
+/// The returned location is usually the spelling location where the name of the
+/// decl occurs in the code.
+SourceLocation findNameLoc(const clang::Decl *D);
+
+/// Returns the qualified name of ND. The scope doesn't contain unwritten scopes
+/// like inline namespaces.
+std::string printQualifiedName(const NamedDecl &ND);
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_AST_H_
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clangd/CMakeLists.txt
new file mode 100644
index 0000000..33a6e84
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/CMakeLists.txt
@@ -0,0 +1,72 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+set(CLANGD_ATOMIC_LIB "")
+if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
+ list(APPEND CLANGD_ATOMIC_LIB "atomic")
+endif()
+
+add_clang_library(clangDaemon
+ AST.cpp
+ ClangdLSPServer.cpp
+ ClangdServer.cpp
+ ClangdUnit.cpp
+ CodeComplete.cpp
+ CodeCompletionStrings.cpp
+ Compiler.cpp
+ Context.cpp
+ Diagnostics.cpp
+ DraftStore.cpp
+ FindSymbols.cpp
+ FileDistance.cpp
+ FuzzyMatch.cpp
+ GlobalCompilationDatabase.cpp
+ Headers.cpp
+ JSONRPCDispatcher.cpp
+ Logger.cpp
+ Protocol.cpp
+ ProtocolHandlers.cpp
+ Quality.cpp
+ SourceCode.cpp
+ Threading.cpp
+ Trace.cpp
+ TUScheduler.cpp
+ URI.cpp
+ XRefs.cpp
+
+ index/CanonicalIncludes.cpp
+ index/FileIndex.cpp
+ index/Index.cpp
+ index/MemIndex.cpp
+ index/Merge.cpp
+ index/SymbolCollector.cpp
+ index/SymbolYAML.cpp
+
+ index/dex/Iterator.cpp
+ index/dex/Trigram.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangDriver
+ clangFormat
+ clangFrontend
+ clangIndex
+ clangLex
+ clangSema
+ clangSerialization
+ clangTooling
+ clangToolingCore
+ clangToolingInclusions
+ clangToolingRefactor
+ ${LLVM_PTHREAD_LIB}
+ ${CLANGD_ATOMIC_LIB}
+ )
+
+if( LLVM_LIB_FUZZING_ENGINE OR LLVM_USE_SANITIZE_COVERAGE )
+ add_subdirectory(fuzzer)
+endif()
+add_subdirectory(tool)
+add_subdirectory(global-symbol-builder)
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdLSPServer.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdLSPServer.cpp
new file mode 100644
index 0000000..7374c6d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -0,0 +1,506 @@
+//===--- ClangdLSPServer.cpp - LSP server ------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "ClangdLSPServer.h"
+#include "Diagnostics.h"
+#include "JSONRPCDispatcher.h"
+#include "SourceCode.h"
+#include "URI.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Path.h"
+
+using namespace clang::clangd;
+using namespace clang;
+using namespace llvm;
+
+namespace {
+
+/// \brief Supports a test URI scheme with relaxed constraints for lit tests.
+/// The path in a test URI will be combined with a platform-specific fake
+/// directory to form an absolute path. For example, test:///a.cpp is resolved
+/// C:\clangd-test\a.cpp on Windows and /clangd-test/a.cpp on Unix.
+class TestScheme : public URIScheme {
+public:
+ llvm::Expected<std::string>
+ getAbsolutePath(llvm::StringRef /*Authority*/, llvm::StringRef Body,
+ llvm::StringRef /*HintPath*/) const override {
+ using namespace llvm::sys;
+ // Still require "/" in body to mimic file scheme, as we want lengths of an
+ // equivalent URI in both schemes to be the same.
+ if (!Body.startswith("/"))
+ return llvm::make_error<llvm::StringError>(
+ "Expect URI body to be an absolute path starting with '/': " + Body,
+ llvm::inconvertibleErrorCode());
+ Body = Body.ltrim('/');
+#ifdef _WIN32
+ constexpr char TestDir[] = "C:\\clangd-test";
+#else
+ constexpr char TestDir[] = "/clangd-test";
+#endif
+ llvm::SmallVector<char, 16> Path(Body.begin(), Body.end());
+ path::native(Path);
+ auto Err = fs::make_absolute(TestDir, Path);
+ if (Err)
+ llvm_unreachable("Failed to make absolute path in test scheme.");
+ return std::string(Path.begin(), Path.end());
+ }
+
+ llvm::Expected<URI>
+ uriFromAbsolutePath(llvm::StringRef AbsolutePath) const override {
+ llvm_unreachable("Clangd must never create a test URI.");
+ }
+};
+
+static URISchemeRegistry::Add<TestScheme>
+ X("test", "Test scheme for clangd lit tests.");
+
+SymbolKindBitset defaultSymbolKinds() {
+ SymbolKindBitset Defaults;
+ for (size_t I = SymbolKindMin; I <= static_cast<size_t>(SymbolKind::Array);
+ ++I)
+ Defaults.set(I);
+ return Defaults;
+}
+
+} // namespace
+
+void ClangdLSPServer::onInitialize(InitializeParams &Params) {
+ if (Params.initializationOptions)
+ applyConfiguration(*Params.initializationOptions);
+
+ if (Params.rootUri && *Params.rootUri)
+ Server.setRootPath(Params.rootUri->file());
+ else if (Params.rootPath && !Params.rootPath->empty())
+ Server.setRootPath(*Params.rootPath);
+
+ CCOpts.EnableSnippets =
+ Params.capabilities.textDocument.completion.completionItem.snippetSupport;
+
+ if (Params.capabilities.workspace && Params.capabilities.workspace->symbol &&
+ Params.capabilities.workspace->symbol->symbolKind) {
+ for (SymbolKind Kind :
+ *Params.capabilities.workspace->symbol->symbolKind->valueSet) {
+ SupportedSymbolKinds.set(static_cast<size_t>(Kind));
+ }
+ }
+
+ reply(json::Object{
+ {{"capabilities",
+ json::Object{
+ {"textDocumentSync", (int)TextDocumentSyncKind::Incremental},
+ {"documentFormattingProvider", true},
+ {"documentRangeFormattingProvider", true},
+ {"documentOnTypeFormattingProvider",
+ json::Object{
+ {"firstTriggerCharacter", "}"},
+ {"moreTriggerCharacter", {}},
+ }},
+ {"codeActionProvider", true},
+ {"completionProvider",
+ json::Object{
+ {"resolveProvider", false},
+ {"triggerCharacters", {".", ">", ":"}},
+ }},
+ {"signatureHelpProvider",
+ json::Object{
+ {"triggerCharacters", {"(", ","}},
+ }},
+ {"definitionProvider", true},
+ {"documentHighlightProvider", true},
+ {"hoverProvider", true},
+ {"renameProvider", true},
+ {"documentSymbolProvider", true},
+ {"workspaceSymbolProvider", true},
+ {"executeCommandProvider",
+ json::Object{
+ {"commands", {ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND}},
+ }},
+ }}}});
+}
+
+void ClangdLSPServer::onShutdown(ShutdownParams &Params) {
+ // Do essentially nothing, just say we're ready to exit.
+ ShutdownRequestReceived = true;
+ reply(nullptr);
+}
+
+void ClangdLSPServer::onExit(ExitParams &Params) { IsDone = true; }
+
+void ClangdLSPServer::onDocumentDidOpen(DidOpenTextDocumentParams &Params) {
+ PathRef File = Params.textDocument.uri.file();
+ if (Params.metadata && !Params.metadata->extraFlags.empty()) {
+ NonCachedCDB.setExtraFlagsForFile(File,
+ std::move(Params.metadata->extraFlags));
+ CDB.invalidate(File);
+ }
+
+ std::string &Contents = Params.textDocument.text;
+
+ DraftMgr.addDraft(File, Contents);
+ Server.addDocument(File, Contents, WantDiagnostics::Yes);
+}
+
+void ClangdLSPServer::onDocumentDidChange(DidChangeTextDocumentParams &Params) {
+ auto WantDiags = WantDiagnostics::Auto;
+ if (Params.wantDiagnostics.hasValue())
+ WantDiags = Params.wantDiagnostics.getValue() ? WantDiagnostics::Yes
+ : WantDiagnostics::No;
+
+ PathRef File = Params.textDocument.uri.file();
+ llvm::Expected<std::string> Contents =
+ DraftMgr.updateDraft(File, Params.contentChanges);
+ if (!Contents) {
+ // If this fails, we are most likely going to be not in sync anymore with
+ // the client. It is better to remove the draft and let further operations
+ // fail rather than giving wrong results.
+ DraftMgr.removeDraft(File);
+ Server.removeDocument(File);
+ CDB.invalidate(File);
+ elog("Failed to update {0}: {1}", File, Contents.takeError());
+ return;
+ }
+
+ Server.addDocument(File, *Contents, WantDiags);
+}
+
+void ClangdLSPServer::onFileEvent(DidChangeWatchedFilesParams &Params) {
+ Server.onFileEvent(Params);
+}
+
+void ClangdLSPServer::onCommand(ExecuteCommandParams &Params) {
+ auto ApplyEdit = [](WorkspaceEdit WE) {
+ ApplyWorkspaceEditParams Edit;
+ Edit.edit = std::move(WE);
+ // We don't need the response so id == 1 is OK.
+ // Ideally, we would wait for the response and if there is no error, we
+ // would reply success/failure to the original RPC.
+ call("workspace/applyEdit", Edit);
+ };
+ if (Params.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND &&
+ Params.workspaceEdit) {
+ // The flow for "apply-fix" :
+ // 1. We publish a diagnostic, including fixits
+ // 2. The user clicks on the diagnostic, the editor asks us for code actions
+ // 3. We send code actions, with the fixit embedded as context
+ // 4. The user selects the fixit, the editor asks us to apply it
+ // 5. We unwrap the changes and send them back to the editor
+ // 6. The editor applies the changes (applyEdit), and sends us a reply (but
+ // we ignore it)
+
+ reply("Fix applied.");
+ ApplyEdit(*Params.workspaceEdit);
+ } else {
+ // We should not get here because ExecuteCommandParams would not have
+ // parsed in the first place and this handler should not be called. But if
+ // more commands are added, this will be here has a safe guard.
+ replyError(
+ ErrorCode::InvalidParams,
+ llvm::formatv("Unsupported command \"{0}\".", Params.command).str());
+ }
+}
+
+void ClangdLSPServer::onWorkspaceSymbol(WorkspaceSymbolParams &Params) {
+ Server.workspaceSymbols(
+ Params.query, CCOpts.Limit,
+ [this](llvm::Expected<std::vector<SymbolInformation>> Items) {
+ if (!Items)
+ return replyError(ErrorCode::InternalError,
+ llvm::toString(Items.takeError()));
+ for (auto &Sym : *Items)
+ Sym.kind = adjustKindToCapability(Sym.kind, SupportedSymbolKinds);
+
+ reply(json::Array(*Items));
+ });
+}
+
+void ClangdLSPServer::onRename(RenameParams &Params) {
+ Path File = Params.textDocument.uri.file();
+ llvm::Optional<std::string> Code = DraftMgr.getDraft(File);
+ if (!Code)
+ return replyError(ErrorCode::InvalidParams,
+ "onRename called for non-added file");
+
+ Server.rename(
+ File, Params.position, Params.newName,
+ [File, Code,
+ Params](llvm::Expected<std::vector<tooling::Replacement>> Replacements) {
+ if (!Replacements)
+ return replyError(ErrorCode::InternalError,
+ llvm::toString(Replacements.takeError()));
+
+ // Turn the replacements into the format specified by the Language
+ // Server Protocol. Fuse them into one big JSON array.
+ std::vector<TextEdit> Edits;
+ for (const auto &R : *Replacements)
+ Edits.push_back(replacementToEdit(*Code, R));
+ WorkspaceEdit WE;
+ WE.changes = {{Params.textDocument.uri.uri(), Edits}};
+ reply(WE);
+ });
+}
+
+void ClangdLSPServer::onDocumentDidClose(DidCloseTextDocumentParams &Params) {
+ PathRef File = Params.textDocument.uri.file();
+ DraftMgr.removeDraft(File);
+ Server.removeDocument(File);
+}
+
+void ClangdLSPServer::onDocumentOnTypeFormatting(
+ DocumentOnTypeFormattingParams &Params) {
+ auto File = Params.textDocument.uri.file();
+ auto Code = DraftMgr.getDraft(File);
+ if (!Code)
+ return replyError(ErrorCode::InvalidParams,
+ "onDocumentOnTypeFormatting called for non-added file");
+
+ auto ReplacementsOrError = Server.formatOnType(*Code, File, Params.position);
+ if (ReplacementsOrError)
+ reply(json::Array(replacementsToEdits(*Code, ReplacementsOrError.get())));
+ else
+ replyError(ErrorCode::UnknownErrorCode,
+ llvm::toString(ReplacementsOrError.takeError()));
+}
+
+void ClangdLSPServer::onDocumentRangeFormatting(
+ DocumentRangeFormattingParams &Params) {
+ auto File = Params.textDocument.uri.file();
+ auto Code = DraftMgr.getDraft(File);
+ if (!Code)
+ return replyError(ErrorCode::InvalidParams,
+ "onDocumentRangeFormatting called for non-added file");
+
+ auto ReplacementsOrError = Server.formatRange(*Code, File, Params.range);
+ if (ReplacementsOrError)
+ reply(json::Array(replacementsToEdits(*Code, ReplacementsOrError.get())));
+ else
+ replyError(ErrorCode::UnknownErrorCode,
+ llvm::toString(ReplacementsOrError.takeError()));
+}
+
+void ClangdLSPServer::onDocumentFormatting(DocumentFormattingParams &Params) {
+ auto File = Params.textDocument.uri.file();
+ auto Code = DraftMgr.getDraft(File);
+ if (!Code)
+ return replyError(ErrorCode::InvalidParams,
+ "onDocumentFormatting called for non-added file");
+
+ auto ReplacementsOrError = Server.formatFile(*Code, File);
+ if (ReplacementsOrError)
+ reply(json::Array(replacementsToEdits(*Code, ReplacementsOrError.get())));
+ else
+ replyError(ErrorCode::UnknownErrorCode,
+ llvm::toString(ReplacementsOrError.takeError()));
+}
+
+void ClangdLSPServer::onDocumentSymbol(DocumentSymbolParams &Params) {
+ Server.documentSymbols(
+ Params.textDocument.uri.file(),
+ [this](llvm::Expected<std::vector<SymbolInformation>> Items) {
+ if (!Items)
+ return replyError(ErrorCode::InvalidParams,
+ llvm::toString(Items.takeError()));
+ for (auto &Sym : *Items)
+ Sym.kind = adjustKindToCapability(Sym.kind, SupportedSymbolKinds);
+ reply(json::Array(*Items));
+ });
+}
+
+void ClangdLSPServer::onCodeAction(CodeActionParams &Params) {
+ // We provide a code action for each diagnostic at the requested location
+ // which has FixIts available.
+ auto Code = DraftMgr.getDraft(Params.textDocument.uri.file());
+ if (!Code)
+ return replyError(ErrorCode::InvalidParams,
+ "onCodeAction called for non-added file");
+
+ json::Array Commands;
+ for (Diagnostic &D : Params.context.diagnostics) {
+ for (auto &F : getFixes(Params.textDocument.uri.file(), D)) {
+ WorkspaceEdit WE;
+ std::vector<TextEdit> Edits(F.Edits.begin(), F.Edits.end());
+ WE.changes = {{Params.textDocument.uri.uri(), std::move(Edits)}};
+ Commands.push_back(json::Object{
+ {"title", llvm::formatv("Apply fix: {0}", F.Message)},
+ {"command", ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND},
+ {"arguments", {WE}},
+ });
+ }
+ }
+ reply(std::move(Commands));
+}
+
+void ClangdLSPServer::onCompletion(TextDocumentPositionParams &Params) {
+ Server.codeComplete(Params.textDocument.uri.file(), Params.position, CCOpts,
+ [this](llvm::Expected<CodeCompleteResult> List) {
+ if (!List)
+ return replyError(ErrorCode::InvalidParams,
+ llvm::toString(List.takeError()));
+ CompletionList LSPList;
+ LSPList.isIncomplete = List->HasMore;
+ for (const auto &R : List->Completions)
+ LSPList.items.push_back(R.render(CCOpts));
+ reply(std::move(LSPList));
+ });
+}
+
+void ClangdLSPServer::onSignatureHelp(TextDocumentPositionParams &Params) {
+ Server.signatureHelp(Params.textDocument.uri.file(), Params.position,
+ [](llvm::Expected<SignatureHelp> SignatureHelp) {
+ if (!SignatureHelp)
+ return replyError(
+ ErrorCode::InvalidParams,
+ llvm::toString(SignatureHelp.takeError()));
+ reply(*SignatureHelp);
+ });
+}
+
+void ClangdLSPServer::onGoToDefinition(TextDocumentPositionParams &Params) {
+ Server.findDefinitions(
+ Params.textDocument.uri.file(), Params.position,
+ [](llvm::Expected<std::vector<Location>> Items) {
+ if (!Items)
+ return replyError(ErrorCode::InvalidParams,
+ llvm::toString(Items.takeError()));
+ reply(json::Array(*Items));
+ });
+}
+
+void ClangdLSPServer::onSwitchSourceHeader(TextDocumentIdentifier &Params) {
+ llvm::Optional<Path> Result = Server.switchSourceHeader(Params.uri.file());
+ reply(Result ? URI::createFile(*Result).toString() : "");
+}
+
+void ClangdLSPServer::onDocumentHighlight(TextDocumentPositionParams &Params) {
+ Server.findDocumentHighlights(
+ Params.textDocument.uri.file(), Params.position,
+ [](llvm::Expected<std::vector<DocumentHighlight>> Highlights) {
+ if (!Highlights)
+ return replyError(ErrorCode::InternalError,
+ llvm::toString(Highlights.takeError()));
+ reply(json::Array(*Highlights));
+ });
+}
+
+void ClangdLSPServer::onHover(TextDocumentPositionParams &Params) {
+ Server.findHover(Params.textDocument.uri.file(), Params.position,
+ [](llvm::Expected<llvm::Optional<Hover>> H) {
+ if (!H) {
+ replyError(ErrorCode::InternalError,
+ llvm::toString(H.takeError()));
+ return;
+ }
+
+ reply(*H);
+ });
+}
+
+void ClangdLSPServer::applyConfiguration(
+ const ClangdConfigurationParamsChange &Settings) {
+ // Compilation database change.
+ if (Settings.compilationDatabasePath.hasValue()) {
+ NonCachedCDB.setCompileCommandsDir(
+ Settings.compilationDatabasePath.getValue());
+ CDB.clear();
+
+ reparseOpenedFiles();
+ }
+}
+
+// FIXME: This function needs to be properly tested.
+void ClangdLSPServer::onChangeConfiguration(
+ DidChangeConfigurationParams &Params) {
+ applyConfiguration(Params.settings);
+}
+
+ClangdLSPServer::ClangdLSPServer(JSONOutput &Out,
+ const clangd::CodeCompleteOptions &CCOpts,
+ llvm::Optional<Path> CompileCommandsDir,
+ const ClangdServer::Options &Opts)
+ : Out(Out), NonCachedCDB(std::move(CompileCommandsDir)), CDB(NonCachedCDB),
+ CCOpts(CCOpts), SupportedSymbolKinds(defaultSymbolKinds()),
+ Server(CDB, FSProvider, /*DiagConsumer=*/*this, Opts) {}
+
+bool ClangdLSPServer::run(std::FILE *In, JSONStreamStyle InputStyle) {
+ assert(!IsDone && "Run was called before");
+
+ // Set up JSONRPCDispatcher.
+ JSONRPCDispatcher Dispatcher([](const json::Value &Params) {
+ replyError(ErrorCode::MethodNotFound, "method not found");
+ });
+ registerCallbackHandlers(Dispatcher, /*Callbacks=*/*this);
+
+ // Run the Language Server loop.
+ runLanguageServerLoop(In, Out, InputStyle, Dispatcher, IsDone);
+
+ // Make sure IsDone is set to true after this method exits to ensure assertion
+ // at the start of the method fires if it's ever executed again.
+ IsDone = true;
+
+ return ShutdownRequestReceived;
+}
+
+std::vector<Fix> ClangdLSPServer::getFixes(StringRef File,
+ const clangd::Diagnostic &D) {
+ std::lock_guard<std::mutex> Lock(FixItsMutex);
+ auto DiagToFixItsIter = FixItsMap.find(File);
+ if (DiagToFixItsIter == FixItsMap.end())
+ return {};
+
+ const auto &DiagToFixItsMap = DiagToFixItsIter->second;
+ auto FixItsIter = DiagToFixItsMap.find(D);
+ if (FixItsIter == DiagToFixItsMap.end())
+ return {};
+
+ return FixItsIter->second;
+}
+
+void ClangdLSPServer::onDiagnosticsReady(PathRef File,
+ std::vector<Diag> Diagnostics) {
+ json::Array DiagnosticsJSON;
+
+ DiagnosticToReplacementMap LocalFixIts; // Temporary storage
+ for (auto &Diag : Diagnostics) {
+ toLSPDiags(Diag, [&](clangd::Diagnostic Diag, llvm::ArrayRef<Fix> Fixes) {
+ DiagnosticsJSON.push_back(json::Object{
+ {"range", Diag.range},
+ {"severity", Diag.severity},
+ {"message", Diag.message},
+ });
+
+ auto &FixItsForDiagnostic = LocalFixIts[Diag];
+ std::copy(Fixes.begin(), Fixes.end(),
+ std::back_inserter(FixItsForDiagnostic));
+ });
+ }
+
+ // Cache FixIts
+ {
+ // FIXME(ibiryukov): should be deleted when documents are removed
+ std::lock_guard<std::mutex> Lock(FixItsMutex);
+ FixItsMap[File] = LocalFixIts;
+ }
+
+ // Publish diagnostics.
+ Out.writeMessage(json::Object{
+ {"jsonrpc", "2.0"},
+ {"method", "textDocument/publishDiagnostics"},
+ {"params",
+ json::Object{
+ {"uri", URIForFile{File}},
+ {"diagnostics", std::move(DiagnosticsJSON)},
+ }},
+ });
+}
+
+void ClangdLSPServer::reparseOpenedFiles() {
+ for (const Path &FilePath : DraftMgr.getActiveFiles())
+ Server.addDocument(FilePath, *DraftMgr.getDraft(FilePath),
+ WantDiagnostics::Auto);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdLSPServer.h b/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdLSPServer.h
new file mode 100644
index 0000000..644e762
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdLSPServer.h
@@ -0,0 +1,126 @@
+//===--- ClangdLSPServer.h - LSP server --------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H
+
+#include "ClangdServer.h"
+#include "DraftStore.h"
+#include "FindSymbols.h"
+#include "GlobalCompilationDatabase.h"
+#include "Path.h"
+#include "Protocol.h"
+#include "ProtocolHandlers.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/Optional.h"
+
+namespace clang {
+namespace clangd {
+
+class JSONOutput;
+class SymbolIndex;
+
+/// This class provides implementation of an LSP server, glueing the JSON
+/// dispatch and ClangdServer together.
+class ClangdLSPServer : private DiagnosticsConsumer, private ProtocolCallbacks {
+public:
+ /// If \p CompileCommandsDir has a value, compile_commands.json will be
+ /// loaded only from \p CompileCommandsDir. Otherwise, clangd will look
+ /// for compile_commands.json in all parent directories of each file.
+ ClangdLSPServer(JSONOutput &Out, const clangd::CodeCompleteOptions &CCOpts,
+ llvm::Optional<Path> CompileCommandsDir,
+ const ClangdServer::Options &Opts);
+
+ /// Run LSP server loop, receiving input for it from \p In. \p In must be
+ /// opened in binary mode. Output will be written using Out variable passed to
+ /// class constructor. This method must not be executed more than once for
+ /// each instance of ClangdLSPServer.
+ ///
+ /// \return Whether we received a 'shutdown' request before an 'exit' request.
+ bool run(std::FILE *In,
+ JSONStreamStyle InputStyle = JSONStreamStyle::Standard);
+
+private:
+ // Implement DiagnosticsConsumer.
+ void onDiagnosticsReady(PathRef File, std::vector<Diag> Diagnostics) override;
+
+ // Implement ProtocolCallbacks.
+ void onInitialize(InitializeParams &Params) override;
+ void onShutdown(ShutdownParams &Params) override;
+ void onExit(ExitParams &Params) override;
+ void onDocumentDidOpen(DidOpenTextDocumentParams &Params) override;
+ void onDocumentDidChange(DidChangeTextDocumentParams &Params) override;
+ void onDocumentDidClose(DidCloseTextDocumentParams &Params) override;
+ void
+ onDocumentOnTypeFormatting(DocumentOnTypeFormattingParams &Params) override;
+ void
+ onDocumentRangeFormatting(DocumentRangeFormattingParams &Params) override;
+ void onDocumentFormatting(DocumentFormattingParams &Params) override;
+ void onDocumentSymbol(DocumentSymbolParams &Params) override;
+ void onCodeAction(CodeActionParams &Params) override;
+ void onCompletion(TextDocumentPositionParams &Params) override;
+ void onSignatureHelp(TextDocumentPositionParams &Params) override;
+ void onGoToDefinition(TextDocumentPositionParams &Params) override;
+ void onSwitchSourceHeader(TextDocumentIdentifier &Params) override;
+ void onDocumentHighlight(TextDocumentPositionParams &Params) override;
+ void onFileEvent(DidChangeWatchedFilesParams &Params) override;
+ void onCommand(ExecuteCommandParams &Params) override;
+ void onWorkspaceSymbol(WorkspaceSymbolParams &Params) override;
+ void onRename(RenameParams &Parames) override;
+ void onHover(TextDocumentPositionParams &Params) override;
+ void onChangeConfiguration(DidChangeConfigurationParams &Params) override;
+
+ std::vector<Fix> getFixes(StringRef File, const clangd::Diagnostic &D);
+
+ /// Forces a reparse of all currently opened files. As a result, this method
+ /// may be very expensive. This method is normally called when the
+ /// compilation database is changed.
+ void reparseOpenedFiles();
+ void applyConfiguration(const ClangdConfigurationParamsChange &Settings);
+
+ JSONOutput &Out;
+ /// Used to indicate that the 'shutdown' request was received from the
+ /// Language Server client.
+ bool ShutdownRequestReceived = false;
+
+ /// Used to indicate that the 'exit' notification was received from the
+ /// Language Server client.
+ /// It's used to break out of the LSP parsing loop.
+ bool IsDone = false;
+
+ std::mutex FixItsMutex;
+ typedef std::map<clangd::Diagnostic, std::vector<Fix>, LSPDiagnosticCompare>
+ DiagnosticToReplacementMap;
+ /// Caches FixIts per file and diagnostics
+ llvm::StringMap<DiagnosticToReplacementMap> FixItsMap;
+
+ // Various ClangdServer parameters go here. It's important they're created
+ // before ClangdServer.
+ DirectoryBasedGlobalCompilationDatabase NonCachedCDB;
+ CachingCompilationDb CDB;
+
+ RealFileSystemProvider FSProvider;
+ /// Options used for code completion
+ clangd::CodeCompleteOptions CCOpts;
+ /// The supported kinds of the client.
+ SymbolKindBitset SupportedSymbolKinds;
+
+ // Store of the current versions of the open documents.
+ DraftStore DraftMgr;
+
+ // Server must be the last member of the class to allow its destructor to exit
+ // the worker thread that may otherwise run an async callback on partially
+ // destructed instance of ClangdLSPServer.
+ ClangdServer Server;
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdServer.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdServer.cpp
new file mode 100644
index 0000000..01cc823
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdServer.cpp
@@ -0,0 +1,475 @@
+//===--- ClangdServer.cpp - Main clangd server code --------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-------------------------------------------------------------------===//
+
+#include "ClangdServer.h"
+#include "CodeComplete.h"
+#include "FindSymbols.h"
+#include "Headers.h"
+#include "SourceCode.h"
+#include "XRefs.h"
+#include "index/Merge.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Refactoring/RefactoringResultConsumer.h"
+#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <future>
+
+using namespace clang;
+using namespace clang::clangd;
+
+namespace {
+
+void ignoreError(llvm::Error Err) {
+ handleAllErrors(std::move(Err), [](const llvm::ErrorInfoBase &) {});
+}
+
+std::string getStandardResourceDir() {
+ static int Dummy; // Just an address in this process.
+ return CompilerInvocation::GetResourcesPath("clangd", (void *)&Dummy);
+}
+
+class RefactoringResultCollector final
+ : public tooling::RefactoringResultConsumer {
+public:
+ void handleError(llvm::Error Err) override {
+ assert(!Result.hasValue());
+ // FIXME: figure out a way to return better message for DiagnosticError.
+ // clangd uses llvm::toString to convert the Err to string, however, for
+ // DiagnosticError, only "clang diagnostic" will be generated.
+ Result = std::move(Err);
+ }
+
+ // Using the handle(SymbolOccurrences) from parent class.
+ using tooling::RefactoringResultConsumer::handle;
+
+ void handle(tooling::AtomicChanges SourceReplacements) override {
+ assert(!Result.hasValue());
+ Result = std::move(SourceReplacements);
+ }
+
+ Optional<Expected<tooling::AtomicChanges>> Result;
+};
+
+} // namespace
+
+ClangdServer::Options ClangdServer::optsForTest() {
+ ClangdServer::Options Opts;
+ Opts.UpdateDebounce = std::chrono::steady_clock::duration::zero(); // Faster!
+ Opts.StorePreamblesInMemory = true;
+ Opts.AsyncThreadsCount = 4; // Consistent!
+ return Opts;
+}
+
+ClangdServer::ClangdServer(GlobalCompilationDatabase &CDB,
+ FileSystemProvider &FSProvider,
+ DiagnosticsConsumer &DiagConsumer,
+ const Options &Opts)
+ : CDB(CDB), DiagConsumer(DiagConsumer), FSProvider(FSProvider),
+ ResourceDir(Opts.ResourceDir ? Opts.ResourceDir->str()
+ : getStandardResourceDir()),
+ FileIdx(Opts.BuildDynamicSymbolIndex ? new FileIndex(Opts.URISchemes)
+ : nullptr),
+ PCHs(std::make_shared<PCHContainerOperations>()),
+ // Pass a callback into `WorkScheduler` to extract symbols from a newly
+ // parsed file and rebuild the file index synchronously each time an AST
+ // is parsed.
+ // FIXME(ioeric): this can be slow and we may be able to index on less
+ // critical paths.
+ WorkScheduler(
+ Opts.AsyncThreadsCount, Opts.StorePreamblesInMemory,
+ FileIdx
+ ? [this](PathRef Path, ASTContext &AST,
+ std::shared_ptr<Preprocessor>
+ PP) { FileIdx->update(Path, &AST, std::move(PP)); }
+ : PreambleParsedCallback(),
+ Opts.UpdateDebounce, Opts.RetentionPolicy) {
+ if (FileIdx && Opts.StaticIndex) {
+ MergedIndex = mergeIndex(FileIdx.get(), Opts.StaticIndex);
+ Index = MergedIndex.get();
+ } else if (FileIdx)
+ Index = FileIdx.get();
+ else if (Opts.StaticIndex)
+ Index = Opts.StaticIndex;
+ else
+ Index = nullptr;
+}
+
+void ClangdServer::setRootPath(PathRef RootPath) {
+ auto FS = FSProvider.getFileSystem();
+ auto Status = FS->status(RootPath);
+ if (!Status)
+ elog("Failed to get status for RootPath {0}: {1}", RootPath,
+ Status.getError().message());
+ else if (Status->isDirectory())
+ this->RootPath = RootPath;
+ else
+ elog("The provided RootPath {0} is not a directory.", RootPath);
+}
+
+void ClangdServer::addDocument(PathRef File, StringRef Contents,
+ WantDiagnostics WantDiags) {
+ DocVersion Version = ++InternalVersion[File];
+ ParseInputs Inputs = {getCompileCommand(File), FSProvider.getFileSystem(),
+ Contents.str()};
+
+ Path FileStr = File.str();
+ WorkScheduler.update(File, std::move(Inputs), WantDiags,
+ [this, FileStr, Version](std::vector<Diag> Diags) {
+ consumeDiagnostics(FileStr, Version, std::move(Diags));
+ });
+}
+
+void ClangdServer::removeDocument(PathRef File) {
+ ++InternalVersion[File];
+ WorkScheduler.remove(File);
+}
+
+void ClangdServer::codeComplete(PathRef File, Position Pos,
+ const clangd::CodeCompleteOptions &Opts,
+ Callback<CodeCompleteResult> CB) {
+ // Copy completion options for passing them to async task handler.
+ auto CodeCompleteOpts = Opts;
+ if (!CodeCompleteOpts.Index) // Respect overridden index.
+ CodeCompleteOpts.Index = Index;
+
+ // Copy PCHs to avoid accessing this->PCHs concurrently
+ std::shared_ptr<PCHContainerOperations> PCHs = this->PCHs;
+ auto FS = FSProvider.getFileSystem();
+ auto Task = [PCHs, Pos, FS,
+ CodeCompleteOpts](Path File, Callback<CodeCompleteResult> CB,
+ llvm::Expected<InputsAndPreamble> IP) {
+ if (!IP)
+ return CB(IP.takeError());
+
+ auto PreambleData = IP->Preamble;
+
+ // FIXME(ibiryukov): even if Preamble is non-null, we may want to check
+ // both the old and the new version in case only one of them matches.
+ CodeCompleteResult Result = clangd::codeComplete(
+ File, IP->Command, PreambleData ? &PreambleData->Preamble : nullptr,
+ PreambleData ? PreambleData->Includes : IncludeStructure(),
+ IP->Contents, Pos, FS, PCHs, CodeCompleteOpts);
+ CB(std::move(Result));
+ };
+
+ WorkScheduler.runWithPreamble("CodeComplete", File,
+ Bind(Task, File.str(), std::move(CB)));
+}
+
+void ClangdServer::signatureHelp(PathRef File, Position Pos,
+ Callback<SignatureHelp> CB) {
+
+ auto PCHs = this->PCHs;
+ auto FS = FSProvider.getFileSystem();
+ auto Action = [Pos, FS, PCHs](Path File, Callback<SignatureHelp> CB,
+ llvm::Expected<InputsAndPreamble> IP) {
+ if (!IP)
+ return CB(IP.takeError());
+
+ auto PreambleData = IP->Preamble;
+ CB(clangd::signatureHelp(File, IP->Command,
+ PreambleData ? &PreambleData->Preamble : nullptr,
+ IP->Contents, Pos, FS, PCHs));
+ };
+
+ WorkScheduler.runWithPreamble("SignatureHelp", File,
+ Bind(Action, File.str(), std::move(CB)));
+}
+
+llvm::Expected<tooling::Replacements>
+ClangdServer::formatRange(StringRef Code, PathRef File, Range Rng) {
+ llvm::Expected<size_t> Begin = positionToOffset(Code, Rng.start);
+ if (!Begin)
+ return Begin.takeError();
+ llvm::Expected<size_t> End = positionToOffset(Code, Rng.end);
+ if (!End)
+ return End.takeError();
+ return formatCode(Code, File, {tooling::Range(*Begin, *End - *Begin)});
+}
+
+llvm::Expected<tooling::Replacements> ClangdServer::formatFile(StringRef Code,
+ PathRef File) {
+ // Format everything.
+ return formatCode(Code, File, {tooling::Range(0, Code.size())});
+}
+
+llvm::Expected<tooling::Replacements>
+ClangdServer::formatOnType(StringRef Code, PathRef File, Position Pos) {
+ // Look for the previous opening brace from the character position and
+ // format starting from there.
+ llvm::Expected<size_t> CursorPos = positionToOffset(Code, Pos);
+ if (!CursorPos)
+ return CursorPos.takeError();
+ size_t PreviousLBracePos = StringRef(Code).find_last_of('{', *CursorPos);
+ if (PreviousLBracePos == StringRef::npos)
+ PreviousLBracePos = *CursorPos;
+ size_t Len = *CursorPos - PreviousLBracePos;
+
+ return formatCode(Code, File, {tooling::Range(PreviousLBracePos, Len)});
+}
+
+void ClangdServer::rename(PathRef File, Position Pos, llvm::StringRef NewName,
+ Callback<std::vector<tooling::Replacement>> CB) {
+ auto Action = [Pos](Path File, std::string NewName,
+ Callback<std::vector<tooling::Replacement>> CB,
+ Expected<InputsAndAST> InpAST) {
+ if (!InpAST)
+ return CB(InpAST.takeError());
+ auto &AST = InpAST->AST;
+
+ RefactoringResultCollector ResultCollector;
+ const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
+ SourceLocation SourceLocationBeg =
+ clangd::getBeginningOfIdentifier(AST, Pos, SourceMgr.getMainFileID());
+ tooling::RefactoringRuleContext Context(
+ AST.getASTContext().getSourceManager());
+ Context.setASTContext(AST.getASTContext());
+ auto Rename = clang::tooling::RenameOccurrences::initiate(
+ Context, SourceRange(SourceLocationBeg), NewName);
+ if (!Rename)
+ return CB(Rename.takeError());
+
+ Rename->invoke(ResultCollector, Context);
+
+ assert(ResultCollector.Result.hasValue());
+ if (!ResultCollector.Result.getValue())
+ return CB(ResultCollector.Result->takeError());
+
+ std::vector<tooling::Replacement> Replacements;
+ for (const tooling::AtomicChange &Change : ResultCollector.Result->get()) {
+ tooling::Replacements ChangeReps = Change.getReplacements();
+ for (const auto &Rep : ChangeReps) {
+ // FIXME: Right now we only support renaming the main file, so we
+ // drop replacements not for the main file. In the future, we might
+ // consider to support:
+ // * rename in any included header
+ // * rename only in the "main" header
+ // * provide an error if there are symbols we won't rename (e.g.
+ // std::vector)
+ // * rename globally in project
+ // * rename in open files
+ if (Rep.getFilePath() == File)
+ Replacements.push_back(Rep);
+ }
+ }
+ return CB(std::move(Replacements));
+ };
+
+ WorkScheduler.runWithAST(
+ "Rename", File, Bind(Action, File.str(), NewName.str(), std::move(CB)));
+}
+
+void ClangdServer::dumpAST(PathRef File,
+ llvm::unique_function<void(std::string)> Callback) {
+ auto Action = [](decltype(Callback) Callback,
+ llvm::Expected<InputsAndAST> InpAST) {
+ if (!InpAST) {
+ ignoreError(InpAST.takeError());
+ return Callback("<no-ast>");
+ }
+ std::string Result;
+
+ llvm::raw_string_ostream ResultOS(Result);
+ clangd::dumpAST(InpAST->AST, ResultOS);
+ ResultOS.flush();
+
+ Callback(Result);
+ };
+
+ WorkScheduler.runWithAST("DumpAST", File, Bind(Action, std::move(Callback)));
+}
+
+void ClangdServer::findDefinitions(PathRef File, Position Pos,
+ Callback<std::vector<Location>> CB) {
+ auto Action = [Pos, this](Callback<std::vector<Location>> CB,
+ llvm::Expected<InputsAndAST> InpAST) {
+ if (!InpAST)
+ return CB(InpAST.takeError());
+ CB(clangd::findDefinitions(InpAST->AST, Pos, Index));
+ };
+
+ WorkScheduler.runWithAST("Definitions", File, Bind(Action, std::move(CB)));
+}
+
+llvm::Optional<Path> ClangdServer::switchSourceHeader(PathRef Path) {
+
+ StringRef SourceExtensions[] = {".cpp", ".c", ".cc", ".cxx",
+ ".c++", ".m", ".mm"};
+ StringRef HeaderExtensions[] = {".h", ".hh", ".hpp", ".hxx", ".inc"};
+
+ StringRef PathExt = llvm::sys::path::extension(Path);
+
+ // Lookup in a list of known extensions.
+ auto SourceIter =
+ std::find_if(std::begin(SourceExtensions), std::end(SourceExtensions),
+ [&PathExt](PathRef SourceExt) {
+ return SourceExt.equals_lower(PathExt);
+ });
+ bool IsSource = SourceIter != std::end(SourceExtensions);
+
+ auto HeaderIter =
+ std::find_if(std::begin(HeaderExtensions), std::end(HeaderExtensions),
+ [&PathExt](PathRef HeaderExt) {
+ return HeaderExt.equals_lower(PathExt);
+ });
+
+ bool IsHeader = HeaderIter != std::end(HeaderExtensions);
+
+ // We can only switch between the known extensions.
+ if (!IsSource && !IsHeader)
+ return llvm::None;
+
+ // Array to lookup extensions for the switch. An opposite of where original
+ // extension was found.
+ ArrayRef<StringRef> NewExts;
+ if (IsSource)
+ NewExts = HeaderExtensions;
+ else
+ NewExts = SourceExtensions;
+
+ // Storage for the new path.
+ SmallString<128> NewPath = StringRef(Path);
+
+ // Instance of vfs::FileSystem, used for file existence checks.
+ auto FS = FSProvider.getFileSystem();
+
+ // Loop through switched extension candidates.
+ for (StringRef NewExt : NewExts) {
+ llvm::sys::path::replace_extension(NewPath, NewExt);
+ if (FS->exists(NewPath))
+ return NewPath.str().str(); // First str() to convert from SmallString to
+ // StringRef, second to convert from StringRef
+ // to std::string
+
+ // Also check NewExt in upper-case, just in case.
+ llvm::sys::path::replace_extension(NewPath, NewExt.upper());
+ if (FS->exists(NewPath))
+ return NewPath.str().str();
+ }
+
+ return llvm::None;
+}
+
+llvm::Expected<tooling::Replacements>
+ClangdServer::formatCode(llvm::StringRef Code, PathRef File,
+ ArrayRef<tooling::Range> Ranges) {
+ // Call clang-format.
+ auto FS = FSProvider.getFileSystem();
+ auto Style = format::getStyle(format::DefaultFormatStyle, File,
+ format::DefaultFallbackStyle, Code, FS.get());
+ if (!Style)
+ return Style.takeError();
+
+ tooling::Replacements IncludeReplaces =
+ format::sortIncludes(*Style, Code, Ranges, File);
+ auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces);
+ if (!Changed)
+ return Changed.takeError();
+
+ return IncludeReplaces.merge(format::reformat(
+ Style.get(), *Changed,
+ tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges),
+ File));
+}
+
+void ClangdServer::findDocumentHighlights(
+ PathRef File, Position Pos, Callback<std::vector<DocumentHighlight>> CB) {
+ auto Action = [Pos](Callback<std::vector<DocumentHighlight>> CB,
+ llvm::Expected<InputsAndAST> InpAST) {
+ if (!InpAST)
+ return CB(InpAST.takeError());
+ CB(clangd::findDocumentHighlights(InpAST->AST, Pos));
+ };
+
+ WorkScheduler.runWithAST("Highlights", File, Bind(Action, std::move(CB)));
+}
+
+void ClangdServer::findHover(PathRef File, Position Pos,
+ Callback<llvm::Optional<Hover>> CB) {
+ auto Action = [Pos](Callback<llvm::Optional<Hover>> CB,
+ llvm::Expected<InputsAndAST> InpAST) {
+ if (!InpAST)
+ return CB(InpAST.takeError());
+ CB(clangd::getHover(InpAST->AST, Pos));
+ };
+
+ WorkScheduler.runWithAST("Hover", File, Bind(Action, std::move(CB)));
+}
+
+void ClangdServer::consumeDiagnostics(PathRef File, DocVersion Version,
+ std::vector<Diag> Diags) {
+ // We need to serialize access to resulting diagnostics to avoid calling
+ // `onDiagnosticsReady` in the wrong order.
+ std::lock_guard<std::mutex> DiagsLock(DiagnosticsMutex);
+ DocVersion &LastReportedDiagsVersion = ReportedDiagnosticVersions[File];
+
+ // FIXME(ibiryukov): get rid of '<' comparison here. In the current
+ // implementation diagnostics will not be reported after version counters'
+ // overflow. This should not happen in practice, since DocVersion is a
+ // 64-bit unsigned integer.
+ if (Version < LastReportedDiagsVersion)
+ return;
+ LastReportedDiagsVersion = Version;
+
+ DiagConsumer.onDiagnosticsReady(File, std::move(Diags));
+}
+
+tooling::CompileCommand ClangdServer::getCompileCommand(PathRef File) {
+ llvm::Optional<tooling::CompileCommand> C = CDB.getCompileCommand(File);
+ if (!C) // FIXME: Suppress diagnostics? Let the user know?
+ C = CDB.getFallbackCommand(File);
+
+ // Inject the resource dir.
+ // FIXME: Don't overwrite it if it's already there.
+ C->CommandLine.push_back("-resource-dir=" + ResourceDir);
+ return std::move(*C);
+}
+
+void ClangdServer::onFileEvent(const DidChangeWatchedFilesParams &Params) {
+ // FIXME: Do nothing for now. This will be used for indexing and potentially
+ // invalidating other caches.
+}
+
+void ClangdServer::workspaceSymbols(
+ StringRef Query, int Limit, Callback<std::vector<SymbolInformation>> CB) {
+ CB(clangd::getWorkspaceSymbols(Query, Limit, Index,
+ RootPath ? *RootPath : ""));
+}
+
+void ClangdServer::documentSymbols(
+ StringRef File, Callback<std::vector<SymbolInformation>> CB) {
+ auto Action = [](Callback<std::vector<SymbolInformation>> CB,
+ llvm::Expected<InputsAndAST> InpAST) {
+ if (!InpAST)
+ return CB(InpAST.takeError());
+ CB(clangd::getDocumentSymbols(InpAST->AST));
+ };
+ WorkScheduler.runWithAST("documentSymbols", File,
+ Bind(Action, std::move(CB)));
+}
+
+std::vector<std::pair<Path, std::size_t>>
+ClangdServer::getUsedBytesPerFile() const {
+ return WorkScheduler.getUsedBytesPerFile();
+}
+
+LLVM_NODISCARD bool
+ClangdServer::blockUntilIdleForTest(llvm::Optional<double> TimeoutSeconds) {
+ return WorkScheduler.blockUntilIdle(timeoutSeconds(TimeoutSeconds));
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdServer.h b/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdServer.h
new file mode 100644
index 0000000..745f8c3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdServer.h
@@ -0,0 +1,246 @@
+//===--- ClangdServer.h - Main clangd server code ----------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H
+
+#include "ClangdUnit.h"
+#include "CodeComplete.h"
+#include "FSProvider.h"
+#include "Function.h"
+#include "GlobalCompilationDatabase.h"
+#include "Protocol.h"
+#include "TUScheduler.h"
+#include "index/FileIndex.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include <functional>
+#include <future>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+namespace clang {
+class PCHContainerOperations;
+
+namespace clangd {
+
+class DiagnosticsConsumer {
+public:
+ virtual ~DiagnosticsConsumer() = default;
+
+ /// Called by ClangdServer when \p Diagnostics for \p File are ready.
+ virtual void onDiagnosticsReady(PathRef File,
+ std::vector<Diag> Diagnostics) = 0;
+};
+
+/// Provides API to manage ASTs for a collection of C++ files and request
+/// various language features.
+/// Currently supports async diagnostics, code completion, formatting and goto
+/// definition.
+class ClangdServer {
+public:
+ struct Options {
+ /// To process requests asynchronously, ClangdServer spawns worker threads.
+ /// If 0, all requests are processed on the calling thread.
+ unsigned AsyncThreadsCount = getDefaultAsyncThreadsCount();
+
+ /// AST caching policy. The default is to keep up to 3 ASTs in memory.
+ ASTRetentionPolicy RetentionPolicy;
+
+ /// Cached preambles are potentially large. If false, store them on disk.
+ bool StorePreamblesInMemory = true;
+
+ /// If true, ClangdServer builds a dynamic in-memory index for symbols in
+ /// opened files and uses the index to augment code completion results.
+ bool BuildDynamicSymbolIndex = false;
+
+ /// URI schemes to use when building the dynamic index.
+ /// If empty, the default schemes in SymbolCollector will be used.
+ std::vector<std::string> URISchemes;
+
+ /// If set, use this index to augment code completion results.
+ SymbolIndex *StaticIndex = nullptr;
+
+ /// The resource directory is used to find internal headers, overriding
+ /// defaults and -resource-dir compiler flag).
+ /// If None, ClangdServer calls CompilerInvocation::GetResourcePath() to
+ /// obtain the standard resource directory.
+ llvm::Optional<StringRef> ResourceDir = llvm::None;
+
+ /// Time to wait after a new file version before computing diagnostics.
+ std::chrono::steady_clock::duration UpdateDebounce =
+ std::chrono::milliseconds(500);
+ };
+ // Sensible default options for use in tests.
+ // Features like indexing must be enabled if desired.
+ static Options optsForTest();
+
+ /// Creates a new ClangdServer instance.
+ ///
+ /// ClangdServer uses \p CDB to obtain compilation arguments for parsing. Note
+ /// that ClangdServer only obtains compilation arguments once for each newly
+ /// added file (i.e., when processing a first call to addDocument) and reuses
+ /// those arguments for subsequent reparses. However, ClangdServer will check
+ /// if compilation arguments changed on calls to forceReparse().
+ ///
+ /// After each parsing request finishes, ClangdServer reports diagnostics to
+ /// \p DiagConsumer. Note that a callback to \p DiagConsumer happens on a
+ /// worker thread. Therefore, instances of \p DiagConsumer must properly
+ /// synchronize access to shared state.
+ ClangdServer(GlobalCompilationDatabase &CDB, FileSystemProvider &FSProvider,
+ DiagnosticsConsumer &DiagConsumer, const Options &Opts);
+
+ /// Set the root path of the workspace.
+ void setRootPath(PathRef RootPath);
+
+ /// Add a \p File to the list of tracked C++ files or update the contents if
+ /// \p File is already tracked. Also schedules parsing of the AST for it on a
+ /// separate thread. When the parsing is complete, DiagConsumer passed in
+ /// constructor will receive onDiagnosticsReady callback.
+ void addDocument(PathRef File, StringRef Contents,
+ WantDiagnostics WD = WantDiagnostics::Auto);
+
+ /// Remove \p File from list of tracked files, schedule a request to free
+ /// resources associated with it.
+ void removeDocument(PathRef File);
+
+ /// Run code completion for \p File at \p Pos.
+ /// Request is processed asynchronously.
+ ///
+ /// This method should only be called for currently tracked files. However, it
+ /// is safe to call removeDocument for \p File after this method returns, even
+ /// while returned future is not yet ready.
+ /// A version of `codeComplete` that runs \p Callback on the processing thread
+ /// when codeComplete results become available.
+ void codeComplete(PathRef File, Position Pos,
+ const clangd::CodeCompleteOptions &Opts,
+ Callback<CodeCompleteResult> CB);
+
+ /// Provide signature help for \p File at \p Pos. This method should only be
+ /// called for tracked files.
+ void signatureHelp(PathRef File, Position Pos, Callback<SignatureHelp> CB);
+
+ /// Get definition of symbol at a specified \p Line and \p Column in \p File.
+ void findDefinitions(PathRef File, Position Pos,
+ Callback<std::vector<Location>> CB);
+
+ /// Helper function that returns a path to the corresponding source file when
+ /// given a header file and vice versa.
+ llvm::Optional<Path> switchSourceHeader(PathRef Path);
+
+ /// Get document highlights for a given position.
+ void findDocumentHighlights(PathRef File, Position Pos,
+ Callback<std::vector<DocumentHighlight>> CB);
+
+ /// Get code hover for a given position.
+ void findHover(PathRef File, Position Pos,
+ Callback<llvm::Optional<Hover>> CB);
+
+ /// Retrieve the top symbols from the workspace matching a query.
+ void workspaceSymbols(StringRef Query, int Limit,
+ Callback<std::vector<SymbolInformation>> CB);
+
+ /// Retrieve the symbols within the specified file.
+ void documentSymbols(StringRef File,
+ Callback<std::vector<SymbolInformation>> CB);
+
+ /// Run formatting for \p Rng inside \p File with content \p Code.
+ llvm::Expected<tooling::Replacements> formatRange(StringRef Code,
+ PathRef File, Range Rng);
+
+ /// Run formatting for the whole \p File with content \p Code.
+ llvm::Expected<tooling::Replacements> formatFile(StringRef Code,
+ PathRef File);
+
+ /// Run formatting after a character was typed at \p Pos in \p File with
+ /// content \p Code.
+ llvm::Expected<tooling::Replacements>
+ formatOnType(StringRef Code, PathRef File, Position Pos);
+
+ /// Rename all occurrences of the symbol at the \p Pos in \p File to
+ /// \p NewName.
+ void rename(PathRef File, Position Pos, llvm::StringRef NewName,
+ Callback<std::vector<tooling::Replacement>> CB);
+
+ /// Only for testing purposes.
+ /// Waits until all requests to worker thread are finished and dumps AST for
+ /// \p File. \p File must be in the list of added documents.
+ void dumpAST(PathRef File, llvm::unique_function<void(std::string)> Callback);
+ /// Called when an event occurs for a watched file in the workspace.
+ void onFileEvent(const DidChangeWatchedFilesParams &Params);
+
+ /// Returns estimated memory usage for each of the currently open files.
+ /// The order of results is unspecified.
+ /// Overall memory usage of clangd may be significantly more than reported
+ /// here, as this metric does not account (at least) for:
+ /// - memory occupied by static and dynamic index,
+ /// - memory required for in-flight requests,
+ /// FIXME: those metrics might be useful too, we should add them.
+ std::vector<std::pair<Path, std::size_t>> getUsedBytesPerFile() const;
+
+ // Blocks the main thread until the server is idle. Only for use in tests.
+ // Returns false if the timeout expires.
+ LLVM_NODISCARD bool
+ blockUntilIdleForTest(llvm::Optional<double> TimeoutSeconds = 10);
+
+private:
+ /// FIXME: This stats several files to find a .clang-format file. I/O can be
+ /// slow. Think of a way to cache this.
+ llvm::Expected<tooling::Replacements>
+ formatCode(llvm::StringRef Code, PathRef File,
+ ArrayRef<tooling::Range> Ranges);
+
+ typedef uint64_t DocVersion;
+
+ void consumeDiagnostics(PathRef File, DocVersion Version,
+ std::vector<Diag> Diags);
+
+ tooling::CompileCommand getCompileCommand(PathRef File);
+
+ GlobalCompilationDatabase &CDB;
+ DiagnosticsConsumer &DiagConsumer;
+ FileSystemProvider &FSProvider;
+
+ /// Used to synchronize diagnostic responses for added and removed files.
+ llvm::StringMap<DocVersion> InternalVersion;
+
+ Path ResourceDir;
+ // The index used to look up symbols. This could be:
+ // - null (all index functionality is optional)
+ // - the dynamic index owned by ClangdServer (FileIdx)
+ // - the static index passed to the constructor
+ // - a merged view of a static and dynamic index (MergedIndex)
+ SymbolIndex *Index;
+ // If present, an up-to-date of symbols in open files. Read via Index.
+ std::unique_ptr<FileIndex> FileIdx;
+ // If present, a merged view of FileIdx and an external index. Read via Index.
+ std::unique_ptr<SymbolIndex> MergedIndex;
+ // If set, this represents the workspace path.
+ llvm::Optional<std::string> RootPath;
+ std::shared_ptr<PCHContainerOperations> PCHs;
+ /// Used to serialize diagnostic callbacks.
+ /// FIXME(ibiryukov): get rid of an extra map and put all version counters
+ /// into CppFile.
+ std::mutex DiagnosticsMutex;
+ /// Maps from a filename to the latest version of reported diagnostics.
+ llvm::StringMap<DocVersion> ReportedDiagnosticVersions;
+ // WorkScheduler has to be the last member, because its destructor has to be
+ // called before all other members to stop the worker thread that references
+ // ClangdServer.
+ TUScheduler WorkScheduler;
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdUnit.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdUnit.cpp
new file mode 100644
index 0000000..86e7497
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdUnit.cpp
@@ -0,0 +1,407 @@
+//===--- ClangdUnit.cpp -----------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "ClangdUnit.h"
+#include "Compiler.h"
+#include "Diagnostics.h"
+#include "Logger.h"
+#include "SourceCode.h"
+#include "Trace.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Index/IndexDataConsumer.h"
+#include "clang/Index/IndexingAction.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Serialization/ASTWriter.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace clang::clangd;
+using namespace clang;
+
+namespace {
+
+bool compileCommandsAreEqual(const tooling::CompileCommand &LHS,
+ const tooling::CompileCommand &RHS) {
+ // We don't check for Output, it should not matter to clangd.
+ return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
+ llvm::makeArrayRef(LHS.CommandLine).equals(RHS.CommandLine);
+}
+
+template <class T> std::size_t getUsedBytes(const std::vector<T> &Vec) {
+ return Vec.capacity() * sizeof(T);
+}
+
+class DeclTrackingASTConsumer : public ASTConsumer {
+public:
+ DeclTrackingASTConsumer(std::vector<Decl *> &TopLevelDecls)
+ : TopLevelDecls(TopLevelDecls) {}
+
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ for (Decl *D : DG) {
+ // ObjCMethodDecl are not actually top-level decls.
+ if (isa<ObjCMethodDecl>(D))
+ continue;
+
+ TopLevelDecls.push_back(D);
+ }
+ return true;
+ }
+
+private:
+ std::vector<Decl *> &TopLevelDecls;
+};
+
+class ClangdFrontendAction : public SyntaxOnlyAction {
+public:
+ std::vector<Decl *> takeTopLevelDecls() { return std::move(TopLevelDecls); }
+
+protected:
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override {
+ return llvm::make_unique<DeclTrackingASTConsumer>(/*ref*/ TopLevelDecls);
+ }
+
+private:
+ std::vector<Decl *> TopLevelDecls;
+};
+
+class CppFilePreambleCallbacks : public PreambleCallbacks {
+public:
+ CppFilePreambleCallbacks(PathRef File, PreambleParsedCallback ParsedCallback)
+ : File(File), ParsedCallback(ParsedCallback) {}
+
+ IncludeStructure takeIncludes() { return std::move(Includes); }
+
+ void AfterExecute(CompilerInstance &CI) override {
+ if (!ParsedCallback)
+ return;
+ trace::Span Tracer("Running PreambleCallback");
+ ParsedCallback(File, CI.getASTContext(), CI.getPreprocessorPtr());
+ }
+
+ void BeforeExecute(CompilerInstance &CI) override {
+ SourceMgr = &CI.getSourceManager();
+ }
+
+ std::unique_ptr<PPCallbacks> createPPCallbacks() override {
+ assert(SourceMgr && "SourceMgr must be set at this point");
+ return collectIncludeStructureCallback(*SourceMgr, &Includes);
+ }
+
+private:
+ PathRef File;
+ PreambleParsedCallback ParsedCallback;
+ IncludeStructure Includes;
+ SourceManager *SourceMgr = nullptr;
+};
+
+} // namespace
+
+void clangd::dumpAST(ParsedAST &AST, llvm::raw_ostream &OS) {
+ AST.getASTContext().getTranslationUnitDecl()->dump(OS, true);
+}
+
+llvm::Optional<ParsedAST>
+ParsedAST::build(std::unique_ptr<clang::CompilerInvocation> CI,
+ std::shared_ptr<const PreambleData> Preamble,
+ std::unique_ptr<llvm::MemoryBuffer> Buffer,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
+ assert(CI);
+ // Command-line parsing sets DisableFree to true by default, but we don't want
+ // to leak memory in clangd.
+ CI->getFrontendOpts().DisableFree = false;
+ const PrecompiledPreamble *PreamblePCH =
+ Preamble ? &Preamble->Preamble : nullptr;
+
+ StoreDiags ASTDiags;
+ auto Clang =
+ prepareCompilerInstance(std::move(CI), PreamblePCH, std::move(Buffer),
+ std::move(PCHs), std::move(VFS), ASTDiags);
+ if (!Clang)
+ return llvm::None;
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
+ Clang.get());
+
+ auto Action = llvm::make_unique<ClangdFrontendAction>();
+ const FrontendInputFile &MainInput = Clang->getFrontendOpts().Inputs[0];
+ if (!Action->BeginSourceFile(*Clang, MainInput)) {
+ log("BeginSourceFile() failed when building AST for {0}",
+ MainInput.getFile());
+ return llvm::None;
+ }
+
+ // Copy over the includes from the preamble, then combine with the
+ // non-preamble includes below.
+ auto Includes = Preamble ? Preamble->Includes : IncludeStructure{};
+ Clang->getPreprocessor().addPPCallbacks(
+ collectIncludeStructureCallback(Clang->getSourceManager(), &Includes));
+
+ if (!Action->Execute())
+ log("Execute() failed when building AST for {0}", MainInput.getFile());
+
+ // UnitDiagsConsumer is local, we can not store it in CompilerInstance that
+ // has a longer lifetime.
+ Clang->getDiagnostics().setClient(new IgnoreDiagnostics);
+ // CompilerInstance won't run this callback, do it directly.
+ ASTDiags.EndSourceFile();
+
+ std::vector<Decl *> ParsedDecls = Action->takeTopLevelDecls();
+ std::vector<Diag> Diags = ASTDiags.take();
+ // Add diagnostics from the preamble, if any.
+ if (Preamble)
+ Diags.insert(Diags.begin(), Preamble->Diags.begin(), Preamble->Diags.end());
+ return ParsedAST(std::move(Preamble), std::move(Clang), std::move(Action),
+ std::move(ParsedDecls), std::move(Diags),
+ std::move(Includes));
+}
+
+ParsedAST::ParsedAST(ParsedAST &&Other) = default;
+
+ParsedAST &ParsedAST::operator=(ParsedAST &&Other) = default;
+
+ParsedAST::~ParsedAST() {
+ if (Action) {
+ Action->EndSourceFile();
+ }
+}
+
+ASTContext &ParsedAST::getASTContext() { return Clang->getASTContext(); }
+
+const ASTContext &ParsedAST::getASTContext() const {
+ return Clang->getASTContext();
+}
+
+Preprocessor &ParsedAST::getPreprocessor() { return Clang->getPreprocessor(); }
+
+std::shared_ptr<Preprocessor> ParsedAST::getPreprocessorPtr() {
+ return Clang->getPreprocessorPtr();
+}
+
+const Preprocessor &ParsedAST::getPreprocessor() const {
+ return Clang->getPreprocessor();
+}
+
+ArrayRef<Decl *> ParsedAST::getLocalTopLevelDecls() {
+ return LocalTopLevelDecls;
+}
+
+const std::vector<Diag> &ParsedAST::getDiagnostics() const { return Diags; }
+
+std::size_t ParsedAST::getUsedBytes() const {
+ auto &AST = getASTContext();
+ // FIXME(ibiryukov): we do not account for the dynamically allocated part of
+ // Message and Fixes inside each diagnostic.
+ std::size_t Total =
+ ::getUsedBytes(LocalTopLevelDecls) + ::getUsedBytes(Diags);
+
+ // FIXME: the rest of the function is almost a direct copy-paste from
+ // libclang's clang_getCXTUResourceUsage. We could share the implementation.
+
+ // Sum up variaous allocators inside the ast context and the preprocessor.
+ Total += AST.getASTAllocatedMemory();
+ Total += AST.getSideTableAllocatedMemory();
+ Total += AST.Idents.getAllocator().getTotalMemory();
+ Total += AST.Selectors.getTotalMemory();
+
+ Total += AST.getSourceManager().getContentCacheSize();
+ Total += AST.getSourceManager().getDataStructureSizes();
+ Total += AST.getSourceManager().getMemoryBufferSizes().malloc_bytes;
+
+ if (ExternalASTSource *Ext = AST.getExternalSource())
+ Total += Ext->getMemoryBufferSizes().malloc_bytes;
+
+ const Preprocessor &PP = getPreprocessor();
+ Total += PP.getTotalMemory();
+ if (PreprocessingRecord *PRec = PP.getPreprocessingRecord())
+ Total += PRec->getTotalMemory();
+ Total += PP.getHeaderSearchInfo().getTotalMemory();
+
+ return Total;
+}
+
+const IncludeStructure &ParsedAST::getIncludeStructure() const {
+ return Includes;
+}
+
+PreambleData::PreambleData(PrecompiledPreamble Preamble,
+ std::vector<Diag> Diags, IncludeStructure Includes)
+ : Preamble(std::move(Preamble)), Diags(std::move(Diags)),
+ Includes(std::move(Includes)) {}
+
+ParsedAST::ParsedAST(std::shared_ptr<const PreambleData> Preamble,
+ std::unique_ptr<CompilerInstance> Clang,
+ std::unique_ptr<FrontendAction> Action,
+ std::vector<Decl *> LocalTopLevelDecls,
+ std::vector<Diag> Diags, IncludeStructure Includes)
+ : Preamble(std::move(Preamble)), Clang(std::move(Clang)),
+ Action(std::move(Action)), Diags(std::move(Diags)),
+ LocalTopLevelDecls(std::move(LocalTopLevelDecls)),
+ Includes(std::move(Includes)) {
+ assert(this->Clang);
+ assert(this->Action);
+}
+
+std::unique_ptr<CompilerInvocation>
+clangd::buildCompilerInvocation(const ParseInputs &Inputs) {
+ std::vector<const char *> ArgStrs;
+ for (const auto &S : Inputs.CompileCommand.CommandLine)
+ ArgStrs.push_back(S.c_str());
+
+ if (Inputs.FS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) {
+ log("Couldn't set working directory when creating compiler invocation.");
+ // We proceed anyway, our lit-tests rely on results for non-existing working
+ // dirs.
+ }
+
+ // FIXME(ibiryukov): store diagnostics from CommandLine when we start
+ // reporting them.
+ IgnoreDiagnostics IgnoreDiagnostics;
+ IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
+ CompilerInstance::createDiagnostics(new DiagnosticOptions,
+ &IgnoreDiagnostics, false);
+ std::unique_ptr<CompilerInvocation> CI = createInvocationFromCommandLine(
+ ArgStrs, CommandLineDiagsEngine, Inputs.FS);
+ if (!CI)
+ return nullptr;
+ // createInvocationFromCommandLine sets DisableFree.
+ CI->getFrontendOpts().DisableFree = false;
+ CI->getLangOpts()->CommentOpts.ParseAllComments = true;
+ return CI;
+}
+
+std::shared_ptr<const PreambleData> clangd::buildPreamble(
+ PathRef FileName, CompilerInvocation &CI,
+ std::shared_ptr<const PreambleData> OldPreamble,
+ const tooling::CompileCommand &OldCompileCommand, const ParseInputs &Inputs,
+ std::shared_ptr<PCHContainerOperations> PCHs, bool StoreInMemory,
+ PreambleParsedCallback PreambleCallback) {
+ // Note that we don't need to copy the input contents, preamble can live
+ // without those.
+ auto ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(Inputs.Contents);
+ auto Bounds =
+ ComputePreambleBounds(*CI.getLangOpts(), ContentsBuffer.get(), 0);
+
+ if (OldPreamble &&
+ compileCommandsAreEqual(Inputs.CompileCommand, OldCompileCommand) &&
+ OldPreamble->Preamble.CanReuse(CI, ContentsBuffer.get(), Bounds,
+ Inputs.FS.get())) {
+ vlog("Reusing preamble for file {0}", Twine(FileName));
+ return OldPreamble;
+ }
+ vlog("Preamble for file {0} cannot be reused. Attempting to rebuild it.",
+ FileName);
+
+ trace::Span Tracer("BuildPreamble");
+ SPAN_ATTACH(Tracer, "File", FileName);
+ StoreDiags PreambleDiagnostics;
+ IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
+ CompilerInstance::createDiagnostics(&CI.getDiagnosticOpts(),
+ &PreambleDiagnostics, false);
+
+ // Skip function bodies when building the preamble to speed up building
+ // the preamble and make it smaller.
+ assert(!CI.getFrontendOpts().SkipFunctionBodies);
+ CI.getFrontendOpts().SkipFunctionBodies = true;
+ // We don't want to write comment locations into PCH. They are racy and slow
+ // to read back. We rely on dynamic index for the comments instead.
+ CI.getPreprocessorOpts().WriteCommentListToPCH = false;
+
+ CppFilePreambleCallbacks SerializedDeclsCollector(FileName, PreambleCallback);
+ if (Inputs.FS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) {
+ log("Couldn't set working directory when building the preamble.");
+ // We proceed anyway, our lit-tests rely on results for non-existing working
+ // dirs.
+ }
+ auto BuiltPreamble = PrecompiledPreamble::Build(
+ CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine, Inputs.FS, PCHs,
+ StoreInMemory, SerializedDeclsCollector);
+
+ // When building the AST for the main file, we do want the function
+ // bodies.
+ CI.getFrontendOpts().SkipFunctionBodies = false;
+
+ if (BuiltPreamble) {
+ vlog("Built preamble of size {0} for file {1}", BuiltPreamble->getSize(),
+ FileName);
+ return std::make_shared<PreambleData>(
+ std::move(*BuiltPreamble), PreambleDiagnostics.take(),
+ SerializedDeclsCollector.takeIncludes());
+ } else {
+ elog("Could not build a preamble for file {0}", FileName);
+ return nullptr;
+ }
+}
+
+llvm::Optional<ParsedAST> clangd::buildAST(
+ PathRef FileName, std::unique_ptr<CompilerInvocation> Invocation,
+ const ParseInputs &Inputs, std::shared_ptr<const PreambleData> Preamble,
+ std::shared_ptr<PCHContainerOperations> PCHs) {
+ trace::Span Tracer("BuildAST");
+ SPAN_ATTACH(Tracer, "File", FileName);
+
+ if (Inputs.FS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) {
+ log("Couldn't set working directory when building the preamble.");
+ // We proceed anyway, our lit-tests rely on results for non-existing working
+ // dirs.
+ }
+
+ return ParsedAST::build(
+ llvm::make_unique<CompilerInvocation>(*Invocation), Preamble,
+ llvm::MemoryBuffer::getMemBufferCopy(Inputs.Contents), PCHs, Inputs.FS);
+}
+
+SourceLocation clangd::getBeginningOfIdentifier(ParsedAST &Unit,
+ const Position &Pos,
+ const FileID FID) {
+ const ASTContext &AST = Unit.getASTContext();
+ const SourceManager &SourceMgr = AST.getSourceManager();
+ auto Offset = positionToOffset(SourceMgr.getBufferData(FID), Pos);
+ if (!Offset) {
+ log("getBeginningOfIdentifier: {0}", Offset.takeError());
+ return SourceLocation();
+ }
+ SourceLocation InputLoc = SourceMgr.getComposedLoc(FID, *Offset);
+
+ // GetBeginningOfToken(pos) is almost what we want, but does the wrong thing
+ // if the cursor is at the end of the identifier.
+ // Instead, we lex at GetBeginningOfToken(pos - 1). The cases are:
+ // 1) at the beginning of an identifier, we'll be looking at something
+ // that isn't an identifier.
+ // 2) at the middle or end of an identifier, we get the identifier.
+ // 3) anywhere outside an identifier, we'll get some non-identifier thing.
+ // We can't actually distinguish cases 1 and 3, but returning the original
+ // location is correct for both!
+ if (*Offset == 0) // Case 1 or 3.
+ return SourceMgr.getMacroArgExpandedLocation(InputLoc);
+ SourceLocation Before =
+ SourceMgr.getMacroArgExpandedLocation(InputLoc.getLocWithOffset(-1));
+ Before = Lexer::GetBeginningOfToken(Before, SourceMgr, AST.getLangOpts());
+ Token Tok;
+ if (Before.isValid() &&
+ !Lexer::getRawToken(Before, Tok, SourceMgr, AST.getLangOpts(), false) &&
+ Tok.is(tok::raw_identifier))
+ return Before; // Case 2.
+ return SourceMgr.getMacroArgExpandedLocation(InputLoc); // Case 1 or 3.
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdUnit.h b/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdUnit.h
new file mode 100644
index 0000000..c7aca17
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/ClangdUnit.h
@@ -0,0 +1,171 @@
+//===--- ClangdUnit.h -------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDUNIT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDUNIT_H
+
+#include "Diagnostics.h"
+#include "Function.h"
+#include "Headers.h"
+#include "Path.h"
+#include "Protocol.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/PrecompiledPreamble.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Serialization/ASTBitCodes.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace llvm {
+class raw_ostream;
+}
+
+namespace clang {
+class PCHContainerOperations;
+
+namespace vfs {
+class FileSystem;
+}
+
+namespace tooling {
+struct CompileCommand;
+}
+
+namespace clangd {
+
+// Stores Preamble and associated data.
+struct PreambleData {
+ PreambleData(PrecompiledPreamble Preamble, std::vector<Diag> Diags,
+ IncludeStructure Includes);
+
+ tooling::CompileCommand CompileCommand;
+ PrecompiledPreamble Preamble;
+ std::vector<Diag> Diags;
+ // Processes like code completions and go-to-definitions will need #include
+ // information, and their compile action skips preamble range.
+ IncludeStructure Includes;
+};
+
+/// Information required to run clang, e.g. to parse AST or do code completion.
+struct ParseInputs {
+ tooling::CompileCommand CompileCommand;
+ IntrusiveRefCntPtr<vfs::FileSystem> FS;
+ std::string Contents;
+};
+
+/// Stores and provides access to parsed AST.
+class ParsedAST {
+public:
+ /// Attempts to run Clang and store parsed AST. If \p Preamble is non-null
+ /// it is reused during parsing.
+ static llvm::Optional<ParsedAST>
+ build(std::unique_ptr<clang::CompilerInvocation> CI,
+ std::shared_ptr<const PreambleData> Preamble,
+ std::unique_ptr<llvm::MemoryBuffer> Buffer,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS);
+
+ ParsedAST(ParsedAST &&Other);
+ ParsedAST &operator=(ParsedAST &&Other);
+
+ ~ParsedAST();
+
+ /// Note that the returned ast will not contain decls from the preamble that
+ /// were not deserialized during parsing. Clients should expect only decls
+ /// from the main file to be in the AST.
+ ASTContext &getASTContext();
+ const ASTContext &getASTContext() const;
+
+ Preprocessor &getPreprocessor();
+ std::shared_ptr<Preprocessor> getPreprocessorPtr();
+ const Preprocessor &getPreprocessor() const;
+
+ /// This function returns top-level decls present in the main file of the AST.
+ /// The result does not include the decls that come from the preamble.
+ /// (These should be const, but RecursiveASTVisitor requires Decl*).
+ ArrayRef<Decl *> getLocalTopLevelDecls();
+
+ const std::vector<Diag> &getDiagnostics() const;
+
+ /// Returns the esitmated size of the AST and the accessory structures, in
+ /// bytes. Does not include the size of the preamble.
+ std::size_t getUsedBytes() const;
+ const IncludeStructure &getIncludeStructure() const;
+
+private:
+ ParsedAST(std::shared_ptr<const PreambleData> Preamble,
+ std::unique_ptr<CompilerInstance> Clang,
+ std::unique_ptr<FrontendAction> Action,
+ std::vector<Decl *> LocalTopLevelDecls, std::vector<Diag> Diags,
+ IncludeStructure Includes);
+
+ // In-memory preambles must outlive the AST, it is important that this member
+ // goes before Clang and Action.
+ std::shared_ptr<const PreambleData> Preamble;
+ // We store an "incomplete" FrontendAction (i.e. no EndSourceFile was called
+ // on it) and CompilerInstance used to run it. That way we don't have to do
+ // complex memory management of all Clang structures on our own. (They are
+ // stored in CompilerInstance and cleaned up by
+ // FrontendAction.EndSourceFile).
+ std::unique_ptr<CompilerInstance> Clang;
+ std::unique_ptr<FrontendAction> Action;
+
+ // Data, stored after parsing.
+ std::vector<Diag> Diags;
+ // Top-level decls inside the current file. Not that this does not include
+ // top-level decls from the preamble.
+ std::vector<Decl *> LocalTopLevelDecls;
+ IncludeStructure Includes;
+};
+
+using PreambleParsedCallback = std::function<void(
+ PathRef Path, ASTContext &, std::shared_ptr<clang::Preprocessor>)>;
+
+/// Builds compiler invocation that could be used to build AST or preamble.
+std::unique_ptr<CompilerInvocation>
+buildCompilerInvocation(const ParseInputs &Inputs);
+
+/// Rebuild the preamble for the new inputs unless the old one can be reused.
+/// If \p OldPreamble can be reused, it is returned unchanged.
+/// If \p OldPreamble is null, always builds the preamble.
+/// If \p PreambleCallback is set, it will be run on top of the AST while
+/// building the preamble. Note that if the old preamble was reused, no AST is
+/// built and, therefore, the callback will not be executed.
+std::shared_ptr<const PreambleData>
+buildPreamble(PathRef FileName, CompilerInvocation &CI,
+ std::shared_ptr<const PreambleData> OldPreamble,
+ const tooling::CompileCommand &OldCompileCommand,
+ const ParseInputs &Inputs,
+ std::shared_ptr<PCHContainerOperations> PCHs, bool StoreInMemory,
+ PreambleParsedCallback PreambleCallback);
+
+/// Build an AST from provided user inputs. This function does not check if
+/// preamble can be reused, as this function expects that \p Preamble is the
+/// result of calling buildPreamble.
+llvm::Optional<ParsedAST>
+buildAST(PathRef FileName, std::unique_ptr<CompilerInvocation> Invocation,
+ const ParseInputs &Inputs,
+ std::shared_ptr<const PreambleData> Preamble,
+ std::shared_ptr<PCHContainerOperations> PCHs);
+
+/// Get the beginning SourceLocation at a specified \p Pos.
+/// May be invalid if Pos is, or if there's no identifier.
+SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos,
+ const FileID FID);
+
+/// For testing/debugging purposes. Note that this method deserializes all
+/// unserialized Decls, so use with care.
+void dumpAST(ParsedAST &AST, llvm::raw_ostream &OS);
+
+} // namespace clangd
+} // namespace clang
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/CodeComplete.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/CodeComplete.cpp
new file mode 100644
index 0000000..a040659
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/CodeComplete.cpp
@@ -0,0 +1,1303 @@
+//===--- CodeComplete.cpp ---------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// Code completion has several moving parts:
+// - AST-based completions are provided using the completion hooks in Sema.
+// - external completions are retrieved from the index (using hints from Sema)
+// - the two sources overlap, and must be merged and overloads bundled
+// - results must be scored and ranked (see Quality.h) before rendering
+//
+// Signature help works in a similar way as code completion, but it is simpler:
+// it's purely AST-based, and there are few candidates.
+//
+//===---------------------------------------------------------------------===//
+
+#include "CodeComplete.h"
+#include "AST.h"
+#include "CodeCompletionStrings.h"
+#include "Compiler.h"
+#include "FileDistance.h"
+#include "FuzzyMatch.h"
+#include "Headers.h"
+#include "Logger.h"
+#include "Quality.h"
+#include "SourceCode.h"
+#include "Trace.h"
+#include "URI.h"
+#include "index/Index.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Index/USRGeneration.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include <queue>
+
+// We log detailed candidate here if you run with -debug-only=codecomplete.
+#define DEBUG_TYPE "CodeComplete"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+CompletionItemKind toCompletionItemKind(index::SymbolKind Kind) {
+ using SK = index::SymbolKind;
+ switch (Kind) {
+ case SK::Unknown:
+ return CompletionItemKind::Missing;
+ case SK::Module:
+ case SK::Namespace:
+ case SK::NamespaceAlias:
+ return CompletionItemKind::Module;
+ case SK::Macro:
+ return CompletionItemKind::Text;
+ case SK::Enum:
+ return CompletionItemKind::Enum;
+ // FIXME(ioeric): use LSP struct instead of class when it is suppoted in the
+ // protocol.
+ case SK::Struct:
+ case SK::Class:
+ case SK::Protocol:
+ case SK::Extension:
+ case SK::Union:
+ return CompletionItemKind::Class;
+ // FIXME(ioeric): figure out whether reference is the right type for aliases.
+ case SK::TypeAlias:
+ case SK::Using:
+ return CompletionItemKind::Reference;
+ case SK::Function:
+ // FIXME(ioeric): this should probably be an operator. This should be fixed
+ // when `Operator` is support type in the protocol.
+ case SK::ConversionFunction:
+ return CompletionItemKind::Function;
+ case SK::Variable:
+ case SK::Parameter:
+ return CompletionItemKind::Variable;
+ case SK::Field:
+ return CompletionItemKind::Field;
+ // FIXME(ioeric): use LSP enum constant when it is supported in the protocol.
+ case SK::EnumConstant:
+ return CompletionItemKind::Value;
+ case SK::InstanceMethod:
+ case SK::ClassMethod:
+ case SK::StaticMethod:
+ case SK::Destructor:
+ return CompletionItemKind::Method;
+ case SK::InstanceProperty:
+ case SK::ClassProperty:
+ case SK::StaticProperty:
+ return CompletionItemKind::Property;
+ case SK::Constructor:
+ return CompletionItemKind::Constructor;
+ }
+ llvm_unreachable("Unhandled clang::index::SymbolKind.");
+}
+
+CompletionItemKind
+toCompletionItemKind(CodeCompletionResult::ResultKind ResKind,
+ const NamedDecl *Decl) {
+ if (Decl)
+ return toCompletionItemKind(index::getSymbolInfo(Decl).Kind);
+ switch (ResKind) {
+ case CodeCompletionResult::RK_Declaration:
+ llvm_unreachable("RK_Declaration without Decl");
+ case CodeCompletionResult::RK_Keyword:
+ return CompletionItemKind::Keyword;
+ case CodeCompletionResult::RK_Macro:
+ return CompletionItemKind::Text; // unfortunately, there's no 'Macro'
+ // completion items in LSP.
+ case CodeCompletionResult::RK_Pattern:
+ return CompletionItemKind::Snippet;
+ }
+ llvm_unreachable("Unhandled CodeCompletionResult::ResultKind.");
+}
+
+/// Get the optional chunk as a string. This function is possibly recursive.
+///
+/// The parameter info for each parameter is appended to the Parameters.
+std::string
+getOptionalParameters(const CodeCompletionString &CCS,
+ std::vector<ParameterInformation> &Parameters) {
+ std::string Result;
+ for (const auto &Chunk : CCS) {
+ switch (Chunk.Kind) {
+ case CodeCompletionString::CK_Optional:
+ assert(Chunk.Optional &&
+ "Expected the optional code completion string to be non-null.");
+ Result += getOptionalParameters(*Chunk.Optional, Parameters);
+ break;
+ case CodeCompletionString::CK_VerticalSpace:
+ break;
+ case CodeCompletionString::CK_Placeholder:
+ // A string that acts as a placeholder for, e.g., a function call
+ // argument.
+ // Intentional fallthrough here.
+ case CodeCompletionString::CK_CurrentParameter: {
+ // A piece of text that describes the parameter that corresponds to
+ // the code-completion location within a function call, message send,
+ // macro invocation, etc.
+ Result += Chunk.Text;
+ ParameterInformation Info;
+ Info.label = Chunk.Text;
+ Parameters.push_back(std::move(Info));
+ break;
+ }
+ default:
+ Result += Chunk.Text;
+ break;
+ }
+ }
+ return Result;
+}
+
+/// Creates a `HeaderFile` from \p Header which can be either a URI or a literal
+/// include.
+static llvm::Expected<HeaderFile> toHeaderFile(StringRef Header,
+ llvm::StringRef HintPath) {
+ if (isLiteralInclude(Header))
+ return HeaderFile{Header.str(), /*Verbatim=*/true};
+ auto U = URI::parse(Header);
+ if (!U)
+ return U.takeError();
+
+ auto IncludePath = URI::includeSpelling(*U);
+ if (!IncludePath)
+ return IncludePath.takeError();
+ if (!IncludePath->empty())
+ return HeaderFile{std::move(*IncludePath), /*Verbatim=*/true};
+
+ auto Resolved = URI::resolve(*U, HintPath);
+ if (!Resolved)
+ return Resolved.takeError();
+ return HeaderFile{std::move(*Resolved), /*Verbatim=*/false};
+}
+
+/// A code completion result, in clang-native form.
+/// It may be promoted to a CompletionItem if it's among the top-ranked results.
+struct CompletionCandidate {
+ llvm::StringRef Name; // Used for filtering and sorting.
+ // We may have a result from Sema, from the index, or both.
+ const CodeCompletionResult *SemaResult = nullptr;
+ const Symbol *IndexResult = nullptr;
+
+ // Returns a token identifying the overload set this is part of.
+ // 0 indicates it's not part of any overload set.
+ size_t overloadSet() const {
+ SmallString<256> Scratch;
+ if (IndexResult) {
+ switch (IndexResult->SymInfo.Kind) {
+ case index::SymbolKind::ClassMethod:
+ case index::SymbolKind::InstanceMethod:
+ case index::SymbolKind::StaticMethod:
+ assert(false && "Don't expect members from index in code completion");
+ // fall through
+ case index::SymbolKind::Function:
+ // We can't group overloads together that need different #includes.
+ // This could break #include insertion.
+ return hash_combine(
+ (IndexResult->Scope + IndexResult->Name).toStringRef(Scratch),
+ headerToInsertIfNotPresent().getValueOr(""));
+ default:
+ return 0;
+ }
+ }
+ assert(SemaResult);
+ // We need to make sure we're consistent with the IndexResult case!
+ const NamedDecl *D = SemaResult->Declaration;
+ if (!D || !D->isFunctionOrFunctionTemplate())
+ return 0;
+ {
+ llvm::raw_svector_ostream OS(Scratch);
+ D->printQualifiedName(OS);
+ }
+ return hash_combine(Scratch, headerToInsertIfNotPresent().getValueOr(""));
+ }
+
+ llvm::Optional<llvm::StringRef> headerToInsertIfNotPresent() const {
+ if (!IndexResult || !IndexResult->Detail ||
+ IndexResult->Detail->IncludeHeader.empty())
+ return llvm::None;
+ if (SemaResult && SemaResult->Declaration) {
+ // Avoid inserting new #include if the declaration is found in the current
+ // file e.g. the symbol is forward declared.
+ auto &SM = SemaResult->Declaration->getASTContext().getSourceManager();
+ for (const Decl *RD : SemaResult->Declaration->redecls())
+ if (SM.isInMainFile(SM.getExpansionLoc(RD->getLocStart())))
+ return llvm::None;
+ }
+ return IndexResult->Detail->IncludeHeader;
+ }
+
+ using Bundle = llvm::SmallVector<CompletionCandidate, 4>;
+};
+using ScoredBundle =
+ std::pair<CompletionCandidate::Bundle, CodeCompletion::Scores>;
+struct ScoredBundleGreater {
+ bool operator()(const ScoredBundle &L, const ScoredBundle &R) {
+ if (L.second.Total != R.second.Total)
+ return L.second.Total > R.second.Total;
+ return L.first.front().Name <
+ R.first.front().Name; // Earlier name is better.
+ }
+};
+
+// Assembles a code completion out of a bundle of >=1 completion candidates.
+// Many of the expensive strings are only computed at this point, once we know
+// the candidate bundle is going to be returned.
+//
+// Many fields are the same for all candidates in a bundle (e.g. name), and are
+// computed from the first candidate, in the constructor.
+// Others vary per candidate, so add() must be called for remaining candidates.
+struct CodeCompletionBuilder {
+ CodeCompletionBuilder(ASTContext &ASTCtx, const CompletionCandidate &C,
+ CodeCompletionString *SemaCCS,
+ const IncludeInserter &Includes, StringRef FileName,
+ const CodeCompleteOptions &Opts)
+ : ASTCtx(ASTCtx), ExtractDocumentation(Opts.IncludeComments) {
+ add(C, SemaCCS);
+ if (C.SemaResult) {
+ Completion.Origin |= SymbolOrigin::AST;
+ Completion.Name = llvm::StringRef(SemaCCS->getTypedText());
+ if (Completion.Scope.empty()) {
+ if ((C.SemaResult->Kind == CodeCompletionResult::RK_Declaration) ||
+ (C.SemaResult->Kind == CodeCompletionResult::RK_Pattern))
+ if (const auto *D = C.SemaResult->getDeclaration())
+ if (const auto *ND = llvm::dyn_cast<NamedDecl>(D))
+ Completion.Scope =
+ splitQualifiedName(printQualifiedName(*ND)).first;
+ }
+ Completion.Kind =
+ toCompletionItemKind(C.SemaResult->Kind, C.SemaResult->Declaration);
+ }
+ if (C.IndexResult) {
+ Completion.Origin |= C.IndexResult->Origin;
+ if (Completion.Scope.empty())
+ Completion.Scope = C.IndexResult->Scope;
+ if (Completion.Kind == CompletionItemKind::Missing)
+ Completion.Kind = toCompletionItemKind(C.IndexResult->SymInfo.Kind);
+ if (Completion.Name.empty())
+ Completion.Name = C.IndexResult->Name;
+ }
+ if (auto Inserted = C.headerToInsertIfNotPresent()) {
+ // Turn absolute path into a literal string that can be #included.
+ auto Include = [&]() -> Expected<std::pair<std::string, bool>> {
+ auto ResolvedDeclaring =
+ toHeaderFile(C.IndexResult->CanonicalDeclaration.FileURI, FileName);
+ if (!ResolvedDeclaring)
+ return ResolvedDeclaring.takeError();
+ auto ResolvedInserted = toHeaderFile(*Inserted, FileName);
+ if (!ResolvedInserted)
+ return ResolvedInserted.takeError();
+ return std::make_pair(Includes.calculateIncludePath(*ResolvedDeclaring,
+ *ResolvedInserted),
+ Includes.shouldInsertInclude(*ResolvedDeclaring,
+ *ResolvedInserted));
+ }();
+ if (Include) {
+ Completion.Header = Include->first;
+ if (Include->second)
+ Completion.HeaderInsertion = Includes.insert(Include->first);
+ } else
+ log("Failed to generate include insertion edits for adding header "
+ "(FileURI='{0}', IncludeHeader='{1}') into {2}",
+ C.IndexResult->CanonicalDeclaration.FileURI,
+ C.IndexResult->Detail->IncludeHeader, FileName);
+ }
+ }
+
+ void add(const CompletionCandidate &C, CodeCompletionString *SemaCCS) {
+ assert(bool(C.SemaResult) == bool(SemaCCS));
+ Bundled.emplace_back();
+ BundledEntry &S = Bundled.back();
+ if (C.SemaResult) {
+ getSignature(*SemaCCS, &S.Signature, &S.SnippetSuffix,
+ &Completion.RequiredQualifier);
+ S.ReturnType = getReturnType(*SemaCCS);
+ } else if (C.IndexResult) {
+ S.Signature = C.IndexResult->Signature;
+ S.SnippetSuffix = C.IndexResult->CompletionSnippetSuffix;
+ if (auto *D = C.IndexResult->Detail)
+ S.ReturnType = D->ReturnType;
+ }
+ if (ExtractDocumentation && Completion.Documentation.empty()) {
+ if (C.IndexResult && C.IndexResult->Detail)
+ Completion.Documentation = C.IndexResult->Detail->Documentation;
+ else if (C.SemaResult)
+ Completion.Documentation = getDocComment(ASTCtx, *C.SemaResult,
+ /*CommentsFromHeader=*/false);
+ }
+ }
+
+ CodeCompletion build() {
+ Completion.ReturnType = summarizeReturnType();
+ Completion.Signature = summarizeSignature();
+ Completion.SnippetSuffix = summarizeSnippet();
+ Completion.BundleSize = Bundled.size();
+ return std::move(Completion);
+ }
+
+private:
+ struct BundledEntry {
+ std::string SnippetSuffix;
+ std::string Signature;
+ std::string ReturnType;
+ };
+
+ // If all BundledEntrys have the same value for a property, return it.
+ template <std::string BundledEntry::*Member>
+ const std::string *onlyValue() const {
+ auto B = Bundled.begin(), E = Bundled.end();
+ for (auto I = B + 1; I != E; ++I)
+ if (I->*Member != B->*Member)
+ return nullptr;
+ return &(B->*Member);
+ }
+
+ std::string summarizeReturnType() const {
+ if (auto *RT = onlyValue<&BundledEntry::ReturnType>())
+ return *RT;
+ return "";
+ }
+
+ std::string summarizeSnippet() const {
+ if (auto *Snippet = onlyValue<&BundledEntry::SnippetSuffix>())
+ return *Snippet;
+ // All bundles are function calls.
+ return "(${0})";
+ }
+
+ std::string summarizeSignature() const {
+ if (auto *Signature = onlyValue<&BundledEntry::Signature>())
+ return *Signature;
+ // All bundles are function calls.
+ return "(…)";
+ }
+
+ ASTContext &ASTCtx;
+ CodeCompletion Completion;
+ SmallVector<BundledEntry, 1> Bundled;
+ bool ExtractDocumentation;
+};
+
+// Determine the symbol ID for a Sema code completion result, if possible.
+llvm::Optional<SymbolID> getSymbolID(const CodeCompletionResult &R) {
+ switch (R.Kind) {
+ case CodeCompletionResult::RK_Declaration:
+ case CodeCompletionResult::RK_Pattern: {
+ llvm::SmallString<128> USR;
+ if (/*Ignore=*/clang::index::generateUSRForDecl(R.Declaration, USR))
+ return None;
+ return SymbolID(USR);
+ }
+ case CodeCompletionResult::RK_Macro:
+ // FIXME: Macros do have USRs, but the CCR doesn't contain enough info.
+ case CodeCompletionResult::RK_Keyword:
+ return None;
+ }
+ llvm_unreachable("unknown CodeCompletionResult kind");
+}
+
+// Scopes of the paritial identifier we're trying to complete.
+// It is used when we query the index for more completion results.
+struct SpecifiedScope {
+ // The scopes we should look in, determined by Sema.
+ //
+ // If the qualifier was fully resolved, we look for completions in these
+ // scopes; if there is an unresolved part of the qualifier, it should be
+ // resolved within these scopes.
+ //
+ // Examples of qualified completion:
+ //
+ // "::vec" => {""}
+ // "using namespace std; ::vec^" => {"", "std::"}
+ // "namespace ns {using namespace std;} ns::^" => {"ns::", "std::"}
+ // "std::vec^" => {""} // "std" unresolved
+ //
+ // Examples of unqualified completion:
+ //
+ // "vec^" => {""}
+ // "using namespace std; vec^" => {"", "std::"}
+ // "using namespace std; namespace ns { vec^ }" => {"ns::", "std::", ""}
+ //
+ // "" for global namespace, "ns::" for normal namespace.
+ std::vector<std::string> AccessibleScopes;
+ // The full scope qualifier as typed by the user (without the leading "::").
+ // Set if the qualifier is not fully resolved by Sema.
+ llvm::Optional<std::string> UnresolvedQualifier;
+
+ // Construct scopes being queried in indexes.
+ // This method format the scopes to match the index request representation.
+ std::vector<std::string> scopesForIndexQuery() {
+ std::vector<std::string> Results;
+ for (llvm::StringRef AS : AccessibleScopes) {
+ Results.push_back(AS);
+ if (UnresolvedQualifier)
+ Results.back() += *UnresolvedQualifier;
+ }
+ return Results;
+ }
+};
+
+// Get all scopes that will be queried in indexes.
+std::vector<std::string> getQueryScopes(CodeCompletionContext &CCContext,
+ const SourceManager &SM) {
+ auto GetAllAccessibleScopes = [](CodeCompletionContext &CCContext) {
+ SpecifiedScope Info;
+ for (auto *Context : CCContext.getVisitedContexts()) {
+ if (isa<TranslationUnitDecl>(Context))
+ Info.AccessibleScopes.push_back(""); // global namespace
+ else if (const auto *NS = dyn_cast<NamespaceDecl>(Context))
+ Info.AccessibleScopes.push_back(NS->getQualifiedNameAsString() + "::");
+ }
+ return Info;
+ };
+
+ auto SS = CCContext.getCXXScopeSpecifier();
+
+ // Unqualified completion (e.g. "vec^").
+ if (!SS) {
+ // FIXME: Once we can insert namespace qualifiers and use the in-scope
+ // namespaces for scoring, search in all namespaces.
+ // FIXME: Capture scopes and use for scoring, for example,
+ // "using namespace std; namespace foo {v^}" =>
+ // foo::value > std::vector > boost::variant
+ return GetAllAccessibleScopes(CCContext).scopesForIndexQuery();
+ }
+
+ // Qualified completion ("std::vec^"), we have two cases depending on whether
+ // the qualifier can be resolved by Sema.
+ if ((*SS)->isValid()) { // Resolved qualifier.
+ return GetAllAccessibleScopes(CCContext).scopesForIndexQuery();
+ }
+
+ // Unresolved qualifier.
+ // FIXME: When Sema can resolve part of a scope chain (e.g.
+ // "known::unknown::id"), we should expand the known part ("known::") rather
+ // than treating the whole thing as unknown.
+ SpecifiedScope Info;
+ Info.AccessibleScopes.push_back(""); // global namespace
+
+ Info.UnresolvedQualifier =
+ Lexer::getSourceText(CharSourceRange::getCharRange((*SS)->getRange()), SM,
+ clang::LangOptions())
+ .ltrim("::");
+ // Sema excludes the trailing "::".
+ if (!Info.UnresolvedQualifier->empty())
+ *Info.UnresolvedQualifier += "::";
+
+ return Info.scopesForIndexQuery();
+}
+
+// Should we perform index-based completion in a context of the specified kind?
+// FIXME: consider allowing completion, but restricting the result types.
+bool contextAllowsIndex(enum CodeCompletionContext::Kind K) {
+ switch (K) {
+ case CodeCompletionContext::CCC_TopLevel:
+ case CodeCompletionContext::CCC_ObjCInterface:
+ case CodeCompletionContext::CCC_ObjCImplementation:
+ case CodeCompletionContext::CCC_ObjCIvarList:
+ case CodeCompletionContext::CCC_ClassStructUnion:
+ case CodeCompletionContext::CCC_Statement:
+ case CodeCompletionContext::CCC_Expression:
+ case CodeCompletionContext::CCC_ObjCMessageReceiver:
+ case CodeCompletionContext::CCC_EnumTag:
+ case CodeCompletionContext::CCC_UnionTag:
+ case CodeCompletionContext::CCC_ClassOrStructTag:
+ case CodeCompletionContext::CCC_ObjCProtocolName:
+ case CodeCompletionContext::CCC_Namespace:
+ case CodeCompletionContext::CCC_Type:
+ case CodeCompletionContext::CCC_Name: // FIXME: why does ns::^ give this?
+ case CodeCompletionContext::CCC_PotentiallyQualifiedName:
+ case CodeCompletionContext::CCC_ParenthesizedExpression:
+ case CodeCompletionContext::CCC_ObjCInterfaceName:
+ case CodeCompletionContext::CCC_ObjCCategoryName:
+ return true;
+ case CodeCompletionContext::CCC_Other: // Be conservative.
+ case CodeCompletionContext::CCC_OtherWithMacros:
+ case CodeCompletionContext::CCC_DotMemberAccess:
+ case CodeCompletionContext::CCC_ArrowMemberAccess:
+ case CodeCompletionContext::CCC_ObjCPropertyAccess:
+ case CodeCompletionContext::CCC_MacroName:
+ case CodeCompletionContext::CCC_MacroNameUse:
+ case CodeCompletionContext::CCC_PreprocessorExpression:
+ case CodeCompletionContext::CCC_PreprocessorDirective:
+ case CodeCompletionContext::CCC_NaturalLanguage:
+ case CodeCompletionContext::CCC_SelectorName:
+ case CodeCompletionContext::CCC_TypeQualifiers:
+ case CodeCompletionContext::CCC_ObjCInstanceMessage:
+ case CodeCompletionContext::CCC_ObjCClassMessage:
+ case CodeCompletionContext::CCC_Recovery:
+ return false;
+ }
+ llvm_unreachable("unknown code completion context");
+}
+
+// Some member calls are blacklisted because they're so rarely useful.
+static bool isBlacklistedMember(const NamedDecl &D) {
+ // Destructor completion is rarely useful, and works inconsistently.
+ // (s.^ completes ~string, but s.~st^ is an error).
+ if (D.getKind() == Decl::CXXDestructor)
+ return true;
+ // Injected name may be useful for A::foo(), but who writes A::A::foo()?
+ if (auto *R = dyn_cast_or_null<RecordDecl>(&D))
+ if (R->isInjectedClassName())
+ return true;
+ // Explicit calls to operators are also rare.
+ auto NameKind = D.getDeclName().getNameKind();
+ if (NameKind == DeclarationName::CXXOperatorName ||
+ NameKind == DeclarationName::CXXLiteralOperatorName ||
+ NameKind == DeclarationName::CXXConversionFunctionName)
+ return true;
+ return false;
+}
+
+// The CompletionRecorder captures Sema code-complete output, including context.
+// It filters out ignored results (but doesn't apply fuzzy-filtering yet).
+// It doesn't do scoring or conversion to CompletionItem yet, as we want to
+// merge with index results first.
+// Generally the fields and methods of this object should only be used from
+// within the callback.
+struct CompletionRecorder : public CodeCompleteConsumer {
+ CompletionRecorder(const CodeCompleteOptions &Opts,
+ llvm::unique_function<void()> ResultsCallback)
+ : CodeCompleteConsumer(Opts.getClangCompleteOpts(),
+ /*OutputIsBinary=*/false),
+ CCContext(CodeCompletionContext::CCC_Other), Opts(Opts),
+ CCAllocator(std::make_shared<GlobalCodeCompletionAllocator>()),
+ CCTUInfo(CCAllocator), ResultsCallback(std::move(ResultsCallback)) {
+ assert(this->ResultsCallback);
+ }
+
+ std::vector<CodeCompletionResult> Results;
+ CodeCompletionContext CCContext;
+ Sema *CCSema = nullptr; // Sema that created the results.
+ // FIXME: Sema is scary. Can we store ASTContext and Preprocessor, instead?
+
+ void ProcessCodeCompleteResults(class Sema &S, CodeCompletionContext Context,
+ CodeCompletionResult *InResults,
+ unsigned NumResults) override final {
+ // Results from recovery mode are generally useless, and the callback after
+ // recovery (if any) is usually more interesting. To make sure we handle the
+ // future callback from sema, we just ignore all callbacks in recovery mode,
+ // as taking only results from recovery mode results in poor completion
+ // results.
+ // FIXME: in case there is no future sema completion callback after the
+ // recovery mode, we might still want to provide some results (e.g. trivial
+ // identifier-based completion).
+ if (Context.getKind() == CodeCompletionContext::CCC_Recovery) {
+ log("Code complete: Ignoring sema code complete callback with Recovery "
+ "context.");
+ return;
+ }
+ // If a callback is called without any sema result and the context does not
+ // support index-based completion, we simply skip it to give way to
+ // potential future callbacks with results.
+ if (NumResults == 0 && !contextAllowsIndex(Context.getKind()))
+ return;
+ if (CCSema) {
+ log("Multiple code complete callbacks (parser backtracked?). "
+ "Dropping results from context {0}, keeping results from {1}.",
+ getCompletionKindString(Context.getKind()),
+ getCompletionKindString(this->CCContext.getKind()));
+ return;
+ }
+ // Record the completion context.
+ CCSema = &S;
+ CCContext = Context;
+
+ // Retain the results we might want.
+ for (unsigned I = 0; I < NumResults; ++I) {
+ auto &Result = InResults[I];
+ // Drop hidden items which cannot be found by lookup after completion.
+ // Exception: some items can be named by using a qualifier.
+ if (Result.Hidden && (!Result.Qualifier || Result.QualifierIsInformative))
+ continue;
+ if (!Opts.IncludeIneligibleResults &&
+ (Result.Availability == CXAvailability_NotAvailable ||
+ Result.Availability == CXAvailability_NotAccessible))
+ continue;
+ if (Result.Declaration &&
+ !Context.getBaseType().isNull() // is this a member-access context?
+ && isBlacklistedMember(*Result.Declaration))
+ continue;
+ // We choose to never append '::' to completion results in clangd.
+ Result.StartsNestedNameSpecifier = false;
+ Results.push_back(Result);
+ }
+ ResultsCallback();
+ }
+
+ CodeCompletionAllocator &getAllocator() override { return *CCAllocator; }
+ CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
+
+ // Returns the filtering/sorting name for Result, which must be from Results.
+ // Returned string is owned by this recorder (or the AST).
+ llvm::StringRef getName(const CodeCompletionResult &Result) {
+ switch (Result.Kind) {
+ case CodeCompletionResult::RK_Declaration:
+ if (auto *ID = Result.Declaration->getIdentifier())
+ return ID->getName();
+ break;
+ case CodeCompletionResult::RK_Keyword:
+ return Result.Keyword;
+ case CodeCompletionResult::RK_Macro:
+ return Result.Macro->getName();
+ case CodeCompletionResult::RK_Pattern:
+ return Result.Pattern->getTypedText();
+ }
+ auto *CCS = codeCompletionString(Result);
+ return CCS->getTypedText();
+ }
+
+ // Build a CodeCompletion string for R, which must be from Results.
+ // The CCS will be owned by this recorder.
+ CodeCompletionString *codeCompletionString(const CodeCompletionResult &R) {
+ // CodeCompletionResult doesn't seem to be const-correct. We own it, anyway.
+ return const_cast<CodeCompletionResult &>(R).CreateCodeCompletionString(
+ *CCSema, CCContext, *CCAllocator, CCTUInfo,
+ /*IncludeBriefComments=*/false);
+ }
+
+private:
+ CodeCompleteOptions Opts;
+ std::shared_ptr<GlobalCodeCompletionAllocator> CCAllocator;
+ CodeCompletionTUInfo CCTUInfo;
+ llvm::unique_function<void()> ResultsCallback;
+};
+
+class SignatureHelpCollector final : public CodeCompleteConsumer {
+
+public:
+ SignatureHelpCollector(const clang::CodeCompleteOptions &CodeCompleteOpts,
+ SignatureHelp &SigHelp)
+ : CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false),
+ SigHelp(SigHelp),
+ Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
+ CCTUInfo(Allocator) {}
+
+ void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
+ OverloadCandidate *Candidates,
+ unsigned NumCandidates) override {
+ SigHelp.signatures.reserve(NumCandidates);
+ // FIXME(rwols): How can we determine the "active overload candidate"?
+ // Right now the overloaded candidates seem to be provided in a "best fit"
+ // order, so I'm not too worried about this.
+ SigHelp.activeSignature = 0;
+ assert(CurrentArg <= (unsigned)std::numeric_limits<int>::max() &&
+ "too many arguments");
+ SigHelp.activeParameter = static_cast<int>(CurrentArg);
+ for (unsigned I = 0; I < NumCandidates; ++I) {
+ const auto &Candidate = Candidates[I];
+ const auto *CCS = Candidate.CreateSignatureString(
+ CurrentArg, S, *Allocator, CCTUInfo, true);
+ assert(CCS && "Expected the CodeCompletionString to be non-null");
+ // FIXME: for headers, we need to get a comment from the index.
+ SigHelp.signatures.push_back(processOverloadCandidate(
+ Candidate, *CCS,
+ getParameterDocComment(S.getASTContext(), Candidate, CurrentArg,
+ /*CommentsFromHeaders=*/false)));
+ }
+ }
+
+ GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
+
+ CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
+
+private:
+ // FIXME(ioeric): consider moving CodeCompletionString logic here to
+ // CompletionString.h.
+ SignatureInformation
+ processOverloadCandidate(const OverloadCandidate &Candidate,
+ const CodeCompletionString &CCS,
+ llvm::StringRef DocComment) const {
+ SignatureInformation Result;
+ const char *ReturnType = nullptr;
+
+ Result.documentation = formatDocumentation(CCS, DocComment);
+
+ for (const auto &Chunk : CCS) {
+ switch (Chunk.Kind) {
+ case CodeCompletionString::CK_ResultType:
+ // A piece of text that describes the type of an entity or,
+ // for functions and methods, the return type.
+ assert(!ReturnType && "Unexpected CK_ResultType");
+ ReturnType = Chunk.Text;
+ break;
+ case CodeCompletionString::CK_Placeholder:
+ // A string that acts as a placeholder for, e.g., a function call
+ // argument.
+ // Intentional fallthrough here.
+ case CodeCompletionString::CK_CurrentParameter: {
+ // A piece of text that describes the parameter that corresponds to
+ // the code-completion location within a function call, message send,
+ // macro invocation, etc.
+ Result.label += Chunk.Text;
+ ParameterInformation Info;
+ Info.label = Chunk.Text;
+ Result.parameters.push_back(std::move(Info));
+ break;
+ }
+ case CodeCompletionString::CK_Optional: {
+ // The rest of the parameters are defaulted/optional.
+ assert(Chunk.Optional &&
+ "Expected the optional code completion string to be non-null.");
+ Result.label +=
+ getOptionalParameters(*Chunk.Optional, Result.parameters);
+ break;
+ }
+ case CodeCompletionString::CK_VerticalSpace:
+ break;
+ default:
+ Result.label += Chunk.Text;
+ break;
+ }
+ }
+ if (ReturnType) {
+ Result.label += " -> ";
+ Result.label += ReturnType;
+ }
+ return Result;
+ }
+
+ SignatureHelp &SigHelp;
+ std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
+ CodeCompletionTUInfo CCTUInfo;
+
+}; // SignatureHelpCollector
+
+struct SemaCompleteInput {
+ PathRef FileName;
+ const tooling::CompileCommand &Command;
+ PrecompiledPreamble const *Preamble;
+ StringRef Contents;
+ Position Pos;
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS;
+ std::shared_ptr<PCHContainerOperations> PCHs;
+};
+
+// Invokes Sema code completion on a file.
+// If \p Includes is set, it will be updated based on the compiler invocation.
+bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
+ const clang::CodeCompleteOptions &Options,
+ const SemaCompleteInput &Input,
+ IncludeStructure *Includes = nullptr) {
+ trace::Span Tracer("Sema completion");
+ std::vector<const char *> ArgStrs;
+ for (const auto &S : Input.Command.CommandLine)
+ ArgStrs.push_back(S.c_str());
+
+ if (Input.VFS->setCurrentWorkingDirectory(Input.Command.Directory)) {
+ log("Couldn't set working directory");
+ // We run parsing anyway, our lit-tests rely on results for non-existing
+ // working dirs.
+ }
+
+ IgnoreDiagnostics DummyDiagsConsumer;
+ auto CI = createInvocationFromCommandLine(
+ ArgStrs,
+ CompilerInstance::createDiagnostics(new DiagnosticOptions,
+ &DummyDiagsConsumer, false),
+ Input.VFS);
+ if (!CI) {
+ elog("Couldn't create CompilerInvocation");
+ return false;
+ }
+ auto &FrontendOpts = CI->getFrontendOpts();
+ FrontendOpts.DisableFree = false;
+ FrontendOpts.SkipFunctionBodies = true;
+ CI->getLangOpts()->CommentOpts.ParseAllComments = true;
+ // Disable typo correction in Sema.
+ CI->getLangOpts()->SpellChecking = false;
+ // Setup code completion.
+ FrontendOpts.CodeCompleteOpts = Options;
+ FrontendOpts.CodeCompletionAt.FileName = Input.FileName;
+ auto Offset = positionToOffset(Input.Contents, Input.Pos);
+ if (!Offset) {
+ elog("Code completion position was invalid {0}", Offset.takeError());
+ return false;
+ }
+ std::tie(FrontendOpts.CodeCompletionAt.Line,
+ FrontendOpts.CodeCompletionAt.Column) =
+ offsetToClangLineColumn(Input.Contents, *Offset);
+
+ std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
+ llvm::MemoryBuffer::getMemBufferCopy(Input.Contents, Input.FileName);
+ // The diagnostic options must be set before creating a CompilerInstance.
+ CI->getDiagnosticOpts().IgnoreWarnings = true;
+ // We reuse the preamble whether it's valid or not. This is a
+ // correctness/performance tradeoff: building without a preamble is slow, and
+ // completion is latency-sensitive.
+ // NOTE: we must call BeginSourceFile after prepareCompilerInstance. Otherwise
+ // the remapped buffers do not get freed.
+ auto Clang = prepareCompilerInstance(
+ std::move(CI), Input.Preamble, std::move(ContentsBuffer),
+ std::move(Input.PCHs), std::move(Input.VFS), DummyDiagsConsumer);
+ Clang->setCodeCompletionConsumer(Consumer.release());
+
+ SyntaxOnlyAction Action;
+ if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
+ log("BeginSourceFile() failed when running codeComplete for {0}",
+ Input.FileName);
+ return false;
+ }
+ if (Includes)
+ Clang->getPreprocessor().addPPCallbacks(
+ collectIncludeStructureCallback(Clang->getSourceManager(), Includes));
+ if (!Action.Execute()) {
+ log("Execute() failed when running codeComplete for {0}", Input.FileName);
+ return false;
+ }
+ Action.EndSourceFile();
+
+ return true;
+}
+
+// Should we allow index completions in the specified context?
+bool allowIndex(CodeCompletionContext &CC) {
+ if (!contextAllowsIndex(CC.getKind()))
+ return false;
+ // We also avoid ClassName::bar (but allow namespace::bar).
+ auto Scope = CC.getCXXScopeSpecifier();
+ if (!Scope)
+ return true;
+ NestedNameSpecifier *NameSpec = (*Scope)->getScopeRep();
+ if (!NameSpec)
+ return true;
+ // We only query the index when qualifier is a namespace.
+ // If it's a class, we rely solely on sema completions.
+ switch (NameSpec->getKind()) {
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ return true;
+ case NestedNameSpecifier::Super:
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ // Unresolved inside a template.
+ case NestedNameSpecifier::Identifier:
+ return false;
+ }
+ llvm_unreachable("invalid NestedNameSpecifier kind");
+}
+
+} // namespace
+
+clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const {
+ clang::CodeCompleteOptions Result;
+ Result.IncludeCodePatterns = EnableSnippets && IncludeCodePatterns;
+ Result.IncludeMacros = IncludeMacros;
+ Result.IncludeGlobals = true;
+ // We choose to include full comments and not do doxygen parsing in
+ // completion.
+ // FIXME: ideally, we should support doxygen in some form, e.g. do markdown
+ // formatting of the comments.
+ Result.IncludeBriefComments = false;
+
+ // When an is used, Sema is responsible for completing the main file,
+ // the index can provide results from the preamble.
+ // Tell Sema not to deserialize the preamble to look for results.
+ Result.LoadExternal = !Index;
+
+ return Result;
+}
+
+// Runs Sema-based (AST) and Index-based completion, returns merged results.
+//
+// There are a few tricky considerations:
+// - the AST provides information needed for the index query (e.g. which
+// namespaces to search in). So Sema must start first.
+// - we only want to return the top results (Opts.Limit).
+// Building CompletionItems for everything else is wasteful, so we want to
+// preserve the "native" format until we're done with scoring.
+// - the data underlying Sema completion items is owned by the AST and various
+// other arenas, which must stay alive for us to build CompletionItems.
+// - we may get duplicate results from Sema and the Index, we need to merge.
+//
+// So we start Sema completion first, and do all our work in its callback.
+// We use the Sema context information to query the index.
+// Then we merge the two result sets, producing items that are Sema/Index/Both.
+// These items are scored, and the top N are synthesized into the LSP response.
+// Finally, we can clean up the data structures created by Sema completion.
+//
+// Main collaborators are:
+// - semaCodeComplete sets up the compiler machinery to run code completion.
+// - CompletionRecorder captures Sema completion results, including context.
+// - SymbolIndex (Opts.Index) provides index completion results as Symbols
+// - CompletionCandidates are the result of merging Sema and Index results.
+// Each candidate points to an underlying CodeCompletionResult (Sema), a
+// Symbol (Index), or both. It computes the result quality score.
+// CompletionCandidate also does conversion to CompletionItem (at the end).
+// - FuzzyMatcher scores how the candidate matches the partial identifier.
+// This score is combined with the result quality score for the final score.
+// - TopN determines the results with the best score.
+class CodeCompleteFlow {
+ PathRef FileName;
+ IncludeStructure Includes; // Complete once the compiler runs.
+ const CodeCompleteOptions &Opts;
+ // Sema takes ownership of Recorder. Recorder is valid until Sema cleanup.
+ CompletionRecorder *Recorder = nullptr;
+ int NSema = 0, NIndex = 0, NBoth = 0; // Counters for logging.
+ bool Incomplete = false; // Would more be available with a higher limit?
+ llvm::Optional<FuzzyMatcher> Filter; // Initialized once Sema runs.
+ std::vector<std::string> QueryScopes; // Initialized once Sema runs.
+ // Include-insertion and proximity scoring rely on the include structure.
+ // This is available after Sema has run.
+ llvm::Optional<IncludeInserter> Inserter; // Available during runWithSema.
+ llvm::Optional<URIDistance> FileProximity; // Initialized once Sema runs.
+
+public:
+ // A CodeCompleteFlow object is only useful for calling run() exactly once.
+ CodeCompleteFlow(PathRef FileName, const IncludeStructure &Includes,
+ const CodeCompleteOptions &Opts)
+ : FileName(FileName), Includes(Includes), Opts(Opts) {}
+
+ CodeCompleteResult run(const SemaCompleteInput &SemaCCInput) && {
+ trace::Span Tracer("CodeCompleteFlow");
+
+ // We run Sema code completion first. It builds an AST and calculates:
+ // - completion results based on the AST.
+ // - partial identifier and context. We need these for the index query.
+ CodeCompleteResult Output;
+ auto RecorderOwner = llvm::make_unique<CompletionRecorder>(Opts, [&]() {
+ assert(Recorder && "Recorder is not set");
+ auto Style =
+ format::getStyle(format::DefaultFormatStyle, SemaCCInput.FileName,
+ format::DefaultFallbackStyle, SemaCCInput.Contents,
+ SemaCCInput.VFS.get());
+ if (!Style) {
+ log("getStyle() failed for file {0}: {1}. Fallback is LLVM style.",
+ SemaCCInput.FileName, Style.takeError());
+ Style = format::getLLVMStyle();
+ }
+ // If preprocessor was run, inclusions from preprocessor callback should
+ // already be added to Includes.
+ Inserter.emplace(
+ SemaCCInput.FileName, SemaCCInput.Contents, *Style,
+ SemaCCInput.Command.Directory,
+ Recorder->CCSema->getPreprocessor().getHeaderSearchInfo());
+ for (const auto &Inc : Includes.MainFileIncludes)
+ Inserter->addExisting(Inc);
+
+ // Most of the cost of file proximity is in initializing the FileDistance
+ // structures based on the observed includes, once per query. Conceptually
+ // that happens here (though the per-URI-scheme initialization is lazy).
+ // The per-result proximity scoring is (amortized) very cheap.
+ FileDistanceOptions ProxOpts{}; // Use defaults.
+ const auto &SM = Recorder->CCSema->getSourceManager();
+ llvm::StringMap<SourceParams> ProxSources;
+ for (auto &Entry : Includes.includeDepth(
+ SM.getFileEntryForID(SM.getMainFileID())->getName())) {
+ auto &Source = ProxSources[Entry.getKey()];
+ Source.Cost = Entry.getValue() * ProxOpts.IncludeCost;
+ // Symbols near our transitive includes are good, but only consider
+ // things in the same directory or below it. Otherwise there can be
+ // many false positives.
+ if (Entry.getValue() > 0)
+ Source.MaxUpTraversals = 1;
+ }
+ FileProximity.emplace(ProxSources, ProxOpts);
+
+ Output = runWithSema();
+ Inserter.reset(); // Make sure this doesn't out-live Clang.
+ SPAN_ATTACH(Tracer, "sema_completion_kind",
+ getCompletionKindString(Recorder->CCContext.getKind()));
+ log("Code complete: sema context {0}, query scopes [{1}]",
+ getCompletionKindString(Recorder->CCContext.getKind()),
+ llvm::join(QueryScopes.begin(), QueryScopes.end(), ","));
+ });
+
+ Recorder = RecorderOwner.get();
+ semaCodeComplete(std::move(RecorderOwner), Opts.getClangCompleteOpts(),
+ SemaCCInput, &Includes);
+
+ SPAN_ATTACH(Tracer, "sema_results", NSema);
+ SPAN_ATTACH(Tracer, "index_results", NIndex);
+ SPAN_ATTACH(Tracer, "merged_results", NBoth);
+ SPAN_ATTACH(Tracer, "returned_results", int64_t(Output.Completions.size()));
+ SPAN_ATTACH(Tracer, "incomplete", Output.HasMore);
+ log("Code complete: {0} results from Sema, {1} from Index, "
+ "{2} matched, {3} returned{4}.",
+ NSema, NIndex, NBoth, Output.Completions.size(),
+ Output.HasMore ? " (incomplete)" : "");
+ assert(!Opts.Limit || Output.Completions.size() <= Opts.Limit);
+ // We don't assert that isIncomplete means we hit a limit.
+ // Indexes may choose to impose their own limits even if we don't have one.
+ return Output;
+ }
+
+private:
+ // This is called by run() once Sema code completion is done, but before the
+ // Sema data structures are torn down. It does all the real work.
+ CodeCompleteResult runWithSema() {
+ Filter = FuzzyMatcher(
+ Recorder->CCSema->getPreprocessor().getCodeCompletionFilter());
+ QueryScopes = getQueryScopes(Recorder->CCContext,
+ Recorder->CCSema->getSourceManager());
+ // Sema provides the needed context to query the index.
+ // FIXME: in addition to querying for extra/overlapping symbols, we should
+ // explicitly request symbols corresponding to Sema results.
+ // We can use their signals even if the index can't suggest them.
+ // We must copy index results to preserve them, but there are at most Limit.
+ auto IndexResults = (Opts.Index && allowIndex(Recorder->CCContext))
+ ? queryIndex()
+ : SymbolSlab();
+ // Merge Sema and Index results, score them, and pick the winners.
+ auto Top = mergeResults(Recorder->Results, IndexResults);
+ // Convert the results to final form, assembling the expensive strings.
+ CodeCompleteResult Output;
+ for (auto &C : Top) {
+ Output.Completions.push_back(toCodeCompletion(C.first));
+ Output.Completions.back().Score = C.second;
+ }
+ Output.HasMore = Incomplete;
+ Output.Context = Recorder->CCContext.getKind();
+ return Output;
+ }
+
+ SymbolSlab queryIndex() {
+ trace::Span Tracer("Query index");
+ SPAN_ATTACH(Tracer, "limit", int64_t(Opts.Limit));
+
+ SymbolSlab::Builder ResultsBuilder;
+ // Build the query.
+ FuzzyFindRequest Req;
+ if (Opts.Limit)
+ Req.MaxCandidateCount = Opts.Limit;
+ Req.Query = Filter->pattern();
+ Req.RestrictForCodeCompletion = true;
+ Req.Scopes = QueryScopes;
+ // FIXME: we should send multiple weighted paths here.
+ Req.ProximityPaths.push_back(FileName);
+ vlog("Code complete: fuzzyFind(\"{0}\", scopes=[{1}])", Req.Query,
+ llvm::join(Req.Scopes.begin(), Req.Scopes.end(), ","));
+ // Run the query against the index.
+ if (Opts.Index->fuzzyFind(
+ Req, [&](const Symbol &Sym) { ResultsBuilder.insert(Sym); }))
+ Incomplete = true;
+ return std::move(ResultsBuilder).build();
+ }
+
+ // Merges Sema and Index results where possible, to form CompletionCandidates.
+ // Groups overloads if desired, to form CompletionCandidate::Bundles.
+ // The bundles are scored and top results are returned, best to worst.
+ std::vector<ScoredBundle>
+ mergeResults(const std::vector<CodeCompletionResult> &SemaResults,
+ const SymbolSlab &IndexResults) {
+ trace::Span Tracer("Merge and score results");
+ std::vector<CompletionCandidate::Bundle> Bundles;
+ llvm::DenseMap<size_t, size_t> BundleLookup;
+ auto AddToBundles = [&](const CodeCompletionResult *SemaResult,
+ const Symbol *IndexResult) {
+ CompletionCandidate C;
+ C.SemaResult = SemaResult;
+ C.IndexResult = IndexResult;
+ C.Name = IndexResult ? IndexResult->Name : Recorder->getName(*SemaResult);
+ if (auto OverloadSet = Opts.BundleOverloads ? C.overloadSet() : 0) {
+ auto Ret = BundleLookup.try_emplace(OverloadSet, Bundles.size());
+ if (Ret.second)
+ Bundles.emplace_back();
+ Bundles[Ret.first->second].push_back(std::move(C));
+ } else {
+ Bundles.emplace_back();
+ Bundles.back().push_back(std::move(C));
+ }
+ };
+ llvm::DenseSet<const Symbol *> UsedIndexResults;
+ auto CorrespondingIndexResult =
+ [&](const CodeCompletionResult &SemaResult) -> const Symbol * {
+ if (auto SymID = getSymbolID(SemaResult)) {
+ auto I = IndexResults.find(*SymID);
+ if (I != IndexResults.end()) {
+ UsedIndexResults.insert(&*I);
+ return &*I;
+ }
+ }
+ return nullptr;
+ };
+ // Emit all Sema results, merging them with Index results if possible.
+ for (auto &SemaResult : Recorder->Results)
+ AddToBundles(&SemaResult, CorrespondingIndexResult(SemaResult));
+ // Now emit any Index-only results.
+ for (const auto &IndexResult : IndexResults) {
+ if (UsedIndexResults.count(&IndexResult))
+ continue;
+ AddToBundles(/*SemaResult=*/nullptr, &IndexResult);
+ }
+ // We only keep the best N results at any time, in "native" format.
+ TopN<ScoredBundle, ScoredBundleGreater> Top(
+ Opts.Limit == 0 ? std::numeric_limits<size_t>::max() : Opts.Limit);
+ for (auto &Bundle : Bundles)
+ addCandidate(Top, std::move(Bundle));
+ return std::move(Top).items();
+ }
+
+ Optional<float> fuzzyScore(const CompletionCandidate &C) {
+ // Macros can be very spammy, so we only support prefix completion.
+ // We won't end up with underfull index results, as macros are sema-only.
+ if (C.SemaResult && C.SemaResult->Kind == CodeCompletionResult::RK_Macro &&
+ !C.Name.startswith_lower(Filter->pattern()))
+ return None;
+ return Filter->match(C.Name);
+ }
+
+ // Scores a candidate and adds it to the TopN structure.
+ void addCandidate(TopN<ScoredBundle, ScoredBundleGreater> &Candidates,
+ CompletionCandidate::Bundle Bundle) {
+ SymbolQualitySignals Quality;
+ SymbolRelevanceSignals Relevance;
+ Relevance.Context = Recorder->CCContext.getKind();
+ Relevance.Query = SymbolRelevanceSignals::CodeComplete;
+ Relevance.FileProximityMatch = FileProximity.getPointer();
+ auto &First = Bundle.front();
+ if (auto FuzzyScore = fuzzyScore(First))
+ Relevance.NameMatch = *FuzzyScore;
+ else
+ return;
+ SymbolOrigin Origin = SymbolOrigin::Unknown;
+ bool FromIndex = false;
+ for (const auto &Candidate : Bundle) {
+ if (Candidate.IndexResult) {
+ Quality.merge(*Candidate.IndexResult);
+ Relevance.merge(*Candidate.IndexResult);
+ Origin |= Candidate.IndexResult->Origin;
+ FromIndex = true;
+ }
+ if (Candidate.SemaResult) {
+ Quality.merge(*Candidate.SemaResult);
+ Relevance.merge(*Candidate.SemaResult);
+ Origin |= SymbolOrigin::AST;
+ }
+ }
+
+ CodeCompletion::Scores Scores;
+ Scores.Quality = Quality.evaluate();
+ Scores.Relevance = Relevance.evaluate();
+ Scores.Total = evaluateSymbolAndRelevance(Scores.Quality, Scores.Relevance);
+ // NameMatch is in fact a multiplier on total score, so rescoring is sound.
+ Scores.ExcludingName = Relevance.NameMatch
+ ? Scores.Total / Relevance.NameMatch
+ : Scores.Quality;
+
+ dlog("CodeComplete: {0} ({1}) = {2}\n{3}{4}\n", First.Name,
+ llvm::to_string(Origin), Scores.Total, llvm::to_string(Quality),
+ llvm::to_string(Relevance));
+
+ NSema += bool(Origin & SymbolOrigin::AST);
+ NIndex += FromIndex;
+ NBoth += bool(Origin & SymbolOrigin::AST) && FromIndex;
+ if (Candidates.push({std::move(Bundle), Scores}))
+ Incomplete = true;
+ }
+
+ CodeCompletion toCodeCompletion(const CompletionCandidate::Bundle &Bundle) {
+ llvm::Optional<CodeCompletionBuilder> Builder;
+ for (const auto &Item : Bundle) {
+ CodeCompletionString *SemaCCS =
+ Item.SemaResult ? Recorder->codeCompletionString(*Item.SemaResult)
+ : nullptr;
+ if (!Builder)
+ Builder.emplace(Recorder->CCSema->getASTContext(), Item, SemaCCS,
+ *Inserter, FileName, Opts);
+ else
+ Builder->add(Item, SemaCCS);
+ }
+ return Builder->build();
+ }
+};
+
+CodeCompleteResult codeComplete(PathRef FileName,
+ const tooling::CompileCommand &Command,
+ PrecompiledPreamble const *Preamble,
+ const IncludeStructure &PreambleInclusions,
+ StringRef Contents, Position Pos,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ CodeCompleteOptions Opts) {
+ return CodeCompleteFlow(FileName, PreambleInclusions, Opts)
+ .run({FileName, Command, Preamble, Contents, Pos, VFS, PCHs});
+}
+
+SignatureHelp signatureHelp(PathRef FileName,
+ const tooling::CompileCommand &Command,
+ PrecompiledPreamble const *Preamble,
+ StringRef Contents, Position Pos,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHs) {
+ SignatureHelp Result;
+ clang::CodeCompleteOptions Options;
+ Options.IncludeGlobals = false;
+ Options.IncludeMacros = false;
+ Options.IncludeCodePatterns = false;
+ Options.IncludeBriefComments = false;
+ IncludeStructure PreambleInclusions; // Unused for signatureHelp
+ semaCodeComplete(llvm::make_unique<SignatureHelpCollector>(Options, Result),
+ Options,
+ {FileName, Command, Preamble, Contents, Pos, std::move(VFS),
+ std::move(PCHs)});
+ return Result;
+}
+
+bool isIndexedForCodeCompletion(const NamedDecl &ND, ASTContext &ASTCtx) {
+ using namespace clang::ast_matchers;
+ auto InTopLevelScope = hasDeclContext(
+ anyOf(namespaceDecl(), translationUnitDecl(), linkageSpecDecl()));
+ return !match(decl(anyOf(InTopLevelScope,
+ hasDeclContext(
+ enumDecl(InTopLevelScope, unless(isScoped()))))),
+ ND, ASTCtx)
+ .empty();
+}
+
+CompletionItem CodeCompletion::render(const CodeCompleteOptions &Opts) const {
+ CompletionItem LSP;
+ LSP.label = (HeaderInsertion ? Opts.IncludeIndicator.Insert
+ : Opts.IncludeIndicator.NoInsert) +
+ (Opts.ShowOrigins ? "[" + llvm::to_string(Origin) + "]" : "") +
+ RequiredQualifier + Name + Signature;
+
+ LSP.kind = Kind;
+ LSP.detail = BundleSize > 1 ? llvm::formatv("[{0} overloads]", BundleSize)
+ : ReturnType;
+ if (!Header.empty())
+ LSP.detail += "\n" + Header;
+ LSP.documentation = Documentation;
+ LSP.sortText = sortText(Score.Total, Name);
+ LSP.filterText = Name;
+ LSP.insertText = RequiredQualifier + Name;
+ if (Opts.EnableSnippets)
+ LSP.insertText += SnippetSuffix;
+ LSP.insertTextFormat = Opts.EnableSnippets ? InsertTextFormat::Snippet
+ : InsertTextFormat::PlainText;
+ if (HeaderInsertion)
+ LSP.additionalTextEdits = {*HeaderInsertion};
+ return LSP;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const CodeCompletion &C) {
+ // For now just lean on CompletionItem.
+ return OS << C.render(CodeCompleteOptions());
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const CodeCompleteResult &R) {
+ OS << "CodeCompleteResult: " << R.Completions.size() << (R.HasMore ? "+" : "")
+ << " (" << getCompletionKindString(R.Context) << ")"
+ << " items:\n";
+ for (const auto &C : R.Completions)
+ OS << C << "\n";
+ return OS;
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/CodeComplete.h b/src/third_party/llvm-project/clang-tools-extra/clangd/CodeComplete.h
new file mode 100644
index 0000000..884149d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/CodeComplete.h
@@ -0,0 +1,184 @@
+//===--- CodeComplete.h -----------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// Code completion provides suggestions for what the user might type next.
+// After "std::string S; S." we might suggest members of std::string.
+// Signature help describes the parameters of a function as you type them.
+//
+//===---------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETE_H
+
+#include "Headers.h"
+#include "Logger.h"
+#include "Path.h"
+#include "Protocol.h"
+#include "index/Index.h"
+#include "clang/Frontend/PrecompiledPreamble.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Sema/CodeCompleteOptions.h"
+#include "clang/Tooling/CompilationDatabase.h"
+
+namespace clang {
+class NamedDecl;
+class PCHContainerOperations;
+namespace clangd {
+
+struct CodeCompleteOptions {
+ /// Returns options that can be passed to clang's completion engine.
+ clang::CodeCompleteOptions getClangCompleteOpts() const;
+
+ /// When true, completion items will contain expandable code snippets in
+ /// completion (e.g. `return ${1:expression}` or `foo(${1:int a}, ${2:int
+ /// b})).
+ bool EnableSnippets = false;
+
+ /// Add code patterns to completion results.
+ /// If EnableSnippets is false, this options is ignored and code patterns will
+ /// always be omitted.
+ bool IncludeCodePatterns = true;
+
+ /// Add macros to code completion results.
+ bool IncludeMacros = true;
+
+ /// Add comments to code completion results, if available.
+ bool IncludeComments = true;
+
+ /// Include results that are not legal completions in the current context.
+ /// For example, private members are usually inaccessible.
+ bool IncludeIneligibleResults = false;
+
+ /// Combine overloads into a single completion item where possible.
+ bool BundleOverloads = false;
+
+ /// Limit the number of results returned (0 means no limit).
+ /// If more results are available, we set CompletionList.isIncomplete.
+ size_t Limit = 0;
+
+ /// A visual indicator to prepend to the completion label to indicate whether
+ /// completion result would trigger an #include insertion or not.
+ struct IncludeInsertionIndicator {
+ std::string Insert = "•";
+ std::string NoInsert = " ";
+ } IncludeIndicator;
+
+ /// Expose origins of completion items in the label (for debugging).
+ bool ShowOrigins = false;
+
+ // Populated internally by clangd, do not set.
+ /// If `Index` is set, it is used to augment the code completion
+ /// results.
+ /// FIXME(ioeric): we might want a better way to pass the index around inside
+ /// clangd.
+ const SymbolIndex *Index = nullptr;
+};
+
+// Semi-structured representation of a code-complete suggestion for our C++ API.
+// We don't use the LSP structures here (unlike most features) as we want
+// to expose more data to allow for more precise testing and evaluation.
+struct CodeCompletion {
+ // The unqualified name of the symbol or other completion item.
+ std::string Name;
+ // The scope qualifier for the symbol name. e.g. "ns1::ns2::"
+ // Empty for non-symbol completions. Not inserted, but may be displayed.
+ std::string Scope;
+ // Text that must be inserted before the name, and displayed (e.g. base::).
+ std::string RequiredQualifier;
+ // Details to be displayed following the name. Not inserted.
+ std::string Signature;
+ // Text to be inserted following the name, in snippet format.
+ std::string SnippetSuffix;
+ // Type to be displayed for this completion.
+ std::string ReturnType;
+ std::string Documentation;
+ CompletionItemKind Kind = CompletionItemKind::Missing;
+ // This completion item may represent several symbols that can be inserted in
+ // the same way, such as function overloads. In this case BundleSize > 1, and
+ // the following fields are summaries:
+ // - Signature is e.g. "(...)" for functions.
+ // - SnippetSuffix is similarly e.g. "(${0})".
+ // - ReturnType may be empty
+ // - Documentation may be from one symbol, or a combination of several
+ // Other fields should apply equally to all bundled completions.
+ unsigned BundleSize = 1;
+ SymbolOrigin Origin = SymbolOrigin::Unknown;
+ // The header through which this symbol could be included.
+ // Quoted string as expected by an #include directive, e.g. "<memory>".
+ // Empty for non-symbol completions, or when not known.
+ std::string Header;
+ // Present if Header is set and should be inserted to use this item.
+ llvm::Optional<TextEdit> HeaderInsertion;
+
+ // Scores are used to rank completion items.
+ struct Scores {
+ // The score that items are ranked by.
+ float Total = 0.f;
+
+ // The finalScore with the fuzzy name match score excluded.
+ // When filtering client-side, editors should calculate the new fuzzy score,
+ // whose scale is 0-1 (with 1 = prefix match, special case 2 = exact match),
+ // and recompute finalScore = fuzzyScore * symbolScore.
+ float ExcludingName = 0.f;
+
+ // Component scores that contributed to the final score:
+
+ // Quality describes how important we think this candidate is,
+ // independent of the query.
+ // e.g. symbols with lots of incoming references have higher quality.
+ float Quality = 0.f;
+ // Relevance describes how well this candidate matched the query.
+ // e.g. symbols from nearby files have higher relevance.
+ float Relevance = 0.f;
+ };
+ Scores Score;
+
+ // Serialize this to an LSP completion item. This is a lossy operation.
+ CompletionItem render(const CodeCompleteOptions &) const;
+};
+raw_ostream &operator<<(raw_ostream &, const CodeCompletion &);
+struct CodeCompleteResult {
+ std::vector<CodeCompletion> Completions;
+ bool HasMore = false;
+ CodeCompletionContext::Kind Context = CodeCompletionContext::CCC_Other;
+};
+raw_ostream &operator<<(raw_ostream &, const CodeCompleteResult &);
+
+/// Get code completions at a specified \p Pos in \p FileName.
+CodeCompleteResult codeComplete(PathRef FileName,
+ const tooling::CompileCommand &Command,
+ PrecompiledPreamble const *Preamble,
+ const IncludeStructure &PreambleInclusions,
+ StringRef Contents, Position Pos,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ CodeCompleteOptions Opts);
+
+/// Get signature help at a specified \p Pos in \p FileName.
+SignatureHelp signatureHelp(PathRef FileName,
+ const tooling::CompileCommand &Command,
+ PrecompiledPreamble const *Preamble,
+ StringRef Contents, Position Pos,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHs);
+
+// For index-based completion, we only consider:
+// * symbols in namespaces or translation unit scopes (e.g. no class
+// members, no locals)
+// * enum constants in unscoped enum decl (e.g. "red" in "enum {red};")
+// * primary templates (no specializations)
+// For the other cases, we let Clang do the completion because it does not
+// need any non-local information and it will be much better at following
+// lookup rules. Other symbols still appear in the index for other purposes,
+// like workspace/symbols or textDocument/definition, but are not used for code
+// completion.
+bool isIndexedForCodeCompletion(const NamedDecl &ND, ASTContext &ASTCtx);
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/CodeCompletionStrings.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/CodeCompletionStrings.cpp
new file mode 100644
index 0000000..88b37da
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/CodeCompletionStrings.cpp
@@ -0,0 +1,204 @@
+//===--- CodeCompletionStrings.cpp -------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "CodeCompletionStrings.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/RawCommentList.h"
+#include "clang/Basic/SourceManager.h"
+#include <utility>
+
+namespace clang {
+namespace clangd {
+
+namespace {
+
+bool isInformativeQualifierChunk(CodeCompletionString::Chunk const &Chunk) {
+ return Chunk.Kind == CodeCompletionString::CK_Informative &&
+ StringRef(Chunk.Text).endswith("::");
+}
+
+void appendEscapeSnippet(const llvm::StringRef Text, std::string *Out) {
+ for (const auto Character : Text) {
+ if (Character == '$' || Character == '}' || Character == '\\')
+ Out->push_back('\\');
+ Out->push_back(Character);
+ }
+}
+
+bool looksLikeDocComment(llvm::StringRef CommentText) {
+ // We don't report comments that only contain "special" chars.
+ // This avoids reporting various delimiters, like:
+ // =================
+ // -----------------
+ // *****************
+ return CommentText.find_first_not_of("/*-= \t\r\n") != llvm::StringRef::npos;
+}
+
+} // namespace
+
+std::string getDocComment(const ASTContext &Ctx,
+ const CodeCompletionResult &Result,
+ bool CommentsFromHeaders) {
+ // FIXME: clang's completion also returns documentation for RK_Pattern if they
+ // contain a pattern for ObjC properties. Unfortunately, there is no API to
+ // get this declaration, so we don't show documentation in that case.
+ if (Result.Kind != CodeCompletionResult::RK_Declaration)
+ return "";
+ auto *Decl = Result.getDeclaration();
+ if (!Decl || llvm::isa<NamespaceDecl>(Decl)) {
+ // Namespaces often have too many redecls for any particular redecl comment
+ // to be useful. Moreover, we often confuse file headers or generated
+ // comments with namespace comments. Therefore we choose to just ignore
+ // the comments for namespaces.
+ return "";
+ }
+ const RawComment *RC = getCompletionComment(Ctx, Decl);
+ if (!RC)
+ return "";
+
+ // Sanity check that the comment does not come from the PCH. We choose to not
+ // write them into PCH, because they are racy and slow to load.
+ assert(!Ctx.getSourceManager().isLoadedSourceLocation(RC->getLocStart()));
+ std::string Doc = RC->getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics());
+ if (!looksLikeDocComment(Doc))
+ return "";
+ return Doc;
+}
+
+std::string
+getParameterDocComment(const ASTContext &Ctx,
+ const CodeCompleteConsumer::OverloadCandidate &Result,
+ unsigned ArgIndex, bool CommentsFromHeaders) {
+ auto *Func = Result.getFunction();
+ if (!Func)
+ return "";
+ const RawComment *RC = getParameterComment(Ctx, Result, ArgIndex);
+ if (!RC)
+ return "";
+ // Sanity check that the comment does not come from the PCH. We choose to not
+ // write them into PCH, because they are racy and slow to load.
+ assert(!Ctx.getSourceManager().isLoadedSourceLocation(RC->getLocStart()));
+ std::string Doc = RC->getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics());
+ if (!looksLikeDocComment(Doc))
+ return "";
+ return Doc;
+}
+
+void getSignature(const CodeCompletionString &CCS, std::string *Signature,
+ std::string *Snippet, std::string *RequiredQualifiers) {
+ unsigned ArgCount = 0;
+ for (const auto &Chunk : CCS) {
+ // Informative qualifier chunks only clutter completion results, skip
+ // them.
+ if (isInformativeQualifierChunk(Chunk))
+ continue;
+
+ switch (Chunk.Kind) {
+ case CodeCompletionString::CK_TypedText:
+ // The typed-text chunk is the actual name. We don't record this chunk.
+ // In general our string looks like <qualifiers><name><signature>.
+ // So once we see the name, any text we recorded so far should be
+ // reclassified as qualifiers.
+ if (RequiredQualifiers)
+ *RequiredQualifiers = std::move(*Signature);
+ Signature->clear();
+ Snippet->clear();
+ break;
+ case CodeCompletionString::CK_Text:
+ *Signature += Chunk.Text;
+ *Snippet += Chunk.Text;
+ break;
+ case CodeCompletionString::CK_Optional:
+ break;
+ case CodeCompletionString::CK_Placeholder:
+ *Signature += Chunk.Text;
+ ++ArgCount;
+ *Snippet += "${" + std::to_string(ArgCount) + ':';
+ appendEscapeSnippet(Chunk.Text, Snippet);
+ *Snippet += '}';
+ break;
+ case CodeCompletionString::CK_Informative:
+ // For example, the word "const" for a const method, or the name of
+ // the base class for methods that are part of the base class.
+ *Signature += Chunk.Text;
+ // Don't put the informative chunks in the snippet.
+ break;
+ case CodeCompletionString::CK_ResultType:
+ // This is not part of the signature.
+ break;
+ case CodeCompletionString::CK_CurrentParameter:
+ // This should never be present while collecting completion items,
+ // only while collecting overload candidates.
+ llvm_unreachable("Unexpected CK_CurrentParameter while collecting "
+ "CompletionItems");
+ break;
+ case CodeCompletionString::CK_LeftParen:
+ case CodeCompletionString::CK_RightParen:
+ case CodeCompletionString::CK_LeftBracket:
+ case CodeCompletionString::CK_RightBracket:
+ case CodeCompletionString::CK_LeftBrace:
+ case CodeCompletionString::CK_RightBrace:
+ case CodeCompletionString::CK_LeftAngle:
+ case CodeCompletionString::CK_RightAngle:
+ case CodeCompletionString::CK_Comma:
+ case CodeCompletionString::CK_Colon:
+ case CodeCompletionString::CK_SemiColon:
+ case CodeCompletionString::CK_Equal:
+ case CodeCompletionString::CK_HorizontalSpace:
+ *Signature += Chunk.Text;
+ *Snippet += Chunk.Text;
+ break;
+ case CodeCompletionString::CK_VerticalSpace:
+ *Snippet += Chunk.Text;
+ // Don't even add a space to the signature.
+ break;
+ }
+ }
+}
+
+std::string formatDocumentation(const CodeCompletionString &CCS,
+ llvm::StringRef DocComment) {
+ // Things like __attribute__((nonnull(1,3))) and [[noreturn]]. Present this
+ // information in the documentation field.
+ std::string Result;
+ const unsigned AnnotationCount = CCS.getAnnotationCount();
+ if (AnnotationCount > 0) {
+ Result += "Annotation";
+ if (AnnotationCount == 1) {
+ Result += ": ";
+ } else /* AnnotationCount > 1 */ {
+ Result += "s: ";
+ }
+ for (unsigned I = 0; I < AnnotationCount; ++I) {
+ Result += CCS.getAnnotation(I);
+ Result.push_back(I == AnnotationCount - 1 ? '\n' : ' ');
+ }
+ }
+ // Add brief documentation (if there is any).
+ if (!DocComment.empty()) {
+ if (!Result.empty()) {
+ // This means we previously added annotations. Add an extra newline
+ // character to make the annotations stand out.
+ Result.push_back('\n');
+ }
+ Result += DocComment;
+ }
+ return Result;
+}
+
+std::string getReturnType(const CodeCompletionString &CCS) {
+ for (const auto &Chunk : CCS)
+ if (Chunk.Kind == CodeCompletionString::CK_ResultType)
+ return Chunk.Text;
+ return "";
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/CodeCompletionStrings.h b/src/third_party/llvm-project/clang-tools-extra/clangd/CodeCompletionStrings.h
new file mode 100644
index 0000000..dac4ba5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/CodeCompletionStrings.h
@@ -0,0 +1,73 @@
+//===--- CodeCompletionStrings.h ---------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// Functions for retrieving code completion information from
+// `CodeCompletionString`.
+//
+//===---------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETIONSTRINGS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETIONSTRINGS_H
+
+#include "clang/Sema/CodeCompleteConsumer.h"
+
+namespace clang {
+class ASTContext;
+
+namespace clangd {
+
+/// Gets a minimally formatted documentation comment of \p Result, with comment
+/// markers stripped. See clang::RawComment::getFormattedText() for the detailed
+/// explanation of how the comment text is transformed.
+/// Returns empty string when no comment is available.
+/// If \p CommentsFromHeaders parameter is set, only comments from the main
+/// file will be returned. It is used to workaround crashes when parsing
+/// comments in the stale headers, coming from completion preamble.
+std::string getDocComment(const ASTContext &Ctx,
+ const CodeCompletionResult &Result,
+ bool CommentsFromHeaders);
+
+/// Gets a minimally formatted documentation for parameter of \p Result,
+/// corresponding to argument number \p ArgIndex.
+/// This currently looks for comments attached to the parameter itself, and
+/// doesn't extract them from function documentation.
+/// Returns empty string when no comment is available.
+/// If \p CommentsFromHeaders parameter is set, only comments from the main
+/// file will be returned. It is used to workaround crashes when parsing
+/// comments in the stale headers, coming from completion preamble.
+std::string
+getParameterDocComment(const ASTContext &Ctx,
+ const CodeCompleteConsumer::OverloadCandidate &Result,
+ unsigned ArgIndex, bool CommentsFromHeaders);
+
+/// Formats the signature for an item, as a display string and snippet.
+/// e.g. for const_reference std::vector<T>::at(size_type) const, this returns:
+/// *Signature = "(size_type) const"
+/// *Snippet = "(${0:size_type})"
+/// If set, RequiredQualifiers is the text that must be typed before the name.
+/// e.g "Base::" when calling a base class member function that's hidden.
+void getSignature(const CodeCompletionString &CCS, std::string *Signature,
+ std::string *Snippet,
+ std::string *RequiredQualifiers = nullptr);
+
+/// Assembles formatted documentation for a completion result. This includes
+/// documentation comments and other relevant information like annotations.
+///
+/// \param DocComment is a documentation comment for the original declaration,
+/// it should be obtained via getDocComment or getParameterDocComment.
+std::string formatDocumentation(const CodeCompletionString &CCS,
+ llvm::StringRef DocComment);
+
+/// Gets detail to be used as the detail field in an LSP completion item. This
+/// is usually the return type of a function.
+std::string getReturnType(const CodeCompletionString &CCS);
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Compiler.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/Compiler.cpp
new file mode 100644
index 0000000..8fcc9a9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Compiler.cpp
@@ -0,0 +1,84 @@
+//===--- Compiler.cpp -------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "Compiler.h"
+#include "Logger.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+
+namespace clang {
+namespace clangd {
+
+void IgnoreDiagnostics::log(DiagnosticsEngine::Level DiagLevel,
+ const clang::Diagnostic &Info) {
+ SmallString<64> Message;
+ Info.FormatDiagnostic(Message);
+
+ SmallString<64> Location;
+ if (Info.hasSourceManager() && Info.getLocation().isValid()) {
+ auto &SourceMgr = Info.getSourceManager();
+ auto Loc = SourceMgr.getFileLoc(Info.getLocation());
+ llvm::raw_svector_ostream OS(Location);
+ Loc.print(OS, SourceMgr);
+ OS << ":";
+ }
+
+ clangd::log("Ignored diagnostic. {0}{1}", Location, Message);
+}
+
+void IgnoreDiagnostics::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const clang::Diagnostic &Info) {
+ IgnoreDiagnostics::log(DiagLevel, Info);
+}
+
+std::unique_ptr<CompilerInstance>
+prepareCompilerInstance(std::unique_ptr<clang::CompilerInvocation> CI,
+ const PrecompiledPreamble *Preamble,
+ std::unique_ptr<llvm::MemoryBuffer> Buffer,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ DiagnosticConsumer &DiagsClient) {
+ assert(VFS && "VFS is null");
+ assert(!CI->getPreprocessorOpts().RetainRemappedFileBuffers &&
+ "Setting RetainRemappedFileBuffers to true will cause a memory leak "
+ "of ContentsBuffer");
+
+ // NOTE: we use Buffer.get() when adding remapped files, so we have to make
+ // sure it will be released if no error is emitted.
+ if (Preamble) {
+ Preamble->OverridePreamble(*CI, VFS, Buffer.get());
+ } else {
+ CI->getPreprocessorOpts().addRemappedFile(
+ CI->getFrontendOpts().Inputs[0].getFile(), Buffer.get());
+ }
+
+ auto Clang = llvm::make_unique<CompilerInstance>(PCHs);
+ Clang->setInvocation(std::move(CI));
+ Clang->createDiagnostics(&DiagsClient, false);
+
+ if (auto VFSWithRemapping = createVFSFromCompilerInvocation(
+ Clang->getInvocation(), Clang->getDiagnostics(), VFS))
+ VFS = VFSWithRemapping;
+ Clang->setVirtualFileSystem(VFS);
+
+ Clang->setTarget(TargetInfo::CreateTargetInfo(
+ Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
+ if (!Clang->hasTarget())
+ return nullptr;
+
+ // RemappedFileBuffers will handle the lifetime of the Buffer pointer,
+ // release it.
+ Buffer.release();
+ return Clang;
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Compiler.h b/src/third_party/llvm-project/clang-tools-extra/clangd/Compiler.h
new file mode 100644
index 0000000..ce058ad
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Compiler.h
@@ -0,0 +1,53 @@
+//===--- Compiler.h ---------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// Shared utilities for invoking the clang compiler.
+// ClangdUnit takes care of much of this, but some features like CodeComplete
+// run their own compile actions that share logic.
+//
+//===---------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_COMPILER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_COMPILER_H
+
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/PrecompiledPreamble.h"
+
+namespace clang {
+namespace clangd {
+
+class IgnoreDiagnostics : public DiagnosticConsumer {
+public:
+ static void log(DiagnosticsEngine::Level DiagLevel,
+ const clang::Diagnostic &Info);
+
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const clang::Diagnostic &Info) override;
+};
+
+/// Creates a compiler instance, configured so that:
+/// - Contents of the parsed file are remapped to \p MainFile.
+/// - Preamble is overriden to use PCH passed to this function. It means the
+/// changes to the preamble headers or files included in the preamble are
+/// not visible to this compiler instance.
+/// - vfs::FileSystem is used for all underlying file accesses. The actual
+/// vfs used by the compiler may be an overlay over the passed vfs.
+/// Returns null on errors. When non-null value is returned, it is expected to
+/// be consumed by FrontendAction::BeginSourceFile to properly destroy \p
+/// MainFile.
+std::unique_ptr<CompilerInstance> prepareCompilerInstance(
+ std::unique_ptr<clang::CompilerInvocation>, const PrecompiledPreamble *,
+ std::unique_ptr<llvm::MemoryBuffer> MainFile,
+ std::shared_ptr<PCHContainerOperations>,
+ IntrusiveRefCntPtr<vfs::FileSystem>, DiagnosticConsumer &);
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Context.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/Context.cpp
new file mode 100644
index 0000000..1a9ef24
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Context.cpp
@@ -0,0 +1,36 @@
+//===--- Context.cpp -----------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "Context.h"
+#include <cassert>
+
+namespace clang {
+namespace clangd {
+
+Context Context::empty() { return Context(/*DataPtr=*/nullptr); }
+
+Context::Context(std::shared_ptr<const Data> DataPtr)
+ : DataPtr(std::move(DataPtr)) {}
+
+Context Context::clone() const { return Context(DataPtr); }
+
+static Context ¤tContext() {
+ static thread_local auto C = Context::empty();
+ return C;
+}
+
+const Context &Context::current() { return currentContext(); }
+
+Context Context::swapCurrent(Context Replacement) {
+ std::swap(Replacement, currentContext());
+ return Replacement;
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Context.h b/src/third_party/llvm-project/clang-tools-extra/clangd/Context.h
new file mode 100644
index 0000000..7e14f86
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Context.h
@@ -0,0 +1,223 @@
+//===--- Context.h - Mechanism for passing implicit data --------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Context for storing and retrieving implicit data. Useful for passing implicit
+// parameters on a per-request basis.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONTEXT_H_
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONTEXT_H_
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+#include <memory>
+#include <type_traits>
+
+namespace clang {
+namespace clangd {
+
+/// Values in a Context are indexed by typed keys.
+/// Key<T> serves two purposes:
+/// - it provides a lookup key for the context (each Key is unique),
+/// - it makes lookup type-safe: a Key<T> can only map to a T (or nothing).
+///
+/// Example:
+/// Key<int> RequestID;
+/// Key<int> Version;
+///
+/// Context Ctx = Context::empty().derive(RequestID, 10).derive(Version, 3);
+/// assert(*Ctx.get(RequestID) == 10);
+/// assert(*Ctx.get(Version) == 3);
+///
+/// Keys are typically used across multiple functions, so most of the time you
+/// would want to make them static class members or global variables.
+template <class Type> class Key {
+public:
+ static_assert(!std::is_reference<Type>::value,
+ "Reference arguments to Key<> are not allowed");
+
+ constexpr Key() = default;
+
+ Key(Key const &) = delete;
+ Key &operator=(Key const &) = delete;
+ Key(Key &&) = delete;
+ Key &operator=(Key &&) = delete;
+};
+
+/// A context is an immutable container for per-request data that must be
+/// propagated through layers that don't care about it. An example is a request
+/// ID that we may want to use when logging.
+///
+/// Conceptually, a context is a heterogeneous map<Key<T>, T>. Each key has
+/// an associated value type, which allows the map to be typesafe.
+///
+/// There is an "ambient" context for each thread, Context::current().
+/// Most functions should read from this, and use WithContextValue or
+/// WithContext to extend or replace the context within a block scope.
+/// Only code dealing with threads and extension points should need to use
+/// other Context objects.
+///
+/// You can't add data to an existing context, instead you create a new
+/// immutable context derived from it with extra data added. When you retrieve
+/// data, the context will walk up the parent chain until the key is found.
+class Context {
+public:
+ /// Returns an empty root context that contains no data.
+ static Context empty();
+ /// Returns the context for the current thread, creating it if needed.
+ static const Context ¤t();
+ // Sets the current() context to Replacement, and returns the old context.
+ // Prefer to use WithContext or WithContextValue to do this safely.
+ static Context swapCurrent(Context Replacement);
+
+private:
+ struct Data;
+ Context(std::shared_ptr<const Data> DataPtr);
+
+public:
+ /// Same as Context::empty(), please use Context::empty() instead.
+ /// Constructor is defined to workaround a bug in MSVC's version of STL.
+ /// (arguments of std::future<> must be default-construcitble in MSVC).
+ Context() = default;
+
+ /// Copy operations for this class are deleted, use an explicit clone() method
+ /// when you need a copy of the context instead.
+ Context(Context const &) = delete;
+ Context &operator=(const Context &) = delete;
+
+ Context(Context &&) = default;
+ Context &operator=(Context &&) = default;
+
+ /// Get data stored for a typed \p Key. If values are not found
+ /// \returns Pointer to the data associated with \p Key. If no data is
+ /// specified for \p Key, return null.
+ template <class Type> const Type *get(const Key<Type> &Key) const {
+ for (const Data *DataPtr = this->DataPtr.get(); DataPtr != nullptr;
+ DataPtr = DataPtr->Parent.get()) {
+ if (DataPtr->KeyPtr == &Key)
+ return static_cast<const Type *>(DataPtr->Value->getValuePtr());
+ }
+ return nullptr;
+ }
+
+ /// A helper to get a reference to a \p Key that must exist in the map.
+ /// Must not be called for keys that are not in the map.
+ template <class Type> const Type &getExisting(const Key<Type> &Key) const {
+ auto Val = get(Key);
+ assert(Val && "Key does not exist");
+ return *Val;
+ }
+
+ /// Derives a child context
+ /// It is safe to move or destroy a parent context after calling derive().
+ /// The child will keep its parent alive, and its data remains accessible.
+ template <class Type>
+ Context derive(const Key<Type> &Key,
+ typename std::decay<Type>::type Value) const & {
+ return Context(std::make_shared<Data>(Data{
+ /*Parent=*/DataPtr, &Key,
+ llvm::make_unique<TypedAnyStorage<typename std::decay<Type>::type>>(
+ std::move(Value))}));
+ }
+
+ template <class Type>
+ Context
+ derive(const Key<Type> &Key,
+ typename std::decay<Type>::type Value) && /* takes ownership */ {
+ return Context(std::make_shared<Data>(Data{
+ /*Parent=*/std::move(DataPtr), &Key,
+ llvm::make_unique<TypedAnyStorage<typename std::decay<Type>::type>>(
+ std::move(Value))}));
+ }
+
+ /// Derives a child context, using an anonymous key.
+ /// Intended for objects stored only for their destructor's side-effect.
+ template <class Type> Context derive(Type &&Value) const & {
+ static Key<typename std::decay<Type>::type> Private;
+ return derive(Private, std::forward<Type>(Value));
+ }
+
+ template <class Type> Context derive(Type &&Value) && {
+ static Key<typename std::decay<Type>::type> Private;
+ return std::move(*this).derive(Private, std::forward<Type>(Value));
+ }
+
+ /// Clone this context object.
+ Context clone() const;
+
+private:
+ class AnyStorage {
+ public:
+ virtual ~AnyStorage() = default;
+ virtual void *getValuePtr() = 0;
+ };
+
+ template <class T> class TypedAnyStorage : public Context::AnyStorage {
+ static_assert(std::is_same<typename std::decay<T>::type, T>::value,
+ "Argument to TypedAnyStorage must be decayed");
+
+ public:
+ TypedAnyStorage(T &&Value) : Value(std::move(Value)) {}
+
+ void *getValuePtr() override { return &Value; }
+
+ private:
+ T Value;
+ };
+
+ struct Data {
+ // We need to make sure Parent outlives the Value, so the order of members
+ // is important. We do that to allow classes stored in Context's child
+ // layers to store references to the data in the parent layers.
+ std::shared_ptr<const Data> Parent;
+ const void *KeyPtr;
+ std::unique_ptr<AnyStorage> Value;
+ };
+
+ std::shared_ptr<const Data> DataPtr;
+};
+
+/// WithContext replaces Context::current() with a provided scope.
+/// When the WithContext is destroyed, the original scope is restored.
+/// For extending the current context with new value, prefer WithContextValue.
+class LLVM_NODISCARD WithContext {
+public:
+ WithContext(Context C) : Restore(Context::swapCurrent(std::move(C))) {}
+ ~WithContext() { Context::swapCurrent(std::move(Restore)); }
+ WithContext(const WithContext &) = delete;
+ WithContext &operator=(const WithContext &) = delete;
+ WithContext(WithContext &&) = delete;
+ WithContext &operator=(WithContext &&) = delete;
+
+private:
+ Context Restore;
+};
+
+/// WithContextValue extends Context::current() with a single value.
+/// When the WithContextValue is destroyed, the original scope is restored.
+class LLVM_NODISCARD WithContextValue {
+public:
+ template <typename T>
+ WithContextValue(const Key<T> &K, typename std::decay<T>::type V)
+ : Restore(Context::current().derive(K, std::move(V))) {}
+
+ // Anonymous values can be used for the destructor side-effect.
+ template <typename T>
+ WithContextValue(T &&V)
+ : Restore(Context::current().derive(std::forward<T>(V))) {}
+
+private:
+ WithContext Restore;
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONTEXT_H_
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Diagnostics.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/Diagnostics.cpp
new file mode 100644
index 0000000..73ac475
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Diagnostics.cpp
@@ -0,0 +1,384 @@
+//===--- Diagnostics.cpp ----------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "Diagnostics.h"
+#include "Compiler.h"
+#include "Logger.h"
+#include "SourceCode.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/Support/Capacity.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+
+namespace clang {
+namespace clangd {
+
+namespace {
+
+bool mentionsMainFile(const Diag &D) {
+ if (D.InsideMainFile)
+ return true;
+ // Fixes are always in the main file.
+ if (!D.Fixes.empty())
+ return true;
+ for (auto &N : D.Notes) {
+ if (N.InsideMainFile)
+ return true;
+ }
+ return false;
+}
+
+// Checks whether a location is within a half-open range.
+// Note that clang also uses closed source ranges, which this can't handle!
+bool locationInRange(SourceLocation L, CharSourceRange R,
+ const SourceManager &M) {
+ assert(R.isCharRange());
+ if (!R.isValid() || M.getFileID(R.getBegin()) != M.getFileID(R.getEnd()) ||
+ M.getFileID(R.getBegin()) != M.getFileID(L))
+ return false;
+ return L != R.getEnd() && M.isPointWithin(L, R.getBegin(), R.getEnd());
+}
+
+// Clang diags have a location (shown as ^) and 0 or more ranges (~~~~).
+// LSP needs a single range.
+Range diagnosticRange(const clang::Diagnostic &D, const LangOptions &L) {
+ auto &M = D.getSourceManager();
+ auto Loc = M.getFileLoc(D.getLocation());
+ // Accept the first range that contains the location.
+ for (const auto &CR : D.getRanges()) {
+ auto R = Lexer::makeFileCharRange(CR, M, L);
+ if (locationInRange(Loc, R, M))
+ return halfOpenToRange(M, R);
+ }
+ // The range may be given as a fixit hint instead.
+ for (const auto &F : D.getFixItHints()) {
+ auto R = Lexer::makeFileCharRange(F.RemoveRange, M, L);
+ if (locationInRange(Loc, R, M))
+ return halfOpenToRange(M, R);
+ }
+ // If no suitable range is found, just use the token at the location.
+ auto R = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(Loc), M, L);
+ if (!R.isValid()) // Fall back to location only, let the editor deal with it.
+ R = CharSourceRange::getCharRange(Loc);
+ return halfOpenToRange(M, R);
+}
+
+TextEdit toTextEdit(const FixItHint &FixIt, const SourceManager &M,
+ const LangOptions &L) {
+ TextEdit Result;
+ Result.range =
+ halfOpenToRange(M, Lexer::makeFileCharRange(FixIt.RemoveRange, M, L));
+ Result.newText = FixIt.CodeToInsert;
+ return Result;
+}
+
+bool isInsideMainFile(const SourceLocation Loc, const SourceManager &M) {
+ return Loc.isValid() && M.isInMainFile(Loc);
+}
+
+bool isInsideMainFile(const clang::Diagnostic &D) {
+ if (!D.hasSourceManager())
+ return false;
+
+ return isInsideMainFile(D.getLocation(), D.getSourceManager());
+}
+
+bool isNote(DiagnosticsEngine::Level L) {
+ return L == DiagnosticsEngine::Note || L == DiagnosticsEngine::Remark;
+}
+
+llvm::StringRef diagLeveltoString(DiagnosticsEngine::Level Lvl) {
+ switch (Lvl) {
+ case DiagnosticsEngine::Ignored:
+ return "ignored";
+ case DiagnosticsEngine::Note:
+ return "note";
+ case DiagnosticsEngine::Remark:
+ return "remark";
+ case DiagnosticsEngine::Warning:
+ return "warning";
+ case DiagnosticsEngine::Error:
+ return "error";
+ case DiagnosticsEngine::Fatal:
+ return "fatal error";
+ }
+ llvm_unreachable("unhandled DiagnosticsEngine::Level");
+}
+
+/// Prints a single diagnostic in a clang-like manner, the output includes
+/// location, severity and error message. An example of the output message is:
+///
+/// main.cpp:12:23: error: undeclared identifier
+///
+/// For main file we only print the basename and for all other files we print
+/// the filename on a separate line to provide a slightly more readable output
+/// in the editors:
+///
+/// dir1/dir2/dir3/../../dir4/header.h:12:23
+/// error: undeclared identifier
+void printDiag(llvm::raw_string_ostream &OS, const DiagBase &D) {
+ if (D.InsideMainFile) {
+ // Paths to main files are often taken from compile_command.json, where they
+ // are typically absolute. To reduce noise we print only basename for them,
+ // it should not be confusing and saves space.
+ OS << llvm::sys::path::filename(D.File) << ":";
+ } else {
+ OS << D.File << ":";
+ }
+ // Note +1 to line and character. clangd::Range is zero-based, but when
+ // printing for users we want one-based indexes.
+ auto Pos = D.Range.start;
+ OS << (Pos.line + 1) << ":" << (Pos.character + 1) << ":";
+ // The non-main-file paths are often too long, putting them on a separate
+ // line improves readability.
+ if (D.InsideMainFile)
+ OS << " ";
+ else
+ OS << "\n";
+ OS << diagLeveltoString(D.Severity) << ": " << D.Message;
+}
+
+/// Returns a message sent to LSP for the main diagnostic in \p D.
+/// The message includes all the notes with their corresponding locations.
+/// However, notes with fix-its are excluded as those usually only contain a
+/// fix-it message and just add noise if included in the message for diagnostic.
+/// Example output:
+///
+/// no matching function for call to 'foo'
+///
+/// main.cpp:3:5: note: candidate function not viable: requires 2 arguments
+///
+/// dir1/dir2/dir3/../../dir4/header.h:12:23
+/// note: candidate function not viable: requires 3 arguments
+std::string mainMessage(const Diag &D) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ OS << D.Message;
+ for (auto &Note : D.Notes) {
+ OS << "\n\n";
+ printDiag(OS, Note);
+ }
+ OS.flush();
+ return Result;
+}
+
+/// Returns a message sent to LSP for the note of the main diagnostic.
+/// The message includes the main diagnostic to provide the necessary context
+/// for the user to understand the note.
+std::string noteMessage(const Diag &Main, const DiagBase &Note) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ OS << Note.Message;
+ OS << "\n\n";
+ printDiag(OS, Main);
+ OS.flush();
+ return Result;
+}
+} // namespace
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const DiagBase &D) {
+ if (!D.InsideMainFile)
+ OS << "[in " << D.File << "] ";
+ return OS << D.Message;
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Fix &F) {
+ OS << F.Message << " {";
+ const char *Sep = "";
+ for (const auto &Edit : F.Edits) {
+ OS << Sep << Edit;
+ Sep = ", ";
+ }
+ return OS << "}";
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diag &D) {
+ OS << static_cast<const DiagBase &>(D);
+ if (!D.Notes.empty()) {
+ OS << ", notes: {";
+ const char *Sep = "";
+ for (auto &Note : D.Notes) {
+ OS << Sep << Note;
+ Sep = ", ";
+ }
+ OS << "}";
+ }
+ if (!D.Fixes.empty()) {
+ OS << ", fixes: {";
+ const char *Sep = "";
+ for (auto &Fix : D.Fixes) {
+ OS << Sep << Fix;
+ Sep = ", ";
+ }
+ }
+ return OS;
+}
+
+void toLSPDiags(
+ const Diag &D,
+ llvm::function_ref<void(clangd::Diagnostic, llvm::ArrayRef<Fix>)> OutFn) {
+ auto FillBasicFields = [](const DiagBase &D) -> clangd::Diagnostic {
+ clangd::Diagnostic Res;
+ Res.range = D.Range;
+ Res.severity = getSeverity(D.Severity);
+ return Res;
+ };
+
+ {
+ clangd::Diagnostic Main = FillBasicFields(D);
+ Main.message = mainMessage(D);
+ OutFn(std::move(Main), D.Fixes);
+ }
+
+ for (auto &Note : D.Notes) {
+ if (!Note.InsideMainFile)
+ continue;
+ clangd::Diagnostic Res = FillBasicFields(Note);
+ Res.message = noteMessage(D, Note);
+ OutFn(std::move(Res), llvm::ArrayRef<Fix>());
+ }
+}
+
+int getSeverity(DiagnosticsEngine::Level L) {
+ switch (L) {
+ case DiagnosticsEngine::Remark:
+ return 4;
+ case DiagnosticsEngine::Note:
+ return 3;
+ case DiagnosticsEngine::Warning:
+ return 2;
+ case DiagnosticsEngine::Fatal:
+ case DiagnosticsEngine::Error:
+ return 1;
+ case DiagnosticsEngine::Ignored:
+ return 0;
+ }
+ llvm_unreachable("Unknown diagnostic level!");
+}
+
+std::vector<Diag> StoreDiags::take() { return std::move(Output); }
+
+void StoreDiags::BeginSourceFile(const LangOptions &Opts,
+ const Preprocessor *) {
+ LangOpts = Opts;
+}
+
+void StoreDiags::EndSourceFile() {
+ flushLastDiag();
+ LangOpts = llvm::None;
+}
+
+void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const clang::Diagnostic &Info) {
+ DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
+
+ if (!LangOpts || !Info.hasSourceManager()) {
+ IgnoreDiagnostics::log(DiagLevel, Info);
+ return;
+ }
+
+ bool InsideMainFile = isInsideMainFile(Info);
+
+ auto FillDiagBase = [&](DiagBase &D) {
+ D.Range = diagnosticRange(Info, *LangOpts);
+ llvm::SmallString<64> Message;
+ Info.FormatDiagnostic(Message);
+ D.Message = Message.str();
+ D.InsideMainFile = InsideMainFile;
+ D.File = Info.getSourceManager().getFilename(Info.getLocation());
+ D.Severity = DiagLevel;
+ return D;
+ };
+
+ auto AddFix = [&](bool SyntheticMessage) -> bool {
+ assert(!Info.getFixItHints().empty() &&
+ "diagnostic does not have attached fix-its");
+ if (!InsideMainFile)
+ return false;
+
+ llvm::SmallVector<TextEdit, 1> Edits;
+ for (auto &FixIt : Info.getFixItHints()) {
+ if (!isInsideMainFile(FixIt.RemoveRange.getBegin(),
+ Info.getSourceManager()))
+ return false;
+ Edits.push_back(toTextEdit(FixIt, Info.getSourceManager(), *LangOpts));
+ }
+
+ llvm::SmallString<64> Message;
+ // If requested and possible, create a message like "change 'foo' to 'bar'".
+ if (SyntheticMessage && Info.getNumFixItHints() == 1) {
+ const auto &FixIt = Info.getFixItHint(0);
+ bool Invalid = false;
+ StringRef Remove = Lexer::getSourceText(
+ FixIt.RemoveRange, Info.getSourceManager(), *LangOpts, &Invalid);
+ StringRef Insert = FixIt.CodeToInsert;
+ if (!Invalid) {
+ llvm::raw_svector_ostream M(Message);
+ if (!Remove.empty() && !Insert.empty())
+ M << "change '" << Remove << "' to '" << Insert << "'";
+ else if (!Remove.empty())
+ M << "remove '" << Remove << "'";
+ else if (!Insert.empty())
+ M << "insert '" << Insert << "'";
+ // Don't allow source code to inject newlines into diagnostics.
+ std::replace(Message.begin(), Message.end(), '\n', ' ');
+ }
+ }
+ if (Message.empty()) // either !SytheticMessage, or we failed to make one.
+ Info.FormatDiagnostic(Message);
+ LastDiag->Fixes.push_back(Fix{Message.str(), std::move(Edits)});
+ return true;
+ };
+
+ if (!isNote(DiagLevel)) {
+ // Handle the new main diagnostic.
+ flushLastDiag();
+
+ LastDiag = Diag();
+ FillDiagBase(*LastDiag);
+
+ if (!Info.getFixItHints().empty())
+ AddFix(true /* try to invent a message instead of repeating the diag */);
+ } else {
+ // Handle a note to an existing diagnostic.
+ if (!LastDiag) {
+ assert(false && "Adding a note without main diagnostic");
+ IgnoreDiagnostics::log(DiagLevel, Info);
+ return;
+ }
+
+ if (!Info.getFixItHints().empty()) {
+ // A clang note with fix-it is not a separate diagnostic in clangd. We
+ // attach it as a Fix to the main diagnostic instead.
+ if (!AddFix(false /* use the note as the message */))
+ IgnoreDiagnostics::log(DiagLevel, Info);
+ } else {
+ // A clang note without fix-its corresponds to clangd::Note.
+ Note N;
+ FillDiagBase(N);
+
+ LastDiag->Notes.push_back(std::move(N));
+ }
+ }
+}
+
+void StoreDiags::flushLastDiag() {
+ if (!LastDiag)
+ return;
+ if (mentionsMainFile(*LastDiag))
+ Output.push_back(std::move(*LastDiag));
+ else
+ log("Dropped diagnostic outside main file: {0}: {1}", LastDiag->File,
+ LastDiag->Message);
+ LastDiag.reset();
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Diagnostics.h b/src/third_party/llvm-project/clang-tools-extra/clangd/Diagnostics.h
new file mode 100644
index 0000000..b43f04a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Diagnostics.h
@@ -0,0 +1,98 @@
+//===--- Diagnostics.h ------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_DIAGNOSTICS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_DIAGNOSTICS_H
+
+#include "Path.h"
+#include "Protocol.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSet.h"
+#include <cassert>
+#include <string>
+
+namespace clang {
+namespace clangd {
+
+/// Contains basic information about a diagnostic.
+struct DiagBase {
+ std::string Message;
+ // Intended to be used only in error messages.
+ // May be relative, absolute or even artifically constructed.
+ std::string File;
+ clangd::Range Range;
+ DiagnosticsEngine::Level Severity = DiagnosticsEngine::Note;
+ // Since File is only descriptive, we store a separate flag to distinguish
+ // diags from the main file.
+ bool InsideMainFile = false;
+};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const DiagBase &D);
+
+/// Represents a single fix-it that editor can apply to fix the error.
+struct Fix {
+ /// Message for the fix-it.
+ std::string Message;
+ /// TextEdits from clang's fix-its. Must be non-empty.
+ llvm::SmallVector<TextEdit, 1> Edits;
+};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Fix &F);
+
+/// Represents a note for the diagnostic. Severity of notes can only be 'note'
+/// or 'remark'.
+struct Note : DiagBase {};
+
+/// A top-level diagnostic that may have Notes and Fixes.
+struct Diag : DiagBase {
+ /// Elaborate on the problem, usually pointing to a related piece of code.
+ std::vector<Note> Notes;
+ /// *Alternative* fixes for this diagnostic, one should be chosen.
+ std::vector<Fix> Fixes;
+};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diag &D);
+
+/// Conversion to LSP diagnostics. Formats the error message of each diagnostic
+/// to include all its notes. Notes inside main file are also provided as
+/// separate diagnostics with their corresponding fixits. Notes outside main
+/// file do not have a corresponding LSP diagnostic, but can still be included
+/// as part of their main diagnostic's message.
+void toLSPDiags(
+ const Diag &D,
+ llvm::function_ref<void(clangd::Diagnostic, llvm::ArrayRef<Fix>)> OutFn);
+
+/// Convert from clang diagnostic level to LSP severity.
+int getSeverity(DiagnosticsEngine::Level L);
+
+/// StoreDiags collects the diagnostics that can later be reported by
+/// clangd. It groups all notes for a diagnostic into a single Diag
+/// and filters out diagnostics that don't mention the main file (i.e. neither
+/// the diag itself nor its notes are in the main file).
+class StoreDiags : public DiagnosticConsumer {
+public:
+ std::vector<Diag> take();
+
+ void BeginSourceFile(const LangOptions &Opts, const Preprocessor *) override;
+ void EndSourceFile() override;
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const clang::Diagnostic &Info) override;
+
+private:
+ void flushLastDiag();
+
+ std::vector<Diag> Output;
+ llvm::Optional<LangOptions> LangOpts;
+ llvm::Optional<Diag> LastDiag;
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/DraftStore.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/DraftStore.cpp
new file mode 100644
index 0000000..8e1cf88
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/DraftStore.cpp
@@ -0,0 +1,107 @@
+//===--- DraftStore.cpp - File contents container ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DraftStore.h"
+#include "SourceCode.h"
+#include "llvm/Support/Errc.h"
+
+using namespace clang;
+using namespace clang::clangd;
+
+llvm::Optional<std::string> DraftStore::getDraft(PathRef File) const {
+ std::lock_guard<std::mutex> Lock(Mutex);
+
+ auto It = Drafts.find(File);
+ if (It == Drafts.end())
+ return llvm::None;
+
+ return It->second;
+}
+
+std::vector<Path> DraftStore::getActiveFiles() const {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ std::vector<Path> ResultVector;
+
+ for (auto DraftIt = Drafts.begin(); DraftIt != Drafts.end(); DraftIt++)
+ ResultVector.push_back(DraftIt->getKey());
+
+ return ResultVector;
+}
+
+void DraftStore::addDraft(PathRef File, StringRef Contents) {
+ std::lock_guard<std::mutex> Lock(Mutex);
+
+ Drafts[File] = Contents;
+}
+
+llvm::Expected<std::string> DraftStore::updateDraft(
+ PathRef File, llvm::ArrayRef<TextDocumentContentChangeEvent> Changes) {
+ std::lock_guard<std::mutex> Lock(Mutex);
+
+ auto EntryIt = Drafts.find(File);
+ if (EntryIt == Drafts.end()) {
+ return llvm::make_error<llvm::StringError>(
+ "Trying to do incremental update on non-added document: " + File,
+ llvm::errc::invalid_argument);
+ }
+
+ std::string Contents = EntryIt->second;
+
+ for (const TextDocumentContentChangeEvent &Change : Changes) {
+ if (!Change.range) {
+ Contents = Change.text;
+ continue;
+ }
+
+ const Position &Start = Change.range->start;
+ llvm::Expected<size_t> StartIndex =
+ positionToOffset(Contents, Start, false);
+ if (!StartIndex)
+ return StartIndex.takeError();
+
+ const Position &End = Change.range->end;
+ llvm::Expected<size_t> EndIndex = positionToOffset(Contents, End, false);
+ if (!EndIndex)
+ return EndIndex.takeError();
+
+ if (*EndIndex < *StartIndex)
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv(
+ "Range's end position ({0}) is before start position ({1})", End,
+ Start),
+ llvm::errc::invalid_argument);
+
+ if (Change.rangeLength &&
+ (ssize_t)(*EndIndex - *StartIndex) != *Change.rangeLength)
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("Change's rangeLength ({0}) doesn't match the "
+ "computed range length ({1}).",
+ *Change.rangeLength, *EndIndex - *StartIndex),
+ llvm::errc::invalid_argument);
+
+ std::string NewContents;
+ NewContents.reserve(*StartIndex + Change.text.length() +
+ (Contents.length() - *EndIndex));
+
+ NewContents = Contents.substr(0, *StartIndex);
+ NewContents += Change.text;
+ NewContents += Contents.substr(*EndIndex);
+
+ Contents = std::move(NewContents);
+ }
+
+ EntryIt->second = Contents;
+ return Contents;
+}
+
+void DraftStore::removeDraft(PathRef File) {
+ std::lock_guard<std::mutex> Lock(Mutex);
+
+ Drafts.erase(File);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/DraftStore.h b/src/third_party/llvm-project/clang-tools-extra/clangd/DraftStore.h
new file mode 100644
index 0000000..90a2d2c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/DraftStore.h
@@ -0,0 +1,60 @@
+//===--- DraftStore.h - File contents container -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_DRAFTSTORE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_DRAFTSTORE_H
+
+#include "Path.h"
+#include "Protocol.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringMap.h"
+#include <mutex>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace clangd {
+
+/// A thread-safe container for files opened in a workspace, addressed by
+/// filenames. The contents are owned by the DraftStore. This class supports
+/// both whole and incremental updates of the documents.
+class DraftStore {
+public:
+ /// \return Contents of the stored document.
+ /// For untracked files, a llvm::None is returned.
+ llvm::Optional<std::string> getDraft(PathRef File) const;
+
+ /// \return List of names of the drafts in this store.
+ std::vector<Path> getActiveFiles() const;
+
+ /// Replace contents of the draft for \p File with \p Contents.
+ void addDraft(PathRef File, StringRef Contents);
+
+ /// Update the contents of the draft for \p File based on \p Changes.
+ /// If a position in \p Changes is invalid (e.g. out-of-range), the
+ /// draft is not modified.
+ ///
+ /// \return The new version of the draft for \p File, or an error if the
+ /// changes couldn't be applied.
+ llvm::Expected<std::string>
+ updateDraft(PathRef File,
+ llvm::ArrayRef<TextDocumentContentChangeEvent> Changes);
+
+ /// Remove the draft from the store.
+ void removeDraft(PathRef File);
+
+private:
+ mutable std::mutex Mutex;
+ llvm::StringMap<std::string> Drafts;
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/FSProvider.h b/src/third_party/llvm-project/clang-tools-extra/clangd/FSProvider.h
new file mode 100644
index 0000000..70dfb44
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/FSProvider.h
@@ -0,0 +1,42 @@
+//===--- FSProvider.h - VFS provider for ClangdServer ------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FSPROVIDER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FSPROVIDER_H
+
+#include "clang/Basic/VirtualFileSystem.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+
+namespace clang {
+namespace clangd {
+
+// Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
+// As FileSystem is not threadsafe, concurrent threads must each obtain one.
+class FileSystemProvider {
+public:
+ virtual ~FileSystemProvider() = default;
+ /// Called by ClangdServer to obtain a vfs::FileSystem to be used for parsing.
+ /// Context::current() will be the context passed to the clang entrypoint,
+ /// such as addDocument(), and will also be propagated to result callbacks.
+ /// Embedders may use this to isolate filesystem accesses.
+ virtual IntrusiveRefCntPtr<vfs::FileSystem> getFileSystem() = 0;
+};
+
+class RealFileSystemProvider : public FileSystemProvider {
+public:
+ // FIXME: returns the single real FS instance, which is not threadsafe.
+ IntrusiveRefCntPtr<vfs::FileSystem> getFileSystem() override {
+ return vfs::getRealFileSystem();
+ }
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/FileDistance.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/FileDistance.cpp
new file mode 100644
index 0000000..a0ce25b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/FileDistance.cpp
@@ -0,0 +1,171 @@
+//===--- FileDistance.cpp - File contents container -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The FileDistance structure allows calculating the minimum distance to paths
+// in a single tree.
+// We simply walk up the path's ancestors until we find a node whose cost is
+// known, and add the cost of walking back down. Initialization ensures this
+// gives the correct path to the roots.
+// We cache the results, so that the runtime is O(|A|), where A is the set of
+// all distinct ancestors of visited paths.
+//
+// Example after initialization with /=2, /bar=0, DownCost = 1:
+// / = 2
+// /bar = 0
+//
+// After querying /foo/bar and /bar/foo:
+// / = 2
+// /bar = 0
+// /bar/foo = 1
+// /foo = 3
+// /foo/bar = 4
+//
+// URIDistance creates FileDistance lazily for each URI scheme encountered. In
+// practice this is a small constant factor.
+//
+//===-------------------------------------------------------------------------//
+
+#include "FileDistance.h"
+#include "Logger.h"
+#include "llvm/ADT/STLExtras.h"
+#include <queue>
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+// Convert a path into the canonical form.
+// Canonical form is either "/", or "/segment" * N:
+// C:\foo\bar --> /c:/foo/bar
+// /foo/ --> /foo
+// a/b/c --> /a/b/c
+static SmallString<128> canonicalize(StringRef Path) {
+ SmallString<128> Result = Path.rtrim('/');
+ native(Result, sys::path::Style::posix);
+ if (Result.empty() || Result.front() != '/')
+ Result.insert(Result.begin(), '/');
+ return Result;
+}
+
+constexpr const unsigned FileDistance::kUnreachable;
+
+FileDistance::FileDistance(StringMap<SourceParams> Sources,
+ const FileDistanceOptions &Opts)
+ : Opts(Opts) {
+ llvm::DenseMap<hash_code, SmallVector<hash_code, 4>> DownEdges;
+ // Compute the best distance following only up edges.
+ // Keep track of down edges, in case we can use them to improve on this.
+ for (const auto &S : Sources) {
+ auto Canonical = canonicalize(S.getKey());
+ dlog("Source {0} = {1}, MaxUp = {2}", Canonical, S.second.Cost,
+ S.second.MaxUpTraversals);
+ // Walk up to ancestors of this source, assigning cost.
+ StringRef Rest = Canonical;
+ llvm::hash_code Hash = hash_value(Rest);
+ for (unsigned I = 0; !Rest.empty(); ++I) {
+ Rest = parent_path(Rest, sys::path::Style::posix);
+ auto NextHash = hash_value(Rest);
+ auto &Down = DownEdges[NextHash];
+ if (std::find(Down.begin(), Down.end(), Hash) == Down.end())
+ DownEdges[NextHash].push_back(Hash);
+ // We can't just break after MaxUpTraversals, must still set DownEdges.
+ if (I > S.getValue().MaxUpTraversals) {
+ if (Cache.find(Hash) != Cache.end())
+ break;
+ } else {
+ unsigned Cost = S.getValue().Cost + I * Opts.UpCost;
+ auto R = Cache.try_emplace(Hash, Cost);
+ if (!R.second) {
+ if (Cost < R.first->second) {
+ R.first->second = Cost;
+ } else {
+ // If we're not the best way to get to this path, stop assigning.
+ break;
+ }
+ }
+ }
+ Hash = NextHash;
+ }
+ }
+ // Now propagate scores parent -> child if that's an improvement.
+ // BFS ensures we propagate down chains (must visit parents before children).
+ std::queue<hash_code> Next;
+ for (auto Child : DownEdges.lookup(hash_value(llvm::StringRef(""))))
+ Next.push(Child);
+ while (!Next.empty()) {
+ auto ParentCost = Cache.lookup(Next.front());
+ for (auto Child : DownEdges.lookup(Next.front())) {
+ auto &ChildCost =
+ Cache.try_emplace(Child, kUnreachable).first->getSecond();
+ if (ParentCost + Opts.DownCost < ChildCost)
+ ChildCost = ParentCost + Opts.DownCost;
+ Next.push(Child);
+ }
+ Next.pop();
+ }
+}
+
+unsigned FileDistance::distance(StringRef Path) {
+ auto Canonical = canonicalize(Path);
+ unsigned Cost = kUnreachable;
+ SmallVector<hash_code, 16> Ancestors;
+ // Walk up ancestors until we find a path we know the distance for.
+ for (StringRef Rest = Canonical; !Rest.empty();
+ Rest = parent_path(Rest, sys::path::Style::posix)) {
+ auto Hash = hash_value(Rest);
+ auto It = Cache.find(Hash);
+ if (It != Cache.end()) {
+ Cost = It->second;
+ break;
+ }
+ Ancestors.push_back(Hash);
+ }
+ // Now we know the costs for (known node, queried node].
+ // Fill these in, walking down the directory tree.
+ for (hash_code Hash : reverse(Ancestors)) {
+ if (Cost != kUnreachable)
+ Cost += Opts.DownCost;
+ Cache.try_emplace(Hash, Cost);
+ }
+ dlog("distance({0} = {1})", Path, Cost);
+ return Cost;
+}
+
+unsigned URIDistance::distance(llvm::StringRef URI) {
+ auto R = Cache.try_emplace(llvm::hash_value(URI), FileDistance::kUnreachable);
+ if (!R.second)
+ return R.first->getSecond();
+ if (auto U = clangd::URI::parse(URI)) {
+ dlog("distance({0} = {1})", URI, U->body());
+ R.first->second = forScheme(U->scheme()).distance(U->body());
+ } else {
+ log("URIDistance::distance() of unparseable {0}: {1}", URI, U.takeError());
+ }
+ return R.first->second;
+}
+
+FileDistance &URIDistance::forScheme(llvm::StringRef Scheme) {
+ auto &Delegate = ByScheme[Scheme];
+ if (!Delegate) {
+ llvm::StringMap<SourceParams> SchemeSources;
+ for (const auto &Source : Sources) {
+ if (auto U = clangd::URI::create(Source.getKey(), Scheme))
+ SchemeSources.try_emplace(U->body(), Source.getValue());
+ else
+ consumeError(U.takeError());
+ }
+ dlog("FileDistance for scheme {0}: {1}/{2} sources", Scheme,
+ SchemeSources.size(), Sources.size());
+ Delegate.reset(new FileDistance(std::move(SchemeSources), Opts));
+ }
+ return *Delegate;
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/FileDistance.h b/src/third_party/llvm-project/clang-tools-extra/clangd/FileDistance.h
new file mode 100644
index 0000000..f07804f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/FileDistance.h
@@ -0,0 +1,109 @@
+//===--- FileDistance.h - File proximity scoring -----------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This library measures the distance between file paths.
+// It's used for ranking symbols, e.g. in code completion.
+// |foo/bar.h -> foo/bar.h| = 0.
+// |foo/bar.h -> foo/baz.h| < |foo/bar.h -> baz.h|.
+// This is an edit-distance, where edits go up or down the directory tree.
+// It's not symmetrical, the costs of going up and down may not match.
+//
+// Dealing with multiple sources:
+// In practice we care about the distance from a source file, but files near
+// its main-header and #included files are considered "close".
+// So we start with a set of (anchor, cost) pairs, and call the distance to a
+// path the minimum of `cost + |source -> path|`.
+//
+// We allow each source to limit the number of up-traversals paths may start
+// with. Up-traversals may reach things that are not "semantically near".
+//
+// Symbol URI schemes:
+// Symbol locations may be represented by URIs rather than file paths directly.
+// In this case we want to perform distance computations in URI space rather
+// than in file-space, without performing redundant conversions.
+// Therefore we have a lookup structure that accepts URIs, so that intermediate
+// calculations for the same scheme can be reused.
+//
+// Caveats:
+// Assuming up and down traversals each have uniform costs is simplistic.
+// Often there are "semantic roots" whose children are almost unrelated.
+// (e.g. /usr/include/, or / in an umbrella repository). We ignore this.
+//
+//===----------------------------------------------------------------------===//
+
+#include "URI.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/StringSaver.h"
+
+namespace clang {
+namespace clangd {
+
+struct FileDistanceOptions {
+ unsigned UpCost = 2; // |foo/bar.h -> foo|
+ unsigned DownCost = 1; // |foo -> foo/bar.h|
+ unsigned IncludeCost = 2; // |foo.cc -> included_header.h|
+};
+
+struct SourceParams {
+ // Base cost for paths starting at this source.
+ unsigned Cost = 0;
+ // Limits the number of upwards traversals allowed from this source.
+ unsigned MaxUpTraversals = std::numeric_limits<unsigned>::max();
+};
+
+// Supports lookups to find the minimum distance to a file from any source.
+// This object should be reused, it memoizes intermediate computations.
+class FileDistance {
+public:
+ static constexpr unsigned kUnreachable = std::numeric_limits<unsigned>::max();
+
+ FileDistance(llvm::StringMap<SourceParams> Sources,
+ const FileDistanceOptions &Opts = {});
+
+ // Computes the minimum distance from any source to the file path.
+ unsigned distance(llvm::StringRef Path);
+
+private:
+ // Costs computed so far. Always contains sources and their ancestors.
+ // We store hash codes only. Collisions are rare and consequences aren't dire.
+ llvm::DenseMap<llvm::hash_code, unsigned> Cache;
+ FileDistanceOptions Opts;
+};
+
+// Supports lookups like FileDistance, but the lookup keys are URIs.
+// We convert each of the sources to the scheme of the URI and do a FileDistance
+// comparison on the bodies.
+class URIDistance {
+public:
+ URIDistance(llvm::StringMap<SourceParams> Sources,
+ const FileDistanceOptions &Opts = {})
+ : Sources(Sources), Opts(Opts) {}
+
+ // Computes the minimum distance from any source to the URI.
+ // Only sources that can be mapped into the URI's scheme are considered.
+ unsigned distance(llvm::StringRef URI);
+
+private:
+ // Returns the FileDistance for a URI scheme, creating it if needed.
+ FileDistance &forScheme(llvm::StringRef Scheme);
+
+ // We cache the results using the original strings so we can skip URI parsing.
+ llvm::DenseMap<llvm::hash_code, unsigned> Cache;
+ llvm::StringMap<SourceParams> Sources;
+ llvm::StringMap<std::unique_ptr<FileDistance>> ByScheme;
+ FileDistanceOptions Opts;
+};
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/FindSymbols.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/FindSymbols.cpp
new file mode 100644
index 0000000..c1ee678
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/FindSymbols.cpp
@@ -0,0 +1,279 @@
+//===--- FindSymbols.cpp ------------------------------------*- C++-*------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "FindSymbols.h"
+
+#include "AST.h"
+#include "ClangdUnit.h"
+#include "FuzzyMatch.h"
+#include "Logger.h"
+#include "Quality.h"
+#include "SourceCode.h"
+#include "index/Index.h"
+#include "clang/Index/IndexDataConsumer.h"
+#include "clang/Index/IndexSymbol.h"
+#include "clang/Index/IndexingAction.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Path.h"
+
+#define DEBUG_TYPE "FindSymbols"
+
+namespace clang {
+namespace clangd {
+
+namespace {
+
+// Convert a index::SymbolKind to clangd::SymbolKind (LSP)
+// Note, some are not perfect matches and should be improved when this LSP
+// issue is addressed:
+// https://github.com/Microsoft/language-server-protocol/issues/344
+SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind) {
+ switch (Kind) {
+ case index::SymbolKind::Unknown:
+ return SymbolKind::Variable;
+ case index::SymbolKind::Module:
+ return SymbolKind::Module;
+ case index::SymbolKind::Namespace:
+ return SymbolKind::Namespace;
+ case index::SymbolKind::NamespaceAlias:
+ return SymbolKind::Namespace;
+ case index::SymbolKind::Macro:
+ return SymbolKind::String;
+ case index::SymbolKind::Enum:
+ return SymbolKind::Enum;
+ case index::SymbolKind::Struct:
+ return SymbolKind::Struct;
+ case index::SymbolKind::Class:
+ return SymbolKind::Class;
+ case index::SymbolKind::Protocol:
+ return SymbolKind::Interface;
+ case index::SymbolKind::Extension:
+ return SymbolKind::Interface;
+ case index::SymbolKind::Union:
+ return SymbolKind::Class;
+ case index::SymbolKind::TypeAlias:
+ return SymbolKind::Class;
+ case index::SymbolKind::Function:
+ return SymbolKind::Function;
+ case index::SymbolKind::Variable:
+ return SymbolKind::Variable;
+ case index::SymbolKind::Field:
+ return SymbolKind::Field;
+ case index::SymbolKind::EnumConstant:
+ return SymbolKind::EnumMember;
+ case index::SymbolKind::InstanceMethod:
+ case index::SymbolKind::ClassMethod:
+ case index::SymbolKind::StaticMethod:
+ return SymbolKind::Method;
+ case index::SymbolKind::InstanceProperty:
+ case index::SymbolKind::ClassProperty:
+ case index::SymbolKind::StaticProperty:
+ return SymbolKind::Property;
+ case index::SymbolKind::Constructor:
+ case index::SymbolKind::Destructor:
+ return SymbolKind::Method;
+ case index::SymbolKind::ConversionFunction:
+ return SymbolKind::Function;
+ case index::SymbolKind::Parameter:
+ return SymbolKind::Variable;
+ case index::SymbolKind::Using:
+ return SymbolKind::Namespace;
+ }
+ llvm_unreachable("invalid symbol kind");
+}
+
+using ScoredSymbolInfo = std::pair<float, SymbolInformation>;
+struct ScoredSymbolGreater {
+ bool operator()(const ScoredSymbolInfo &L, const ScoredSymbolInfo &R) {
+ if (L.first != R.first)
+ return L.first > R.first;
+ return L.second.name < R.second.name; // Earlier name is better.
+ }
+};
+
+} // namespace
+
+llvm::Expected<std::vector<SymbolInformation>>
+getWorkspaceSymbols(StringRef Query, int Limit, const SymbolIndex *const Index,
+ StringRef HintPath) {
+ std::vector<SymbolInformation> Result;
+ if (Query.empty() || !Index)
+ return Result;
+
+ auto Names = splitQualifiedName(Query);
+
+ FuzzyFindRequest Req;
+ Req.Query = Names.second;
+
+ // FuzzyFind doesn't want leading :: qualifier
+ bool IsGlobalQuery = Names.first.consume_front("::");
+ // Restrict results to the scope in the query string if present (global or
+ // not).
+ if (IsGlobalQuery || !Names.first.empty())
+ Req.Scopes = {Names.first};
+ if (Limit)
+ Req.MaxCandidateCount = Limit;
+ TopN<ScoredSymbolInfo, ScoredSymbolGreater> Top(Req.MaxCandidateCount);
+ FuzzyMatcher Filter(Req.Query);
+ Index->fuzzyFind(Req, [HintPath, &Top, &Filter](const Symbol &Sym) {
+ // Prefer the definition over e.g. a function declaration in a header
+ auto &CD = Sym.Definition ? Sym.Definition : Sym.CanonicalDeclaration;
+ auto Uri = URI::parse(CD.FileURI);
+ if (!Uri) {
+ log("Workspace symbol: Could not parse URI '{0}' for symbol '{1}'.",
+ CD.FileURI, Sym.Name);
+ return;
+ }
+ auto Path = URI::resolve(*Uri, HintPath);
+ if (!Path) {
+ log("Workspace symbol: Could not resolve path for URI '{0}' for symbol "
+ "'{1}'.",
+ Uri->toString(), Sym.Name);
+ return;
+ }
+ Location L;
+ L.uri = URIForFile((*Path));
+ Position Start, End;
+ Start.line = CD.Start.Line;
+ Start.character = CD.Start.Column;
+ End.line = CD.End.Line;
+ End.character = CD.End.Column;
+ L.range = {Start, End};
+ SymbolKind SK = indexSymbolKindToSymbolKind(Sym.SymInfo.Kind);
+ std::string Scope = Sym.Scope;
+ StringRef ScopeRef = Scope;
+ ScopeRef.consume_back("::");
+ SymbolInformation Info = {Sym.Name, SK, L, ScopeRef};
+
+ SymbolQualitySignals Quality;
+ Quality.merge(Sym);
+ SymbolRelevanceSignals Relevance;
+ Relevance.Query = SymbolRelevanceSignals::Generic;
+ if (auto NameMatch = Filter.match(Sym.Name))
+ Relevance.NameMatch = *NameMatch;
+ else {
+ log("Workspace symbol: {0} didn't match query {1}", Sym.Name,
+ Filter.pattern());
+ return;
+ }
+ Relevance.merge(Sym);
+ auto Score =
+ evaluateSymbolAndRelevance(Quality.evaluate(), Relevance.evaluate());
+ dlog("FindSymbols: {0}{1} = {2}\n{3}{4}\n", Sym.Scope, Sym.Name, Score,
+ Quality, Relevance);
+
+ Top.push({Score, std::move(Info)});
+ });
+ for (auto &R : std::move(Top).items())
+ Result.push_back(std::move(R.second));
+ return Result;
+}
+
+namespace {
+/// Finds document symbols in the main file of the AST.
+class DocumentSymbolsConsumer : public index::IndexDataConsumer {
+ ASTContext &AST;
+ std::vector<SymbolInformation> Symbols;
+ // We are always list document for the same file, so cache the value.
+ llvm::Optional<URIForFile> MainFileUri;
+
+public:
+ DocumentSymbolsConsumer(ASTContext &AST) : AST(AST) {}
+ std::vector<SymbolInformation> takeSymbols() { return std::move(Symbols); }
+
+ void initialize(ASTContext &Ctx) override {
+ // Compute the absolute path of the main file which we will use for all
+ // results.
+ const SourceManager &SM = AST.getSourceManager();
+ const FileEntry *F = SM.getFileEntryForID(SM.getMainFileID());
+ if (!F)
+ return;
+ auto FilePath = getAbsoluteFilePath(F, SM);
+ if (FilePath)
+ MainFileUri = URIForFile(*FilePath);
+ }
+
+ bool shouldIncludeSymbol(const NamedDecl *ND) {
+ if (!ND || ND->isImplicit())
+ return false;
+ // Skip anonymous declarations, e.g (anonymous enum/class/struct).
+ if (ND->getDeclName().isEmpty())
+ return false;
+ return true;
+ }
+
+ bool
+ handleDeclOccurence(const Decl *, index::SymbolRoleSet Roles,
+ ArrayRef<index::SymbolRelation> Relations,
+ SourceLocation Loc,
+ index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
+ assert(ASTNode.OrigD);
+ // No point in continuing the index consumer if we could not get the
+ // absolute path of the main file.
+ if (!MainFileUri)
+ return false;
+ // We only want declarations and definitions, i.e. no references.
+ if (!(Roles & static_cast<unsigned>(index::SymbolRole::Declaration) ||
+ Roles & static_cast<unsigned>(index::SymbolRole::Definition)))
+ return true;
+ SourceLocation NameLoc = findNameLoc(ASTNode.OrigD);
+ const SourceManager &SourceMgr = AST.getSourceManager();
+ // We should be only be looking at "local" decls in the main file.
+ if (!SourceMgr.isWrittenInMainFile(NameLoc)) {
+ // Even thought we are visiting only local (non-preamble) decls,
+ // we can get here when in the presense of "extern" decls.
+ return true;
+ }
+ const NamedDecl *ND = llvm::dyn_cast<NamedDecl>(ASTNode.OrigD);
+ if (!shouldIncludeSymbol(ND))
+ return true;
+
+ SourceLocation EndLoc =
+ Lexer::getLocForEndOfToken(NameLoc, 0, SourceMgr, AST.getLangOpts());
+ Position Begin = sourceLocToPosition(SourceMgr, NameLoc);
+ Position End = sourceLocToPosition(SourceMgr, EndLoc);
+ Range R = {Begin, End};
+ Location L;
+ L.uri = *MainFileUri;
+ L.range = R;
+
+ std::string QName = printQualifiedName(*ND);
+ StringRef Scope, Name;
+ std::tie(Scope, Name) = splitQualifiedName(QName);
+ Scope.consume_back("::");
+
+ index::SymbolInfo SymInfo = index::getSymbolInfo(ND);
+ SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo.Kind);
+
+ SymbolInformation SI;
+ SI.name = Name;
+ SI.kind = SK;
+ SI.location = L;
+ SI.containerName = Scope;
+ Symbols.push_back(std::move(SI));
+ return true;
+ }
+};
+} // namespace
+
+llvm::Expected<std::vector<SymbolInformation>>
+getDocumentSymbols(ParsedAST &AST) {
+ DocumentSymbolsConsumer DocumentSymbolsCons(AST.getASTContext());
+
+ index::IndexingOptions IndexOpts;
+ IndexOpts.SystemSymbolFilter =
+ index::IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly;
+ IndexOpts.IndexFunctionLocals = false;
+ indexTopLevelDecls(AST.getASTContext(), AST.getLocalTopLevelDecls(),
+ DocumentSymbolsCons, IndexOpts);
+
+ return DocumentSymbolsCons.takeSymbols();
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/FindSymbols.h b/src/third_party/llvm-project/clang-tools-extra/clangd/FindSymbols.h
new file mode 100644
index 0000000..4e6e75a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/FindSymbols.h
@@ -0,0 +1,45 @@
+//===--- FindSymbols.h --------------------------------------*- C++-*------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Queries that provide a list of symbols matching a string.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FINDSYMBOLS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FINDSYMBOLS_H
+
+#include "Protocol.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace clangd {
+class ParsedAST;
+class SymbolIndex;
+
+/// Searches for the symbols matching \p Query. The syntax of \p Query can be
+/// the non-qualified name or fully qualified of a symbol. For example, "vector"
+/// will match the symbol std::vector and "std::vector" would also match it.
+/// Direct children of scopes (namepaces, etc) can be listed with a trailing
+/// "::". For example, "std::" will list all children of the std namespace and
+/// "::" alone will list all children of the global namespace.
+/// \p Limit limits the number of results returned (0 means no limit).
+/// \p HintPath This is used when resolving URIs. If empty, URI resolution can
+/// fail if a hint path is required for the scheme of a specific URI.
+llvm::Expected<std::vector<SymbolInformation>>
+getWorkspaceSymbols(llvm::StringRef Query, int Limit,
+ const SymbolIndex *const Index, llvm::StringRef HintPath);
+
+/// Retrieves the symbols contained in the "main file" section of an AST in the
+/// same order that they appear.
+llvm::Expected<std::vector<SymbolInformation>>
+getDocumentSymbols(ParsedAST &AST);
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Function.h b/src/third_party/llvm-project/clang-tools-extra/clangd/Function.h
new file mode 100644
index 0000000..88a5bc0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Function.h
@@ -0,0 +1,89 @@
+//===--- Function.h - Utility callable wrappers -----------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides utilities for callable objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H
+
+#include "llvm/ADT/FunctionExtras.h"
+#include "llvm/Support/Error.h"
+#include <tuple>
+#include <utility>
+
+namespace clang {
+namespace clangd {
+
+/// A Callback<T> is a void function that accepts Expected<T>.
+/// This is accepted by ClangdServer functions that logically return T.
+template <typename T>
+using Callback = llvm::unique_function<void(llvm::Expected<T>)>;
+
+/// Stores a callable object (Func) and arguments (Args) and allows to call the
+/// callable with provided arguments later using `operator ()`. The arguments
+/// are std::forward'ed into the callable in the body of `operator()`. Therefore
+/// `operator()` can only be called once, as some of the arguments could be
+/// std::move'ed into the callable on first call.
+template <class Func, class... Args> struct ForwardBinder {
+ using Tuple = std::tuple<typename std::decay<Func>::type,
+ typename std::decay<Args>::type...>;
+ Tuple FuncWithArguments;
+#ifndef NDEBUG
+ bool WasCalled = false;
+#endif
+
+public:
+ ForwardBinder(Tuple FuncWithArguments)
+ : FuncWithArguments(std::move(FuncWithArguments)) {}
+
+private:
+ template <std::size_t... Indexes, class... RestArgs>
+ auto CallImpl(llvm::integer_sequence<std::size_t, Indexes...> Seq,
+ RestArgs &&... Rest)
+ -> decltype(std::get<0>(this->FuncWithArguments)(
+ std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))...,
+ std::forward<RestArgs>(Rest)...)) {
+ return std::get<0>(this->FuncWithArguments)(
+ std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))...,
+ std::forward<RestArgs>(Rest)...);
+ }
+
+public:
+ template <class... RestArgs>
+ auto operator()(RestArgs &&... Rest)
+ -> decltype(this->CallImpl(llvm::index_sequence_for<Args...>(),
+ std::forward<RestArgs>(Rest)...)) {
+
+#ifndef NDEBUG
+ assert(!WasCalled && "Can only call result of Bind once.");
+ WasCalled = true;
+#endif
+ return CallImpl(llvm::index_sequence_for<Args...>(),
+ std::forward<RestArgs>(Rest)...);
+ }
+};
+
+/// Creates an object that stores a callable (\p F) and first arguments to the
+/// callable (\p As) and allows to call \p F with \Args at a later point.
+/// Similar to std::bind, but also works with move-only \p F and \p As.
+///
+/// The returned object must be called no more than once, as \p As are
+/// std::forwarded'ed (therefore can be moved) into \p F during the call.
+template <class Func, class... Args>
+ForwardBinder<Func, Args...> Bind(Func F, Args &&... As) {
+ return ForwardBinder<Func, Args...>(
+ std::make_tuple(std::forward<Func>(F), std::forward<Args>(As)...));
+}
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/FuzzyMatch.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/FuzzyMatch.cpp
new file mode 100644
index 0000000..b81020a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/FuzzyMatch.cpp
@@ -0,0 +1,395 @@
+//===--- FuzzyMatch.h - Approximate identifier matching ---------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// To check for a match between a Pattern ('u_p') and a Word ('unique_ptr'),
+// we consider the possible partial match states:
+//
+// u n i q u e _ p t r
+// +---------------------
+// |A . . . . . . . . . .
+// u|
+// |. . . . . . . . . . .
+// _|
+// |. . . . . . . O . . .
+// p|
+// |. . . . . . . . . . B
+//
+// Each dot represents some prefix of the pattern being matched against some
+// prefix of the word.
+// - A is the initial state: '' matched against ''
+// - O is an intermediate state: 'u_' matched against 'unique_'
+// - B is the target state: 'u_p' matched against 'unique_ptr'
+//
+// We aim to find the best path from A->B.
+// - Moving right (consuming a word character)
+// Always legal: not all word characters must match.
+// - Moving diagonally (consuming both a word and pattern character)
+// Legal if the characters match.
+// - Moving down (consuming a pattern character) is never legal.
+// Never legal: all pattern characters must match something.
+// Characters are matched case-insensitively.
+// The first pattern character may only match the start of a word segment.
+//
+// The scoring is based on heuristics:
+// - when matching a character, apply a bonus or penalty depending on the
+// match quality (does case match, do word segments align, etc)
+// - when skipping a character, apply a penalty if it hurts the match
+// (it starts a word segment, or splits the matched region, etc)
+//
+// These heuristics require the ability to "look backward" one character, to
+// see whether it was matched or not. Therefore the dynamic-programming matrix
+// has an extra dimension (last character matched).
+// Each entry also has an additional flag indicating whether the last-but-one
+// character matched, which is needed to trace back through the scoring table
+// and reconstruct the match.
+//
+// We treat strings as byte-sequences, so only ASCII has first-class support.
+//
+// This algorithm was inspired by VS code's client-side filtering, and aims
+// to be mostly-compatible.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FuzzyMatch.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/Format.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+constexpr int FuzzyMatcher::MaxPat;
+constexpr int FuzzyMatcher::MaxWord;
+
+static char lower(char C) { return C >= 'A' && C <= 'Z' ? C + ('a' - 'A') : C; }
+// A "negative infinity" score that won't overflow.
+// We use this to mark unreachable states and forbidden solutions.
+// Score field is 15 bits wide, min value is -2^14, we use half of that.
+static constexpr int AwfulScore = -(1 << 13);
+static bool isAwful(int S) { return S < AwfulScore / 2; }
+static constexpr int PerfectBonus = 3; // Perfect per-pattern-char score.
+
+FuzzyMatcher::FuzzyMatcher(StringRef Pattern)
+ : PatN(std::min<int>(MaxPat, Pattern.size())),
+ ScoreScale(PatN ? float{1} / (PerfectBonus * PatN) : 0), WordN(0) {
+ std::copy(Pattern.begin(), Pattern.begin() + PatN, Pat);
+ for (int I = 0; I < PatN; ++I)
+ LowPat[I] = lower(Pat[I]);
+ Scores[0][0][Miss] = {0, Miss};
+ Scores[0][0][Match] = {AwfulScore, Miss};
+ for (int P = 0; P <= PatN; ++P)
+ for (int W = 0; W < P; ++W)
+ for (Action A : {Miss, Match})
+ Scores[P][W][A] = {AwfulScore, Miss};
+ PatTypeSet =
+ calculateRoles(StringRef(Pat, PatN), makeMutableArrayRef(PatRole, PatN));
+}
+
+Optional<float> FuzzyMatcher::match(StringRef Word) {
+ if (!(WordContainsPattern = init(Word)))
+ return None;
+ if (!PatN)
+ return 1;
+ buildGraph();
+ auto Best = std::max(Scores[PatN][WordN][Miss].Score,
+ Scores[PatN][WordN][Match].Score);
+ if (isAwful(Best))
+ return None;
+ float Score =
+ ScoreScale * std::min(PerfectBonus * PatN, std::max<int>(0, Best));
+ // If the pattern is as long as the word, we have an exact string match,
+ // since every pattern character must match something.
+ if (WordN == PatN)
+ Score *= 2; // May not be perfect 2 if case differs in a significant way.
+ return Score;
+}
+
+// We get CharTypes from a lookup table. Each is 2 bits, 4 fit in each byte.
+// The top 6 bits of the char select the byte, the bottom 2 select the offset.
+// e.g. 'q' = 010100 01 = byte 28 (55), bits 3-2 (01) -> Lower.
+constexpr static uint8_t CharTypes[] = {
+ 0x00, 0x00, 0x00, 0x00, // Control characters
+ 0x00, 0x00, 0x00, 0x00, // Control characters
+ 0xff, 0xff, 0xff, 0xff, // Punctuation
+ 0x55, 0x55, 0xf5, 0xff, // Numbers->Lower, more Punctuation.
+ 0xab, 0xaa, 0xaa, 0xaa, // @ and A-O
+ 0xaa, 0xaa, 0xea, 0xff, // P-Z, more Punctuation.
+ 0x57, 0x55, 0x55, 0x55, // ` and a-o
+ 0x55, 0x55, 0xd5, 0x3f, // p-z, Punctuation, DEL.
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, // Bytes over 127 -> Lower.
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, // (probably UTF-8).
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+};
+
+// The Role can be determined from the Type of a character and its neighbors:
+//
+// Example | Chars | Type | Role
+// ---------+--------------+-----
+// F(o)oBar | Foo | Ull | Tail
+// Foo(B)ar | oBa | lUl | Head
+// (f)oo | ^fo | Ell | Head
+// H(T)TP | HTT | UUU | Tail
+//
+// Our lookup table maps a 6 bit key (Prev, Curr, Next) to a 2-bit Role.
+// A byte packs 4 Roles. (Prev, Curr) selects a byte, Next selects the offset.
+// e.g. Lower, Upper, Lower -> 01 10 01 -> byte 6 (aa), bits 3-2 (10) -> Head.
+constexpr static uint8_t CharRoles[] = {
+ // clang-format off
+ // Curr= Empty Lower Upper Separ
+ /* Prev=Empty */ 0x00, 0xaa, 0xaa, 0xff, // At start, Lower|Upper->Head
+ /* Prev=Lower */ 0x00, 0x55, 0xaa, 0xff, // In word, Upper->Head;Lower->Tail
+ /* Prev=Upper */ 0x00, 0x55, 0x59, 0xff, // Ditto, but U(U)U->Tail
+ /* Prev=Separ */ 0x00, 0xaa, 0xaa, 0xff, // After separator, like at start
+ // clang-format on
+};
+
+template <typename T> static T packedLookup(const uint8_t *Data, int I) {
+ return static_cast<T>((Data[I >> 2] >> ((I & 3) * 2)) & 3);
+}
+CharTypeSet calculateRoles(StringRef Text, MutableArrayRef<CharRole> Roles) {
+ assert(Text.size() == Roles.size());
+ if (Text.size() == 0)
+ return 0;
+ CharType Type = packedLookup<CharType>(CharTypes, Text[0]);
+ CharTypeSet TypeSet = 1 << Type;
+ // Types holds a sliding window of (Prev, Curr, Next) types.
+ // Initial value is (Empty, Empty, type of Text[0]).
+ int Types = Type;
+ // Rotate slides in the type of the next character.
+ auto Rotate = [&](CharType T) { Types = ((Types << 2) | T) & 0x3f; };
+ for (unsigned I = 0; I < Text.size() - 1; ++I) {
+ // For each character, rotate in the next, and look up the role.
+ Type = packedLookup<CharType>(CharTypes, Text[I + 1]);
+ TypeSet |= 1 << Type;
+ Rotate(Type);
+ Roles[I] = packedLookup<CharRole>(CharRoles, Types);
+ }
+ // For the last character, the "next character" is Empty.
+ Rotate(Empty);
+ Roles[Text.size() - 1] = packedLookup<CharRole>(CharRoles, Types);
+ return TypeSet;
+}
+
+// Sets up the data structures matching Word.
+// Returns false if we can cheaply determine that no match is possible.
+bool FuzzyMatcher::init(StringRef NewWord) {
+ WordN = std::min<int>(MaxWord, NewWord.size());
+ if (PatN > WordN)
+ return false;
+ std::copy(NewWord.begin(), NewWord.begin() + WordN, Word);
+ if (PatN == 0)
+ return true;
+ for (int I = 0; I < WordN; ++I)
+ LowWord[I] = lower(Word[I]);
+
+ // Cheap subsequence check.
+ for (int W = 0, P = 0; P != PatN; ++W) {
+ if (W == WordN)
+ return false;
+ if (LowWord[W] == LowPat[P])
+ ++P;
+ }
+
+ // FIXME: some words are hard to tokenize algorithmically.
+ // e.g. vsprintf is V S Print F, and should match [pri] but not [int].
+ // We could add a tokenization dictionary for common stdlib names.
+ WordTypeSet = calculateRoles(StringRef(Word, WordN),
+ makeMutableArrayRef(WordRole, WordN));
+ return true;
+}
+
+// The forwards pass finds the mappings of Pattern onto Word.
+// Score = best score achieved matching Word[..W] against Pat[..P].
+// Unlike other tables, indices range from 0 to N *inclusive*
+// Matched = whether we chose to match Word[W] with Pat[P] or not.
+//
+// Points are mostly assigned to matched characters, with 1 being a good score
+// and 3 being a great one. So we treat the score range as [0, 3 * PatN].
+// This range is not strict: we can apply larger bonuses/penalties, or penalize
+// non-matched characters.
+void FuzzyMatcher::buildGraph() {
+ for (int W = 0; W < WordN; ++W) {
+ Scores[0][W + 1][Miss] = {Scores[0][W][Miss].Score - skipPenalty(W, Miss),
+ Miss};
+ Scores[0][W + 1][Match] = {AwfulScore, Miss};
+ }
+ for (int P = 0; P < PatN; ++P) {
+ for (int W = P; W < WordN; ++W) {
+ auto &Score = Scores[P + 1][W + 1], &PreMiss = Scores[P + 1][W];
+
+ auto MatchMissScore = PreMiss[Match].Score;
+ auto MissMissScore = PreMiss[Miss].Score;
+ if (P < PatN - 1) { // Skipping trailing characters is always free.
+ MatchMissScore -= skipPenalty(W, Match);
+ MissMissScore -= skipPenalty(W, Miss);
+ }
+ Score[Miss] = (MatchMissScore > MissMissScore)
+ ? ScoreInfo{MatchMissScore, Match}
+ : ScoreInfo{MissMissScore, Miss};
+
+ auto &PreMatch = Scores[P][W];
+ auto MatchMatchScore =
+ allowMatch(P, W, Match)
+ ? PreMatch[Match].Score + matchBonus(P, W, Match)
+ : AwfulScore;
+ auto MissMatchScore = allowMatch(P, W, Miss)
+ ? PreMatch[Miss].Score + matchBonus(P, W, Miss)
+ : AwfulScore;
+ Score[Match] = (MatchMatchScore > MissMatchScore)
+ ? ScoreInfo{MatchMatchScore, Match}
+ : ScoreInfo{MissMatchScore, Miss};
+ }
+ }
+}
+
+bool FuzzyMatcher::allowMatch(int P, int W, Action Last) const {
+ if (LowPat[P] != LowWord[W])
+ return false;
+ // We require a "strong" match:
+ // - for the first pattern character. [foo] !~ "barefoot"
+ // - after a gap. [pat] !~ "patnther"
+ if (Last == Miss) {
+ // We're banning matches outright, so conservatively accept some other cases
+ // where our segmentation might be wrong:
+ // - allow matching B in ABCDef (but not in NDEBUG)
+ // - we'd like to accept print in sprintf, but too many false positives
+ if (WordRole[W] == Tail &&
+ (Word[W] == LowWord[W] || !(WordTypeSet & 1 << Lower)))
+ return false;
+ }
+ return true;
+}
+
+int FuzzyMatcher::skipPenalty(int W, Action Last) const {
+ int S = 0;
+ if (WordRole[W] == Head) // Skipping a segment.
+ S += 1;
+ if (Last == Match) // Non-consecutive match.
+ S += 2; // We'd rather skip a segment than split our match.
+ return S;
+}
+
+int FuzzyMatcher::matchBonus(int P, int W, Action Last) const {
+ assert(LowPat[P] == LowWord[W]);
+ int S = 1;
+ // Bonus: pattern so far is a (case-insensitive) prefix of the word.
+ if (P == W) // We can't skip pattern characters, so we must have matched all.
+ ++S;
+ // Bonus: case matches, or a Head in the pattern aligns with one in the word.
+ if ((Pat[P] == Word[W] && ((PatTypeSet & 1 << Upper) || P == W)) ||
+ (PatRole[P] == Head && WordRole[W] == Head))
+ ++S;
+ // Penalty: matching inside a segment (and previous char wasn't matched).
+ if (WordRole[W] == Tail && P && Last == Miss)
+ S -= 3;
+ // Penalty: a Head in the pattern matches in the middle of a word segment.
+ if (PatRole[P] == Head && WordRole[W] == Tail)
+ --S;
+ // Penalty: matching the first pattern character in the middle of a segment.
+ if (P == 0 && WordRole[W] == Tail)
+ S -= 4;
+ assert(S <= PerfectBonus);
+ return S;
+}
+
+llvm::SmallString<256> FuzzyMatcher::dumpLast(llvm::raw_ostream &OS) const {
+ llvm::SmallString<256> Result;
+ OS << "=== Match \"" << StringRef(Word, WordN) << "\" against ["
+ << StringRef(Pat, PatN) << "] ===\n";
+ if (PatN == 0) {
+ OS << "Pattern is empty: perfect match.\n";
+ return Result = StringRef(Word, WordN);
+ }
+ if (WordN == 0) {
+ OS << "Word is empty: no match.\n";
+ return Result;
+ }
+ if (!WordContainsPattern) {
+ OS << "Substring check failed.\n";
+ return Result;
+ } else if (isAwful(std::max(Scores[PatN][WordN][Match].Score,
+ Scores[PatN][WordN][Miss].Score))) {
+ OS << "Substring check passed, but all matches are forbidden\n";
+ }
+ if (!(PatTypeSet & 1 << Upper))
+ OS << "Lowercase query, so scoring ignores case\n";
+
+ // Traverse Matched table backwards to reconstruct the Pattern/Word mapping.
+ // The Score table has cumulative scores, subtracting along this path gives
+ // us the per-letter scores.
+ Action Last =
+ (Scores[PatN][WordN][Match].Score > Scores[PatN][WordN][Miss].Score)
+ ? Match
+ : Miss;
+ int S[MaxWord];
+ Action A[MaxWord];
+ for (int W = WordN - 1, P = PatN - 1; W >= 0; --W) {
+ A[W] = Last;
+ const auto &Cell = Scores[P + 1][W + 1][Last];
+ if (Last == Match)
+ --P;
+ const auto &Prev = Scores[P + 1][W][Cell.Prev];
+ S[W] = Cell.Score - Prev.Score;
+ Last = Cell.Prev;
+ }
+ for (int I = 0; I < WordN; ++I) {
+ if (A[I] == Match && (I == 0 || A[I - 1] == Miss))
+ Result.push_back('[');
+ if (A[I] == Miss && I > 0 && A[I - 1] == Match)
+ Result.push_back(']');
+ Result.push_back(Word[I]);
+ }
+ if (A[WordN - 1] == Match)
+ Result.push_back(']');
+
+ for (char C : StringRef(Word, WordN))
+ OS << " " << C << " ";
+ OS << "\n";
+ for (int I = 0, J = 0; I < WordN; I++)
+ OS << " " << (A[I] == Match ? Pat[J++] : ' ') << " ";
+ OS << "\n";
+ for (int I = 0; I < WordN; I++)
+ OS << format("%2d ", S[I]);
+ OS << "\n";
+
+ OS << "\nSegmentation:";
+ OS << "\n'" << StringRef(Word, WordN) << "'\n ";
+ for (int I = 0; I < WordN; ++I)
+ OS << "?-+ "[static_cast<int>(WordRole[I])];
+ OS << "\n[" << StringRef(Pat, PatN) << "]\n ";
+ for (int I = 0; I < PatN; ++I)
+ OS << "?-+ "[static_cast<int>(PatRole[I])];
+ OS << "\n";
+
+ OS << "\nScoring table (last-Miss, last-Match):\n";
+ OS << " | ";
+ for (char C : StringRef(Word, WordN))
+ OS << " " << C << " ";
+ OS << "\n";
+ OS << "-+----" << std::string(WordN * 4, '-') << "\n";
+ for (int I = 0; I <= PatN; ++I) {
+ for (Action A : {Miss, Match}) {
+ OS << ((I && A == Miss) ? Pat[I - 1] : ' ') << "|";
+ for (int J = 0; J <= WordN; ++J) {
+ if (!isAwful(Scores[I][J][A].Score))
+ OS << format("%3d%c", Scores[I][J][A].Score,
+ Scores[I][J][A].Prev == Match ? '*' : ' ');
+ else
+ OS << " ";
+ }
+ OS << "\n";
+ }
+ }
+
+ return Result;
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/FuzzyMatch.h b/src/third_party/llvm-project/clang-tools-extra/clangd/FuzzyMatch.h
new file mode 100644
index 0000000..f0c7e72
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/FuzzyMatch.h
@@ -0,0 +1,137 @@
+//===--- FuzzyMatch.h - Approximate identifier matching ---------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements fuzzy-matching of strings against identifiers.
+// It indicates both the existence and quality of a match:
+// 'eb' matches both 'emplace_back' and 'embed', the former has a better score.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUZZYMATCH_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUZZYMATCH_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace clangd {
+
+// Utilities for word segmentation.
+// FuzzyMatcher already incorporates this logic, so most users don't need this.
+//
+// A name like "fooBar_baz" consists of several parts foo, bar, baz.
+// Aligning segmentation of word and pattern improves the fuzzy-match.
+// For example: [lol] matches "LaughingOutLoud" better than "LionPopulation"
+//
+// First we classify each character into types (uppercase, lowercase, etc).
+// Then we look at the sequence: e.g. [upper, lower] is the start of a segment.
+
+// We distinguish the types of characters that affect segmentation.
+// It's not obvious how to segment digits, we treat them as lowercase letters.
+// As we don't decode UTF-8, we treat bytes over 127 as lowercase too.
+// This means we require exact (case-sensitive) match for those characters.
+enum CharType : unsigned char {
+ Empty = 0, // Before-the-start and after-the-end (and control chars).
+ Lower = 1, // Lowercase letters, digits, and non-ASCII bytes.
+ Upper = 2, // Uppercase letters.
+ Punctuation = 3, // ASCII punctuation (including Space)
+};
+// A CharTypeSet is a bitfield representing all the character types in a word.
+// Its bits are 1<<Empty, 1<<Lower, etc.
+using CharTypeSet = unsigned char;
+
+// Each character's Role is the Head or Tail of a segment, or a Separator.
+// e.g. XMLHttpRequest_Async
+// +--+---+------ +----
+// ^Head ^Tail ^Separator
+enum CharRole : unsigned char {
+ Unknown = 0, // Stray control characters or impossible states.
+ Tail = 1, // Part of a word segment, but not the first character.
+ Head = 2, // The first character of a word segment.
+ Separator = 3, // Punctuation characters that separate word segments.
+};
+
+// Compute segmentation of Text.
+// Character roles are stored in Roles (Roles.size() must equal Text.size()).
+// The set of character types encountered is returned, this may inform
+// heuristics for dealing with poorly-segmented identifiers like "strndup".
+CharTypeSet calculateRoles(llvm::StringRef Text,
+ llvm::MutableArrayRef<CharRole> Roles);
+
+// A matcher capable of matching and scoring strings against a single pattern.
+// It's optimized for matching against many strings - match() does not allocate.
+class FuzzyMatcher {
+public:
+ // Characters beyond MaxPat are ignored.
+ FuzzyMatcher(llvm::StringRef Pattern);
+
+ // If Word matches the pattern, return a score indicating the quality match.
+ // Scores usually fall in a [0,1] range, with 1 being a very good score.
+ // "Super" scores in (1,2] are possible if the pattern is the full word.
+ // Characters beyond MaxWord are ignored.
+ llvm::Optional<float> match(llvm::StringRef Word);
+
+ llvm::StringRef pattern() const { return llvm::StringRef(Pat, PatN); }
+ bool empty() const { return PatN == 0; }
+
+ // Dump internal state from the last match() to the stream, for debugging.
+ // Returns the pattern with [] around matched characters, e.g.
+ // [u_p] + "unique_ptr" --> "[u]nique[_p]tr"
+ llvm::SmallString<256> dumpLast(llvm::raw_ostream &) const;
+
+private:
+ // We truncate the pattern and the word to bound the cost of matching.
+ constexpr static int MaxPat = 63, MaxWord = 127;
+ // Action describes how a word character was matched to the pattern.
+ // It should be an enum, but this causes bitfield problems:
+ // - for MSVC the enum type must be explicitly unsigned for correctness
+ // - GCC 4.8 complains not all values fit if the type is unsigned
+ using Action = bool;
+ constexpr static Action Miss = false; // Word character was skipped.
+ constexpr static Action Match = true; // Matched against a pattern character.
+
+ bool init(llvm::StringRef Word);
+ void buildGraph();
+ bool allowMatch(int P, int W, Action Last) const;
+ int skipPenalty(int W, Action Last) const;
+ int matchBonus(int P, int W, Action Last) const;
+
+ // Pattern data is initialized by the constructor, then constant.
+ char Pat[MaxPat]; // Pattern data
+ int PatN; // Length
+ char LowPat[MaxPat]; // Pattern in lowercase
+ CharRole PatRole[MaxPat]; // Pattern segmentation info
+ CharTypeSet PatTypeSet; // Bitmask of 1<<CharType for all Pattern characters
+ float ScoreScale; // Normalizes scores for the pattern length.
+
+ // Word data is initialized on each call to match(), mostly by init().
+ char Word[MaxWord]; // Word data
+ int WordN; // Length
+ char LowWord[MaxWord]; // Word in lowercase
+ CharRole WordRole[MaxWord]; // Word segmentation info
+ CharTypeSet WordTypeSet; // Bitmask of 1<<CharType for all Word characters
+ bool WordContainsPattern; // Simple substring check
+
+ // Cumulative best-match score table.
+ // Boundary conditions are filled in by the constructor.
+ // The rest is repopulated for each match(), by buildGraph().
+ struct ScoreInfo {
+ signed int Score : 15;
+ Action Prev : 1;
+ };
+ ScoreInfo Scores[MaxPat + 1][MaxWord + 1][/* Last Action */ 2];
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
new file mode 100644
index 0000000..be03e4c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -0,0 +1,156 @@
+//===--- GlobalCompilationDatabase.cpp --------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "GlobalCompilationDatabase.h"
+#include "Logger.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+namespace clang {
+namespace clangd {
+
+tooling::CompileCommand
+GlobalCompilationDatabase::getFallbackCommand(PathRef File) const {
+ std::vector<std::string> Argv = {"clang"};
+ // Clang treats .h files as C by default, resulting in unhelpful diagnostics.
+ // Parsing as Objective C++ is friendly to more cases.
+ if (llvm::sys::path::extension(File) == ".h")
+ Argv.push_back("-xobjective-c++-header");
+ Argv.push_back(File);
+ return tooling::CompileCommand(llvm::sys::path::parent_path(File),
+ llvm::sys::path::filename(File),
+ std::move(Argv),
+ /*Output=*/"");
+}
+
+DirectoryBasedGlobalCompilationDatabase::
+ DirectoryBasedGlobalCompilationDatabase(
+ llvm::Optional<Path> CompileCommandsDir)
+ : CompileCommandsDir(std::move(CompileCommandsDir)) {}
+
+DirectoryBasedGlobalCompilationDatabase::
+ ~DirectoryBasedGlobalCompilationDatabase() = default;
+
+llvm::Optional<tooling::CompileCommand>
+DirectoryBasedGlobalCompilationDatabase::getCompileCommand(PathRef File) const {
+ if (auto CDB = getCDBForFile(File)) {
+ auto Candidates = CDB->getCompileCommands(File);
+ if (!Candidates.empty()) {
+ addExtraFlags(File, Candidates.front());
+ return std::move(Candidates.front());
+ }
+ } else {
+ log("Failed to find compilation database for {0}", File);
+ }
+ return llvm::None;
+}
+
+tooling::CompileCommand
+DirectoryBasedGlobalCompilationDatabase::getFallbackCommand(
+ PathRef File) const {
+ auto C = GlobalCompilationDatabase::getFallbackCommand(File);
+ addExtraFlags(File, C);
+ return C;
+}
+
+void DirectoryBasedGlobalCompilationDatabase::setCompileCommandsDir(Path P) {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ CompileCommandsDir = P;
+ CompilationDatabases.clear();
+}
+
+void DirectoryBasedGlobalCompilationDatabase::setExtraFlagsForFile(
+ PathRef File, std::vector<std::string> ExtraFlags) {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ ExtraFlagsForFile[File] = std::move(ExtraFlags);
+}
+
+void DirectoryBasedGlobalCompilationDatabase::addExtraFlags(
+ PathRef File, tooling::CompileCommand &C) const {
+ std::lock_guard<std::mutex> Lock(Mutex);
+
+ auto It = ExtraFlagsForFile.find(File);
+ if (It == ExtraFlagsForFile.end())
+ return;
+
+ auto &Args = C.CommandLine;
+ assert(Args.size() >= 2 && "Expected at least [compiler, source file]");
+ // The last argument of CommandLine is the name of the input file.
+ // Add ExtraFlags before it.
+ Args.insert(Args.end() - 1, It->second.begin(), It->second.end());
+}
+
+tooling::CompilationDatabase *
+DirectoryBasedGlobalCompilationDatabase::getCDBInDirLocked(PathRef Dir) const {
+ // FIXME(ibiryukov): Invalidate cached compilation databases on changes
+ auto CachedIt = CompilationDatabases.find(Dir);
+ if (CachedIt != CompilationDatabases.end())
+ return CachedIt->second.get();
+ std::string Error = "";
+ auto CDB = tooling::CompilationDatabase::loadFromDirectory(Dir, Error);
+ if (CDB)
+ CDB = tooling::inferMissingCompileCommands(std::move(CDB));
+ auto Result = CDB.get();
+ CompilationDatabases.insert(std::make_pair(Dir, std::move(CDB)));
+ return Result;
+}
+
+tooling::CompilationDatabase *
+DirectoryBasedGlobalCompilationDatabase::getCDBForFile(PathRef File) const {
+ namespace path = llvm::sys::path;
+ assert((path::is_absolute(File, path::Style::posix) ||
+ path::is_absolute(File, path::Style::windows)) &&
+ "path must be absolute");
+
+ std::lock_guard<std::mutex> Lock(Mutex);
+ if (CompileCommandsDir)
+ return getCDBInDirLocked(*CompileCommandsDir);
+ for (auto Path = path::parent_path(File); !Path.empty();
+ Path = path::parent_path(Path))
+ if (auto CDB = getCDBInDirLocked(Path))
+ return CDB;
+ return nullptr;
+}
+
+CachingCompilationDb::CachingCompilationDb(
+ const GlobalCompilationDatabase &InnerCDB)
+ : InnerCDB(InnerCDB) {}
+
+llvm::Optional<tooling::CompileCommand>
+CachingCompilationDb::getCompileCommand(PathRef File) const {
+ std::unique_lock<std::mutex> Lock(Mut);
+ auto It = Cached.find(File);
+ if (It != Cached.end())
+ return It->second;
+
+ Lock.unlock();
+ llvm::Optional<tooling::CompileCommand> Command =
+ InnerCDB.getCompileCommand(File);
+ Lock.lock();
+ return Cached.try_emplace(File, std::move(Command)).first->getValue();
+}
+
+tooling::CompileCommand
+CachingCompilationDb::getFallbackCommand(PathRef File) const {
+ return InnerCDB.getFallbackCommand(File);
+}
+
+void CachingCompilationDb::invalidate(PathRef File) {
+ std::unique_lock<std::mutex> Lock(Mut);
+ Cached.erase(File);
+}
+
+void CachingCompilationDb::clear() {
+ std::unique_lock<std::mutex> Lock(Mut);
+ Cached.clear();
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/GlobalCompilationDatabase.h b/src/third_party/llvm-project/clang-tools-extra/clangd/GlobalCompilationDatabase.h
new file mode 100644
index 0000000..ab89a18
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/GlobalCompilationDatabase.h
@@ -0,0 +1,119 @@
+//===--- GlobalCompilationDatabase.h ----------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_GLOBALCOMPILATIONDATABASE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_GLOBALCOMPILATIONDATABASE_H
+
+#include "Path.h"
+#include "llvm/ADT/StringMap.h"
+#include <memory>
+#include <mutex>
+#include <vector>
+
+namespace clang {
+
+namespace tooling {
+class CompilationDatabase;
+struct CompileCommand;
+} // namespace tooling
+
+namespace clangd {
+
+class Logger;
+
+/// Provides compilation arguments used for parsing C and C++ files.
+class GlobalCompilationDatabase {
+public:
+ virtual ~GlobalCompilationDatabase() = default;
+
+ /// If there are any known-good commands for building this file, returns one.
+ virtual llvm::Optional<tooling::CompileCommand>
+ getCompileCommand(PathRef File) const = 0;
+
+ /// Makes a guess at how to build a file.
+ /// The default implementation just runs clang on the file.
+ /// Clangd should treat the results as unreliable.
+ virtual tooling::CompileCommand getFallbackCommand(PathRef File) const;
+
+ /// FIXME(ibiryukov): add facilities to track changes to compilation flags of
+ /// existing targets.
+};
+
+/// Gets compile args from tooling::CompilationDatabases built for parent
+/// directories.
+class DirectoryBasedGlobalCompilationDatabase
+ : public GlobalCompilationDatabase {
+public:
+ DirectoryBasedGlobalCompilationDatabase(
+ llvm::Optional<Path> CompileCommandsDir);
+ ~DirectoryBasedGlobalCompilationDatabase() override;
+
+ /// Scans File's parents looking for compilation databases.
+ /// Any extra flags will be added.
+ llvm::Optional<tooling::CompileCommand>
+ getCompileCommand(PathRef File) const override;
+
+ /// Uses the default fallback command, adding any extra flags.
+ tooling::CompileCommand getFallbackCommand(PathRef File) const override;
+
+ /// Set the compile commands directory to \p P.
+ void setCompileCommandsDir(Path P);
+
+ /// Sets the extra flags that should be added to a file.
+ void setExtraFlagsForFile(PathRef File, std::vector<std::string> ExtraFlags);
+
+private:
+ tooling::CompilationDatabase *getCDBForFile(PathRef File) const;
+ tooling::CompilationDatabase *getCDBInDirLocked(PathRef File) const;
+ void addExtraFlags(PathRef File, tooling::CompileCommand &C) const;
+
+ mutable std::mutex Mutex;
+ /// Caches compilation databases loaded from directories(keys are
+ /// directories).
+ mutable llvm::StringMap<std::unique_ptr<clang::tooling::CompilationDatabase>>
+ CompilationDatabases;
+
+ /// Stores extra flags per file.
+ llvm::StringMap<std::vector<std::string>> ExtraFlagsForFile;
+ /// Used for command argument pointing to folder where compile_commands.json
+ /// is located.
+ llvm::Optional<Path> CompileCommandsDir;
+};
+
+/// A wrapper around GlobalCompilationDatabase that caches the compile commands.
+/// Note that only results of getCompileCommand are cached.
+class CachingCompilationDb : public GlobalCompilationDatabase {
+public:
+ explicit CachingCompilationDb(const GlobalCompilationDatabase &InnerCDB);
+
+ /// Gets compile command for \p File from cache or CDB if it's not in the
+ /// cache.
+ llvm::Optional<tooling::CompileCommand>
+ getCompileCommand(PathRef File) const override;
+
+ /// Forwards to the inner CDB. Results of this function are not cached.
+ tooling::CompileCommand getFallbackCommand(PathRef File) const override;
+
+ /// Removes an entry for \p File if it's present in the cache.
+ void invalidate(PathRef File);
+
+ /// Removes all cached compile commands.
+ void clear();
+
+private:
+ const GlobalCompilationDatabase &InnerCDB;
+ mutable std::mutex Mut;
+ mutable llvm::StringMap<llvm::Optional<tooling::CompileCommand>>
+ Cached; /* GUARDED_BY(Mut) */
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Headers.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/Headers.cpp
new file mode 100644
index 0000000..137b29a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Headers.cpp
@@ -0,0 +1,173 @@
+//===--- Headers.cpp - Include headers ---------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Headers.h"
+#include "Compiler.h"
+#include "Logger.h"
+#include "SourceCode.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "llvm/Support/Path.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+class RecordHeaders : public PPCallbacks {
+public:
+ RecordHeaders(const SourceManager &SM, IncludeStructure *Out)
+ : SM(SM), Out(Out) {}
+
+ // Record existing #includes - both written and resolved paths. Only #includes
+ // in the main file are collected.
+ void InclusionDirective(SourceLocation HashLoc, const Token & /*IncludeTok*/,
+ llvm::StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange, const FileEntry *File,
+ llvm::StringRef /*SearchPath*/,
+ llvm::StringRef /*RelativePath*/,
+ const Module * /*Imported*/,
+ SrcMgr::CharacteristicKind /*FileType*/) override {
+ if (SM.isInMainFile(HashLoc))
+ Out->MainFileIncludes.push_back({
+ halfOpenToRange(SM, FilenameRange),
+ (IsAngled ? "<" + FileName + ">" : "\"" + FileName + "\"").str(),
+ File ? File->tryGetRealPathName() : "",
+ });
+ if (File) {
+ auto *IncludingFileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc));
+ if (!IncludingFileEntry) {
+ assert(SM.getBufferName(HashLoc).startswith("<") &&
+ "Expected #include location to be a file or <built-in>");
+ // Treat as if included from the main file.
+ IncludingFileEntry = SM.getFileEntryForID(SM.getMainFileID());
+ }
+ Out->recordInclude(IncludingFileEntry->getName(), File->getName(),
+ File->tryGetRealPathName());
+ }
+ }
+
+private:
+ const SourceManager &SM;
+ IncludeStructure *Out;
+};
+
+} // namespace
+
+bool isLiteralInclude(llvm::StringRef Include) {
+ return Include.startswith("<") || Include.startswith("\"");
+}
+
+bool HeaderFile::valid() const {
+ return (Verbatim && isLiteralInclude(File)) ||
+ (!Verbatim && llvm::sys::path::is_absolute(File));
+}
+
+std::unique_ptr<PPCallbacks>
+collectIncludeStructureCallback(const SourceManager &SM,
+ IncludeStructure *Out) {
+ return llvm::make_unique<RecordHeaders>(SM, Out);
+}
+
+void IncludeStructure::recordInclude(llvm::StringRef IncludingName,
+ llvm::StringRef IncludedName,
+ llvm::StringRef IncludedRealName) {
+ auto Child = fileIndex(IncludedName);
+ if (!IncludedRealName.empty() && RealPathNames[Child].empty())
+ RealPathNames[Child] = IncludedRealName;
+ auto Parent = fileIndex(IncludingName);
+ IncludeChildren[Parent].push_back(Child);
+}
+
+unsigned IncludeStructure::fileIndex(llvm::StringRef Name) {
+ auto R = NameToIndex.try_emplace(Name, RealPathNames.size());
+ if (R.second)
+ RealPathNames.emplace_back();
+ return R.first->getValue();
+}
+
+llvm::StringMap<unsigned>
+IncludeStructure::includeDepth(llvm::StringRef Root) const {
+ // Include depth 0 is the main file only.
+ llvm::StringMap<unsigned> Result;
+ Result[Root] = 0;
+ std::vector<unsigned> CurrentLevel;
+ llvm::DenseSet<unsigned> Seen;
+ auto It = NameToIndex.find(Root);
+ if (It != NameToIndex.end()) {
+ CurrentLevel.push_back(It->second);
+ Seen.insert(It->second);
+ }
+
+ // Each round of BFS traversal finds the next depth level.
+ std::vector<unsigned> PreviousLevel;
+ for (unsigned Level = 1; !CurrentLevel.empty(); ++Level) {
+ PreviousLevel.clear();
+ PreviousLevel.swap(CurrentLevel);
+ for (const auto &Parent : PreviousLevel) {
+ for (const auto &Child : IncludeChildren.lookup(Parent)) {
+ if (Seen.insert(Child).second) {
+ CurrentLevel.push_back(Child);
+ const auto &Name = RealPathNames[Child];
+ // Can't include files if we don't have their real path.
+ if (!Name.empty())
+ Result[Name] = Level;
+ }
+ }
+ }
+ }
+ return Result;
+}
+
+/// FIXME(ioeric): we might not want to insert an absolute include path if the
+/// path is not shortened.
+bool IncludeInserter::shouldInsertInclude(
+ const HeaderFile &DeclaringHeader, const HeaderFile &InsertedHeader) const {
+ assert(DeclaringHeader.valid() && InsertedHeader.valid());
+ if (FileName == DeclaringHeader.File || FileName == InsertedHeader.File)
+ return false;
+ llvm::StringSet<> IncludedHeaders;
+ for (const auto &Inc : Inclusions) {
+ IncludedHeaders.insert(Inc.Written);
+ if (!Inc.Resolved.empty())
+ IncludedHeaders.insert(Inc.Resolved);
+ }
+ auto Included = [&](llvm::StringRef Header) {
+ return IncludedHeaders.find(Header) != IncludedHeaders.end();
+ };
+ return !Included(DeclaringHeader.File) && !Included(InsertedHeader.File);
+}
+
+std::string
+IncludeInserter::calculateIncludePath(const HeaderFile &DeclaringHeader,
+ const HeaderFile &InsertedHeader) const {
+ assert(DeclaringHeader.valid() && InsertedHeader.valid());
+ if (InsertedHeader.Verbatim)
+ return InsertedHeader.File;
+ bool IsSystem = false;
+ std::string Suggested = HeaderSearchInfo.suggestPathToFileForDiagnostics(
+ InsertedHeader.File, BuildDir, &IsSystem);
+ if (IsSystem)
+ Suggested = "<" + Suggested + ">";
+ else
+ Suggested = "\"" + Suggested + "\"";
+ return Suggested;
+}
+
+Optional<TextEdit> IncludeInserter::insert(StringRef VerbatimHeader) const {
+ Optional<TextEdit> Edit = None;
+ if (auto Insertion = Inserter.insert(VerbatimHeader.trim("\"<>"),
+ VerbatimHeader.startswith("<")))
+ Edit = replacementToEdit(Code, *Insertion);
+ return Edit;
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Headers.h b/src/third_party/llvm-project/clang-tools-extra/clangd/Headers.h
new file mode 100644
index 0000000..2abf27c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Headers.h
@@ -0,0 +1,144 @@
+//===--- Headers.h - Include headers -----------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_HEADERS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_HEADERS_H
+
+#include "Path.h"
+#include "Protocol.h"
+#include "SourceCode.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Format/Format.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Tooling/Inclusions/HeaderIncludes.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace clangd {
+
+/// Returns true if \p Include is literal include like "path" or <path>.
+bool isLiteralInclude(llvm::StringRef Include);
+
+/// Represents a header file to be #include'd.
+struct HeaderFile {
+ std::string File;
+ /// If this is true, `File` is a literal string quoted with <> or "" that
+ /// can be #included directly; otherwise, `File` is an absolute file path.
+ bool Verbatim;
+
+ bool valid() const;
+};
+
+// An #include directive that we found in the main file.
+struct Inclusion {
+ Range R; // Inclusion range.
+ std::string Written; // Inclusion name as written e.g. <vector>.
+ Path Resolved; // Resolved path of included file. Empty if not resolved.
+};
+
+// Information captured about the inclusion graph in a translation unit.
+// This includes detailed information about the direct #includes, and summary
+// information about all transitive includes.
+//
+// It should be built incrementally with collectIncludeStructureCallback().
+// When we build the preamble, we capture and store its include structure along
+// with the preamble data. When we use the preamble, we can copy its
+// IncludeStructure and use another collectIncludeStructureCallback() to fill
+// in any non-preamble inclusions.
+class IncludeStructure {
+public:
+ std::vector<Inclusion> MainFileIncludes;
+
+ // Return all transitively reachable files, and their minimum include depth.
+ // All transitive includes (absolute paths), with their minimum include depth.
+ // Root --> 0, #included file --> 1, etc.
+ // Root is clang's name for a file, which may not be absolute.
+ // Usually it should be SM.getFileEntryForID(SM.getMainFileID())->getName().
+ llvm::StringMap<unsigned> includeDepth(llvm::StringRef Root) const;
+
+ // This updates IncludeDepth(), but not MainFileIncludes.
+ void recordInclude(llvm::StringRef IncludingName,
+ llvm::StringRef IncludedName,
+ llvm::StringRef IncludedRealName);
+
+private:
+ // Identifying files in a way that persists from preamble build to subsequent
+ // builds is surprisingly hard. FileID is unavailable in InclusionDirective(),
+ // and RealPathName and UniqueID are not preseved in the preamble.
+ // We use the FileEntry::Name, which is stable, interned into a "file index".
+ // The paths we want to expose are the RealPathName, so store those too.
+ std::vector<std::string> RealPathNames; // In file index order.
+ unsigned fileIndex(llvm::StringRef Name);
+ llvm::StringMap<unsigned> NameToIndex; // Values are file indexes.
+ // Maps a file's index to that of the files it includes.
+ llvm::DenseMap<unsigned, SmallVector<unsigned, 8>> IncludeChildren;
+};
+
+/// Returns a PPCallback that visits all inclusions in the main file.
+std::unique_ptr<PPCallbacks>
+collectIncludeStructureCallback(const SourceManager &SM, IncludeStructure *Out);
+
+// Calculates insertion edit for including a new header in a file.
+class IncludeInserter {
+public:
+ IncludeInserter(StringRef FileName, StringRef Code,
+ const format::FormatStyle &Style, StringRef BuildDir,
+ HeaderSearch &HeaderSearchInfo)
+ : FileName(FileName), Code(Code), BuildDir(BuildDir),
+ HeaderSearchInfo(HeaderSearchInfo),
+ Inserter(FileName, Code, Style.IncludeStyle) {}
+
+ void addExisting(Inclusion Inc) { Inclusions.push_back(std::move(Inc)); }
+
+ /// Checks whether to add an #include of the header into \p File.
+ /// An #include will not be added if:
+ /// - Either \p DeclaringHeader or \p InsertedHeader is already (directly)
+ /// in \p Inclusions (including those included via different paths).
+ /// - \p DeclaringHeader or \p InsertedHeader is the same as \p File.
+ ///
+ /// \param DeclaringHeader is the original header corresponding to \p
+ /// InsertedHeader e.g. the header that declares a symbol.
+ /// \param InsertedHeader The preferred header to be inserted. This could be
+ /// the same as DeclaringHeader but must be provided.
+ bool shouldInsertInclude(const HeaderFile &DeclaringHeader,
+ const HeaderFile &InsertedHeader) const;
+
+ /// Determines the preferred way to #include a file, taking into account the
+ /// search path. Usually this will prefer a shorter representation like
+ /// 'Foo/Bar.h' over a longer one like 'Baz/include/Foo/Bar.h'.
+ ///
+ /// \param DeclaringHeader is the original header corresponding to \p
+ /// InsertedHeader e.g. the header that declares a symbol.
+ /// \param InsertedHeader The preferred header to be inserted. This could be
+ /// the same as DeclaringHeader but must be provided.
+ ///
+ /// \return A quoted "path" or <path> to be included.
+ std::string calculateIncludePath(const HeaderFile &DeclaringHeader,
+ const HeaderFile &InsertedHeader) const;
+
+ /// Calculates an edit that inserts \p VerbatimHeader into code. If the header
+ /// is already included, this returns None.
+ llvm::Optional<TextEdit> insert(llvm::StringRef VerbatimHeader) const;
+
+private:
+ StringRef FileName;
+ StringRef Code;
+ StringRef BuildDir;
+ HeaderSearch &HeaderSearchInfo;
+ std::vector<Inclusion> Inclusions;
+ tooling::HeaderIncludes Inserter; // Computers insertion replacement.
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_HEADERS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/JSONRPCDispatcher.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/JSONRPCDispatcher.cpp
new file mode 100644
index 0000000..2741c66
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/JSONRPCDispatcher.cpp
@@ -0,0 +1,368 @@
+//===--- JSONRPCDispatcher.cpp - Main JSON parser entry point -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JSONRPCDispatcher.h"
+#include "ProtocolHandlers.h"
+#include "Trace.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/SourceMgr.h"
+#include <istream>
+
+using namespace llvm;
+using namespace clang;
+using namespace clangd;
+
+namespace {
+static Key<json::Value> RequestID;
+static Key<JSONOutput *> RequestOut;
+
+// When tracing, we trace a request and attach the repsonse in reply().
+// Because the Span isn't available, we find the current request using Context.
+class RequestSpan {
+ RequestSpan(llvm::json::Object *Args) : Args(Args) {}
+ std::mutex Mu;
+ llvm::json::Object *Args;
+ static Key<std::unique_ptr<RequestSpan>> RSKey;
+
+public:
+ // Return a context that's aware of the enclosing request, identified by Span.
+ static Context stash(const trace::Span &Span) {
+ return Context::current().derive(
+ RSKey, std::unique_ptr<RequestSpan>(new RequestSpan(Span.Args)));
+ }
+
+ // If there's an enclosing request and the tracer is interested, calls \p F
+ // with a json::Object where request info can be added.
+ template <typename Func> static void attach(Func &&F) {
+ auto *RequestArgs = Context::current().get(RSKey);
+ if (!RequestArgs || !*RequestArgs || !(*RequestArgs)->Args)
+ return;
+ std::lock_guard<std::mutex> Lock((*RequestArgs)->Mu);
+ F(*(*RequestArgs)->Args);
+ }
+};
+Key<std::unique_ptr<RequestSpan>> RequestSpan::RSKey;
+} // namespace
+
+void JSONOutput::writeMessage(const json::Value &Message) {
+ std::string S;
+ llvm::raw_string_ostream OS(S);
+ if (Pretty)
+ OS << llvm::formatv("{0:2}", Message);
+ else
+ OS << Message;
+ OS.flush();
+
+ {
+ std::lock_guard<std::mutex> Guard(StreamMutex);
+ Outs << "Content-Length: " << S.size() << "\r\n\r\n" << S;
+ Outs.flush();
+ }
+ vlog(">>> {0}\n", S);
+}
+
+void JSONOutput::log(Logger::Level Level,
+ const llvm::formatv_object_base &Message) {
+ if (Level < MinLevel)
+ return;
+ llvm::sys::TimePoint<> Timestamp = std::chrono::system_clock::now();
+ trace::log(Message);
+ std::lock_guard<std::mutex> Guard(StreamMutex);
+ Logs << llvm::formatv("{0}[{1:%H:%M:%S.%L}] {2}\n", indicator(Level),
+ Timestamp, Message);
+ Logs.flush();
+}
+
+void JSONOutput::mirrorInput(const Twine &Message) {
+ if (!InputMirror)
+ return;
+
+ *InputMirror << Message;
+ InputMirror->flush();
+}
+
+void clangd::reply(json::Value &&Result) {
+ auto ID = Context::current().get(RequestID);
+ if (!ID) {
+ elog("Attempted to reply to a notification!");
+ return;
+ }
+ RequestSpan::attach([&](json::Object &Args) { Args["Reply"] = Result; });
+ log("--> reply({0})", *ID);
+ Context::current()
+ .getExisting(RequestOut)
+ ->writeMessage(json::Object{
+ {"jsonrpc", "2.0"},
+ {"id", *ID},
+ {"result", std::move(Result)},
+ });
+}
+
+void clangd::replyError(ErrorCode Code, const llvm::StringRef &Message) {
+ elog("Error {0}: {1}", static_cast<int>(Code), Message);
+ RequestSpan::attach([&](json::Object &Args) {
+ Args["Error"] = json::Object{{"code", static_cast<int>(Code)},
+ {"message", Message.str()}};
+ });
+
+ if (auto ID = Context::current().get(RequestID)) {
+ log("--> reply({0}) error: {1}", *ID, Message);
+ Context::current()
+ .getExisting(RequestOut)
+ ->writeMessage(json::Object{
+ {"jsonrpc", "2.0"},
+ {"id", *ID},
+ {"error", json::Object{{"code", static_cast<int>(Code)},
+ {"message", Message}}},
+ });
+ }
+}
+
+void clangd::call(StringRef Method, json::Value &&Params) {
+ RequestSpan::attach([&](json::Object &Args) {
+ Args["Call"] = json::Object{{"method", Method.str()}, {"params", Params}};
+ });
+ // FIXME: Generate/Increment IDs for every request so that we can get proper
+ // replies once we need to.
+ auto ID = 1;
+ log("--> {0}({1})", Method, ID);
+ Context::current()
+ .getExisting(RequestOut)
+ ->writeMessage(json::Object{
+ {"jsonrpc", "2.0"},
+ {"id", ID},
+ {"method", Method},
+ {"params", std::move(Params)},
+ });
+}
+
+void JSONRPCDispatcher::registerHandler(StringRef Method, Handler H) {
+ assert(!Handlers.count(Method) && "Handler already registered!");
+ Handlers[Method] = std::move(H);
+}
+
+static void logIncomingMessage(const llvm::Optional<json::Value> &ID,
+ llvm::Optional<StringRef> Method,
+ const json::Object *Error) {
+ if (Method) { // incoming request
+ if (ID) // call
+ log("<-- {0}({1})", *Method, *ID);
+ else // notification
+ log("<-- {0}", *Method);
+ } else if (ID) { // response, ID must be provided
+ if (Error)
+ log("<-- reply({0}) error: {1}", *ID,
+ Error->getString("message").getValueOr("<no message>"));
+ else
+ log("<-- reply({0})", *ID);
+ }
+}
+
+bool JSONRPCDispatcher::call(const json::Value &Message,
+ JSONOutput &Out) const {
+ // Message must be an object with "jsonrpc":"2.0".
+ auto *Object = Message.getAsObject();
+ if (!Object || Object->getString("jsonrpc") != Optional<StringRef>("2.0"))
+ return false;
+ // ID may be any JSON value. If absent, this is a notification.
+ llvm::Optional<json::Value> ID;
+ if (auto *I = Object->get("id"))
+ ID = std::move(*I);
+ auto Method = Object->getString("method");
+ logIncomingMessage(ID, Method, Object->getObject("error"));
+ if (!Method) // We only handle incoming requests, and ignore responses.
+ return false;
+ // Params should be given, use null if not.
+ json::Value Params = nullptr;
+ if (auto *P = Object->get("params"))
+ Params = std::move(*P);
+
+ auto I = Handlers.find(*Method);
+ auto &Handler = I != Handlers.end() ? I->second : UnknownHandler;
+
+ // Create a Context that contains request information.
+ WithContextValue WithRequestOut(RequestOut, &Out);
+ llvm::Optional<WithContextValue> WithID;
+ if (ID)
+ WithID.emplace(RequestID, *ID);
+
+ // Create a tracing Span covering the whole request lifetime.
+ trace::Span Tracer(*Method);
+ if (ID)
+ SPAN_ATTACH(Tracer, "ID", *ID);
+ SPAN_ATTACH(Tracer, "Params", Params);
+
+ // Stash a reference to the span args, so later calls can add metadata.
+ WithContext WithRequestSpan(RequestSpan::stash(Tracer));
+ Handler(std::move(Params));
+ return true;
+}
+
+// Tries to read a line up to and including \n.
+// If failing, feof() or ferror() will be set.
+static bool readLine(std::FILE *In, std::string &Out) {
+ static constexpr int BufSize = 1024;
+ size_t Size = 0;
+ Out.clear();
+ for (;;) {
+ Out.resize(Size + BufSize);
+ // Handle EINTR which is sent when a debugger attaches on some platforms.
+ if (!llvm::sys::RetryAfterSignal(nullptr, ::fgets, &Out[Size], BufSize, In))
+ return false;
+ clearerr(In);
+ // If the line contained null bytes, anything after it (including \n) will
+ // be ignored. Fortunately this is not a legal header or JSON.
+ size_t Read = std::strlen(&Out[Size]);
+ if (Read > 0 && Out[Size + Read - 1] == '\n') {
+ Out.resize(Size + Read);
+ return true;
+ }
+ Size += Read;
+ }
+}
+
+// Returns None when:
+// - ferror() or feof() are set.
+// - Content-Length is missing or empty (protocol error)
+static llvm::Optional<std::string> readStandardMessage(std::FILE *In,
+ JSONOutput &Out) {
+ // A Language Server Protocol message starts with a set of HTTP headers,
+ // delimited by \r\n, and terminated by an empty line (\r\n).
+ unsigned long long ContentLength = 0;
+ std::string Line;
+ while (true) {
+ if (feof(In) || ferror(In) || !readLine(In, Line))
+ return llvm::None;
+
+ Out.mirrorInput(Line);
+ llvm::StringRef LineRef(Line);
+
+ // We allow comments in headers. Technically this isn't part
+ // of the LSP specification, but makes writing tests easier.
+ if (LineRef.startswith("#"))
+ continue;
+
+ // Content-Length is a mandatory header, and the only one we handle.
+ if (LineRef.consume_front("Content-Length: ")) {
+ if (ContentLength != 0) {
+ elog("Warning: Duplicate Content-Length header received. "
+ "The previous value for this message ({0}) was ignored.",
+ ContentLength);
+ }
+ llvm::getAsUnsignedInteger(LineRef.trim(), 0, ContentLength);
+ continue;
+ } else if (!LineRef.trim().empty()) {
+ // It's another header, ignore it.
+ continue;
+ } else {
+ // An empty line indicates the end of headers.
+ // Go ahead and read the JSON.
+ break;
+ }
+ }
+
+ // The fuzzer likes crashing us by sending "Content-Length: 9999999999999999"
+ if (ContentLength > 1 << 30) { // 1024M
+ elog("Refusing to read message with long Content-Length: {0}. "
+ "Expect protocol errors",
+ ContentLength);
+ return llvm::None;
+ }
+ if (ContentLength == 0) {
+ log("Warning: Missing Content-Length header, or zero-length message.");
+ return llvm::None;
+ }
+
+ std::string JSON(ContentLength, '\0');
+ for (size_t Pos = 0, Read; Pos < ContentLength; Pos += Read) {
+ // Handle EINTR which is sent when a debugger attaches on some platforms.
+ Read = llvm::sys::RetryAfterSignal(0u, ::fread, &JSON[Pos], 1,
+ ContentLength - Pos, In);
+ Out.mirrorInput(StringRef(&JSON[Pos], Read));
+ if (Read == 0) {
+ elog("Input was aborted. Read only {0} bytes of expected {1}.", Pos,
+ ContentLength);
+ return llvm::None;
+ }
+ clearerr(In); // If we're done, the error was transient. If we're not done,
+ // either it was transient or we'll see it again on retry.
+ Pos += Read;
+ }
+ return std::move(JSON);
+}
+
+// For lit tests we support a simplified syntax:
+// - messages are delimited by '---' on a line by itself
+// - lines starting with # are ignored.
+// This is a testing path, so favor simplicity over performance here.
+// When returning None, feof() or ferror() will be set.
+static llvm::Optional<std::string> readDelimitedMessage(std::FILE *In,
+ JSONOutput &Out) {
+ std::string JSON;
+ std::string Line;
+ while (readLine(In, Line)) {
+ auto LineRef = llvm::StringRef(Line).trim();
+ if (LineRef.startswith("#")) // comment
+ continue;
+
+ // found a delimiter
+ if (LineRef.rtrim() == "---")
+ break;
+
+ JSON += Line;
+ }
+
+ if (ferror(In)) {
+ elog("Input error while reading message!");
+ return llvm::None;
+ } else { // Including EOF
+ Out.mirrorInput(
+ llvm::formatv("Content-Length: {0}\r\n\r\n{1}", JSON.size(), JSON));
+ return std::move(JSON);
+ }
+}
+
+// The use of C-style std::FILE* IO deserves some explanation.
+// Previously, std::istream was used. When a debugger attached on MacOS, the
+// process received EINTR, the stream went bad, and clangd exited.
+// A retry-on-EINTR loop around reads solved this problem, but caused clangd to
+// sometimes hang rather than exit on other OSes. The interaction between
+// istreams and signals isn't well-specified, so it's hard to get this right.
+// The C APIs seem to be clearer in this respect.
+void clangd::runLanguageServerLoop(std::FILE *In, JSONOutput &Out,
+ JSONStreamStyle InputStyle,
+ JSONRPCDispatcher &Dispatcher,
+ bool &IsDone) {
+ auto &ReadMessage =
+ (InputStyle == Delimited) ? readDelimitedMessage : readStandardMessage;
+ while (!IsDone && !feof(In)) {
+ if (ferror(In)) {
+ elog("IO error: {0}", llvm::sys::StrError());
+ return;
+ }
+ if (auto JSON = ReadMessage(In, Out)) {
+ if (auto Doc = json::parse(*JSON)) {
+ // Log the formatted message.
+ vlog(Out.Pretty ? "<<< {0:2}\n" : "<<< {0}\n", *Doc);
+ // Finally, execute the action for this JSON message.
+ if (!Dispatcher.call(*Doc, Out))
+ elog("JSON dispatch failed!");
+ } else {
+ // Parse error. Log the raw message.
+ vlog("<<< {0}\n", *JSON);
+ elog("JSON parse error: {0}", llvm::toString(Doc.takeError()));
+ }
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/JSONRPCDispatcher.h b/src/third_party/llvm-project/clang-tools-extra/clangd/JSONRPCDispatcher.h
new file mode 100644
index 0000000..e8c96fc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/JSONRPCDispatcher.h
@@ -0,0 +1,117 @@
+//===--- JSONRPCDispatcher.h - Main JSON parser entry point -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_JSONRPCDISPATCHER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_JSONRPCDISPATCHER_H
+
+#include "Logger.h"
+#include "Protocol.h"
+#include "Trace.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/JSON.h"
+#include <iosfwd>
+#include <mutex>
+
+namespace clang {
+namespace clangd {
+
+/// Encapsulates output and logs streams and provides thread-safe access to
+/// them.
+class JSONOutput : public Logger {
+ // FIXME(ibiryukov): figure out if we can shrink the public interface of
+ // JSONOutput now that we pass Context everywhere.
+public:
+ JSONOutput(llvm::raw_ostream &Outs, llvm::raw_ostream &Logs,
+ Logger::Level MinLevel, llvm::raw_ostream *InputMirror = nullptr,
+ bool Pretty = false)
+ : Pretty(Pretty), MinLevel(MinLevel), Outs(Outs), Logs(Logs),
+ InputMirror(InputMirror) {}
+
+ /// Emit a JSONRPC message.
+ void writeMessage(const llvm::json::Value &Result);
+
+ /// Write a line to the logging stream.
+ void log(Level, const llvm::formatv_object_base &Message) override;
+
+ /// Mirror \p Message into InputMirror stream. Does nothing if InputMirror is
+ /// null.
+ /// Unlike other methods of JSONOutput, mirrorInput is not thread-safe.
+ void mirrorInput(const Twine &Message);
+
+ // Whether output should be pretty-printed.
+ const bool Pretty;
+
+private:
+ Logger::Level MinLevel;
+ llvm::raw_ostream &Outs;
+ llvm::raw_ostream &Logs;
+ llvm::raw_ostream *InputMirror;
+
+ std::mutex StreamMutex;
+};
+
+/// Sends a successful reply.
+/// Current context must derive from JSONRPCDispatcher::Handler.
+void reply(llvm::json::Value &&Result);
+/// Sends an error response to the client, and logs it.
+/// Current context must derive from JSONRPCDispatcher::Handler.
+void replyError(ErrorCode Code, const llvm::StringRef &Message);
+/// Sends a request to the client.
+/// Current context must derive from JSONRPCDispatcher::Handler.
+void call(llvm::StringRef Method, llvm::json::Value &&Params);
+
+/// Main JSONRPC entry point. This parses the JSONRPC "header" and calls the
+/// registered Handler for the method received.
+class JSONRPCDispatcher {
+public:
+ // A handler responds to requests for a particular method name.
+ using Handler = std::function<void(const llvm::json::Value &)>;
+
+ /// Create a new JSONRPCDispatcher. UnknownHandler is called when an unknown
+ /// method is received.
+ JSONRPCDispatcher(Handler UnknownHandler)
+ : UnknownHandler(std::move(UnknownHandler)) {}
+
+ /// Registers a Handler for the specified Method.
+ void registerHandler(StringRef Method, Handler H);
+
+ /// Parses a JSONRPC message and calls the Handler for it.
+ bool call(const llvm::json::Value &Message, JSONOutput &Out) const;
+
+private:
+ llvm::StringMap<Handler> Handlers;
+ Handler UnknownHandler;
+};
+
+/// Controls the way JSON-RPC messages are encoded (both input and output).
+enum JSONStreamStyle {
+ /// Encoding per the LSP specification, with mandatory Content-Length header.
+ Standard,
+ /// Messages are delimited by a '---' line. Comment lines start with #.
+ Delimited
+};
+
+/// Parses input queries from LSP client (coming from \p In) and runs call
+/// method of \p Dispatcher for each query.
+/// After handling each query checks if \p IsDone is set true and exits the loop
+/// if it is.
+/// Input stream(\p In) must be opened in binary mode to avoid preliminary
+/// replacements of \r\n with \n.
+/// We use C-style FILE* for reading as std::istream has unclear interaction
+/// with signals, which are sent by debuggers on some OSs.
+void runLanguageServerLoop(std::FILE *In, JSONOutput &Out,
+ JSONStreamStyle InputStyle,
+ JSONRPCDispatcher &Dispatcher, bool &IsDone);
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Logger.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/Logger.cpp
new file mode 100644
index 0000000..5ce3351
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Logger.cpp
@@ -0,0 +1,48 @@
+//===--- Logger.cpp - Logger interface for clangd -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Logger.h"
+#include "llvm/Support/raw_ostream.h"
+#include <mutex>
+
+namespace clang {
+namespace clangd {
+
+namespace {
+Logger *L = nullptr;
+} // namespace
+
+LoggingSession::LoggingSession(clangd::Logger &Instance) {
+ assert(!L);
+ L = &Instance;
+}
+
+LoggingSession::~LoggingSession() { L = nullptr; }
+
+void detail::log(Logger::Level Level,
+ const llvm::formatv_object_base &Message) {
+ if (L)
+ L->log(Level, Message);
+ else {
+ static std::mutex Mu;
+ std::lock_guard<std::mutex> Guard(Mu);
+ llvm::errs() << Message << "\n";
+ }
+}
+
+const char *detail::debugType(const char *Filename) {
+ if (const char *Slash = strrchr(Filename, '/'))
+ return Slash + 1;
+ if (const char *Backslash = strrchr(Filename, '\\'))
+ return Backslash + 1;
+ return Filename;
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Logger.h b/src/third_party/llvm-project/clang-tools-extra/clangd/Logger.h
new file mode 100644
index 0000000..cc6e3a0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Logger.h
@@ -0,0 +1,92 @@
+//===--- Logger.h - Logger interface for clangd ------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_LOGGER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_LOGGER_H
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+
+namespace clang {
+namespace clangd {
+
+/// Interface to allow custom logging in clangd.
+class Logger {
+public:
+ virtual ~Logger() = default;
+
+ enum Level { Debug, Verbose, Info, Error };
+ static char indicator(Level L) { return "DVIE"[L]; }
+
+ /// Implementations of this method must be thread-safe.
+ virtual void log(Level, const llvm::formatv_object_base &Message) = 0;
+};
+
+namespace detail {
+const char *debugType(const char *Filename);
+void log(Logger::Level, const llvm::formatv_object_base &);
+
+// We often want to consume llvm::Errors by value when passing them to log().
+// We automatically wrap them in llvm::fmt_consume() as formatv requires.
+template <typename T> T &&wrap(T &&V) { return std::forward<T>(V); }
+inline decltype(fmt_consume(llvm::Error::success())) wrap(llvm::Error &&V) {
+ return fmt_consume(std::move(V));
+}
+template <typename... Ts>
+void log(Logger::Level L, const char *Fmt, Ts &&... Vals) {
+ detail::log(L, llvm::formatv(Fmt, detail::wrap(std::forward<Ts>(Vals))...));
+}
+} // namespace detail
+
+// Clangd logging functions write to a global logger set by LoggingSession.
+// If no logger is registered, writes to llvm::errs().
+// All accept llvm::formatv()-style arguments, e.g. log("Text={0}", Text).
+
+// elog() is used for "loud" errors and warnings.
+// This level is often visible to users.
+template <typename... Ts> void elog(const char *Fmt, Ts &&... Vals) {
+ detail::log(Logger::Error, Fmt, std::forward<Ts>(Vals)...);
+}
+// log() is used for information important to understanding a clangd session.
+// e.g. the names of LSP messages sent are logged at this level.
+// This level could be enabled in production builds to allow later inspection.
+template <typename... Ts> void log(const char *Fmt, Ts &&... Vals) {
+ detail::log(Logger::Info, Fmt, std::forward<Ts>(Vals)...);
+}
+// vlog() is used for details often needed for debugging clangd sessions.
+// This level would typically be enabled for clangd developers.
+template <typename... Ts> void vlog(const char *Fmt, Ts &&... Vals) {
+ detail::log(Logger::Verbose, Fmt, std::forward<Ts>(Vals)...);
+}
+// dlog only logs if --debug was passed, or --debug_only=Basename.
+// This level would be enabled in a targeted way when debugging.
+#define dlog(...) \
+ DEBUG_WITH_TYPE(::clang::clangd::detail::debugType(__FILE__), \
+ ::clang::clangd::detail::log(Logger::Debug, __VA_ARGS__))
+
+/// Only one LoggingSession can be active at a time.
+class LoggingSession {
+public:
+ LoggingSession(clangd::Logger &Instance);
+ ~LoggingSession();
+
+ LoggingSession(LoggingSession &&) = delete;
+ LoggingSession &operator=(LoggingSession &&) = delete;
+
+ LoggingSession(LoggingSession const &) = delete;
+ LoggingSession &operator=(LoggingSession const &) = delete;
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Path.h b/src/third_party/llvm-project/clang-tools-extra/clangd/Path.h
new file mode 100644
index 0000000..b4c9335
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Path.h
@@ -0,0 +1,29 @@
+//===--- Path.h - Helper typedefs --------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_PATH_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_PATH_H
+
+#include "llvm/ADT/StringRef.h"
+#include <string>
+
+namespace clang {
+namespace clangd {
+
+/// A typedef to represent a file path. Used solely for more descriptive
+/// signatures.
+using Path = std::string;
+/// A typedef to represent a ref to file path. Used solely for more descriptive
+/// signatures.
+using PathRef = llvm::StringRef;
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Protocol.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/Protocol.cpp
new file mode 100644
index 0000000..5ecd719
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Protocol.cpp
@@ -0,0 +1,601 @@
+//===--- Protocol.cpp - Language Server Protocol Implementation -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the serialization code for the LSP structs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Protocol.h"
+#include "Logger.h"
+#include "URI.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+URIForFile::URIForFile(std::string AbsPath) {
+ assert(llvm::sys::path::is_absolute(AbsPath) && "the path is relative");
+ File = std::move(AbsPath);
+}
+
+bool fromJSON(const json::Value &E, URIForFile &R) {
+ if (auto S = E.getAsString()) {
+ auto U = URI::parse(*S);
+ if (!U) {
+ elog("Failed to parse URI {0}: {1}", *S, U.takeError());
+ return false;
+ }
+ if (U->scheme() != "file" && U->scheme() != "test") {
+ elog("Clangd only supports 'file' URI scheme for workspace files: {0}",
+ *S);
+ return false;
+ }
+ auto Path = URI::resolve(*U);
+ if (!Path) {
+ log("{0}", Path.takeError());
+ return false;
+ }
+ R = URIForFile(*Path);
+ return true;
+ }
+ return false;
+}
+
+json::Value toJSON(const URIForFile &U) { return U.uri(); }
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const URIForFile &U) {
+ return OS << U.uri();
+}
+
+json::Value toJSON(const TextDocumentIdentifier &R) {
+ return json::Object{{"uri", R.uri}};
+}
+
+bool fromJSON(const json::Value &Params, TextDocumentIdentifier &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("uri", R.uri);
+}
+
+bool fromJSON(const json::Value &Params, Position &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("line", R.line) && O.map("character", R.character);
+}
+
+json::Value toJSON(const Position &P) {
+ return json::Object{
+ {"line", P.line},
+ {"character", P.character},
+ };
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Position &P) {
+ return OS << P.line << ':' << P.character;
+}
+
+bool fromJSON(const json::Value &Params, Range &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("start", R.start) && O.map("end", R.end);
+}
+
+json::Value toJSON(const Range &P) {
+ return json::Object{
+ {"start", P.start},
+ {"end", P.end},
+ };
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Range &R) {
+ return OS << R.start << '-' << R.end;
+}
+
+json::Value toJSON(const Location &P) {
+ return json::Object{
+ {"uri", P.uri},
+ {"range", P.range},
+ };
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Location &L) {
+ return OS << L.range << '@' << L.uri;
+}
+
+bool fromJSON(const json::Value &Params, TextDocumentItem &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("uri", R.uri) && O.map("languageId", R.languageId) &&
+ O.map("version", R.version) && O.map("text", R.text);
+}
+
+bool fromJSON(const json::Value &Params, Metadata &R) {
+ json::ObjectMapper O(Params);
+ if (!O)
+ return false;
+ O.map("extraFlags", R.extraFlags);
+ return true;
+}
+
+bool fromJSON(const json::Value &Params, TextEdit &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("range", R.range) && O.map("newText", R.newText);
+}
+
+json::Value toJSON(const TextEdit &P) {
+ return json::Object{
+ {"range", P.range},
+ {"newText", P.newText},
+ };
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TextEdit &TE) {
+ OS << TE.range << " => \"";
+ printEscapedString(TE.newText, OS);
+ return OS << '"';
+}
+
+bool fromJSON(const json::Value &E, TraceLevel &Out) {
+ if (auto S = E.getAsString()) {
+ if (*S == "off") {
+ Out = TraceLevel::Off;
+ return true;
+ } else if (*S == "messages") {
+ Out = TraceLevel::Messages;
+ return true;
+ } else if (*S == "verbose") {
+ Out = TraceLevel::Verbose;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool fromJSON(const json::Value &Params, CompletionItemClientCapabilities &R) {
+ json::ObjectMapper O(Params);
+ if (!O)
+ return false;
+ O.map("snippetSupport", R.snippetSupport);
+ O.map("commitCharacterSupport", R.commitCharacterSupport);
+ return true;
+}
+
+bool fromJSON(const json::Value &Params, CompletionClientCapabilities &R) {
+ json::ObjectMapper O(Params);
+ if (!O)
+ return false;
+ O.map("dynamicRegistration", R.dynamicRegistration);
+ O.map("completionItem", R.completionItem);
+ O.map("contextSupport", R.contextSupport);
+ return true;
+}
+
+bool fromJSON(const json::Value &E, SymbolKind &Out) {
+ if (auto T = E.getAsInteger()) {
+ if (*T < static_cast<int>(SymbolKind::File) ||
+ *T > static_cast<int>(SymbolKind::TypeParameter))
+ return false;
+ Out = static_cast<SymbolKind>(*T);
+ return true;
+ }
+ return false;
+}
+
+bool fromJSON(const json::Value &E, std::vector<SymbolKind> &Out) {
+ if (auto *A = E.getAsArray()) {
+ Out.clear();
+ for (size_t I = 0; I < A->size(); ++I) {
+ SymbolKind KindOut;
+ if (fromJSON((*A)[I], KindOut))
+ Out.push_back(KindOut);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool fromJSON(const json::Value &Params, SymbolKindCapabilities &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("valueSet", R.valueSet);
+}
+
+SymbolKind adjustKindToCapability(SymbolKind Kind,
+ SymbolKindBitset &SupportedSymbolKinds) {
+ auto KindVal = static_cast<size_t>(Kind);
+ if (KindVal >= SymbolKindMin && KindVal <= SupportedSymbolKinds.size() &&
+ SupportedSymbolKinds[KindVal])
+ return Kind;
+
+ switch (Kind) {
+ // Provide some fall backs for common kinds that are close enough.
+ case SymbolKind::Struct:
+ return SymbolKind::Class;
+ case SymbolKind::EnumMember:
+ return SymbolKind::Enum;
+ default:
+ return SymbolKind::String;
+ }
+}
+
+bool fromJSON(const json::Value &Params, WorkspaceSymbolCapabilities &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("symbolKind", R.symbolKind);
+}
+
+bool fromJSON(const json::Value &Params, WorkspaceClientCapabilities &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("symbol", R.symbol);
+}
+
+bool fromJSON(const json::Value &Params, TextDocumentClientCapabilities &R) {
+ json::ObjectMapper O(Params);
+ if (!O)
+ return false;
+ O.map("completion", R.completion);
+ return true;
+}
+
+bool fromJSON(const json::Value &Params, ClientCapabilities &R) {
+ json::ObjectMapper O(Params);
+ if (!O)
+ return false;
+ O.map("textDocument", R.textDocument);
+ O.map("workspace", R.workspace);
+ return true;
+}
+
+bool fromJSON(const json::Value &Params, InitializeParams &R) {
+ json::ObjectMapper O(Params);
+ if (!O)
+ return false;
+ // We deliberately don't fail if we can't parse individual fields.
+ // Failing to handle a slightly malformed initialize would be a disaster.
+ O.map("processId", R.processId);
+ O.map("rootUri", R.rootUri);
+ O.map("rootPath", R.rootPath);
+ O.map("capabilities", R.capabilities);
+ O.map("trace", R.trace);
+ O.map("initializationOptions", R.initializationOptions);
+ return true;
+}
+
+bool fromJSON(const json::Value &Params, DidOpenTextDocumentParams &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("textDocument", R.textDocument) &&
+ O.map("metadata", R.metadata);
+}
+
+bool fromJSON(const json::Value &Params, DidCloseTextDocumentParams &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("textDocument", R.textDocument);
+}
+
+bool fromJSON(const json::Value &Params, DidChangeTextDocumentParams &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("textDocument", R.textDocument) &&
+ O.map("contentChanges", R.contentChanges) &&
+ O.map("wantDiagnostics", R.wantDiagnostics);
+}
+
+bool fromJSON(const json::Value &E, FileChangeType &Out) {
+ if (auto T = E.getAsInteger()) {
+ if (*T < static_cast<int>(FileChangeType::Created) ||
+ *T > static_cast<int>(FileChangeType::Deleted))
+ return false;
+ Out = static_cast<FileChangeType>(*T);
+ return true;
+ }
+ return false;
+}
+
+bool fromJSON(const json::Value &Params, FileEvent &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("uri", R.uri) && O.map("type", R.type);
+}
+
+bool fromJSON(const json::Value &Params, DidChangeWatchedFilesParams &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("changes", R.changes);
+}
+
+bool fromJSON(const json::Value &Params, TextDocumentContentChangeEvent &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("range", R.range) && O.map("rangeLength", R.rangeLength) &&
+ O.map("text", R.text);
+}
+
+bool fromJSON(const json::Value &Params, FormattingOptions &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("tabSize", R.tabSize) &&
+ O.map("insertSpaces", R.insertSpaces);
+}
+
+json::Value toJSON(const FormattingOptions &P) {
+ return json::Object{
+ {"tabSize", P.tabSize},
+ {"insertSpaces", P.insertSpaces},
+ };
+}
+
+bool fromJSON(const json::Value &Params, DocumentRangeFormattingParams &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("textDocument", R.textDocument) &&
+ O.map("range", R.range) && O.map("options", R.options);
+}
+
+bool fromJSON(const json::Value &Params, DocumentOnTypeFormattingParams &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("textDocument", R.textDocument) &&
+ O.map("position", R.position) && O.map("ch", R.ch) &&
+ O.map("options", R.options);
+}
+
+bool fromJSON(const json::Value &Params, DocumentFormattingParams &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("textDocument", R.textDocument) &&
+ O.map("options", R.options);
+}
+
+bool fromJSON(const json::Value &Params, DocumentSymbolParams &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("textDocument", R.textDocument);
+}
+
+bool fromJSON(const json::Value &Params, Diagnostic &R) {
+ json::ObjectMapper O(Params);
+ if (!O || !O.map("range", R.range) || !O.map("message", R.message))
+ return false;
+ O.map("severity", R.severity);
+ return true;
+}
+
+bool fromJSON(const json::Value &Params, CodeActionContext &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("diagnostics", R.diagnostics);
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diagnostic &D) {
+ OS << D.range << " [";
+ switch (D.severity) {
+ case 1:
+ OS << "error";
+ break;
+ case 2:
+ OS << "warning";
+ break;
+ case 3:
+ OS << "note";
+ break;
+ case 4:
+ OS << "remark";
+ break;
+ default:
+ OS << "diagnostic";
+ break;
+ }
+ return OS << '(' << D.severity << "): " << D.message << "]";
+}
+
+bool fromJSON(const json::Value &Params, CodeActionParams &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("textDocument", R.textDocument) &&
+ O.map("range", R.range) && O.map("context", R.context);
+}
+
+bool fromJSON(const json::Value &Params, WorkspaceEdit &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("changes", R.changes);
+}
+
+const llvm::StringLiteral ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND =
+ "clangd.applyFix";
+bool fromJSON(const json::Value &Params, ExecuteCommandParams &R) {
+ json::ObjectMapper O(Params);
+ if (!O || !O.map("command", R.command))
+ return false;
+
+ auto Args = Params.getAsObject()->getArray("arguments");
+ if (R.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND) {
+ return Args && Args->size() == 1 &&
+ fromJSON(Args->front(), R.workspaceEdit);
+ }
+ return false; // Unrecognized command.
+}
+
+json::Value toJSON(const SymbolInformation &P) {
+ return json::Object{
+ {"name", P.name},
+ {"kind", static_cast<int>(P.kind)},
+ {"location", P.location},
+ {"containerName", P.containerName},
+ };
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
+ const SymbolInformation &SI) {
+ O << SI.containerName << "::" << SI.name << " - " << toJSON(SI);
+ return O;
+}
+
+bool fromJSON(const json::Value &Params, WorkspaceSymbolParams &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("query", R.query);
+}
+
+json::Value toJSON(const Command &C) {
+ auto Cmd = json::Object{{"title", C.title}, {"command", C.command}};
+ if (C.workspaceEdit)
+ Cmd["arguments"] = {*C.workspaceEdit};
+ return std::move(Cmd);
+}
+
+json::Value toJSON(const WorkspaceEdit &WE) {
+ if (!WE.changes)
+ return json::Object{};
+ json::Object FileChanges;
+ for (auto &Change : *WE.changes)
+ FileChanges[Change.first] = json::Array(Change.second);
+ return json::Object{{"changes", std::move(FileChanges)}};
+}
+
+json::Value toJSON(const ApplyWorkspaceEditParams &Params) {
+ return json::Object{{"edit", Params.edit}};
+}
+
+bool fromJSON(const json::Value &Params, TextDocumentPositionParams &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("textDocument", R.textDocument) &&
+ O.map("position", R.position);
+}
+
+static StringRef toTextKind(MarkupKind Kind) {
+ switch (Kind) {
+ case MarkupKind::PlainText:
+ return "plaintext";
+ case MarkupKind::Markdown:
+ return "markdown";
+ }
+ llvm_unreachable("Invalid MarkupKind");
+}
+
+json::Value toJSON(const MarkupContent &MC) {
+ if (MC.value.empty())
+ return nullptr;
+
+ return json::Object{
+ {"kind", toTextKind(MC.kind)},
+ {"value", MC.value},
+ };
+}
+
+json::Value toJSON(const Hover &H) {
+ json::Object Result{{"contents", toJSON(H.contents)}};
+
+ if (H.range.hasValue())
+ Result["range"] = toJSON(*H.range);
+
+ return std::move(Result);
+}
+
+json::Value toJSON(const CompletionItem &CI) {
+ assert(!CI.label.empty() && "completion item label is required");
+ json::Object Result{{"label", CI.label}};
+ if (CI.kind != CompletionItemKind::Missing)
+ Result["kind"] = static_cast<int>(CI.kind);
+ if (!CI.detail.empty())
+ Result["detail"] = CI.detail;
+ if (!CI.documentation.empty())
+ Result["documentation"] = CI.documentation;
+ if (!CI.sortText.empty())
+ Result["sortText"] = CI.sortText;
+ if (!CI.filterText.empty())
+ Result["filterText"] = CI.filterText;
+ if (!CI.insertText.empty())
+ Result["insertText"] = CI.insertText;
+ if (CI.insertTextFormat != InsertTextFormat::Missing)
+ Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);
+ if (CI.textEdit)
+ Result["textEdit"] = *CI.textEdit;
+ if (!CI.additionalTextEdits.empty())
+ Result["additionalTextEdits"] = json::Array(CI.additionalTextEdits);
+ return std::move(Result);
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CompletionItem &I) {
+ O << I.label << " - " << toJSON(I);
+ return O;
+}
+
+bool operator<(const CompletionItem &L, const CompletionItem &R) {
+ return (L.sortText.empty() ? L.label : L.sortText) <
+ (R.sortText.empty() ? R.label : R.sortText);
+}
+
+json::Value toJSON(const CompletionList &L) {
+ return json::Object{
+ {"isIncomplete", L.isIncomplete},
+ {"items", json::Array(L.items)},
+ };
+}
+
+json::Value toJSON(const ParameterInformation &PI) {
+ assert(!PI.label.empty() && "parameter information label is required");
+ json::Object Result{{"label", PI.label}};
+ if (!PI.documentation.empty())
+ Result["documentation"] = PI.documentation;
+ return std::move(Result);
+}
+
+json::Value toJSON(const SignatureInformation &SI) {
+ assert(!SI.label.empty() && "signature information label is required");
+ json::Object Result{
+ {"label", SI.label},
+ {"parameters", json::Array(SI.parameters)},
+ };
+ if (!SI.documentation.empty())
+ Result["documentation"] = SI.documentation;
+ return std::move(Result);
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
+ const SignatureInformation &I) {
+ O << I.label << " - " << toJSON(I);
+ return O;
+}
+
+json::Value toJSON(const SignatureHelp &SH) {
+ assert(SH.activeSignature >= 0 &&
+ "Unexpected negative value for number of active signatures.");
+ assert(SH.activeParameter >= 0 &&
+ "Unexpected negative value for active parameter index");
+ return json::Object{
+ {"activeSignature", SH.activeSignature},
+ {"activeParameter", SH.activeParameter},
+ {"signatures", json::Array(SH.signatures)},
+ };
+}
+
+bool fromJSON(const json::Value &Params, RenameParams &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("textDocument", R.textDocument) &&
+ O.map("position", R.position) && O.map("newName", R.newName);
+}
+
+json::Value toJSON(const DocumentHighlight &DH) {
+ return json::Object{
+ {"range", toJSON(DH.range)},
+ {"kind", static_cast<int>(DH.kind)},
+ };
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
+ const DocumentHighlight &V) {
+ O << V.range;
+ if (V.kind == DocumentHighlightKind::Read)
+ O << "(r)";
+ if (V.kind == DocumentHighlightKind::Write)
+ O << "(w)";
+ return O;
+}
+
+bool fromJSON(const json::Value &Params, DidChangeConfigurationParams &CCP) {
+ json::ObjectMapper O(Params);
+ return O && O.map("settings", CCP.settings);
+}
+
+bool fromJSON(const json::Value &Params,
+ ClangdConfigurationParamsChange &CCPC) {
+ json::ObjectMapper O(Params);
+ return O && O.map("compilationDatabasePath", CCPC.compilationDatabasePath);
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Protocol.h b/src/third_party/llvm-project/clang-tools-extra/clangd/Protocol.h
new file mode 100644
index 0000000..7f33976
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Protocol.h
@@ -0,0 +1,844 @@
+//===--- Protocol.h - Language Server Protocol Implementation ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains structs based on the LSP specification at
+// https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md
+//
+// This is not meant to be a complete implementation, new interfaces are added
+// when they're needed.
+//
+// Each struct has a toJSON and fromJSON function, that converts between
+// the struct and a JSON representation. (See JSON.h)
+//
+// Some structs also have operator<< serialization. This is for debugging and
+// tests, and is not generally machine-readable.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_PROTOCOL_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_PROTOCOL_H
+
+#include "URI.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/JSON.h"
+#include <bitset>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace clangd {
+
+enum class ErrorCode {
+ // Defined by JSON RPC.
+ ParseError = -32700,
+ InvalidRequest = -32600,
+ MethodNotFound = -32601,
+ InvalidParams = -32602,
+ InternalError = -32603,
+
+ ServerNotInitialized = -32002,
+ UnknownErrorCode = -32001,
+
+ // Defined by the protocol.
+ RequestCancelled = -32800,
+};
+
+struct URIForFile {
+ URIForFile() = default;
+ explicit URIForFile(std::string AbsPath);
+
+ /// Retrieves absolute path to the file.
+ llvm::StringRef file() const { return File; }
+
+ explicit operator bool() const { return !File.empty(); }
+ std::string uri() const { return URI::createFile(File).toString(); }
+
+ friend bool operator==(const URIForFile &LHS, const URIForFile &RHS) {
+ return LHS.File == RHS.File;
+ }
+
+ friend bool operator!=(const URIForFile &LHS, const URIForFile &RHS) {
+ return !(LHS == RHS);
+ }
+
+ friend bool operator<(const URIForFile &LHS, const URIForFile &RHS) {
+ return LHS.File < RHS.File;
+ }
+
+private:
+ std::string File;
+};
+
+/// Serialize/deserialize \p URIForFile to/from a string URI.
+llvm::json::Value toJSON(const URIForFile &U);
+bool fromJSON(const llvm::json::Value &, URIForFile &);
+
+struct TextDocumentIdentifier {
+ /// The text document's URI.
+ URIForFile uri;
+};
+llvm::json::Value toJSON(const TextDocumentIdentifier &);
+bool fromJSON(const llvm::json::Value &, TextDocumentIdentifier &);
+
+struct Position {
+ /// Line position in a document (zero-based).
+ int line = 0;
+
+ /// Character offset on a line in a document (zero-based).
+ /// WARNING: this is in UTF-16 codepoints, not bytes or characters!
+ /// Use the functions in SourceCode.h to construct/interpret Positions.
+ int character = 0;
+
+ friend bool operator==(const Position &LHS, const Position &RHS) {
+ return std::tie(LHS.line, LHS.character) ==
+ std::tie(RHS.line, RHS.character);
+ }
+ friend bool operator!=(const Position &LHS, const Position &RHS) {
+ return !(LHS == RHS);
+ }
+ friend bool operator<(const Position &LHS, const Position &RHS) {
+ return std::tie(LHS.line, LHS.character) <
+ std::tie(RHS.line, RHS.character);
+ }
+ friend bool operator<=(const Position &LHS, const Position &RHS) {
+ return std::tie(LHS.line, LHS.character) <=
+ std::tie(RHS.line, RHS.character);
+ }
+};
+bool fromJSON(const llvm::json::Value &, Position &);
+llvm::json::Value toJSON(const Position &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Position &);
+
+struct Range {
+ /// The range's start position.
+ Position start;
+
+ /// The range's end position.
+ Position end;
+
+ friend bool operator==(const Range &LHS, const Range &RHS) {
+ return std::tie(LHS.start, LHS.end) == std::tie(RHS.start, RHS.end);
+ }
+ friend bool operator!=(const Range &LHS, const Range &RHS) {
+ return !(LHS == RHS);
+ }
+ friend bool operator<(const Range &LHS, const Range &RHS) {
+ return std::tie(LHS.start, LHS.end) < std::tie(RHS.start, RHS.end);
+ }
+
+ bool contains(Position Pos) const { return start <= Pos && Pos < end; }
+};
+bool fromJSON(const llvm::json::Value &, Range &);
+llvm::json::Value toJSON(const Range &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Range &);
+
+struct Location {
+ /// The text document's URI.
+ URIForFile uri;
+ Range range;
+
+ friend bool operator==(const Location &LHS, const Location &RHS) {
+ return LHS.uri == RHS.uri && LHS.range == RHS.range;
+ }
+
+ friend bool operator!=(const Location &LHS, const Location &RHS) {
+ return !(LHS == RHS);
+ }
+
+ friend bool operator<(const Location &LHS, const Location &RHS) {
+ return std::tie(LHS.uri, LHS.range) < std::tie(RHS.uri, RHS.range);
+ }
+};
+llvm::json::Value toJSON(const Location &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Location &);
+
+struct Metadata {
+ std::vector<std::string> extraFlags;
+};
+bool fromJSON(const llvm::json::Value &, Metadata &);
+
+struct TextEdit {
+ /// The range of the text document to be manipulated. To insert
+ /// text into a document create a range where start === end.
+ Range range;
+
+ /// The string to be inserted. For delete operations use an
+ /// empty string.
+ std::string newText;
+};
+bool fromJSON(const llvm::json::Value &, TextEdit &);
+llvm::json::Value toJSON(const TextEdit &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const TextEdit &);
+
+struct TextDocumentItem {
+ /// The text document's URI.
+ URIForFile uri;
+
+ /// The text document's language identifier.
+ std::string languageId;
+
+ /// The version number of this document (it will strictly increase after each
+ int version = 0;
+
+ /// The content of the opened text document.
+ std::string text;
+};
+bool fromJSON(const llvm::json::Value &, TextDocumentItem &);
+
+enum class TraceLevel {
+ Off = 0,
+ Messages = 1,
+ Verbose = 2,
+};
+bool fromJSON(const llvm::json::Value &E, TraceLevel &Out);
+
+struct NoParams {};
+inline bool fromJSON(const llvm::json::Value &, NoParams &) { return true; }
+using ShutdownParams = NoParams;
+using ExitParams = NoParams;
+
+/// Defines how the host (editor) should sync document changes to the language
+/// server.
+enum class TextDocumentSyncKind {
+ /// Documents should not be synced at all.
+ None = 0,
+
+ /// Documents are synced by always sending the full content of the document.
+ Full = 1,
+
+ /// Documents are synced by sending the full content on open. After that
+ /// only incremental updates to the document are send.
+ Incremental = 2,
+};
+
+struct CompletionItemClientCapabilities {
+ /// Client supports snippets as insert text.
+ bool snippetSupport = false;
+ /// Client supports commit characters on a completion item.
+ bool commitCharacterSupport = false;
+ // Client supports the follow content formats for the documentation property.
+ // The order describes the preferred format of the client.
+ // NOTE: not used by clangd at the moment.
+ // std::vector<MarkupKind> documentationFormat;
+};
+bool fromJSON(const llvm::json::Value &, CompletionItemClientCapabilities &);
+
+struct CompletionClientCapabilities {
+ /// Whether completion supports dynamic registration.
+ bool dynamicRegistration = false;
+ /// The client supports the following `CompletionItem` specific capabilities.
+ CompletionItemClientCapabilities completionItem;
+ // NOTE: not used by clangd at the moment.
+ // llvm::Optional<CompletionItemKindCapabilities> completionItemKind;
+
+ /// The client supports to send additional context information for a
+ /// `textDocument/completion` request.
+ bool contextSupport = false;
+};
+bool fromJSON(const llvm::json::Value &, CompletionClientCapabilities &);
+
+/// A symbol kind.
+enum class SymbolKind {
+ File = 1,
+ Module = 2,
+ Namespace = 3,
+ Package = 4,
+ Class = 5,
+ Method = 6,
+ Property = 7,
+ Field = 8,
+ Constructor = 9,
+ Enum = 10,
+ Interface = 11,
+ Function = 12,
+ Variable = 13,
+ Constant = 14,
+ String = 15,
+ Number = 16,
+ Boolean = 17,
+ Array = 18,
+ Object = 19,
+ Key = 20,
+ Null = 21,
+ EnumMember = 22,
+ Struct = 23,
+ Event = 24,
+ Operator = 25,
+ TypeParameter = 26
+};
+
+constexpr auto SymbolKindMin = static_cast<size_t>(SymbolKind::File);
+constexpr auto SymbolKindMax = static_cast<size_t>(SymbolKind::TypeParameter);
+using SymbolKindBitset = std::bitset<SymbolKindMax + 1>;
+
+bool fromJSON(const llvm::json::Value &, SymbolKind &);
+
+struct SymbolKindCapabilities {
+ /// The SymbolKinds that the client supports. If not set, the client only
+ /// supports <= SymbolKind::Array and will not fall back to a valid default
+ /// value.
+ llvm::Optional<std::vector<SymbolKind>> valueSet;
+};
+bool fromJSON(const llvm::json::Value &, std::vector<SymbolKind> &);
+bool fromJSON(const llvm::json::Value &, SymbolKindCapabilities &);
+SymbolKind adjustKindToCapability(SymbolKind Kind,
+ SymbolKindBitset &supportedSymbolKinds);
+
+struct WorkspaceSymbolCapabilities {
+ /// Capabilities SymbolKind.
+ llvm::Optional<SymbolKindCapabilities> symbolKind;
+};
+bool fromJSON(const llvm::json::Value &, WorkspaceSymbolCapabilities &);
+
+// FIXME: most of the capabilities are missing from this struct. Only the ones
+// used by clangd are currently there.
+struct WorkspaceClientCapabilities {
+ /// Capabilities specific to `workspace/symbol`.
+ llvm::Optional<WorkspaceSymbolCapabilities> symbol;
+};
+bool fromJSON(const llvm::json::Value &, WorkspaceClientCapabilities &);
+
+// FIXME: most of the capabilities are missing from this struct. Only the ones
+// used by clangd are currently there.
+struct TextDocumentClientCapabilities {
+ /// Capabilities specific to the `textDocument/completion`
+ CompletionClientCapabilities completion;
+};
+bool fromJSON(const llvm::json::Value &, TextDocumentClientCapabilities &);
+
+struct ClientCapabilities {
+ // Workspace specific client capabilities.
+ llvm::Optional<WorkspaceClientCapabilities> workspace;
+
+ // Text document specific client capabilities.
+ TextDocumentClientCapabilities textDocument;
+};
+
+bool fromJSON(const llvm::json::Value &, ClientCapabilities &);
+
+/// Clangd extension to set clangd-specific "initializationOptions" in the
+/// "initialize" request and for the "workspace/didChangeConfiguration"
+/// notification since the data received is described as 'any' type in LSP.
+struct ClangdConfigurationParamsChange {
+ llvm::Optional<std::string> compilationDatabasePath;
+};
+bool fromJSON(const llvm::json::Value &, ClangdConfigurationParamsChange &);
+
+struct ClangdInitializationOptions : public ClangdConfigurationParamsChange {};
+
+struct InitializeParams {
+ /// The process Id of the parent process that started
+ /// the server. Is null if the process has not been started by another
+ /// process. If the parent process is not alive then the server should exit
+ /// (see exit notification) its process.
+ llvm::Optional<int> processId;
+
+ /// The rootPath of the workspace. Is null
+ /// if no folder is open.
+ ///
+ /// @deprecated in favour of rootUri.
+ llvm::Optional<std::string> rootPath;
+
+ /// The rootUri of the workspace. Is null if no
+ /// folder is open. If both `rootPath` and `rootUri` are set
+ /// `rootUri` wins.
+ llvm::Optional<URIForFile> rootUri;
+
+ // User provided initialization options.
+ // initializationOptions?: any;
+
+ /// The capabilities provided by the client (editor or tool)
+ ClientCapabilities capabilities;
+
+ /// The initial trace setting. If omitted trace is disabled ('off').
+ llvm::Optional<TraceLevel> trace;
+
+ // We use this predefined struct because it is easier to use
+ // than the protocol specified type of 'any'.
+ llvm::Optional<ClangdInitializationOptions> initializationOptions;
+};
+bool fromJSON(const llvm::json::Value &, InitializeParams &);
+
+struct DidOpenTextDocumentParams {
+ /// The document that was opened.
+ TextDocumentItem textDocument;
+
+ /// Extension storing per-file metadata, such as compilation flags.
+ llvm::Optional<Metadata> metadata;
+};
+bool fromJSON(const llvm::json::Value &, DidOpenTextDocumentParams &);
+
+struct DidCloseTextDocumentParams {
+ /// The document that was closed.
+ TextDocumentIdentifier textDocument;
+};
+bool fromJSON(const llvm::json::Value &, DidCloseTextDocumentParams &);
+
+struct TextDocumentContentChangeEvent {
+ /// The range of the document that changed.
+ llvm::Optional<Range> range;
+
+ /// The length of the range that got replaced.
+ llvm::Optional<int> rangeLength;
+
+ /// The new text of the range/document.
+ std::string text;
+};
+bool fromJSON(const llvm::json::Value &, TextDocumentContentChangeEvent &);
+
+struct DidChangeTextDocumentParams {
+ /// The document that did change. The version number points
+ /// to the version after all provided content changes have
+ /// been applied.
+ TextDocumentIdentifier textDocument;
+
+ /// The actual content changes.
+ std::vector<TextDocumentContentChangeEvent> contentChanges;
+
+ /// Forces diagnostics to be generated, or to not be generated, for this
+ /// version of the file. If not set, diagnostics are eventually consistent:
+ /// either they will be provided for this version or some subsequent one.
+ /// This is a clangd extension.
+ llvm::Optional<bool> wantDiagnostics;
+};
+bool fromJSON(const llvm::json::Value &, DidChangeTextDocumentParams &);
+
+enum class FileChangeType {
+ /// The file got created.
+ Created = 1,
+ /// The file got changed.
+ Changed = 2,
+ /// The file got deleted.
+ Deleted = 3
+};
+bool fromJSON(const llvm::json::Value &E, FileChangeType &Out);
+
+struct FileEvent {
+ /// The file's URI.
+ URIForFile uri;
+ /// The change type.
+ FileChangeType type = FileChangeType::Created;
+};
+bool fromJSON(const llvm::json::Value &, FileEvent &);
+
+struct DidChangeWatchedFilesParams {
+ /// The actual file events.
+ std::vector<FileEvent> changes;
+};
+bool fromJSON(const llvm::json::Value &, DidChangeWatchedFilesParams &);
+
+struct DidChangeConfigurationParams {
+ // We use this predefined struct because it is easier to use
+ // than the protocol specified type of 'any'.
+ ClangdConfigurationParamsChange settings;
+};
+bool fromJSON(const llvm::json::Value &, DidChangeConfigurationParams &);
+
+struct FormattingOptions {
+ /// Size of a tab in spaces.
+ int tabSize = 0;
+
+ /// Prefer spaces over tabs.
+ bool insertSpaces = false;
+};
+bool fromJSON(const llvm::json::Value &, FormattingOptions &);
+llvm::json::Value toJSON(const FormattingOptions &);
+
+struct DocumentRangeFormattingParams {
+ /// The document to format.
+ TextDocumentIdentifier textDocument;
+
+ /// The range to format
+ Range range;
+
+ /// The format options
+ FormattingOptions options;
+};
+bool fromJSON(const llvm::json::Value &, DocumentRangeFormattingParams &);
+
+struct DocumentOnTypeFormattingParams {
+ /// The document to format.
+ TextDocumentIdentifier textDocument;
+
+ /// The position at which this request was sent.
+ Position position;
+
+ /// The character that has been typed.
+ std::string ch;
+
+ /// The format options.
+ FormattingOptions options;
+};
+bool fromJSON(const llvm::json::Value &, DocumentOnTypeFormattingParams &);
+
+struct DocumentFormattingParams {
+ /// The document to format.
+ TextDocumentIdentifier textDocument;
+
+ /// The format options
+ FormattingOptions options;
+};
+bool fromJSON(const llvm::json::Value &, DocumentFormattingParams &);
+
+struct DocumentSymbolParams {
+ // The text document to find symbols in.
+ TextDocumentIdentifier textDocument;
+};
+bool fromJSON(const llvm::json::Value &, DocumentSymbolParams &);
+
+struct Diagnostic {
+ /// The range at which the message applies.
+ Range range;
+
+ /// The diagnostic's severity. Can be omitted. If omitted it is up to the
+ /// client to interpret diagnostics as error, warning, info or hint.
+ int severity = 0;
+
+ /// The diagnostic's code. Can be omitted.
+ /// Note: Not currently used by clangd
+ // std::string code;
+
+ /// A human-readable string describing the source of this
+ /// diagnostic, e.g. 'typescript' or 'super lint'.
+ /// Note: Not currently used by clangd
+ // std::string source;
+
+ /// The diagnostic's message.
+ std::string message;
+};
+
+/// A LSP-specific comparator used to find diagnostic in a container like
+/// std:map.
+/// We only use the required fields of Diagnostic to do the comparsion to avoid
+/// any regression issues from LSP clients (e.g. VScode), see
+/// https://git.io/vbr29
+struct LSPDiagnosticCompare {
+ bool operator()(const Diagnostic &LHS, const Diagnostic &RHS) const {
+ return std::tie(LHS.range, LHS.message) < std::tie(RHS.range, RHS.message);
+ }
+};
+bool fromJSON(const llvm::json::Value &, Diagnostic &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Diagnostic &);
+
+struct CodeActionContext {
+ /// An array of diagnostics.
+ std::vector<Diagnostic> diagnostics;
+};
+bool fromJSON(const llvm::json::Value &, CodeActionContext &);
+
+struct CodeActionParams {
+ /// The document in which the command was invoked.
+ TextDocumentIdentifier textDocument;
+
+ /// The range for which the command was invoked.
+ Range range;
+
+ /// Context carrying additional information.
+ CodeActionContext context;
+};
+bool fromJSON(const llvm::json::Value &, CodeActionParams &);
+
+struct WorkspaceEdit {
+ /// Holds changes to existing resources.
+ llvm::Optional<std::map<std::string, std::vector<TextEdit>>> changes;
+
+ /// Note: "documentChanges" is not currently used because currently there is
+ /// no support for versioned edits.
+};
+bool fromJSON(const llvm::json::Value &, WorkspaceEdit &);
+llvm::json::Value toJSON(const WorkspaceEdit &WE);
+
+/// Exact commands are not specified in the protocol so we define the
+/// ones supported by Clangd here. The protocol specifies the command arguments
+/// to be "any[]" but to make this safer and more manageable, each command we
+/// handle maps to a certain llvm::Optional of some struct to contain its
+/// arguments. Different commands could reuse the same llvm::Optional as
+/// arguments but a command that needs different arguments would simply add a
+/// new llvm::Optional and not use any other ones. In practice this means only
+/// one argument type will be parsed and set.
+struct ExecuteCommandParams {
+ // Command to apply fix-its. Uses WorkspaceEdit as argument.
+ const static llvm::StringLiteral CLANGD_APPLY_FIX_COMMAND;
+
+ /// The command identifier, e.g. CLANGD_APPLY_FIX_COMMAND
+ std::string command;
+
+ // Arguments
+ llvm::Optional<WorkspaceEdit> workspaceEdit;
+};
+bool fromJSON(const llvm::json::Value &, ExecuteCommandParams &);
+
+struct Command : public ExecuteCommandParams {
+ std::string title;
+};
+
+llvm::json::Value toJSON(const Command &C);
+
+/// Represents information about programming constructs like variables, classes,
+/// interfaces etc.
+struct SymbolInformation {
+ /// The name of this symbol.
+ std::string name;
+
+ /// The kind of this symbol.
+ SymbolKind kind;
+
+ /// The location of this symbol.
+ Location location;
+
+ /// The name of the symbol containing this symbol.
+ std::string containerName;
+};
+llvm::json::Value toJSON(const SymbolInformation &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const SymbolInformation &);
+
+/// The parameters of a Workspace Symbol Request.
+struct WorkspaceSymbolParams {
+ /// A non-empty query string
+ std::string query;
+};
+bool fromJSON(const llvm::json::Value &, WorkspaceSymbolParams &);
+
+struct ApplyWorkspaceEditParams {
+ WorkspaceEdit edit;
+};
+llvm::json::Value toJSON(const ApplyWorkspaceEditParams &);
+
+struct TextDocumentPositionParams {
+ /// The text document.
+ TextDocumentIdentifier textDocument;
+
+ /// The position inside the text document.
+ Position position;
+};
+bool fromJSON(const llvm::json::Value &, TextDocumentPositionParams &);
+
+enum class MarkupKind {
+ PlainText,
+ Markdown,
+};
+
+struct MarkupContent {
+ MarkupKind kind = MarkupKind::PlainText;
+ std::string value;
+};
+llvm::json::Value toJSON(const MarkupContent &MC);
+
+struct Hover {
+ /// The hover's content
+ MarkupContent contents;
+
+ /// An optional range is a range inside a text document
+ /// that is used to visualize a hover, e.g. by changing the background color.
+ llvm::Optional<Range> range;
+};
+llvm::json::Value toJSON(const Hover &H);
+
+/// The kind of a completion entry.
+enum class CompletionItemKind {
+ Missing = 0,
+ Text = 1,
+ Method = 2,
+ Function = 3,
+ Constructor = 4,
+ Field = 5,
+ Variable = 6,
+ Class = 7,
+ Interface = 8,
+ Module = 9,
+ Property = 10,
+ Unit = 11,
+ Value = 12,
+ Enum = 13,
+ Keyword = 14,
+ Snippet = 15,
+ Color = 16,
+ File = 17,
+ Reference = 18,
+};
+
+/// Defines whether the insert text in a completion item should be interpreted
+/// as plain text or a snippet.
+enum class InsertTextFormat {
+ Missing = 0,
+ /// The primary text to be inserted is treated as a plain string.
+ PlainText = 1,
+ /// The primary text to be inserted is treated as a snippet.
+ ///
+ /// A snippet can define tab stops and placeholders with `$1`, `$2`
+ /// and `${3:foo}`. `$0` defines the final tab stop, it defaults to the end
+ /// of the snippet. Placeholders with equal identifiers are linked, that is
+ /// typing in one will update others too.
+ ///
+ /// See also:
+ /// https//github.com/Microsoft/vscode/blob/master/src/vs/editor/contrib/snippet/common/snippet.md
+ Snippet = 2,
+};
+
+struct CompletionItem {
+ /// The label of this completion item. By default also the text that is
+ /// inserted when selecting this completion.
+ std::string label;
+
+ /// The kind of this completion item. Based of the kind an icon is chosen by
+ /// the editor.
+ CompletionItemKind kind = CompletionItemKind::Missing;
+
+ /// A human-readable string with additional information about this item, like
+ /// type or symbol information.
+ std::string detail;
+
+ /// A human-readable string that represents a doc-comment.
+ std::string documentation;
+
+ /// A string that should be used when comparing this item with other items.
+ /// When `falsy` the label is used.
+ std::string sortText;
+
+ /// A string that should be used when filtering a set of completion items.
+ /// When `falsy` the label is used.
+ std::string filterText;
+
+ /// A string that should be inserted to a document when selecting this
+ /// completion. When `falsy` the label is used.
+ std::string insertText;
+
+ /// The format of the insert text. The format applies to both the `insertText`
+ /// property and the `newText` property of a provided `textEdit`.
+ InsertTextFormat insertTextFormat = InsertTextFormat::Missing;
+
+ /// An edit which is applied to a document when selecting this completion.
+ /// When an edit is provided `insertText` is ignored.
+ ///
+ /// Note: The range of the edit must be a single line range and it must
+ /// contain the position at which completion has been requested.
+ llvm::Optional<TextEdit> textEdit;
+
+ /// An optional array of additional text edits that are applied when selecting
+ /// this completion. Edits must not overlap with the main edit nor with
+ /// themselves.
+ std::vector<TextEdit> additionalTextEdits;
+
+ // TODO(krasimir): The following optional fields defined by the language
+ // server protocol are unsupported:
+ //
+ // data?: any - A data entry field that is preserved on a completion item
+ // between a completion and a completion resolve request.
+};
+llvm::json::Value toJSON(const CompletionItem &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const CompletionItem &);
+
+bool operator<(const CompletionItem &, const CompletionItem &);
+
+/// Represents a collection of completion items to be presented in the editor.
+struct CompletionList {
+ /// The list is not complete. Further typing should result in recomputing the
+ /// list.
+ bool isIncomplete = false;
+
+ /// The completion items.
+ std::vector<CompletionItem> items;
+};
+llvm::json::Value toJSON(const CompletionList &);
+
+/// A single parameter of a particular signature.
+struct ParameterInformation {
+
+ /// The label of this parameter. Mandatory.
+ std::string label;
+
+ /// The documentation of this parameter. Optional.
+ std::string documentation;
+};
+llvm::json::Value toJSON(const ParameterInformation &);
+
+/// Represents the signature of something callable.
+struct SignatureInformation {
+
+ /// The label of this signature. Mandatory.
+ std::string label;
+
+ /// The documentation of this signature. Optional.
+ std::string documentation;
+
+ /// The parameters of this signature.
+ std::vector<ParameterInformation> parameters;
+};
+llvm::json::Value toJSON(const SignatureInformation &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &,
+ const SignatureInformation &);
+
+/// Represents the signature of a callable.
+struct SignatureHelp {
+
+ /// The resulting signatures.
+ std::vector<SignatureInformation> signatures;
+
+ /// The active signature.
+ int activeSignature = 0;
+
+ /// The active parameter of the active signature.
+ int activeParameter = 0;
+};
+llvm::json::Value toJSON(const SignatureHelp &);
+
+struct RenameParams {
+ /// The document that was opened.
+ TextDocumentIdentifier textDocument;
+
+ /// The position at which this request was sent.
+ Position position;
+
+ /// The new name of the symbol.
+ std::string newName;
+};
+bool fromJSON(const llvm::json::Value &, RenameParams &);
+
+enum class DocumentHighlightKind { Text = 1, Read = 2, Write = 3 };
+
+/// A document highlight is a range inside a text document which deserves
+/// special attention. Usually a document highlight is visualized by changing
+/// the background color of its range.
+
+struct DocumentHighlight {
+ /// The range this highlight applies to.
+ Range range;
+
+ /// The highlight kind, default is DocumentHighlightKind.Text.
+ DocumentHighlightKind kind = DocumentHighlightKind::Text;
+
+ friend bool operator<(const DocumentHighlight &LHS,
+ const DocumentHighlight &RHS) {
+ int LHSKind = static_cast<int>(LHS.kind);
+ int RHSKind = static_cast<int>(RHS.kind);
+ return std::tie(LHS.range, LHSKind) < std::tie(RHS.range, RHSKind);
+ }
+
+ friend bool operator==(const DocumentHighlight &LHS,
+ const DocumentHighlight &RHS) {
+ return LHS.kind == RHS.kind && LHS.range == RHS.range;
+ }
+};
+llvm::json::Value toJSON(const DocumentHighlight &DH);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &);
+
+} // namespace clangd
+} // namespace clang
+
+namespace llvm {
+template <> struct format_provider<clang::clangd::Position> {
+ static void format(const clang::clangd::Position &Pos, raw_ostream &OS,
+ StringRef Style) {
+ assert(Style.empty() && "style modifiers for this type are not supported");
+ OS << Pos;
+ }
+};
+} // namespace llvm
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/ProtocolHandlers.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/ProtocolHandlers.cpp
new file mode 100644
index 0000000..deb5b9d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/ProtocolHandlers.cpp
@@ -0,0 +1,78 @@
+//===--- ProtocolHandlers.cpp - LSP callbacks -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProtocolHandlers.h"
+#include "ClangdLSPServer.h"
+#include "ClangdServer.h"
+#include "DraftStore.h"
+#include "Trace.h"
+
+using namespace clang;
+using namespace clang::clangd;
+using namespace llvm;
+
+namespace {
+
+// Helper for attaching ProtocolCallbacks methods to a JSONRPCDispatcher.
+// Invoke like: Registerer("foo", &ProtocolCallbacks::onFoo)
+// onFoo should be: void onFoo(Ctx &C, FooParams &Params)
+// FooParams should have a fromJSON function.
+struct HandlerRegisterer {
+ template <typename Param>
+ void operator()(StringRef Method, void (ProtocolCallbacks::*Handler)(Param)) {
+ // Capture pointers by value, as the lambda will outlive this object.
+ auto *Callbacks = this->Callbacks;
+ Dispatcher.registerHandler(Method, [=](const json::Value &RawParams) {
+ typename std::remove_reference<Param>::type P;
+ if (fromJSON(RawParams, P)) {
+ (Callbacks->*Handler)(P);
+ } else {
+ elog("Failed to decode {0} request.", Method);
+ }
+ });
+ }
+
+ JSONRPCDispatcher &Dispatcher;
+ ProtocolCallbacks *Callbacks;
+};
+
+} // namespace
+
+void clangd::registerCallbackHandlers(JSONRPCDispatcher &Dispatcher,
+ ProtocolCallbacks &Callbacks) {
+ HandlerRegisterer Register{Dispatcher, &Callbacks};
+
+ Register("initialize", &ProtocolCallbacks::onInitialize);
+ Register("shutdown", &ProtocolCallbacks::onShutdown);
+ Register("exit", &ProtocolCallbacks::onExit);
+ Register("textDocument/didOpen", &ProtocolCallbacks::onDocumentDidOpen);
+ Register("textDocument/didClose", &ProtocolCallbacks::onDocumentDidClose);
+ Register("textDocument/didChange", &ProtocolCallbacks::onDocumentDidChange);
+ Register("textDocument/rangeFormatting",
+ &ProtocolCallbacks::onDocumentRangeFormatting);
+ Register("textDocument/onTypeFormatting",
+ &ProtocolCallbacks::onDocumentOnTypeFormatting);
+ Register("textDocument/formatting", &ProtocolCallbacks::onDocumentFormatting);
+ Register("textDocument/codeAction", &ProtocolCallbacks::onCodeAction);
+ Register("textDocument/completion", &ProtocolCallbacks::onCompletion);
+ Register("textDocument/signatureHelp", &ProtocolCallbacks::onSignatureHelp);
+ Register("textDocument/definition", &ProtocolCallbacks::onGoToDefinition);
+ Register("textDocument/switchSourceHeader",
+ &ProtocolCallbacks::onSwitchSourceHeader);
+ Register("textDocument/rename", &ProtocolCallbacks::onRename);
+ Register("textDocument/hover", &ProtocolCallbacks::onHover);
+ Register("textDocument/documentSymbol", &ProtocolCallbacks::onDocumentSymbol);
+ Register("workspace/didChangeWatchedFiles", &ProtocolCallbacks::onFileEvent);
+ Register("workspace/executeCommand", &ProtocolCallbacks::onCommand);
+ Register("textDocument/documentHighlight",
+ &ProtocolCallbacks::onDocumentHighlight);
+ Register("workspace/didChangeConfiguration",
+ &ProtocolCallbacks::onChangeConfiguration);
+ Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/ProtocolHandlers.h b/src/third_party/llvm-project/clang-tools-extra/clangd/ProtocolHandlers.h
new file mode 100644
index 0000000..63fd99d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/ProtocolHandlers.h
@@ -0,0 +1,66 @@
+//===--- ProtocolHandlers.h - LSP callbacks ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// ProtocolHandlers translates incoming JSON requests from JSONRPCDispatcher
+// into method calls on ClangLSPServer.
+//
+// Currently it parses requests into objects, but the ClangLSPServer is
+// responsible for producing JSON responses. We should move that here, too.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_PROTOCOLHANDLERS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_PROTOCOLHANDLERS_H
+
+#include "JSONRPCDispatcher.h"
+#include "Protocol.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace clangd {
+
+// The interface implemented by ClangLSPServer to handle incoming requests.
+class ProtocolCallbacks {
+public:
+ virtual ~ProtocolCallbacks() = default;
+
+ virtual void onInitialize(InitializeParams &Params) = 0;
+ virtual void onShutdown(ShutdownParams &Params) = 0;
+ virtual void onExit(ExitParams &Params) = 0;
+ virtual void onDocumentDidOpen(DidOpenTextDocumentParams &Params) = 0;
+ virtual void onDocumentDidChange(DidChangeTextDocumentParams &Params) = 0;
+ virtual void onDocumentDidClose(DidCloseTextDocumentParams &Params) = 0;
+ virtual void onDocumentFormatting(DocumentFormattingParams &Params) = 0;
+ virtual void onDocumentSymbol(DocumentSymbolParams &Params) = 0;
+ virtual void
+ onDocumentOnTypeFormatting(DocumentOnTypeFormattingParams &Params) = 0;
+ virtual void
+ onDocumentRangeFormatting(DocumentRangeFormattingParams &Params) = 0;
+ virtual void onCodeAction(CodeActionParams &Params) = 0;
+ virtual void onCompletion(TextDocumentPositionParams &Params) = 0;
+ virtual void onSignatureHelp(TextDocumentPositionParams &Params) = 0;
+ virtual void onGoToDefinition(TextDocumentPositionParams &Params) = 0;
+ virtual void onSwitchSourceHeader(TextDocumentIdentifier &Params) = 0;
+ virtual void onFileEvent(DidChangeWatchedFilesParams &Params) = 0;
+ virtual void onCommand(ExecuteCommandParams &Params) = 0;
+ virtual void onWorkspaceSymbol(WorkspaceSymbolParams &Params) = 0;
+ virtual void onRename(RenameParams &Parames) = 0;
+ virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0;
+ virtual void onHover(TextDocumentPositionParams &Params) = 0;
+ virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0;
+};
+
+void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher,
+ ProtocolCallbacks &Callbacks);
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Quality.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/Quality.cpp
new file mode 100644
index 0000000..61195b5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Quality.cpp
@@ -0,0 +1,398 @@
+//===--- Quality.cpp --------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#include "Quality.h"
+#include "FileDistance.h"
+#include "URI.h"
+#include "index/Index.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cmath>
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+static bool isReserved(StringRef Name) {
+ // FIXME: Should we exclude _Bool and others recognized by the standard?
+ return Name.size() >= 2 && Name[0] == '_' &&
+ (isUppercase(Name[1]) || Name[1] == '_');
+}
+
+static bool hasDeclInMainFile(const Decl &D) {
+ auto &SourceMgr = D.getASTContext().getSourceManager();
+ for (auto *Redecl : D.redecls()) {
+ auto Loc = SourceMgr.getSpellingLoc(Redecl->getLocation());
+ if (SourceMgr.isWrittenInMainFile(Loc))
+ return true;
+ }
+ return false;
+}
+
+static bool hasUsingDeclInMainFile(const CodeCompletionResult &R) {
+ const auto &Context = R.Declaration->getASTContext();
+ const auto &SourceMgr = Context.getSourceManager();
+ if (R.ShadowDecl) {
+ const auto Loc = SourceMgr.getExpansionLoc(R.ShadowDecl->getLocation());
+ if (SourceMgr.isWrittenInMainFile(Loc))
+ return true;
+ }
+ return false;
+}
+
+static SymbolQualitySignals::SymbolCategory categorize(const NamedDecl &ND) {
+ class Switch
+ : public ConstDeclVisitor<Switch, SymbolQualitySignals::SymbolCategory> {
+ public:
+#define MAP(DeclType, Category) \
+ SymbolQualitySignals::SymbolCategory Visit##DeclType(const DeclType *) { \
+ return SymbolQualitySignals::Category; \
+ }
+ MAP(NamespaceDecl, Namespace);
+ MAP(NamespaceAliasDecl, Namespace);
+ MAP(TypeDecl, Type);
+ MAP(TypeAliasTemplateDecl, Type);
+ MAP(ClassTemplateDecl, Type);
+ MAP(CXXConstructorDecl, Constructor);
+ MAP(ValueDecl, Variable);
+ MAP(VarTemplateDecl, Variable);
+ MAP(FunctionDecl, Function);
+ MAP(FunctionTemplateDecl, Function);
+ MAP(Decl, Unknown);
+#undef MAP
+ };
+ return Switch().Visit(&ND);
+}
+
+static SymbolQualitySignals::SymbolCategory
+categorize(const CodeCompletionResult &R) {
+ if (R.Declaration)
+ return categorize(*R.Declaration);
+ if (R.Kind == CodeCompletionResult::RK_Macro)
+ return SymbolQualitySignals::Macro;
+ // Everything else is a keyword or a pattern. Patterns are mostly keywords
+ // too, except a few which we recognize by cursor kind.
+ switch (R.CursorKind) {
+ case CXCursor_CXXMethod:
+ return SymbolQualitySignals::Function;
+ case CXCursor_ModuleImportDecl:
+ return SymbolQualitySignals::Namespace;
+ case CXCursor_MacroDefinition:
+ return SymbolQualitySignals::Macro;
+ case CXCursor_TypeRef:
+ return SymbolQualitySignals::Type;
+ case CXCursor_MemberRef:
+ return SymbolQualitySignals::Variable;
+ case CXCursor_Constructor:
+ return SymbolQualitySignals::Constructor;
+ default:
+ return SymbolQualitySignals::Keyword;
+ }
+}
+
+static SymbolQualitySignals::SymbolCategory
+categorize(const index::SymbolInfo &D) {
+ switch (D.Kind) {
+ case index::SymbolKind::Namespace:
+ case index::SymbolKind::NamespaceAlias:
+ return SymbolQualitySignals::Namespace;
+ case index::SymbolKind::Macro:
+ return SymbolQualitySignals::Macro;
+ case index::SymbolKind::Enum:
+ case index::SymbolKind::Struct:
+ case index::SymbolKind::Class:
+ case index::SymbolKind::Protocol:
+ case index::SymbolKind::Extension:
+ case index::SymbolKind::Union:
+ case index::SymbolKind::TypeAlias:
+ return SymbolQualitySignals::Type;
+ case index::SymbolKind::Function:
+ case index::SymbolKind::ClassMethod:
+ case index::SymbolKind::InstanceMethod:
+ case index::SymbolKind::StaticMethod:
+ case index::SymbolKind::InstanceProperty:
+ case index::SymbolKind::ClassProperty:
+ case index::SymbolKind::StaticProperty:
+ case index::SymbolKind::Destructor:
+ case index::SymbolKind::ConversionFunction:
+ return SymbolQualitySignals::Function;
+ case index::SymbolKind::Constructor:
+ return SymbolQualitySignals::Constructor;
+ case index::SymbolKind::Variable:
+ case index::SymbolKind::Field:
+ case index::SymbolKind::EnumConstant:
+ case index::SymbolKind::Parameter:
+ return SymbolQualitySignals::Variable;
+ case index::SymbolKind::Using:
+ case index::SymbolKind::Module:
+ case index::SymbolKind::Unknown:
+ return SymbolQualitySignals::Unknown;
+ }
+ llvm_unreachable("Unknown index::SymbolKind");
+}
+
+static bool isInstanceMember(const NamedDecl *ND) {
+ if (!ND)
+ return false;
+ if (const auto *TP = dyn_cast<FunctionTemplateDecl>(ND))
+ ND = TP->TemplateDecl::getTemplatedDecl();
+ if (const auto *CM = dyn_cast<CXXMethodDecl>(ND))
+ return !CM->isStatic();
+ return isa<FieldDecl>(ND); // Note that static fields are VarDecl.
+}
+
+static bool isInstanceMember(const index::SymbolInfo &D) {
+ switch (D.Kind) {
+ case index::SymbolKind::InstanceMethod:
+ case index::SymbolKind::InstanceProperty:
+ case index::SymbolKind::Field:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void SymbolQualitySignals::merge(const CodeCompletionResult &SemaCCResult) {
+ if (SemaCCResult.Availability == CXAvailability_Deprecated)
+ Deprecated = true;
+
+ Category = categorize(SemaCCResult);
+
+ if (SemaCCResult.Declaration) {
+ if (auto *ID = SemaCCResult.Declaration->getIdentifier())
+ ReservedName = ReservedName || isReserved(ID->getName());
+ } else if (SemaCCResult.Kind == CodeCompletionResult::RK_Macro)
+ ReservedName = ReservedName || isReserved(SemaCCResult.Macro->getName());
+}
+
+void SymbolQualitySignals::merge(const Symbol &IndexResult) {
+ References = std::max(IndexResult.References, References);
+ Category = categorize(IndexResult.SymInfo);
+ ReservedName = ReservedName || isReserved(IndexResult.Name);
+}
+
+float SymbolQualitySignals::evaluate() const {
+ float Score = 1;
+
+ // This avoids a sharp gradient for tail symbols, and also neatly avoids the
+ // question of whether 0 references means a bad symbol or missing data.
+ if (References >= 10) {
+ // Use a sigmoid style boosting function, which flats out nicely for large
+ // numbers (e.g. 2.58 for 1M refererences).
+ // The following boosting function is equivalent to:
+ // m = 0.06
+ // f = 12.0
+ // boost = f * sigmoid(m * std::log(References)) - 0.5 * f + 0.59
+ // Sample data points: (10, 1.00), (100, 1.41), (1000, 1.82),
+ // (10K, 2.21), (100K, 2.58), (1M, 2.94)
+ float S = std::pow(References, -0.06);
+ Score *= 6.0 * (1 - S) / (1 + S) + 0.59;
+ }
+
+ if (Deprecated)
+ Score *= 0.1f;
+ if (ReservedName)
+ Score *= 0.1f;
+
+ switch (Category) {
+ case Keyword: // Often relevant, but misses most signals.
+ Score *= 4; // FIXME: important keywords should have specific boosts.
+ break;
+ case Type:
+ case Function:
+ case Variable:
+ Score *= 1.1f;
+ break;
+ case Namespace:
+ Score *= 0.8f;
+ break;
+ case Macro:
+ Score *= 0.2f;
+ break;
+ case Unknown:
+ case Constructor: // No boost constructors so they are after class types.
+ break;
+ }
+
+ return Score;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolQualitySignals &S) {
+ OS << formatv("=== Symbol quality: {0}\n", S.evaluate());
+ OS << formatv("\tReferences: {0}\n", S.References);
+ OS << formatv("\tDeprecated: {0}\n", S.Deprecated);
+ OS << formatv("\tReserved name: {0}\n", S.ReservedName);
+ OS << formatv("\tCategory: {0}\n", static_cast<int>(S.Category));
+ return OS;
+}
+
+static SymbolRelevanceSignals::AccessibleScope
+computeScope(const NamedDecl *D) {
+ // Injected "Foo" within the class "Foo" has file scope, not class scope.
+ const DeclContext *DC = D->getDeclContext();
+ if (auto *R = dyn_cast_or_null<RecordDecl>(D))
+ if (R->isInjectedClassName())
+ DC = DC->getParent();
+ // Class constructor should have the same scope as the class.
+ if (isa<CXXConstructorDecl>(D))
+ DC = DC->getParent();
+ bool InClass = false;
+ for (; !DC->isFileContext(); DC = DC->getParent()) {
+ if (DC->isFunctionOrMethod())
+ return SymbolRelevanceSignals::FunctionScope;
+ InClass = InClass || DC->isRecord();
+ }
+ if (InClass)
+ return SymbolRelevanceSignals::ClassScope;
+ // This threshold could be tweaked, e.g. to treat module-visible as global.
+ if (D->getLinkageInternal() < ExternalLinkage)
+ return SymbolRelevanceSignals::FileScope;
+ return SymbolRelevanceSignals::GlobalScope;
+}
+
+void SymbolRelevanceSignals::merge(const Symbol &IndexResult) {
+ // FIXME: Index results always assumed to be at global scope. If Scope becomes
+ // relevant to non-completion requests, we should recognize class members etc.
+
+ SymbolURI = IndexResult.CanonicalDeclaration.FileURI;
+ IsInstanceMember |= isInstanceMember(IndexResult.SymInfo);
+}
+
+void SymbolRelevanceSignals::merge(const CodeCompletionResult &SemaCCResult) {
+ if (SemaCCResult.Availability == CXAvailability_NotAvailable ||
+ SemaCCResult.Availability == CXAvailability_NotAccessible)
+ Forbidden = true;
+
+ if (SemaCCResult.Declaration) {
+ // We boost things that have decls in the main file. We give a fixed score
+ // for all other declarations in sema as they are already included in the
+ // translation unit.
+ float DeclProximity = (hasDeclInMainFile(*SemaCCResult.Declaration) ||
+ hasUsingDeclInMainFile(SemaCCResult))
+ ? 1.0
+ : 0.6;
+ SemaProximityScore = std::max(DeclProximity, SemaProximityScore);
+ IsInstanceMember |= isInstanceMember(SemaCCResult.Declaration);
+ }
+
+ // Declarations are scoped, others (like macros) are assumed global.
+ if (SemaCCResult.Declaration)
+ Scope = std::min(Scope, computeScope(SemaCCResult.Declaration));
+}
+
+static std::pair<float, unsigned> proximityScore(llvm::StringRef SymbolURI,
+ URIDistance *D) {
+ if (!D || SymbolURI.empty())
+ return {0.f, 0u};
+ unsigned Distance = D->distance(SymbolURI);
+ // Assume approximately default options are used for sensible scoring.
+ return {std::exp(Distance * -0.4f / FileDistanceOptions().UpCost), Distance};
+}
+
+float SymbolRelevanceSignals::evaluate() const {
+ float Score = 1;
+
+ if (Forbidden)
+ return 0;
+
+ Score *= NameMatch;
+
+ // Proximity scores are [0,1] and we translate them into a multiplier in the
+ // range from 1 to 3.
+ Score *= 1 + 2 * std::max(proximityScore(SymbolURI, FileProximityMatch).first,
+ SemaProximityScore);
+
+ // Symbols like local variables may only be referenced within their scope.
+ // Conversely if we're in that scope, it's likely we'll reference them.
+ if (Query == CodeComplete) {
+ // The narrower the scope where a symbol is visible, the more likely it is
+ // to be relevant when it is available.
+ switch (Scope) {
+ case GlobalScope:
+ break;
+ case FileScope:
+ Score *= 1.5;
+ break;
+ case ClassScope:
+ Score *= 2;
+ break;
+ case FunctionScope:
+ Score *= 4;
+ break;
+ }
+ }
+
+ // Penalize non-instance members when they are accessed via a class instance.
+ if (!IsInstanceMember &&
+ (Context == CodeCompletionContext::CCC_DotMemberAccess ||
+ Context == CodeCompletionContext::CCC_ArrowMemberAccess)) {
+ Score *= 0.5;
+ }
+
+ return Score;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolRelevanceSignals &S) {
+ OS << formatv("=== Symbol relevance: {0}\n", S.evaluate());
+ OS << formatv("\tName match: {0}\n", S.NameMatch);
+ OS << formatv("\tForbidden: {0}\n", S.Forbidden);
+ OS << formatv("\tIsInstanceMember: {0}\n", S.IsInstanceMember);
+ OS << formatv("\tContext: {0}\n", getCompletionKindString(S.Context));
+ OS << formatv("\tSymbol URI: {0}\n", S.SymbolURI);
+ if (S.FileProximityMatch) {
+ auto Score = proximityScore(S.SymbolURI, S.FileProximityMatch);
+ OS << formatv("\tIndex proximity: {0} (distance={1})\n", Score.first,
+ Score.second);
+ }
+ OS << formatv("\tSema proximity: {0}\n", S.SemaProximityScore);
+ OS << formatv("\tQuery type: {0}\n", static_cast<int>(S.Query));
+ OS << formatv("\tScope: {0}\n", static_cast<int>(S.Scope));
+ return OS;
+}
+
+float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance) {
+ return SymbolQuality * SymbolRelevance;
+}
+
+// Produces an integer that sorts in the same order as F.
+// That is: a < b <==> encodeFloat(a) < encodeFloat(b).
+static uint32_t encodeFloat(float F) {
+ static_assert(std::numeric_limits<float>::is_iec559, "");
+ constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1);
+
+ // Get the bits of the float. Endianness is the same as for integers.
+ uint32_t U = FloatToBits(F);
+ // IEEE 754 floats compare like sign-magnitude integers.
+ if (U & TopBit) // Negative float.
+ return 0 - U; // Map onto the low half of integers, order reversed.
+ return U + TopBit; // Positive floats map onto the high half of integers.
+}
+
+std::string sortText(float Score, llvm::StringRef Name) {
+ // We convert -Score to an integer, and hex-encode for readability.
+ // Example: [0.5, "foo"] -> "41000000foo"
+ std::string S;
+ llvm::raw_string_ostream OS(S);
+ write_hex(OS, encodeFloat(-Score), llvm::HexPrintStyle::Lower,
+ /*Width=*/2 * sizeof(Score));
+ OS << Name;
+ OS.flush();
+ return S;
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Quality.h b/src/third_party/llvm-project/clang-tools-extra/clangd/Quality.h
new file mode 100644
index 0000000..0aed496
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Quality.h
@@ -0,0 +1,167 @@
+//===--- Quality.h - Ranking alternatives for ambiguous queries -*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+///
+/// Some operations such as code completion produce a set of candidates.
+/// Usually the user can choose between them, but we should put the best options
+/// at the top (they're easier to select, and more likely to be seen).
+///
+/// This file defines building blocks for ranking candidates.
+/// It's used by the features directly and also in the implementation of
+/// indexes, as indexes also need to heuristically limit their results.
+///
+/// The facilities here are:
+/// - retrieving scoring signals from e.g. indexes, AST, CodeCompletionString
+/// These are structured in a way that they can be debugged, and are fairly
+/// consistent regardless of the source.
+/// - compute scores from scoring signals. These are suitable for sorting.
+/// - sorting utilities like the TopN container.
+/// These could be split up further to isolate dependencies if we care.
+///
+//===---------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_QUALITY_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_QUALITY_H
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <algorithm>
+#include <functional>
+#include <vector>
+namespace llvm {
+class raw_ostream;
+}
+namespace clang {
+class CodeCompletionResult;
+namespace clangd {
+struct Symbol;
+class URIDistance;
+
+// Signals structs are designed to be aggregated from 0 or more sources.
+// A default instance has neutral signals, and sources are merged into it.
+// They can be dumped for debugging, and evaluate()d into a score.
+
+/// Attributes of a symbol that affect how much we like it.
+struct SymbolQualitySignals {
+ bool Deprecated = false;
+ bool ReservedName = false; // __foo, _Foo are usually implementation details.
+ // FIXME: make these findable once user types _.
+ unsigned References = 0;
+
+ enum SymbolCategory {
+ Unknown = 0,
+ Variable,
+ Macro,
+ Type,
+ Function,
+ Constructor,
+ Namespace,
+ Keyword,
+ } Category = Unknown;
+
+ void merge(const CodeCompletionResult &SemaCCResult);
+ void merge(const Symbol &IndexResult);
+
+ // Condense these signals down to a single number, higher is better.
+ float evaluate() const;
+};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &,
+ const SymbolQualitySignals &);
+
+/// Attributes of a symbol-query pair that affect how much we like it.
+struct SymbolRelevanceSignals {
+ /// 0-1+ fuzzy-match score for unqualified name. Must be explicitly assigned.
+ float NameMatch = 1;
+ bool Forbidden = false; // Unavailable (e.g const) or inaccessible (private).
+
+ URIDistance *FileProximityMatch = nullptr;
+ /// This is used to calculate proximity between the index symbol and the
+ /// query.
+ llvm::StringRef SymbolURI;
+ /// Proximity between best declaration and the query. [0-1], 1 is closest.
+ /// FIXME: unify with index proximity score - signals should be
+ /// source-independent.
+ float SemaProximityScore = 0;
+
+ // An approximate measure of where we expect the symbol to be used.
+ enum AccessibleScope {
+ FunctionScope,
+ ClassScope,
+ FileScope,
+ GlobalScope,
+ } Scope = GlobalScope;
+
+ enum QueryType {
+ CodeComplete,
+ Generic,
+ } Query = Generic;
+
+ CodeCompletionContext::Kind Context = CodeCompletionContext::CCC_Other;
+
+ // Whether symbol is an instance member of a class.
+ bool IsInstanceMember = false;
+
+ void merge(const CodeCompletionResult &SemaResult);
+ void merge(const Symbol &IndexResult);
+
+ // Condense these signals down to a single number, higher is better.
+ float evaluate() const;
+};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &,
+ const SymbolRelevanceSignals &);
+
+/// Combine symbol quality and relevance into a single score.
+float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance);
+
+/// TopN<T> is a lossy container that preserves only the "best" N elements.
+template <typename T, typename Compare = std::greater<T>> class TopN {
+public:
+ using value_type = T;
+ TopN(size_t N, Compare Greater = Compare())
+ : N(N), Greater(std::move(Greater)) {}
+
+ // Adds a candidate to the set.
+ // Returns true if a candidate was dropped to get back under N.
+ bool push(value_type &&V) {
+ bool Dropped = false;
+ if (Heap.size() >= N) {
+ Dropped = true;
+ if (N > 0 && Greater(V, Heap.front())) {
+ std::pop_heap(Heap.begin(), Heap.end(), Greater);
+ Heap.back() = std::move(V);
+ std::push_heap(Heap.begin(), Heap.end(), Greater);
+ }
+ } else {
+ Heap.push_back(std::move(V));
+ std::push_heap(Heap.begin(), Heap.end(), Greater);
+ }
+ assert(Heap.size() <= N);
+ assert(std::is_heap(Heap.begin(), Heap.end(), Greater));
+ return Dropped;
+ }
+
+ // Returns candidates from best to worst.
+ std::vector<value_type> items() && {
+ std::sort_heap(Heap.begin(), Heap.end(), Greater);
+ assert(Heap.size() <= N);
+ return std::move(Heap);
+ }
+
+private:
+ const size_t N;
+ std::vector<value_type> Heap; // Min-heap, comparator is Greater.
+ Compare Greater;
+};
+
+/// Returns a string that sorts in the same order as (-Score, Tiebreak), for
+/// LSP. (The highest score compares smallest so it sorts at the top).
+std::string sortText(float Score, llvm::StringRef Tiebreak = "");
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/SourceCode.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/SourceCode.cpp
new file mode 100644
index 0000000..d302518
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/SourceCode.cpp
@@ -0,0 +1,203 @@
+//===--- SourceCode.h - Manipulating source code as strings -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "SourceCode.h"
+
+#include "Logger.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Path.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+// Here be dragons. LSP positions use columns measured in *UTF-16 code units*!
+// Clangd uses UTF-8 and byte-offsets internally, so conversion is nontrivial.
+
+// Iterates over unicode codepoints in the (UTF-8) string. For each,
+// invokes CB(UTF-8 length, UTF-16 length), and breaks if it returns true.
+// Returns true if CB returned true, false if we hit the end of string.
+template <typename Callback>
+static bool iterateCodepoints(StringRef U8, const Callback &CB) {
+ for (size_t I = 0; I < U8.size();) {
+ unsigned char C = static_cast<unsigned char>(U8[I]);
+ if (LLVM_LIKELY(!(C & 0x80))) { // ASCII character.
+ if (CB(1, 1))
+ return true;
+ ++I;
+ continue;
+ }
+ // This convenient property of UTF-8 holds for all non-ASCII characters.
+ size_t UTF8Length = countLeadingOnes(C);
+ // 0xxx is ASCII, handled above. 10xxx is a trailing byte, invalid here.
+ // 11111xxx is not valid UTF-8 at all. Assert because it's probably our bug.
+ assert((UTF8Length >= 2 && UTF8Length <= 4) &&
+ "Invalid UTF-8, or transcoding bug?");
+ I += UTF8Length; // Skip over all trailing bytes.
+ // A codepoint takes two UTF-16 code unit if it's astral (outside BMP).
+ // Astral codepoints are encoded as 4 bytes in UTF-8 (11110xxx ...)
+ if (CB(UTF8Length, UTF8Length == 4 ? 2 : 1))
+ return true;
+ }
+ return false;
+}
+
+// Returns the offset into the string that matches \p Units UTF-16 code units.
+// Conceptually, this converts to UTF-16, truncates to CodeUnits, converts back
+// to UTF-8, and returns the length in bytes.
+static size_t measureUTF16(StringRef U8, int U16Units, bool &Valid) {
+ size_t Result = 0;
+ Valid = U16Units == 0 || iterateCodepoints(U8, [&](int U8Len, int U16Len) {
+ Result += U8Len;
+ U16Units -= U16Len;
+ return U16Units <= 0;
+ });
+ if (U16Units < 0) // Offset was into the middle of a surrogate pair.
+ Valid = false;
+ // Don't return an out-of-range index if we overran.
+ return std::min(Result, U8.size());
+}
+
+// Counts the number of UTF-16 code units needed to represent a string.
+// Like most strings in clangd, the input is UTF-8 encoded.
+static size_t utf16Len(StringRef U8) {
+ // A codepoint takes two UTF-16 code unit if it's astral (outside BMP).
+ // Astral codepoints are encoded as 4 bytes in UTF-8, starting with 11110xxx.
+ size_t Count = 0;
+ iterateCodepoints(U8, [&](int U8Len, int U16Len) {
+ Count += U16Len;
+ return false;
+ });
+ return Count;
+}
+
+llvm::Expected<size_t> positionToOffset(StringRef Code, Position P,
+ bool AllowColumnsBeyondLineLength) {
+ if (P.line < 0)
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("Line value can't be negative ({0})", P.line),
+ llvm::errc::invalid_argument);
+ if (P.character < 0)
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("Character value can't be negative ({0})", P.character),
+ llvm::errc::invalid_argument);
+ size_t StartOfLine = 0;
+ for (int I = 0; I != P.line; ++I) {
+ size_t NextNL = Code.find('\n', StartOfLine);
+ if (NextNL == StringRef::npos)
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("Line value is out of range ({0})", P.line),
+ llvm::errc::invalid_argument);
+ StartOfLine = NextNL + 1;
+ }
+
+ size_t NextNL = Code.find('\n', StartOfLine);
+ if (NextNL == StringRef::npos)
+ NextNL = Code.size();
+
+ bool Valid;
+ size_t ByteOffsetInLine = measureUTF16(
+ Code.substr(StartOfLine, NextNL - StartOfLine), P.character, Valid);
+ if (!Valid && !AllowColumnsBeyondLineLength)
+ return llvm::make_error<llvm::StringError>(
+ llvm::formatv("UTF-16 offset {0} is invalid for line {1}", P.character,
+ P.line),
+ llvm::errc::invalid_argument);
+ return StartOfLine + ByteOffsetInLine;
+}
+
+Position offsetToPosition(StringRef Code, size_t Offset) {
+ Offset = std::min(Code.size(), Offset);
+ StringRef Before = Code.substr(0, Offset);
+ int Lines = Before.count('\n');
+ size_t PrevNL = Before.rfind('\n');
+ size_t StartOfLine = (PrevNL == StringRef::npos) ? 0 : (PrevNL + 1);
+ Position Pos;
+ Pos.line = Lines;
+ Pos.character = utf16Len(Before.substr(StartOfLine));
+ return Pos;
+}
+
+Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc) {
+ // We use the SourceManager's line tables, but its column number is in bytes.
+ FileID FID;
+ unsigned Offset;
+ std::tie(FID, Offset) = SM.getDecomposedSpellingLoc(Loc);
+ Position P;
+ P.line = static_cast<int>(SM.getLineNumber(FID, Offset)) - 1;
+ bool Invalid = false;
+ StringRef Code = SM.getBufferData(FID, &Invalid);
+ if (!Invalid) {
+ auto ColumnInBytes = SM.getColumnNumber(FID, Offset) - 1;
+ auto LineSoFar = Code.substr(Offset - ColumnInBytes, ColumnInBytes);
+ P.character = utf16Len(LineSoFar);
+ }
+ return P;
+}
+
+Range halfOpenToRange(const SourceManager &SM, CharSourceRange R) {
+ // Clang is 1-based, LSP uses 0-based indexes.
+ Position Begin = sourceLocToPosition(SM, R.getBegin());
+ Position End = sourceLocToPosition(SM, R.getEnd());
+
+ return {Begin, End};
+}
+
+std::pair<size_t, size_t> offsetToClangLineColumn(StringRef Code,
+ size_t Offset) {
+ Offset = std::min(Code.size(), Offset);
+ StringRef Before = Code.substr(0, Offset);
+ int Lines = Before.count('\n');
+ size_t PrevNL = Before.rfind('\n');
+ size_t StartOfLine = (PrevNL == StringRef::npos) ? 0 : (PrevNL + 1);
+ return {Lines + 1, Offset - StartOfLine + 1};
+}
+
+std::pair<llvm::StringRef, llvm::StringRef>
+splitQualifiedName(llvm::StringRef QName) {
+ size_t Pos = QName.rfind("::");
+ if (Pos == llvm::StringRef::npos)
+ return {StringRef(), QName};
+ return {QName.substr(0, Pos + 2), QName.substr(Pos + 2)};
+}
+
+TextEdit replacementToEdit(StringRef Code, const tooling::Replacement &R) {
+ Range ReplacementRange = {
+ offsetToPosition(Code, R.getOffset()),
+ offsetToPosition(Code, R.getOffset() + R.getLength())};
+ return {ReplacementRange, R.getReplacementText()};
+}
+
+std::vector<TextEdit> replacementsToEdits(StringRef Code,
+ const tooling::Replacements &Repls) {
+ std::vector<TextEdit> Edits;
+ for (const auto &R : Repls)
+ Edits.push_back(replacementToEdit(Code, R));
+ return Edits;
+}
+
+llvm::Optional<std::string>
+getAbsoluteFilePath(const FileEntry *F, const SourceManager &SourceMgr) {
+ SmallString<64> FilePath = F->tryGetRealPathName();
+ if (FilePath.empty())
+ FilePath = F->getName();
+ if (!llvm::sys::path::is_absolute(FilePath)) {
+ if (!SourceMgr.getFileManager().makeAbsolutePath(FilePath)) {
+ log("Could not turn relative path to absolute: {0}", FilePath);
+ return llvm::None;
+ }
+ }
+ return FilePath.str().str();
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/SourceCode.h b/src/third_party/llvm-project/clang-tools-extra/clangd/SourceCode.h
new file mode 100644
index 0000000..b67fe6e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/SourceCode.h
@@ -0,0 +1,69 @@
+//===--- SourceCode.h - Manipulating source code as strings -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Various code that examines C++ source code without using heavy AST machinery
+// (and often not even the lexer). To be used sparingly!
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SOURCECODE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SOURCECODE_H
+#include "Protocol.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Core/Replacement.h"
+
+namespace clang {
+class SourceManager;
+
+namespace clangd {
+
+/// Turn a [line, column] pair into an offset in Code.
+///
+/// If P.character exceeds the line length, returns the offset at end-of-line.
+/// (If !AllowColumnsBeyondLineLength, then returns an error instead).
+/// If the line number is out of range, returns an error.
+///
+/// The returned value is in the range [0, Code.size()].
+llvm::Expected<size_t>
+positionToOffset(llvm::StringRef Code, Position P,
+ bool AllowColumnsBeyondLineLength = true);
+
+/// Turn an offset in Code into a [line, column] pair.
+/// The offset must be in range [0, Code.size()].
+Position offsetToPosition(llvm::StringRef Code, size_t Offset);
+
+/// Turn a SourceLocation into a [line, column] pair.
+/// FIXME: This should return an error if the location is invalid.
+Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc);
+
+// Converts a half-open clang source range to an LSP range.
+// Note that clang also uses closed source ranges, which this can't handle!
+Range halfOpenToRange(const SourceManager &SM, CharSourceRange R);
+
+// Converts an offset to a clang line/column (1-based, columns are bytes).
+// The offset must be in range [0, Code.size()].
+// Prefer to use SourceManager if one is available.
+std::pair<size_t, size_t> offsetToClangLineColumn(llvm::StringRef Code,
+ size_t Offset);
+
+/// From "a::b::c", return {"a::b::", "c"}. Scope is empty if there's no
+/// qualifier.
+std::pair<llvm::StringRef, llvm::StringRef>
+splitQualifiedName(llvm::StringRef QName);
+
+TextEdit replacementToEdit(StringRef Code, const tooling::Replacement &R);
+
+std::vector<TextEdit> replacementsToEdits(StringRef Code,
+ const tooling::Replacements &Repls);
+
+/// Get the absolute file path of a given file entry.
+llvm::Optional<std::string> getAbsoluteFilePath(const FileEntry *F,
+ const SourceManager &SourceMgr);
+} // namespace clangd
+} // namespace clang
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/TUScheduler.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/TUScheduler.cpp
new file mode 100644
index 0000000..81a75bb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/TUScheduler.cpp
@@ -0,0 +1,764 @@
+//===--- TUScheduler.cpp -----------------------------------------*-C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// For each file, managed by TUScheduler, we create a single ASTWorker that
+// manages an AST for that file. All operations that modify or read the AST are
+// run on a separate dedicated thread asynchronously in FIFO order.
+//
+// We start processing each update immediately after we receive it. If two or
+// more updates come subsequently without reads in-between, we attempt to drop
+// an older one to not waste time building the ASTs we don't need.
+//
+// The processing thread of the ASTWorker is also responsible for building the
+// preamble. However, unlike AST, the same preamble can be read concurrently, so
+// we run each of async preamble reads on its own thread.
+//
+// To limit the concurrent load that clangd produces we mantain a semaphore that
+// keeps more than a fixed number of threads from running concurrently.
+//
+// Rationale for cancelling updates.
+// LSP clients can send updates to clangd on each keystroke. Some files take
+// significant time to parse (e.g. a few seconds) and clangd can get starved by
+// the updates to those files. Therefore we try to process only the last update,
+// if possible.
+// Our current strategy to do that is the following:
+// - For each update we immediately schedule rebuild of the AST.
+// - Rebuild of the AST checks if it was cancelled before doing any actual work.
+// If it was, it does not do an actual rebuild, only reports llvm::None to the
+// callback
+// - When adding an update, we cancel the last update in the queue if it didn't
+// have any reads.
+// There is probably a optimal ways to do that. One approach we might take is
+// the following:
+// - For each update we remember the pending inputs, but delay rebuild of the
+// AST for some timeout.
+// - If subsequent updates come before rebuild was started, we replace the
+// pending inputs and reset the timer.
+// - If any reads of the AST are scheduled, we start building the AST
+// immediately.
+
+#include "TUScheduler.h"
+#include "Logger.h"
+#include "Trace.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/PCHContainerOperations.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+#include <memory>
+#include <queue>
+#include <thread>
+
+namespace clang {
+namespace clangd {
+using std::chrono::steady_clock;
+
+namespace {
+class ASTWorker;
+}
+
+/// An LRU cache of idle ASTs.
+/// Because we want to limit the overall number of these we retain, the cache
+/// owns ASTs (and may evict them) while their workers are idle.
+/// Workers borrow ASTs when active, and return them when done.
+class TUScheduler::ASTCache {
+public:
+ using Key = const ASTWorker *;
+
+ ASTCache(unsigned MaxRetainedASTs) : MaxRetainedASTs(MaxRetainedASTs) {}
+
+ /// Returns result of getUsedBytes() for the AST cached by \p K.
+ /// If no AST is cached, 0 is returned.
+ std::size_t getUsedBytes(Key K) {
+ std::lock_guard<std::mutex> Lock(Mut);
+ auto It = findByKey(K);
+ if (It == LRU.end() || !It->second)
+ return 0;
+ return It->second->getUsedBytes();
+ }
+
+ /// Store the value in the pool, possibly removing the last used AST.
+ /// The value should not be in the pool when this function is called.
+ void put(Key K, std::unique_ptr<ParsedAST> V) {
+ std::unique_lock<std::mutex> Lock(Mut);
+ assert(findByKey(K) == LRU.end());
+
+ LRU.insert(LRU.begin(), {K, std::move(V)});
+ if (LRU.size() <= MaxRetainedASTs)
+ return;
+ // We're past the limit, remove the last element.
+ std::unique_ptr<ParsedAST> ForCleanup = std::move(LRU.back().second);
+ LRU.pop_back();
+ // Run the expensive destructor outside the lock.
+ Lock.unlock();
+ ForCleanup.reset();
+ }
+
+ /// Returns the cached value for \p K, or llvm::None if the value is not in
+ /// the cache anymore. If nullptr was cached for \p K, this function will
+ /// return a null unique_ptr wrapped into an optional.
+ llvm::Optional<std::unique_ptr<ParsedAST>> take(Key K) {
+ std::unique_lock<std::mutex> Lock(Mut);
+ auto Existing = findByKey(K);
+ if (Existing == LRU.end())
+ return llvm::None;
+ std::unique_ptr<ParsedAST> V = std::move(Existing->second);
+ LRU.erase(Existing);
+ // GCC 4.8 fails to compile `return V;`, as it tries to call the copy
+ // constructor of unique_ptr, so we call the move ctor explicitly to avoid
+ // this miscompile.
+ return llvm::Optional<std::unique_ptr<ParsedAST>>(std::move(V));
+ }
+
+private:
+ using KVPair = std::pair<Key, std::unique_ptr<ParsedAST>>;
+
+ std::vector<KVPair>::iterator findByKey(Key K) {
+ return std::find_if(LRU.begin(), LRU.end(),
+ [K](const KVPair &P) { return P.first == K; });
+ }
+
+ std::mutex Mut;
+ unsigned MaxRetainedASTs;
+ /// Items sorted in LRU order, i.e. first item is the most recently accessed
+ /// one.
+ std::vector<KVPair> LRU; /* GUARDED_BY(Mut) */
+};
+
+namespace {
+class ASTWorkerHandle;
+
+/// Owns one instance of the AST, schedules updates and reads of it.
+/// Also responsible for building and providing access to the preamble.
+/// Each ASTWorker processes the async requests sent to it on a separate
+/// dedicated thread.
+/// The ASTWorker that manages the AST is shared by both the processing thread
+/// and the TUScheduler. The TUScheduler should discard an ASTWorker when
+/// remove() is called, but its thread may be busy and we don't want to block.
+/// So the workers are accessed via an ASTWorkerHandle. Destroying the handle
+/// signals the worker to exit its run loop and gives up shared ownership of the
+/// worker.
+class ASTWorker {
+ friend class ASTWorkerHandle;
+ ASTWorker(PathRef FileName, TUScheduler::ASTCache &LRUCache,
+ Semaphore &Barrier, bool RunSync,
+ steady_clock::duration UpdateDebounce,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ bool StorePreamblesInMemory,
+ PreambleParsedCallback PreambleCallback);
+
+public:
+ /// Create a new ASTWorker and return a handle to it.
+ /// The processing thread is spawned using \p Tasks. However, when \p Tasks
+ /// is null, all requests will be processed on the calling thread
+ /// synchronously instead. \p Barrier is acquired when processing each
+ /// request, it is be used to limit the number of actively running threads.
+ static ASTWorkerHandle create(PathRef FileName,
+ TUScheduler::ASTCache &IdleASTs,
+ AsyncTaskRunner *Tasks, Semaphore &Barrier,
+ steady_clock::duration UpdateDebounce,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ bool StorePreamblesInMemory,
+ PreambleParsedCallback PreambleCallback);
+ ~ASTWorker();
+
+ void update(ParseInputs Inputs, WantDiagnostics,
+ llvm::unique_function<void(std::vector<Diag>)> OnUpdated);
+ void
+ runWithAST(llvm::StringRef Name,
+ llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action);
+ bool blockUntilIdle(Deadline Timeout) const;
+
+ std::shared_ptr<const PreambleData> getPossiblyStalePreamble() const;
+ /// Wait for the first build of preamble to finish. Preamble itself can be
+ /// accessed via getPossibleStalePreamble(). Note that this function will
+ /// return after an unsuccessful build of the preamble too, i.e. result of
+ /// getPossiblyStalePreamble() can be null even after this function returns.
+ void waitForFirstPreamble() const;
+
+ std::size_t getUsedBytes() const;
+ bool isASTCached() const;
+
+private:
+ // Must be called exactly once on processing thread. Will return after
+ // stop() is called on a separate thread and all pending requests are
+ // processed.
+ void run();
+ /// Signal that run() should finish processing pending requests and exit.
+ void stop();
+ /// Adds a new task to the end of the request queue.
+ void startTask(llvm::StringRef Name, llvm::unique_function<void()> Task,
+ llvm::Optional<WantDiagnostics> UpdateType);
+ /// Determines the next action to perform.
+ /// All actions that should never run are disarded.
+ /// Returns a deadline for the next action. If it's expired, run now.
+ /// scheduleLocked() is called again at the deadline, or if requests arrive.
+ Deadline scheduleLocked();
+ /// Should the first task in the queue be skipped instead of run?
+ bool shouldSkipHeadLocked() const;
+
+ struct Request {
+ llvm::unique_function<void()> Action;
+ std::string Name;
+ steady_clock::time_point AddTime;
+ Context Ctx;
+ llvm::Optional<WantDiagnostics> UpdateType;
+ };
+
+ /// Handles retention of ASTs.
+ TUScheduler::ASTCache &IdleASTs;
+ const bool RunSync;
+ /// Time to wait after an update to see whether another update obsoletes it.
+ const steady_clock::duration UpdateDebounce;
+ /// File that ASTWorker is reponsible for.
+ const Path FileName;
+ /// Whether to keep the built preambles in memory or on disk.
+ const bool StorePreambleInMemory;
+ /// Callback, passed to the preamble builder.
+ const PreambleParsedCallback PreambleCallback;
+ /// Helper class required to build the ASTs.
+ const std::shared_ptr<PCHContainerOperations> PCHs;
+
+ Semaphore &Barrier;
+ /// Inputs, corresponding to the current state of AST.
+ ParseInputs FileInputs;
+ /// Whether the diagnostics for the current FileInputs were reported to the
+ /// users before.
+ bool DiagsWereReported = false;
+ /// Size of the last AST
+ /// Guards members used by both TUScheduler and the worker thread.
+ mutable std::mutex Mutex;
+ std::shared_ptr<const PreambleData> LastBuiltPreamble; /* GUARDED_BY(Mutex) */
+ /// Becomes ready when the first preamble build finishes.
+ Notification PreambleWasBuilt;
+ /// Set to true to signal run() to finish processing.
+ bool Done; /* GUARDED_BY(Mutex) */
+ std::deque<Request> Requests; /* GUARDED_BY(Mutex) */
+ mutable std::condition_variable RequestsCV;
+};
+
+/// A smart-pointer-like class that points to an active ASTWorker.
+/// In destructor, signals to the underlying ASTWorker that no new requests will
+/// be sent and the processing loop may exit (after running all pending
+/// requests).
+class ASTWorkerHandle {
+ friend class ASTWorker;
+ ASTWorkerHandle(std::shared_ptr<ASTWorker> Worker)
+ : Worker(std::move(Worker)) {
+ assert(this->Worker);
+ }
+
+public:
+ ASTWorkerHandle(const ASTWorkerHandle &) = delete;
+ ASTWorkerHandle &operator=(const ASTWorkerHandle &) = delete;
+ ASTWorkerHandle(ASTWorkerHandle &&) = default;
+ ASTWorkerHandle &operator=(ASTWorkerHandle &&) = default;
+
+ ~ASTWorkerHandle() {
+ if (Worker)
+ Worker->stop();
+ }
+
+ ASTWorker &operator*() {
+ assert(Worker && "Handle was moved from");
+ return *Worker;
+ }
+
+ ASTWorker *operator->() {
+ assert(Worker && "Handle was moved from");
+ return Worker.get();
+ }
+
+ /// Returns an owning reference to the underlying ASTWorker that can outlive
+ /// the ASTWorkerHandle. However, no new requests to an active ASTWorker can
+ /// be schedule via the returned reference, i.e. only reads of the preamble
+ /// are possible.
+ std::shared_ptr<const ASTWorker> lock() { return Worker; }
+
+private:
+ std::shared_ptr<ASTWorker> Worker;
+};
+
+ASTWorkerHandle ASTWorker::create(PathRef FileName,
+ TUScheduler::ASTCache &IdleASTs,
+ AsyncTaskRunner *Tasks, Semaphore &Barrier,
+ steady_clock::duration UpdateDebounce,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ bool StorePreamblesInMemory,
+ PreambleParsedCallback PreambleCallback) {
+ std::shared_ptr<ASTWorker> Worker(new ASTWorker(
+ FileName, IdleASTs, Barrier, /*RunSync=*/!Tasks, UpdateDebounce,
+ std::move(PCHs), StorePreamblesInMemory, std::move(PreambleCallback)));
+ if (Tasks)
+ Tasks->runAsync("worker:" + llvm::sys::path::filename(FileName),
+ [Worker]() { Worker->run(); });
+
+ return ASTWorkerHandle(std::move(Worker));
+}
+
+ASTWorker::ASTWorker(PathRef FileName, TUScheduler::ASTCache &LRUCache,
+ Semaphore &Barrier, bool RunSync,
+ steady_clock::duration UpdateDebounce,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ bool StorePreamblesInMemory,
+ PreambleParsedCallback PreambleCallback)
+ : IdleASTs(LRUCache), RunSync(RunSync), UpdateDebounce(UpdateDebounce),
+ FileName(FileName), StorePreambleInMemory(StorePreamblesInMemory),
+ PreambleCallback(std::move(PreambleCallback)), PCHs(std::move(PCHs)),
+ Barrier(Barrier), Done(false) {}
+
+ASTWorker::~ASTWorker() {
+ // Make sure we remove the cached AST, if any.
+ IdleASTs.take(this);
+#ifndef NDEBUG
+ std::lock_guard<std::mutex> Lock(Mutex);
+ assert(Done && "handle was not destroyed");
+ assert(Requests.empty() && "unprocessed requests when destroying ASTWorker");
+#endif
+}
+
+void ASTWorker::update(
+ ParseInputs Inputs, WantDiagnostics WantDiags,
+ llvm::unique_function<void(std::vector<Diag>)> OnUpdated) {
+ auto Task = [=](decltype(OnUpdated) OnUpdated) mutable {
+ // Will be used to check if we can avoid rebuilding the AST.
+ bool InputsAreTheSame =
+ std::tie(FileInputs.CompileCommand, FileInputs.Contents) ==
+ std::tie(Inputs.CompileCommand, Inputs.Contents);
+
+ tooling::CompileCommand OldCommand = std::move(FileInputs.CompileCommand);
+ bool PrevDiagsWereReported = DiagsWereReported;
+ FileInputs = Inputs;
+ DiagsWereReported = false;
+
+ log("Updating file {0} with command [{1}] {2}", FileName,
+ Inputs.CompileCommand.Directory,
+ llvm::join(Inputs.CompileCommand.CommandLine, " "));
+ // Rebuild the preamble and the AST.
+ std::unique_ptr<CompilerInvocation> Invocation =
+ buildCompilerInvocation(Inputs);
+ if (!Invocation) {
+ elog("Could not build CompilerInvocation for file {0}", FileName);
+ // Remove the old AST if it's still in cache.
+ IdleASTs.take(this);
+ // Make sure anyone waiting for the preamble gets notified it could not
+ // be built.
+ PreambleWasBuilt.notify();
+ return;
+ }
+
+ std::shared_ptr<const PreambleData> OldPreamble =
+ getPossiblyStalePreamble();
+ std::shared_ptr<const PreambleData> NewPreamble =
+ buildPreamble(FileName, *Invocation, OldPreamble, OldCommand, Inputs,
+ PCHs, StorePreambleInMemory, PreambleCallback);
+
+ bool CanReuseAST = InputsAreTheSame && (OldPreamble == NewPreamble);
+ {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ if (NewPreamble)
+ LastBuiltPreamble = NewPreamble;
+ }
+ // Before doing the expensive AST reparse, we want to release our reference
+ // to the old preamble, so it can be freed if there are no other references
+ // to it.
+ OldPreamble.reset();
+ PreambleWasBuilt.notify();
+
+ if (!CanReuseAST) {
+ IdleASTs.take(this); // Remove the old AST if it's still in cache.
+ } else {
+ // Since we don't need to rebuild the AST, we might've already reported
+ // the diagnostics for it.
+ if (PrevDiagsWereReported) {
+ DiagsWereReported = true;
+ // Take a shortcut and don't report the diagnostics, since they should
+ // not changed. All the clients should handle the lack of OnUpdated()
+ // call anyway to handle empty result from buildAST.
+ // FIXME(ibiryukov): the AST could actually change if non-preamble
+ // includes changed, but we choose to ignore it.
+ // FIXME(ibiryukov): should we refresh the cache in IdleASTs for the
+ // current file at this point?
+ log("Skipping rebuild of the AST for {0}, inputs are the same.",
+ FileName);
+ return;
+ }
+ }
+
+ // We only need to build the AST if diagnostics were requested.
+ if (WantDiags == WantDiagnostics::No)
+ return;
+
+ // Get the AST for diagnostics.
+ llvm::Optional<std::unique_ptr<ParsedAST>> AST = IdleASTs.take(this);
+ if (!AST) {
+ llvm::Optional<ParsedAST> NewAST =
+ buildAST(FileName, std::move(Invocation), Inputs, NewPreamble, PCHs);
+ AST = NewAST ? llvm::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
+ }
+ // We want to report the diagnostics even if this update was cancelled.
+ // It seems more useful than making the clients wait indefinitely if they
+ // spam us with updates.
+ // Note *AST can be still be null if buildAST fails.
+ if (*AST) {
+ OnUpdated((*AST)->getDiagnostics());
+ DiagsWereReported = true;
+ }
+ // Stash the AST in the cache for further use.
+ IdleASTs.put(this, std::move(*AST));
+ };
+
+ startTask("Update", Bind(Task, std::move(OnUpdated)), WantDiags);
+}
+
+void ASTWorker::runWithAST(
+ llvm::StringRef Name,
+ llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action) {
+ auto Task = [=](decltype(Action) Action) {
+ llvm::Optional<std::unique_ptr<ParsedAST>> AST = IdleASTs.take(this);
+ if (!AST) {
+ std::unique_ptr<CompilerInvocation> Invocation =
+ buildCompilerInvocation(FileInputs);
+ // Try rebuilding the AST.
+ llvm::Optional<ParsedAST> NewAST =
+ Invocation
+ ? buildAST(FileName,
+ llvm::make_unique<CompilerInvocation>(*Invocation),
+ FileInputs, getPossiblyStalePreamble(), PCHs)
+ : llvm::None;
+ AST = NewAST ? llvm::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
+ }
+ // Make sure we put the AST back into the LRU cache.
+ auto _ = llvm::make_scope_exit(
+ [&AST, this]() { IdleASTs.put(this, std::move(*AST)); });
+ // Run the user-provided action.
+ if (!*AST)
+ return Action(llvm::make_error<llvm::StringError>(
+ "invalid AST", llvm::errc::invalid_argument));
+ Action(InputsAndAST{FileInputs, **AST});
+ };
+ startTask(Name, Bind(Task, std::move(Action)),
+ /*UpdateType=*/llvm::None);
+}
+
+std::shared_ptr<const PreambleData>
+ASTWorker::getPossiblyStalePreamble() const {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ return LastBuiltPreamble;
+}
+
+void ASTWorker::waitForFirstPreamble() const {
+ PreambleWasBuilt.wait();
+}
+
+std::size_t ASTWorker::getUsedBytes() const {
+ // Note that we don't report the size of ASTs currently used for processing
+ // the in-flight requests. We used this information for debugging purposes
+ // only, so this should be fine.
+ std::size_t Result = IdleASTs.getUsedBytes(this);
+ if (auto Preamble = getPossiblyStalePreamble())
+ Result += Preamble->Preamble.getSize();
+ return Result;
+}
+
+bool ASTWorker::isASTCached() const { return IdleASTs.getUsedBytes(this) != 0; }
+
+void ASTWorker::stop() {
+ {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ assert(!Done && "stop() called twice");
+ Done = true;
+ }
+ RequestsCV.notify_all();
+}
+
+void ASTWorker::startTask(llvm::StringRef Name,
+ llvm::unique_function<void()> Task,
+ llvm::Optional<WantDiagnostics> UpdateType) {
+ if (RunSync) {
+ assert(!Done && "running a task after stop()");
+ trace::Span Tracer(Name + ":" + llvm::sys::path::filename(FileName));
+ Task();
+ return;
+ }
+
+ {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ assert(!Done && "running a task after stop()");
+ Requests.push_back({std::move(Task), Name, steady_clock::now(),
+ Context::current().clone(), UpdateType});
+ }
+ RequestsCV.notify_all();
+}
+
+void ASTWorker::run() {
+ while (true) {
+ Request Req;
+ {
+ std::unique_lock<std::mutex> Lock(Mutex);
+ for (auto Wait = scheduleLocked(); !Wait.expired();
+ Wait = scheduleLocked()) {
+ if (Done) {
+ if (Requests.empty())
+ return;
+ else // Even though Done is set, finish pending requests.
+ break; // However, skip delays to shutdown fast.
+ }
+
+ // Tracing: we have a next request, attribute this sleep to it.
+ Optional<WithContext> Ctx;
+ Optional<trace::Span> Tracer;
+ if (!Requests.empty()) {
+ Ctx.emplace(Requests.front().Ctx.clone());
+ Tracer.emplace("Debounce");
+ SPAN_ATTACH(*Tracer, "next_request", Requests.front().Name);
+ if (!(Wait == Deadline::infinity()))
+ SPAN_ATTACH(*Tracer, "sleep_ms",
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ Wait.time() - steady_clock::now())
+ .count());
+ }
+
+ wait(Lock, RequestsCV, Wait);
+ }
+ Req = std::move(Requests.front());
+ // Leave it on the queue for now, so waiters don't see an empty queue.
+ } // unlock Mutex
+
+ {
+ std::lock_guard<Semaphore> BarrierLock(Barrier);
+ WithContext Guard(std::move(Req.Ctx));
+ trace::Span Tracer(Req.Name);
+ Req.Action();
+ }
+
+ {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ Requests.pop_front();
+ }
+ RequestsCV.notify_all();
+ }
+}
+
+Deadline ASTWorker::scheduleLocked() {
+ if (Requests.empty())
+ return Deadline::infinity(); // Wait for new requests.
+ while (shouldSkipHeadLocked())
+ Requests.pop_front();
+ assert(!Requests.empty() && "skipped the whole queue");
+ // Some updates aren't dead yet, but never end up being used.
+ // e.g. the first keystroke is live until obsoleted by the second.
+ // We debounce "maybe-unused" writes, sleeping 500ms in case they become dead.
+ // But don't delay reads (including updates where diagnostics are needed).
+ for (const auto &R : Requests)
+ if (R.UpdateType == None || R.UpdateType == WantDiagnostics::Yes)
+ return Deadline::zero();
+ // Front request needs to be debounced, so determine when we're ready.
+ Deadline D(Requests.front().AddTime + UpdateDebounce);
+ return D;
+}
+
+// Returns true if Requests.front() is a dead update that can be skipped.
+bool ASTWorker::shouldSkipHeadLocked() const {
+ assert(!Requests.empty());
+ auto Next = Requests.begin();
+ auto UpdateType = Next->UpdateType;
+ if (!UpdateType) // Only skip updates.
+ return false;
+ ++Next;
+ // An update is live if its AST might still be read.
+ // That is, if it's not immediately followed by another update.
+ if (Next == Requests.end() || !Next->UpdateType)
+ return false;
+ // The other way an update can be live is if its diagnostics might be used.
+ switch (*UpdateType) {
+ case WantDiagnostics::Yes:
+ return false; // Always used.
+ case WantDiagnostics::No:
+ return true; // Always dead.
+ case WantDiagnostics::Auto:
+ // Used unless followed by an update that generates diagnostics.
+ for (; Next != Requests.end(); ++Next)
+ if (Next->UpdateType == WantDiagnostics::Yes ||
+ Next->UpdateType == WantDiagnostics::Auto)
+ return true; // Prefer later diagnostics.
+ return false;
+ }
+ llvm_unreachable("Unknown WantDiagnostics");
+}
+
+bool ASTWorker::blockUntilIdle(Deadline Timeout) const {
+ std::unique_lock<std::mutex> Lock(Mutex);
+ return wait(Lock, RequestsCV, Timeout, [&] { return Requests.empty(); });
+}
+
+} // namespace
+
+unsigned getDefaultAsyncThreadsCount() {
+ unsigned HardwareConcurrency = std::thread::hardware_concurrency();
+ // C++ standard says that hardware_concurrency()
+ // may return 0, fallback to 1 worker thread in
+ // that case.
+ if (HardwareConcurrency == 0)
+ return 1;
+ return HardwareConcurrency;
+}
+
+struct TUScheduler::FileData {
+ /// Latest inputs, passed to TUScheduler::update().
+ std::string Contents;
+ tooling::CompileCommand Command;
+ ASTWorkerHandle Worker;
+};
+
+TUScheduler::TUScheduler(unsigned AsyncThreadsCount,
+ bool StorePreamblesInMemory,
+ PreambleParsedCallback PreambleCallback,
+ std::chrono::steady_clock::duration UpdateDebounce,
+ ASTRetentionPolicy RetentionPolicy)
+ : StorePreamblesInMemory(StorePreamblesInMemory),
+ PCHOps(std::make_shared<PCHContainerOperations>()),
+ PreambleCallback(std::move(PreambleCallback)), Barrier(AsyncThreadsCount),
+ IdleASTs(llvm::make_unique<ASTCache>(RetentionPolicy.MaxRetainedASTs)),
+ UpdateDebounce(UpdateDebounce) {
+ if (0 < AsyncThreadsCount) {
+ PreambleTasks.emplace();
+ WorkerThreads.emplace();
+ }
+}
+
+TUScheduler::~TUScheduler() {
+ // Notify all workers that they need to stop.
+ Files.clear();
+
+ // Wait for all in-flight tasks to finish.
+ if (PreambleTasks)
+ PreambleTasks->wait();
+ if (WorkerThreads)
+ WorkerThreads->wait();
+}
+
+bool TUScheduler::blockUntilIdle(Deadline D) const {
+ for (auto &File : Files)
+ if (!File.getValue()->Worker->blockUntilIdle(D))
+ return false;
+ if (PreambleTasks)
+ if (!PreambleTasks->wait(D))
+ return false;
+ return true;
+}
+
+void TUScheduler::update(
+ PathRef File, ParseInputs Inputs, WantDiagnostics WantDiags,
+ llvm::unique_function<void(std::vector<Diag>)> OnUpdated) {
+ std::unique_ptr<FileData> &FD = Files[File];
+ if (!FD) {
+ // Create a new worker to process the AST-related tasks.
+ ASTWorkerHandle Worker = ASTWorker::create(
+ File, *IdleASTs, WorkerThreads ? WorkerThreads.getPointer() : nullptr,
+ Barrier, UpdateDebounce, PCHOps, StorePreamblesInMemory,
+ PreambleCallback);
+ FD = std::unique_ptr<FileData>(new FileData{
+ Inputs.Contents, Inputs.CompileCommand, std::move(Worker)});
+ } else {
+ FD->Contents = Inputs.Contents;
+ FD->Command = Inputs.CompileCommand;
+ }
+ FD->Worker->update(std::move(Inputs), WantDiags, std::move(OnUpdated));
+}
+
+void TUScheduler::remove(PathRef File) {
+ bool Removed = Files.erase(File);
+ if (!Removed)
+ elog("Trying to remove file from TUScheduler that is not tracked: {0}",
+ File);
+}
+
+void TUScheduler::runWithAST(
+ llvm::StringRef Name, PathRef File,
+ llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action) {
+ auto It = Files.find(File);
+ if (It == Files.end()) {
+ Action(llvm::make_error<llvm::StringError>(
+ "trying to get AST for non-added document",
+ llvm::errc::invalid_argument));
+ return;
+ }
+
+ It->second->Worker->runWithAST(Name, std::move(Action));
+}
+
+void TUScheduler::runWithPreamble(
+ llvm::StringRef Name, PathRef File,
+ llvm::unique_function<void(llvm::Expected<InputsAndPreamble>)> Action) {
+ auto It = Files.find(File);
+ if (It == Files.end()) {
+ Action(llvm::make_error<llvm::StringError>(
+ "trying to get preamble for non-added document",
+ llvm::errc::invalid_argument));
+ return;
+ }
+
+ if (!PreambleTasks) {
+ trace::Span Tracer(Name);
+ SPAN_ATTACH(Tracer, "file", File);
+ std::shared_ptr<const PreambleData> Preamble =
+ It->second->Worker->getPossiblyStalePreamble();
+ Action(InputsAndPreamble{It->second->Contents, It->second->Command,
+ Preamble.get()});
+ return;
+ }
+
+ std::shared_ptr<const ASTWorker> Worker = It->second->Worker.lock();
+ auto Task = [Worker, this](std::string Name, std::string File,
+ std::string Contents,
+ tooling::CompileCommand Command, Context Ctx,
+ decltype(Action) Action) mutable {
+ // We don't want to be running preamble actions before the preamble was
+ // built for the first time. This avoids extra work of processing the
+ // preamble headers in parallel multiple times.
+ Worker->waitForFirstPreamble();
+
+ std::lock_guard<Semaphore> BarrierLock(Barrier);
+ WithContext Guard(std::move(Ctx));
+ trace::Span Tracer(Name);
+ SPAN_ATTACH(Tracer, "file", File);
+ std::shared_ptr<const PreambleData> Preamble =
+ Worker->getPossiblyStalePreamble();
+ Action(InputsAndPreamble{Contents, Command, Preamble.get()});
+ };
+
+ PreambleTasks->runAsync("task:" + llvm::sys::path::filename(File),
+ Bind(Task, std::string(Name), std::string(File),
+ It->second->Contents, It->second->Command,
+ Context::current().clone(), std::move(Action)));
+}
+
+std::vector<std::pair<Path, std::size_t>>
+TUScheduler::getUsedBytesPerFile() const {
+ std::vector<std::pair<Path, std::size_t>> Result;
+ Result.reserve(Files.size());
+ for (auto &&PathAndFile : Files)
+ Result.push_back(
+ {PathAndFile.first(), PathAndFile.second->Worker->getUsedBytes()});
+ return Result;
+}
+
+std::vector<Path> TUScheduler::getFilesWithCachedAST() const {
+ std::vector<Path> Result;
+ for (auto &&PathAndFile : Files) {
+ if (!PathAndFile.second->Worker->isASTCached())
+ continue;
+ Result.push_back(PathAndFile.first());
+ }
+ return Result;
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/TUScheduler.h b/src/third_party/llvm-project/clang-tools-extra/clangd/TUScheduler.h
new file mode 100644
index 0000000..af1ff36
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/TUScheduler.h
@@ -0,0 +1,141 @@
+//===--- TUScheduler.h -------------------------------------------*-C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_TUSCHEDULER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_TUSCHEDULER_H
+
+#include "ClangdUnit.h"
+#include "Function.h"
+#include "Threading.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace clang {
+namespace clangd {
+
+/// Returns a number of a default async threads to use for TUScheduler.
+/// Returned value is always >= 1 (i.e. will not cause requests to be processed
+/// synchronously).
+unsigned getDefaultAsyncThreadsCount();
+
+struct InputsAndAST {
+ const ParseInputs &Inputs;
+ ParsedAST &AST;
+};
+
+struct InputsAndPreamble {
+ llvm::StringRef Contents;
+ const tooling::CompileCommand &Command;
+ const PreambleData *Preamble;
+};
+
+/// Determines whether diagnostics should be generated for a file snapshot.
+enum class WantDiagnostics {
+ Yes, /// Diagnostics must be generated for this snapshot.
+ No, /// Diagnostics must not be generated for this snapshot.
+ Auto, /// Diagnostics must be generated for this snapshot or a subsequent one,
+ /// within a bounded amount of time.
+};
+
+/// Configuration of the AST retention policy. This only covers retention of
+/// *idle* ASTs. If queue has operations requiring the AST, they might be
+/// kept in memory.
+struct ASTRetentionPolicy {
+ /// Maximum number of ASTs to be retained in memory when there are no pending
+ /// requests for them.
+ unsigned MaxRetainedASTs = 3;
+};
+
+/// Handles running tasks for ClangdServer and managing the resources (e.g.,
+/// preambles and ASTs) for opened files.
+/// TUScheduler is not thread-safe, only one thread should be providing updates
+/// and scheduling tasks.
+/// Callbacks are run on a threadpool and it's appropriate to do slow work in
+/// them. Each task has a name, used for tracing (should be UpperCamelCase).
+/// FIXME(sammccall): pull out a scheduler options struct.
+class TUScheduler {
+public:
+ TUScheduler(unsigned AsyncThreadsCount, bool StorePreamblesInMemory,
+ PreambleParsedCallback PreambleCallback,
+ std::chrono::steady_clock::duration UpdateDebounce,
+ ASTRetentionPolicy RetentionPolicy);
+ ~TUScheduler();
+
+ /// Returns estimated memory usage for each of the currently open files.
+ /// The order of results is unspecified.
+ std::vector<std::pair<Path, std::size_t>> getUsedBytesPerFile() const;
+
+ /// Returns a list of files with ASTs currently stored in memory. This method
+ /// is not very reliable and is only used for test. E.g., the results will not
+ /// contain files that currently run something over their AST.
+ std::vector<Path> getFilesWithCachedAST() const;
+
+ /// Schedule an update for \p File. Adds \p File to a list of tracked files if
+ /// \p File was not part of it before.
+ /// FIXME(ibiryukov): remove the callback from this function.
+ void update(PathRef File, ParseInputs Inputs, WantDiagnostics WD,
+ llvm::unique_function<void(std::vector<Diag>)> OnUpdated);
+
+ /// Remove \p File from the list of tracked files and schedule removal of its
+ /// resources.
+ void remove(PathRef File);
+
+ /// Schedule an async read of the AST. \p Action will be called when AST is
+ /// ready. The AST passed to \p Action refers to the version of \p File
+ /// tracked at the time of the call, even if new updates are received before
+ /// \p Action is executed.
+ /// If an error occurs during processing, it is forwarded to the \p Action
+ /// callback.
+ void runWithAST(llvm::StringRef Name, PathRef File,
+ Callback<InputsAndAST> Action);
+
+ /// Schedule an async read of the Preamble.
+ /// The preamble may be stale, generated from an older version of the file.
+ /// Reading from locations in the preamble may cause the files to be re-read.
+ /// This gives callers two options:
+ /// - validate that the preamble is still valid, and only use it in this case
+ /// - accept that preamble contents may be outdated, and try to avoid reading
+ /// source code from headers.
+ /// If there's no preamble yet (because the file was just opened), we'll wait
+ /// for it to build. The preamble may still be null if it fails to build or is
+ /// empty.
+ /// If an error occurs during processing, it is forwarded to the \p Action
+ /// callback.
+ void runWithPreamble(llvm::StringRef Name, PathRef File,
+ Callback<InputsAndPreamble> Action);
+
+ /// Wait until there are no scheduled or running tasks.
+ /// Mostly useful for synchronizing tests.
+ bool blockUntilIdle(Deadline D) const;
+
+private:
+ /// This class stores per-file data in the Files map.
+ struct FileData;
+
+public:
+ /// Responsible for retaining and rebuilding idle ASTs. An implementation is
+ /// an LRU cache.
+ class ASTCache;
+
+private:
+ const bool StorePreamblesInMemory;
+ const std::shared_ptr<PCHContainerOperations> PCHOps;
+ const PreambleParsedCallback PreambleCallback;
+ Semaphore Barrier;
+ llvm::StringMap<std::unique_ptr<FileData>> Files;
+ std::unique_ptr<ASTCache> IdleASTs;
+ // None when running tasks synchronously and non-None when running tasks
+ // asynchronously.
+ llvm::Optional<AsyncTaskRunner> PreambleTasks;
+ llvm::Optional<AsyncTaskRunner> WorkerThreads;
+ std::chrono::steady_clock::duration UpdateDebounce;
+};
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Threading.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/Threading.cpp
new file mode 100644
index 0000000..aa9dd8f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Threading.cpp
@@ -0,0 +1,100 @@
+#include "Threading.h"
+#include "Trace.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Threading.h"
+#include <thread>
+
+namespace clang {
+namespace clangd {
+
+void Notification::notify() {
+ {
+ std::lock_guard<std::mutex> Lock(Mu);
+ Notified = true;
+ }
+ CV.notify_all();
+}
+
+void Notification::wait() const {
+ std::unique_lock<std::mutex> Lock(Mu);
+ CV.wait(Lock, [this] { return Notified; });
+}
+
+Semaphore::Semaphore(std::size_t MaxLocks) : FreeSlots(MaxLocks) {}
+
+void Semaphore::lock() {
+ trace::Span Span("WaitForFreeSemaphoreSlot");
+ // trace::Span can also acquire locks in ctor and dtor, we make sure it
+ // happens when Semaphore's own lock is not held.
+ {
+ std::unique_lock<std::mutex> Lock(Mutex);
+ SlotsChanged.wait(Lock, [&]() { return FreeSlots > 0; });
+ --FreeSlots;
+ }
+}
+
+void Semaphore::unlock() {
+ std::unique_lock<std::mutex> Lock(Mutex);
+ ++FreeSlots;
+ Lock.unlock();
+
+ SlotsChanged.notify_one();
+}
+
+AsyncTaskRunner::~AsyncTaskRunner() { wait(); }
+
+bool AsyncTaskRunner::wait(Deadline D) const {
+ std::unique_lock<std::mutex> Lock(Mutex);
+ return clangd::wait(Lock, TasksReachedZero, D,
+ [&] { return InFlightTasks == 0; });
+}
+
+void AsyncTaskRunner::runAsync(const llvm::Twine &Name,
+ llvm::unique_function<void()> Action) {
+ {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ ++InFlightTasks;
+ }
+
+ auto CleanupTask = llvm::make_scope_exit([this]() {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ int NewTasksCnt = --InFlightTasks;
+ if (NewTasksCnt == 0) {
+ // Note: we can't unlock here because we don't want the object to be
+ // destroyed before we notify.
+ TasksReachedZero.notify_one();
+ }
+ });
+
+ std::thread(
+ [](std::string Name, decltype(Action) Action, decltype(CleanupTask)) {
+ llvm::set_thread_name(Name);
+ Action();
+ // Make sure function stored by Action is destroyed before CleanupTask
+ // is run.
+ Action = nullptr;
+ },
+ Name.str(), std::move(Action), std::move(CleanupTask))
+ .detach();
+}
+
+Deadline timeoutSeconds(llvm::Optional<double> Seconds) {
+ using namespace std::chrono;
+ if (!Seconds)
+ return Deadline::infinity();
+ return steady_clock::now() +
+ duration_cast<steady_clock::duration>(duration<double>(*Seconds));
+}
+
+void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV,
+ Deadline D) {
+ if (D == Deadline::zero())
+ return;
+ if (D == Deadline::infinity())
+ return CV.wait(Lock);
+ CV.wait_until(Lock, D.time());
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Threading.h b/src/third_party/llvm-project/clang-tools-extra/clangd/Threading.h
new file mode 100644
index 0000000..6dad841
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Threading.h
@@ -0,0 +1,120 @@
+//===--- ThreadPool.h --------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_THREADING_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_THREADING_H
+
+#include "Context.h"
+#include "Function.h"
+#include "llvm/ADT/Twine.h"
+#include <cassert>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+namespace clang {
+namespace clangd {
+
+/// A threadsafe flag that is initially clear.
+class Notification {
+public:
+ // Sets the flag. No-op if already set.
+ void notify();
+ // Blocks until flag is set.
+ void wait() const;
+
+private:
+ bool Notified = false;
+ mutable std::condition_variable CV;
+ mutable std::mutex Mu;
+};
+
+/// Limits the number of threads that can acquire the lock at the same time.
+class Semaphore {
+public:
+ Semaphore(std::size_t MaxLocks);
+
+ void lock();
+ void unlock();
+
+private:
+ std::mutex Mutex;
+ std::condition_variable SlotsChanged;
+ std::size_t FreeSlots;
+};
+
+/// A point in time we can wait for.
+/// Can be zero (don't wait) or infinity (wait forever).
+/// (Not time_point::max(), because many std::chrono implementations overflow).
+class Deadline {
+public:
+ Deadline(std::chrono::steady_clock::time_point Time)
+ : Type(Finite), Time(Time) {}
+ static Deadline zero() { return Deadline(Zero); }
+ static Deadline infinity() { return Deadline(Infinite); }
+
+ std::chrono::steady_clock::time_point time() const {
+ assert(Type == Finite);
+ return Time;
+ }
+ bool expired() const {
+ return (Type == Zero) ||
+ (Type == Finite && Time < std::chrono::steady_clock::now());
+ }
+ bool operator==(const Deadline &Other) const {
+ return (Type == Other.Type) && (Type != Finite || Time == Other.Time);
+ }
+
+private:
+ enum Type { Zero, Infinite, Finite };
+
+ Deadline(enum Type Type) : Type(Type) {}
+ enum Type Type;
+ std::chrono::steady_clock::time_point Time;
+};
+
+/// Makes a deadline from a timeout in seconds. None means wait forever.
+Deadline timeoutSeconds(llvm::Optional<double> Seconds);
+/// Wait once on CV for the specified duration.
+void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV,
+ Deadline D);
+/// Waits on a condition variable until F() is true or D expires.
+template <typename Func>
+LLVM_NODISCARD bool wait(std::unique_lock<std::mutex> &Lock,
+ std::condition_variable &CV, Deadline D, Func F) {
+ while (!F()) {
+ if (D.expired())
+ return false;
+ wait(Lock, CV, D);
+ }
+ return true;
+}
+
+/// Runs tasks on separate (detached) threads and wait for all tasks to finish.
+/// Objects that need to spawn threads can own an AsyncTaskRunner to ensure they
+/// all complete on destruction.
+class AsyncTaskRunner {
+public:
+ /// Destructor waits for all pending tasks to finish.
+ ~AsyncTaskRunner();
+
+ void wait() const { (void)wait(Deadline::infinity()); }
+ LLVM_NODISCARD bool wait(Deadline D) const;
+ // The name is used for tracing and debugging (e.g. to name a spawned thread).
+ void runAsync(const llvm::Twine &Name, llvm::unique_function<void()> Action);
+
+private:
+ mutable std::mutex Mutex;
+ mutable std::condition_variable TasksReachedZero;
+ std::size_t InFlightTasks = 0;
+};
+} // namespace clangd
+} // namespace clang
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Trace.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/Trace.cpp
new file mode 100644
index 0000000..24c1fdd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Trace.cpp
@@ -0,0 +1,233 @@
+//===--- Trace.cpp - Performance tracing facilities -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Trace.h"
+#include "Context.h"
+#include "Function.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/FormatProviders.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Threading.h"
+#include <atomic>
+#include <mutex>
+
+namespace clang {
+namespace clangd {
+namespace trace {
+using namespace llvm;
+
+namespace {
+// The current implementation is naive: each thread writes to Out guarded by Mu.
+// Perhaps we should replace this by something that disturbs performance less.
+class JSONTracer : public EventTracer {
+public:
+ JSONTracer(raw_ostream &Out, bool Pretty)
+ : Out(Out), Sep(""), Start(std::chrono::system_clock::now()),
+ JSONFormat(Pretty ? "{0:2}" : "{0}") {
+ // The displayTimeUnit must be ns to avoid low-precision overlap
+ // calculations!
+ Out << R"({"displayTimeUnit":"ns","traceEvents":[)"
+ << "\n";
+ rawEvent("M", json::Object{
+ {"name", "process_name"},
+ {"args", json::Object{{"name", "clangd"}}},
+ });
+ }
+
+ ~JSONTracer() {
+ Out << "\n]}";
+ Out.flush();
+ }
+
+ // We stash a Span object in the context. It will record the start/end,
+ // and this also allows us to look up the parent Span's information.
+ Context beginSpan(llvm::StringRef Name, json::Object *Args) override {
+ return Context::current().derive(
+ SpanKey, llvm::make_unique<JSONSpan>(this, Name, Args));
+ }
+
+ // Trace viewer requires each thread to properly stack events.
+ // So we need to mark only duration that the span was active on the thread.
+ // (Hopefully any off-thread activity will be connected by a flow event).
+ // Record the end time here, but don't write the event: Args aren't ready yet.
+ void endSpan() override {
+ Context::current().getExisting(SpanKey)->markEnded();
+ }
+
+ void instant(llvm::StringRef Name, json::Object &&Args) override {
+ captureThreadMetadata();
+ jsonEvent("i", json::Object{{"name", Name}, {"args", std::move(Args)}});
+ }
+
+ // Record an event on the current thread. ph, pid, tid, ts are set.
+ // Contents must be a list of the other JSON key/values.
+ void jsonEvent(StringRef Phase, json::Object &&Contents,
+ uint64_t TID = get_threadid(), double Timestamp = 0) {
+ Contents["ts"] = Timestamp ? Timestamp : timestamp();
+ Contents["tid"] = int64_t(TID);
+ std::lock_guard<std::mutex> Lock(Mu);
+ rawEvent(Phase, std::move(Contents));
+ }
+
+private:
+ class JSONSpan {
+ public:
+ JSONSpan(JSONTracer *Tracer, llvm::StringRef Name, json::Object *Args)
+ : StartTime(Tracer->timestamp()), EndTime(0), Name(Name),
+ TID(get_threadid()), Tracer(Tracer), Args(Args) {
+ // ~JSONSpan() may run in a different thread, so we need to capture now.
+ Tracer->captureThreadMetadata();
+
+ // We don't record begin events here (and end events in the destructor)
+ // because B/E pairs have to appear in the right order, which is awkward.
+ // Instead we send the complete (X) event in the destructor.
+
+ // If our parent was on a different thread, add an arrow to this span.
+ auto *Parent = Context::current().get(SpanKey);
+ if (Parent && *Parent && (*Parent)->TID != TID) {
+ // If the parent span ended already, then show this as "following" it.
+ // Otherwise show us as "parallel".
+ double OriginTime = (*Parent)->EndTime;
+ if (!OriginTime)
+ OriginTime = (*Parent)->StartTime;
+
+ auto FlowID = nextID();
+ Tracer->jsonEvent("s",
+ json::Object{{"id", FlowID},
+ {"name", "Context crosses threads"},
+ {"cat", "dummy"}},
+ (*Parent)->TID, (*Parent)->StartTime);
+ Tracer->jsonEvent("f",
+ json::Object{{"id", FlowID},
+ {"bp", "e"},
+ {"name", "Context crosses threads"},
+ {"cat", "dummy"}},
+ TID);
+ }
+ }
+
+ ~JSONSpan() {
+ // Finally, record the event (ending at EndTime, not timestamp())!
+ Tracer->jsonEvent("X",
+ json::Object{{"name", std::move(Name)},
+ {"args", std::move(*Args)},
+ {"dur", EndTime - StartTime}},
+ TID, StartTime);
+ }
+
+ // May be called by any thread.
+ void markEnded() {
+ EndTime = Tracer->timestamp();
+ }
+
+ private:
+ static int64_t nextID() {
+ static std::atomic<int64_t> Next = {0};
+ return Next++;
+ }
+
+ double StartTime;
+ std::atomic<double> EndTime; // Filled in by markEnded().
+ std::string Name;
+ uint64_t TID;
+ JSONTracer *Tracer;
+ json::Object *Args;
+ };
+ static Key<std::unique_ptr<JSONSpan>> SpanKey;
+
+ // Record an event. ph and pid are set.
+ // Contents must be a list of the other JSON key/values.
+ void rawEvent(StringRef Phase, json::Object &&Event) /*REQUIRES(Mu)*/ {
+ // PID 0 represents the clangd process.
+ Event["pid"] = 0;
+ Event["ph"] = Phase;
+ Out << Sep << formatv(JSONFormat, json::Value(std::move(Event)));
+ Sep = ",\n";
+ }
+
+ // If we haven't already, emit metadata describing this thread.
+ void captureThreadMetadata() {
+ uint64_t TID = get_threadid();
+ std::lock_guard<std::mutex> Lock(Mu);
+ if (ThreadsWithMD.insert(TID).second) {
+ SmallString<32> Name;
+ get_thread_name(Name);
+ if (!Name.empty()) {
+ rawEvent("M", json::Object{
+ {"tid", int64_t(TID)},
+ {"name", "thread_name"},
+ {"args", json::Object{{"name", Name}}},
+ });
+ }
+ }
+ }
+
+ double timestamp() {
+ using namespace std::chrono;
+ return duration<double, std::micro>(system_clock::now() - Start).count();
+ }
+
+ std::mutex Mu;
+ raw_ostream &Out /*GUARDED_BY(Mu)*/;
+ const char *Sep /*GUARDED_BY(Mu)*/;
+ DenseSet<uint64_t> ThreadsWithMD /*GUARDED_BY(Mu)*/;
+ const sys::TimePoint<> Start;
+ const char *JSONFormat;
+};
+
+Key<std::unique_ptr<JSONTracer::JSONSpan>> JSONTracer::SpanKey;
+
+EventTracer *T = nullptr;
+} // namespace
+
+Session::Session(EventTracer &Tracer) {
+ assert(!T && "Resetting global tracer is not allowed.");
+ T = &Tracer;
+}
+
+Session::~Session() { T = nullptr; }
+
+std::unique_ptr<EventTracer> createJSONTracer(llvm::raw_ostream &OS,
+ bool Pretty) {
+ return llvm::make_unique<JSONTracer>(OS, Pretty);
+}
+
+void log(const Twine &Message) {
+ if (!T)
+ return;
+ T->instant("Log", json::Object{{"Message", Message.str()}});
+}
+
+// Returned context owns Args.
+static Context makeSpanContext(llvm::Twine Name, json::Object *Args) {
+ if (!T)
+ return Context::current().clone();
+ WithContextValue WithArgs{std::unique_ptr<json::Object>(Args)};
+ return T->beginSpan(Name.isSingleStringRef() ? Name.getSingleStringRef()
+ : llvm::StringRef(Name.str()),
+ Args);
+}
+
+// Span keeps a non-owning pointer to the args, which is how users access them.
+// The args are owned by the context though. They stick around until the
+// beginSpan() context is destroyed, when the tracing engine will consume them.
+Span::Span(llvm::Twine Name)
+ : Args(T ? new json::Object() : nullptr),
+ RestoreCtx(makeSpanContext(Name, Args)) {}
+
+Span::~Span() {
+ if (T)
+ T->endSpan();
+}
+
+} // namespace trace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/Trace.h b/src/third_party/llvm-project/clang-tools-extra/clangd/Trace.h
new file mode 100644
index 0000000..0c4c461
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/Trace.h
@@ -0,0 +1,108 @@
+//===--- Trace.h - Performance tracing facilities ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Supports writing performance traces describing clangd's behavior.
+// Traces are consumed by implementations of the EventTracer interface.
+//
+//
+// All APIs are no-ops unless a Session is active (created by ClangdMain).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_TRACE_H_
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_TRACE_H_
+
+#include "Context.h"
+#include "Function.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace clangd {
+namespace trace {
+
+/// A consumer of trace events. The events are produced by Spans and trace::log.
+/// Implmentations of this interface must be thread-safe.
+class EventTracer {
+public:
+ virtual ~EventTracer() = default;
+
+ /// Called when event that has a duration starts. \p Name describes the event.
+ /// Returns a derived context that will be destroyed when the event ends.
+ /// Usually implementations will store an object in the returned context
+ /// whose destructor records the end of the event.
+ /// The args are *Args, only complete when the event ends.
+ virtual Context beginSpan(llvm::StringRef Name, llvm::json::Object *Args) = 0;
+ // Called when a Span is destroyed (it may still be active on other threads).
+ // beginSpan() and endSpan() will always form a proper stack on each thread.
+ // The Context returned by beginSpan is active, but Args is not ready.
+ // Tracers should not override this unless they need to observe strict
+ // per-thread nesting. Instead they should observe context destruction.
+ virtual void endSpan(){};
+
+ /// Called for instant events.
+ virtual void instant(llvm::StringRef Name, llvm::json::Object &&Args) = 0;
+};
+
+/// Sets up a global EventTracer that consumes events produced by Span and
+/// trace::log. Only one TracingSession can be active at a time and it should be
+/// set up before calling any clangd-specific functions.
+class Session {
+public:
+ Session(EventTracer &Tracer);
+ ~Session();
+};
+
+/// Create an instance of EventTracer that produces an output in the Trace Event
+/// format supported by Chrome's trace viewer (chrome://tracing).
+///
+/// The format is documented here:
+/// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
+std::unique_ptr<EventTracer> createJSONTracer(llvm::raw_ostream &OS,
+ bool Pretty = false);
+
+/// Records a single instant event, associated with the current thread.
+void log(const llvm::Twine &Name);
+
+/// Records an event whose duration is the lifetime of the Span object.
+/// This lifetime is extended when the span's context is reused.
+///
+/// This is the main public interface for producing tracing events.
+///
+/// Arbitrary JSON metadata can be attached while this span is active:
+/// SPAN_ATTACH(MySpan, "Payload", SomeJSONExpr);
+///
+/// SomeJSONExpr is evaluated and copied only if actually needed.
+class Span {
+public:
+ Span(llvm::Twine Name);
+ ~Span();
+
+ /// Mutable metadata, if this span is interested.
+ /// Prefer to use SPAN_ATTACH rather than accessing this directly.
+ llvm::json::Object *const Args;
+
+private:
+ WithContext RestoreCtx;
+};
+
+/// Attach a key-value pair to a Span event.
+/// This is not threadsafe when used with the same Span.
+#define SPAN_ATTACH(S, Name, Expr) \
+ do { \
+ if (auto *Args = (S).Args) \
+ (*Args)[Name] = Expr; \
+ } while (0)
+
+} // namespace trace
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_TRACE_H_
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/URI.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/URI.cpp
new file mode 100644
index 0000000..a722640
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/URI.cpp
@@ -0,0 +1,207 @@
+//===---- URI.h - File URIs with schemes -------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "URI.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+#include <iomanip>
+#include <sstream>
+
+LLVM_INSTANTIATE_REGISTRY(clang::clangd::URISchemeRegistry)
+
+namespace clang {
+namespace clangd {
+namespace {
+
+inline llvm::Error make_string_error(const llvm::Twine &Message) {
+ return llvm::make_error<llvm::StringError>(Message,
+ llvm::inconvertibleErrorCode());
+}
+
+/// \brief This manages file paths in the file system. All paths in the scheme
+/// are absolute (with leading '/').
+class FileSystemScheme : public URIScheme {
+public:
+ static const char *Scheme;
+
+ llvm::Expected<std::string>
+ getAbsolutePath(llvm::StringRef /*Authority*/, llvm::StringRef Body,
+ llvm::StringRef /*HintPath*/) const override {
+ if (!Body.startswith("/"))
+ return make_string_error("File scheme: expect body to be an absolute "
+ "path starting with '/': " +
+ Body);
+ // For Windows paths e.g. /X:
+ if (Body.size() > 2 && Body[0] == '/' && Body[2] == ':')
+ Body.consume_front("/");
+ llvm::SmallVector<char, 16> Path(Body.begin(), Body.end());
+ llvm::sys::path::native(Path);
+ return std::string(Path.begin(), Path.end());
+ }
+
+ llvm::Expected<URI>
+ uriFromAbsolutePath(llvm::StringRef AbsolutePath) const override {
+ using namespace llvm::sys;
+
+ std::string Body;
+ // For Windows paths e.g. X:
+ if (AbsolutePath.size() > 1 && AbsolutePath[1] == ':')
+ Body = "/";
+ Body += path::convert_to_slash(AbsolutePath);
+ return URI(Scheme, /*Authority=*/"", Body);
+ }
+};
+
+const char *FileSystemScheme::Scheme = "file";
+
+static URISchemeRegistry::Add<FileSystemScheme>
+ X(FileSystemScheme::Scheme,
+ "URI scheme for absolute paths in the file system.");
+
+llvm::Expected<std::unique_ptr<URIScheme>>
+findSchemeByName(llvm::StringRef Scheme) {
+ for (auto I = URISchemeRegistry::begin(), E = URISchemeRegistry::end();
+ I != E; ++I) {
+ if (I->getName() != Scheme)
+ continue;
+ return I->instantiate();
+ }
+ return make_string_error("Can't find scheme: " + Scheme);
+}
+
+bool shouldEscape(unsigned char C) {
+ // Unreserved characters.
+ if ((C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') ||
+ (C >= '0' && C <= '9'))
+ return false;
+ switch (C) {
+ case '-':
+ case '_':
+ case '.':
+ case '~':
+ case '/': // '/' is only reserved when parsing.
+ return false;
+ }
+ return true;
+}
+
+/// Encodes a string according to percent-encoding.
+/// - Unreserved characters are not escaped.
+/// - Reserved characters always escaped with exceptions like '/'.
+/// - All other characters are escaped.
+std::string percentEncode(llvm::StringRef Content) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ for (unsigned char C : Content)
+ if (shouldEscape(C))
+ OS << '%' << llvm::format_hex_no_prefix(C, 2);
+ else
+ OS << C;
+
+ OS.flush();
+ return Result;
+}
+
+/// Decodes a string according to percent-encoding.
+std::string percentDecode(llvm::StringRef Content) {
+ std::string Result;
+ for (auto I = Content.begin(), E = Content.end(); I != E; ++I) {
+ if (*I != '%') {
+ Result += *I;
+ continue;
+ }
+ if (*I == '%' && I + 2 < Content.end() && llvm::isHexDigit(*(I + 1)) &&
+ llvm::isHexDigit(*(I + 2))) {
+ Result.push_back(llvm::hexFromNibbles(*(I + 1), *(I + 2)));
+ I += 2;
+ } else
+ Result.push_back(*I);
+ }
+ return Result;
+}
+
+} // namespace
+
+URI::URI(llvm::StringRef Scheme, llvm::StringRef Authority,
+ llvm::StringRef Body)
+ : Scheme(Scheme), Authority(Authority), Body(Body) {
+ assert(!Scheme.empty());
+ assert((Authority.empty() || Body.startswith("/")) &&
+ "URI body must start with '/' when authority is present.");
+}
+
+std::string URI::toString() const {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ OS << percentEncode(Scheme) << ":";
+ if (Authority.empty() && Body.empty())
+ return OS.str();
+ // If authority if empty, we only print body if it starts with "/"; otherwise,
+ // the URI is invalid.
+ if (!Authority.empty() || llvm::StringRef(Body).startswith("/"))
+ OS << "//" << percentEncode(Authority);
+ OS << percentEncode(Body);
+ OS.flush();
+ return Result;
+}
+
+llvm::Expected<URI> URI::parse(llvm::StringRef OrigUri) {
+ URI U;
+ llvm::StringRef Uri = OrigUri;
+
+ auto Pos = Uri.find(':');
+ if (Pos == 0 || Pos == llvm::StringRef::npos)
+ return make_string_error("Scheme must be provided in URI: " + OrigUri);
+ U.Scheme = percentDecode(Uri.substr(0, Pos));
+ Uri = Uri.substr(Pos + 1);
+ if (Uri.consume_front("//")) {
+ Pos = Uri.find('/');
+ U.Authority = percentDecode(Uri.substr(0, Pos));
+ Uri = Uri.substr(Pos);
+ }
+ U.Body = percentDecode(Uri);
+ return U;
+}
+
+llvm::Expected<URI> URI::create(llvm::StringRef AbsolutePath,
+ llvm::StringRef Scheme) {
+ if (!llvm::sys::path::is_absolute(AbsolutePath))
+ return make_string_error("Not a valid absolute path: " + AbsolutePath);
+ auto S = findSchemeByName(Scheme);
+ if (!S)
+ return S.takeError();
+ return S->get()->uriFromAbsolutePath(AbsolutePath);
+}
+
+URI URI::createFile(llvm::StringRef AbsolutePath) {
+ auto U = create(AbsolutePath, "file");
+ if (!U)
+ llvm_unreachable(llvm::toString(U.takeError()).c_str());
+ return std::move(*U);
+}
+
+llvm::Expected<std::string> URI::resolve(const URI &Uri,
+ llvm::StringRef HintPath) {
+ auto S = findSchemeByName(Uri.Scheme);
+ if (!S)
+ return S.takeError();
+ return S->get()->getAbsolutePath(Uri.Authority, Uri.Body, HintPath);
+}
+
+llvm::Expected<std::string> URI::includeSpelling(const URI &Uri) {
+ auto S = findSchemeByName(Uri.Scheme);
+ if (!S)
+ return S.takeError();
+ return S->get()->getIncludeSpelling(Uri);
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/URI.h b/src/third_party/llvm-project/clang-tools-extra/clangd/URI.h
new file mode 100644
index 0000000..112264f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/URI.h
@@ -0,0 +1,122 @@
+//===--- URI.h - File URIs with schemes --------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_PATHURI_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_PATHURI_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Registry.h"
+
+namespace clang {
+namespace clangd {
+
+/// A URI describes the location of a source file.
+/// In the simplest case, this is a "file" URI that directly encodes the
+/// absolute path to a file. More abstract cases are possible: a shared index
+/// service might expose repo:// URIs that are relative to the source control
+/// root.
+///
+/// Clangd handles URIs of the form <scheme>:[//<authority>]<body>. It doesn't
+/// further split the authority or body into constituent parts (e.g. query
+/// strings is included in the body).
+class URI {
+public:
+ URI(llvm::StringRef Scheme, llvm::StringRef Authority, llvm::StringRef Body);
+
+ /// Returns decoded scheme e.g. "https"
+ llvm::StringRef scheme() const { return Scheme; }
+ /// Returns decoded authority e.g. "reviews.lvm.org"
+ llvm::StringRef authority() const { return Authority; }
+ /// Returns decoded body e.g. "/D41946"
+ llvm::StringRef body() const { return Body; }
+
+ /// Returns a string URI with all components percent-encoded.
+ std::string toString() const;
+
+ /// Creates a URI for a file in the given scheme. \p Scheme must be
+ /// registered. The URI is percent-encoded.
+ static llvm::Expected<URI> create(llvm::StringRef AbsolutePath,
+ llvm::StringRef Scheme);
+
+ /// This creates a file:// URI for \p AbsolutePath. The path must be absolute.
+ static URI createFile(llvm::StringRef AbsolutePath);
+
+ /// Parse a URI string "<scheme>:[//<authority>/]<path>". Percent-encoded
+ /// characters in the URI will be decoded.
+ static llvm::Expected<URI> parse(llvm::StringRef Uri);
+
+ /// Resolves the absolute path of \p U. If there is no matching scheme, or the
+ /// URI is invalid in the scheme, this returns an error.
+ ///
+ /// \p HintPath A related path, such as the current file or working directory,
+ /// which can help disambiguate when the same file exists in many workspaces.
+ static llvm::Expected<std::string> resolve(const URI &U,
+ llvm::StringRef HintPath = "");
+
+ /// Gets the preferred spelling of this file for #include, if there is one,
+ /// e.g. <system_header.h>, "path/to/x.h".
+ ///
+ /// This allows URI schemas to provide their customized include paths.
+ ///
+ /// Returns an empty string if normal include-shortening based on the absolute
+ /// path should be used.
+ /// Fails if the URI is not valid in the schema.
+ static llvm::Expected<std::string> includeSpelling(const URI &U);
+
+ friend bool operator==(const URI &LHS, const URI &RHS) {
+ return std::tie(LHS.Scheme, LHS.Authority, LHS.Body) ==
+ std::tie(RHS.Scheme, RHS.Authority, RHS.Body);
+ }
+
+ friend bool operator<(const URI &LHS, const URI &RHS) {
+ return std::tie(LHS.Scheme, LHS.Authority, LHS.Body) <
+ std::tie(RHS.Scheme, RHS.Authority, RHS.Body);
+ }
+
+private:
+ URI() = default;
+
+ std::string Scheme;
+ std::string Authority;
+ std::string Body;
+};
+
+/// URIScheme is an extension point for teaching clangd to recognize a custom
+/// URI scheme. This is expected to be implemented and exposed via the
+/// URISchemeRegistry.
+class URIScheme {
+public:
+ virtual ~URIScheme() = default;
+
+ /// Returns the absolute path of the file corresponding to the URI
+ /// authority+body in the file system. See URI::resolve for semantics of
+ /// \p HintPath.
+ virtual llvm::Expected<std::string>
+ getAbsolutePath(llvm::StringRef Authority, llvm::StringRef Body,
+ llvm::StringRef HintPath) const = 0;
+
+ virtual llvm::Expected<URI>
+ uriFromAbsolutePath(llvm::StringRef AbsolutePath) const = 0;
+
+ /// Returns the include path of the file (e.g. <path>, "path"), which can be
+ /// #included directly. See URI::includeSpelling for details.
+ virtual llvm::Expected<std::string> getIncludeSpelling(const URI &U) const {
+ return ""; // no customized include path for this scheme.
+ }
+};
+
+/// By default, a "file" scheme is supported where URI paths are always absolute
+/// in the file system.
+typedef llvm::Registry<URIScheme> URISchemeRegistry;
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_PATHURI_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/XRefs.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/XRefs.cpp
new file mode 100644
index 0000000..99ccd21
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/XRefs.cpp
@@ -0,0 +1,673 @@
+//===--- XRefs.cpp ----------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#include "XRefs.h"
+#include "AST.h"
+#include "Logger.h"
+#include "SourceCode.h"
+#include "URI.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Index/IndexDataConsumer.h"
+#include "clang/Index/IndexingAction.h"
+#include "clang/Index/USRGeneration.h"
+#include "llvm/Support/Path.h"
+namespace clang {
+namespace clangd {
+using namespace llvm;
+namespace {
+
+// Get the definition from a given declaration `D`.
+// Return nullptr if no definition is found, or the declaration type of `D` is
+// not supported.
+const Decl *getDefinition(const Decl *D) {
+ assert(D);
+ if (const auto *TD = dyn_cast<TagDecl>(D))
+ return TD->getDefinition();
+ else if (const auto *VD = dyn_cast<VarDecl>(D))
+ return VD->getDefinition();
+ else if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getDefinition();
+ return nullptr;
+}
+
+// Convert a SymbolLocation to LSP's Location.
+// HintPath is used to resolve the path of URI.
+// FIXME: figure out a good home for it, and share the implementation with
+// FindSymbols.
+llvm::Optional<Location> toLSPLocation(const SymbolLocation &Loc,
+ llvm::StringRef HintPath) {
+ if (!Loc)
+ return llvm::None;
+ auto Uri = URI::parse(Loc.FileURI);
+ if (!Uri) {
+ log("Could not parse URI: {0}", Loc.FileURI);
+ return llvm::None;
+ }
+ auto Path = URI::resolve(*Uri, HintPath);
+ if (!Path) {
+ log("Could not resolve URI: {0}", Loc.FileURI);
+ return llvm::None;
+ }
+ Location LSPLoc;
+ LSPLoc.uri = URIForFile(*Path);
+ LSPLoc.range.start.line = Loc.Start.Line;
+ LSPLoc.range.start.character = Loc.Start.Column;
+ LSPLoc.range.end.line = Loc.End.Line;
+ LSPLoc.range.end.character = Loc.End.Column;
+ return LSPLoc;
+}
+
+struct MacroDecl {
+ StringRef Name;
+ const MacroInfo *Info;
+};
+
+/// Finds declarations locations that a given source location refers to.
+class DeclarationAndMacrosFinder : public index::IndexDataConsumer {
+ std::vector<const Decl *> Decls;
+ std::vector<MacroDecl> MacroInfos;
+ const SourceLocation &SearchedLocation;
+ const ASTContext &AST;
+ Preprocessor &PP;
+
+public:
+ DeclarationAndMacrosFinder(raw_ostream &OS,
+ const SourceLocation &SearchedLocation,
+ ASTContext &AST, Preprocessor &PP)
+ : SearchedLocation(SearchedLocation), AST(AST), PP(PP) {}
+
+ std::vector<const Decl *> takeDecls() {
+ // Don't keep the same declaration multiple times.
+ // This can happen when nodes in the AST are visited twice.
+ std::sort(Decls.begin(), Decls.end());
+ auto Last = std::unique(Decls.begin(), Decls.end());
+ Decls.erase(Last, Decls.end());
+ return std::move(Decls);
+ }
+
+ std::vector<MacroDecl> takeMacroInfos() {
+ // Don't keep the same Macro info multiple times.
+ std::sort(MacroInfos.begin(), MacroInfos.end(),
+ [](const MacroDecl &Left, const MacroDecl &Right) {
+ return Left.Info < Right.Info;
+ });
+
+ auto Last = std::unique(MacroInfos.begin(), MacroInfos.end(),
+ [](const MacroDecl &Left, const MacroDecl &Right) {
+ return Left.Info == Right.Info;
+ });
+ MacroInfos.erase(Last, MacroInfos.end());
+ return std::move(MacroInfos);
+ }
+
+ bool
+ handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
+ ArrayRef<index::SymbolRelation> Relations,
+ SourceLocation Loc,
+ index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
+ if (Loc == SearchedLocation) {
+ // Find and add definition declarations (for GoToDefinition).
+ // We don't use parameter `D`, as Parameter `D` is the canonical
+ // declaration, which is the first declaration of a redeclarable
+ // declaration, and it could be a forward declaration.
+ if (const auto *Def = getDefinition(D)) {
+ Decls.push_back(Def);
+ } else {
+ // Couldn't find a definition, fall back to use `D`.
+ Decls.push_back(D);
+ }
+ }
+ return true;
+ }
+
+private:
+ void finish() override {
+ // Also handle possible macro at the searched location.
+ Token Result;
+ auto &Mgr = AST.getSourceManager();
+ if (!Lexer::getRawToken(Mgr.getSpellingLoc(SearchedLocation), Result, Mgr,
+ AST.getLangOpts(), false)) {
+ if (Result.is(tok::raw_identifier)) {
+ PP.LookUpIdentifierInfo(Result);
+ }
+ IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo();
+ if (IdentifierInfo && IdentifierInfo->hadMacroDefinition()) {
+ std::pair<FileID, unsigned int> DecLoc =
+ Mgr.getDecomposedExpansionLoc(SearchedLocation);
+ // Get the definition just before the searched location so that a macro
+ // referenced in a '#undef MACRO' can still be found.
+ SourceLocation BeforeSearchedLocation = Mgr.getMacroArgExpandedLocation(
+ Mgr.getLocForStartOfFile(DecLoc.first)
+ .getLocWithOffset(DecLoc.second - 1));
+ MacroDefinition MacroDef =
+ PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation);
+ MacroInfo *MacroInf = MacroDef.getMacroInfo();
+ if (MacroInf) {
+ MacroInfos.push_back(MacroDecl{IdentifierInfo->getName(), MacroInf});
+ assert(Decls.empty());
+ }
+ }
+ }
+ }
+};
+
+struct IdentifiedSymbol {
+ std::vector<const Decl *> Decls;
+ std::vector<MacroDecl> Macros;
+};
+
+IdentifiedSymbol getSymbolAtPosition(ParsedAST &AST, SourceLocation Pos) {
+ auto DeclMacrosFinder = DeclarationAndMacrosFinder(
+ llvm::errs(), Pos, AST.getASTContext(), AST.getPreprocessor());
+ index::IndexingOptions IndexOpts;
+ IndexOpts.SystemSymbolFilter =
+ index::IndexingOptions::SystemSymbolFilterKind::All;
+ IndexOpts.IndexFunctionLocals = true;
+ indexTopLevelDecls(AST.getASTContext(), AST.getLocalTopLevelDecls(),
+ DeclMacrosFinder, IndexOpts);
+
+ return {DeclMacrosFinder.takeDecls(), DeclMacrosFinder.takeMacroInfos()};
+}
+
+llvm::Optional<Location>
+makeLocation(ParsedAST &AST, const SourceRange &ValSourceRange) {
+ const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
+ const LangOptions &LangOpts = AST.getASTContext().getLangOpts();
+ SourceLocation LocStart = ValSourceRange.getBegin();
+
+ const FileEntry *F =
+ SourceMgr.getFileEntryForID(SourceMgr.getFileID(LocStart));
+ if (!F)
+ return llvm::None;
+ SourceLocation LocEnd = Lexer::getLocForEndOfToken(ValSourceRange.getEnd(), 0,
+ SourceMgr, LangOpts);
+ Position Begin = sourceLocToPosition(SourceMgr, LocStart);
+ Position End = sourceLocToPosition(SourceMgr, LocEnd);
+ Range R = {Begin, End};
+ Location L;
+
+ auto FilePath = getAbsoluteFilePath(F, SourceMgr);
+ if (!FilePath) {
+ log("failed to get path!");
+ return llvm::None;
+ }
+ L.uri = URIForFile(*FilePath);
+ L.range = R;
+ return L;
+}
+
+// Get the symbol ID for a declaration, if possible.
+llvm::Optional<SymbolID> getSymbolID(const Decl *D) {
+ llvm::SmallString<128> USR;
+ if (index::generateUSRForDecl(D, USR)) {
+ return None;
+ }
+ return SymbolID(USR);
+}
+
+} // namespace
+
+std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
+ const SymbolIndex *Index) {
+ const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
+
+ std::vector<Location> Result;
+ // Handle goto definition for #include.
+ for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
+ if (!Inc.Resolved.empty() && Inc.R.contains(Pos))
+ Result.push_back(Location{URIForFile{Inc.Resolved}, {}});
+ }
+ if (!Result.empty())
+ return Result;
+
+ // Identified symbols at a specific position.
+ SourceLocation SourceLocationBeg =
+ getBeginningOfIdentifier(AST, Pos, SourceMgr.getMainFileID());
+ auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
+
+ for (auto Item : Symbols.Macros) {
+ auto Loc = Item.Info->getDefinitionLoc();
+ auto L = makeLocation(AST, SourceRange(Loc, Loc));
+ if (L)
+ Result.push_back(*L);
+ }
+
+ // Declaration and definition are different terms in C-family languages, and
+ // LSP only defines the "GoToDefinition" specification, so we try to perform
+ // the "most sensible" GoTo operation:
+ //
+ // - We use the location from AST and index (if available) to provide the
+ // final results. When there are duplicate results, we prefer AST over
+ // index because AST is more up-to-date.
+ //
+ // - For each symbol, we will return a location of the canonical declaration
+ // (e.g. function declaration in header), and a location of definition if
+ // they are available.
+ //
+ // So the work flow:
+ //
+ // 1. Identify the symbols being search for by traversing the AST.
+ // 2. Populate one of the locations with the AST location.
+ // 3. Use the AST information to query the index, and populate the index
+ // location (if available).
+ // 4. Return all populated locations for all symbols, definition first (
+ // which we think is the users wants most often).
+ struct CandidateLocation {
+ llvm::Optional<Location> Def;
+ llvm::Optional<Location> Decl;
+ };
+ llvm::DenseMap<SymbolID, CandidateLocation> ResultCandidates;
+
+ // Emit all symbol locations (declaration or definition) from AST.
+ for (const auto *D : Symbols.Decls) {
+ // Fake key for symbols don't have USR (no SymbolID).
+ // Ideally, there should be a USR for each identified symbols. Symbols
+ // without USR are rare and unimportant cases, we use the a fake holder to
+ // minimize the invasiveness of these cases.
+ SymbolID Key("");
+ if (auto ID = getSymbolID(D))
+ Key = *ID;
+
+ auto &Candidate = ResultCandidates[Key];
+ auto Loc = findNameLoc(D);
+ auto L = makeLocation(AST, SourceRange(Loc, Loc));
+ // The declaration in the identified symbols is a definition if possible
+ // otherwise it is declaration.
+ bool IsDef = getDefinition(D) == D;
+ // Populate one of the slots with location for the AST.
+ if (!IsDef)
+ Candidate.Decl = L;
+ else
+ Candidate.Def = L;
+ }
+
+ if (Index) {
+ LookupRequest QueryRequest;
+ // Build request for index query, using SymbolID.
+ for (auto It : ResultCandidates)
+ QueryRequest.IDs.insert(It.first);
+ std::string HintPath;
+ const FileEntry *FE =
+ SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
+ if (auto Path = getAbsoluteFilePath(FE, SourceMgr))
+ HintPath = *Path;
+ // Query the index and populate the empty slot.
+ Index->lookup(
+ QueryRequest, [&HintPath, &ResultCandidates](const Symbol &Sym) {
+ auto It = ResultCandidates.find(Sym.ID);
+ assert(It != ResultCandidates.end());
+ auto &Value = It->second;
+
+ if (!Value.Def)
+ Value.Def = toLSPLocation(Sym.Definition, HintPath);
+ if (!Value.Decl)
+ Value.Decl = toLSPLocation(Sym.CanonicalDeclaration, HintPath);
+ });
+ }
+
+ // Populate the results, definition first.
+ for (auto It : ResultCandidates) {
+ const auto &Candidate = It.second;
+ if (Candidate.Def)
+ Result.push_back(*Candidate.Def);
+ if (Candidate.Decl &&
+ Candidate.Decl != Candidate.Def) // Decl and Def might be the same
+ Result.push_back(*Candidate.Decl);
+ }
+
+ return Result;
+}
+
+namespace {
+
+/// Finds document highlights that a given list of declarations refers to.
+class DocumentHighlightsFinder : public index::IndexDataConsumer {
+ std::vector<const Decl *> &Decls;
+ std::vector<DocumentHighlight> DocumentHighlights;
+ const ASTContext &AST;
+
+public:
+ DocumentHighlightsFinder(raw_ostream &OS, ASTContext &AST, Preprocessor &PP,
+ std::vector<const Decl *> &Decls)
+ : Decls(Decls), AST(AST) {}
+ std::vector<DocumentHighlight> takeHighlights() {
+ // Don't keep the same highlight multiple times.
+ // This can happen when nodes in the AST are visited twice.
+ std::sort(DocumentHighlights.begin(), DocumentHighlights.end());
+ auto Last =
+ std::unique(DocumentHighlights.begin(), DocumentHighlights.end());
+ DocumentHighlights.erase(Last, DocumentHighlights.end());
+ return std::move(DocumentHighlights);
+ }
+
+ bool
+ handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
+ ArrayRef<index::SymbolRelation> Relations,
+ SourceLocation Loc,
+ index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
+ const SourceManager &SourceMgr = AST.getSourceManager();
+ SourceLocation HighlightStartLoc = SourceMgr.getFileLoc(Loc);
+ if (SourceMgr.getMainFileID() != SourceMgr.getFileID(HighlightStartLoc) ||
+ std::find(Decls.begin(), Decls.end(), D) == Decls.end()) {
+ return true;
+ }
+ SourceLocation End;
+ const LangOptions &LangOpts = AST.getLangOpts();
+ End = Lexer::getLocForEndOfToken(HighlightStartLoc, 0, SourceMgr, LangOpts);
+ SourceRange SR(HighlightStartLoc, End);
+
+ DocumentHighlightKind Kind = DocumentHighlightKind::Text;
+ if (static_cast<index::SymbolRoleSet>(index::SymbolRole::Write) & Roles)
+ Kind = DocumentHighlightKind::Write;
+ else if (static_cast<index::SymbolRoleSet>(index::SymbolRole::Read) & Roles)
+ Kind = DocumentHighlightKind::Read;
+
+ DocumentHighlights.push_back(getDocumentHighlight(SR, Kind));
+ return true;
+ }
+
+private:
+ DocumentHighlight getDocumentHighlight(SourceRange SR,
+ DocumentHighlightKind Kind) {
+ const SourceManager &SourceMgr = AST.getSourceManager();
+ Position Begin = sourceLocToPosition(SourceMgr, SR.getBegin());
+ Position End = sourceLocToPosition(SourceMgr, SR.getEnd());
+ Range R = {Begin, End};
+ DocumentHighlight DH;
+ DH.range = R;
+ DH.kind = Kind;
+ return DH;
+ }
+};
+
+} // namespace
+
+std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
+ Position Pos) {
+ const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
+ SourceLocation SourceLocationBeg =
+ getBeginningOfIdentifier(AST, Pos, SourceMgr.getMainFileID());
+
+ auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
+ std::vector<const Decl *> SelectedDecls = Symbols.Decls;
+
+ DocumentHighlightsFinder DocHighlightsFinder(
+ llvm::errs(), AST.getASTContext(), AST.getPreprocessor(), SelectedDecls);
+
+ index::IndexingOptions IndexOpts;
+ IndexOpts.SystemSymbolFilter =
+ index::IndexingOptions::SystemSymbolFilterKind::All;
+ IndexOpts.IndexFunctionLocals = true;
+ indexTopLevelDecls(AST.getASTContext(), AST.getLocalTopLevelDecls(),
+ DocHighlightsFinder, IndexOpts);
+
+ return DocHighlightsFinder.takeHighlights();
+}
+
+static PrintingPolicy printingPolicyForDecls(PrintingPolicy Base) {
+ PrintingPolicy Policy(Base);
+
+ Policy.AnonymousTagLocations = false;
+ Policy.TerseOutput = true;
+ Policy.PolishForDeclaration = true;
+ Policy.ConstantsAsWritten = true;
+ Policy.SuppressTagKeyword = false;
+
+ return Policy;
+}
+
+/// Return a string representation (e.g. "class MyNamespace::MyClass") of
+/// the type declaration \p TD.
+static std::string typeDeclToString(const TypeDecl *TD) {
+ QualType Type = TD->getASTContext().getTypeDeclType(TD);
+
+ PrintingPolicy Policy =
+ printingPolicyForDecls(TD->getASTContext().getPrintingPolicy());
+
+ std::string Name;
+ llvm::raw_string_ostream Stream(Name);
+ Type.print(Stream, Policy);
+
+ return Stream.str();
+}
+
+/// Return a string representation (e.g. "namespace ns1::ns2") of
+/// the named declaration \p ND.
+static std::string namedDeclQualifiedName(const NamedDecl *ND,
+ StringRef Prefix) {
+ PrintingPolicy Policy =
+ printingPolicyForDecls(ND->getASTContext().getPrintingPolicy());
+
+ std::string Name;
+ llvm::raw_string_ostream Stream(Name);
+ Stream << Prefix << ' ';
+ ND->printQualifiedName(Stream, Policy);
+
+ return Stream.str();
+}
+
+/// Given a declaration \p D, return a human-readable string representing the
+/// scope in which it is declared. If the declaration is in the global scope,
+/// return the string "global namespace".
+static llvm::Optional<std::string> getScopeName(const Decl *D) {
+ const DeclContext *DC = D->getDeclContext();
+
+ if (isa<TranslationUnitDecl>(DC))
+ return std::string("global namespace");
+ if (const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
+ return typeDeclToString(TD);
+ else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC))
+ return namedDeclQualifiedName(ND, "namespace");
+ else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
+ return namedDeclQualifiedName(FD, "function");
+
+ return llvm::None;
+}
+
+/// Generate a \p Hover object given the declaration \p D.
+static Hover getHoverContents(const Decl *D) {
+ Hover H;
+ llvm::Optional<std::string> NamedScope = getScopeName(D);
+
+ // Generate the "Declared in" section.
+ if (NamedScope) {
+ assert(!NamedScope->empty());
+
+ H.contents.value += "Declared in ";
+ H.contents.value += *NamedScope;
+ H.contents.value += "\n\n";
+ }
+
+ // We want to include the template in the Hover.
+ if (TemplateDecl *TD = D->getDescribedTemplate())
+ D = TD;
+
+ std::string DeclText;
+ llvm::raw_string_ostream OS(DeclText);
+
+ PrintingPolicy Policy =
+ printingPolicyForDecls(D->getASTContext().getPrintingPolicy());
+
+ D->print(OS, Policy);
+
+ OS.flush();
+
+ H.contents.value += DeclText;
+ return H;
+}
+
+/// Generate a \p Hover object given the type \p T.
+static Hover getHoverContents(QualType T, ASTContext &ASTCtx) {
+ Hover H;
+ std::string TypeText;
+ llvm::raw_string_ostream OS(TypeText);
+ PrintingPolicy Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
+ T.print(OS, Policy);
+ OS.flush();
+ H.contents.value += TypeText;
+ return H;
+}
+
+/// Generate a \p Hover object given the macro \p MacroInf.
+static Hover getHoverContents(StringRef MacroName) {
+ Hover H;
+
+ H.contents.value = "#define ";
+ H.contents.value += MacroName;
+
+ return H;
+}
+
+namespace {
+/// Computes the deduced type at a given location by visiting the relevant
+/// nodes. We use this to display the actual type when hovering over an "auto"
+/// keyword or "decltype()" expression.
+/// FIXME: This could have been a lot simpler by visiting AutoTypeLocs but it
+/// seems that the AutoTypeLocs that can be visited along with their AutoType do
+/// not have the deduced type set. Instead, we have to go to the appropriate
+/// DeclaratorDecl/FunctionDecl and work our back to the AutoType that does have
+/// a deduced type set. The AST should be improved to simplify this scenario.
+class DeducedTypeVisitor : public RecursiveASTVisitor<DeducedTypeVisitor> {
+ SourceLocation SearchedLocation;
+ llvm::Optional<QualType> DeducedType;
+
+public:
+ DeducedTypeVisitor(SourceLocation SearchedLocation)
+ : SearchedLocation(SearchedLocation) {}
+
+ llvm::Optional<QualType> getDeducedType() { return DeducedType; }
+
+ // Handle auto initializers:
+ //- auto i = 1;
+ //- decltype(auto) i = 1;
+ //- auto& i = 1;
+ bool VisitDeclaratorDecl(DeclaratorDecl *D) {
+ if (!D->getTypeSourceInfo() ||
+ D->getTypeSourceInfo()->getTypeLoc().getLocStart() != SearchedLocation)
+ return true;
+
+ auto DeclT = D->getType();
+ // "auto &" is represented as a ReferenceType containing an AutoType
+ if (const ReferenceType *RT = dyn_cast<ReferenceType>(DeclT.getTypePtr()))
+ DeclT = RT->getPointeeType();
+
+ const AutoType *AT = dyn_cast<AutoType>(DeclT.getTypePtr());
+ if (AT && !AT->getDeducedType().isNull()) {
+ // For auto, use the underlying type because the const& would be
+ // represented twice: written in the code and in the hover.
+ // Example: "const auto I = 1", we only want "int" when hovering on auto,
+ // not "const int".
+ //
+ // For decltype(auto), take the type as is because it cannot be written
+ // with qualifiers or references but its decuded type can be const-ref.
+ DeducedType = AT->isDecltypeAuto() ? DeclT : DeclT.getUnqualifiedType();
+ }
+ return true;
+ }
+
+ // Handle auto return types:
+ //- auto foo() {}
+ //- auto& foo() {}
+ //- auto foo() -> decltype(1+1) {}
+ //- operator auto() const { return 10; }
+ bool VisitFunctionDecl(FunctionDecl *D) {
+ if (!D->getTypeSourceInfo())
+ return true;
+ // Loc of auto in return type (c++14).
+ auto CurLoc = D->getReturnTypeSourceRange().getBegin();
+ // Loc of "auto" in operator auto()
+ if (CurLoc.isInvalid() && dyn_cast<CXXConversionDecl>(D))
+ CurLoc = D->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
+ // Loc of "auto" in function with traling return type (c++11).
+ if (CurLoc.isInvalid())
+ CurLoc = D->getSourceRange().getBegin();
+ if (CurLoc != SearchedLocation)
+ return true;
+
+ auto T = D->getReturnType();
+ // "auto &" is represented as a ReferenceType containing an AutoType.
+ if (const ReferenceType *RT = dyn_cast<ReferenceType>(T.getTypePtr()))
+ T = RT->getPointeeType();
+
+ const AutoType *AT = dyn_cast<AutoType>(T.getTypePtr());
+ if (AT && !AT->getDeducedType().isNull()) {
+ DeducedType = T.getUnqualifiedType();
+ } else { // auto in a trailing return type just points to a DecltypeType.
+ const DecltypeType *DT = dyn_cast<DecltypeType>(T.getTypePtr());
+ if (!DT->getUnderlyingType().isNull())
+ DeducedType = DT->getUnderlyingType();
+ }
+ return true;
+ }
+
+ // Handle non-auto decltype, e.g.:
+ // - auto foo() -> decltype(expr) {}
+ // - decltype(expr);
+ bool VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
+ if (TL.getBeginLoc() != SearchedLocation)
+ return true;
+
+ // A DecltypeType's underlying type can be another DecltypeType! E.g.
+ // int I = 0;
+ // decltype(I) J = I;
+ // decltype(J) K = J;
+ const DecltypeType *DT = dyn_cast<DecltypeType>(TL.getTypePtr());
+ while (DT && !DT->getUnderlyingType().isNull()) {
+ DeducedType = DT->getUnderlyingType();
+ DT = dyn_cast<DecltypeType>(DeducedType->getTypePtr());
+ }
+ return true;
+ }
+};
+} // namespace
+
+/// Retrieves the deduced type at a given location (auto, decltype).
+llvm::Optional<QualType> getDeducedType(ParsedAST &AST,
+ SourceLocation SourceLocationBeg) {
+ Token Tok;
+ auto &ASTCtx = AST.getASTContext();
+ // Only try to find a deduced type if the token is auto or decltype.
+ if (!SourceLocationBeg.isValid() ||
+ Lexer::getRawToken(SourceLocationBeg, Tok, ASTCtx.getSourceManager(),
+ ASTCtx.getLangOpts(), false) ||
+ !Tok.is(tok::raw_identifier)) {
+ return {};
+ }
+ AST.getPreprocessor().LookUpIdentifierInfo(Tok);
+ if (!(Tok.is(tok::kw_auto) || Tok.is(tok::kw_decltype)))
+ return {};
+
+ DeducedTypeVisitor V(SourceLocationBeg);
+ for (Decl *D : AST.getLocalTopLevelDecls())
+ V.TraverseDecl(D);
+ return V.getDeducedType();
+}
+
+Optional<Hover> getHover(ParsedAST &AST, Position Pos) {
+ const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
+ SourceLocation SourceLocationBeg =
+ getBeginningOfIdentifier(AST, Pos, SourceMgr.getMainFileID());
+ // Identified symbols at a specific position.
+ auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
+
+ if (!Symbols.Macros.empty())
+ return getHoverContents(Symbols.Macros[0].Name);
+
+ if (!Symbols.Decls.empty())
+ return getHoverContents(Symbols.Decls[0]);
+
+ auto DeducedType = getDeducedType(AST, SourceLocationBeg);
+ if (DeducedType && !DeducedType->isNull())
+ return getHoverContents(*DeducedType, AST.getASTContext());
+
+ return None;
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/XRefs.h b/src/third_party/llvm-project/clang-tools-extra/clangd/XRefs.h
new file mode 100644
index 0000000..d698a61
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/XRefs.h
@@ -0,0 +1,38 @@
+//===--- XRefs.h ------------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// Features that traverse references between symbols.
+//
+//===---------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_XREFS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_XREFS_H
+
+#include "ClangdUnit.h"
+#include "Protocol.h"
+#include "index/Index.h"
+#include "llvm/ADT/Optional.h"
+#include <vector>
+
+namespace clang {
+namespace clangd {
+
+/// Get definition of symbol at a specified \p Pos.
+std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
+ const SymbolIndex *Index = nullptr);
+
+/// Returns highlights for all usages of a symbol at \p Pos.
+std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
+ Position Pos);
+
+/// Get the hover information when hovering at \p Pos.
+llvm::Optional<Hover> getHover(ParsedAST &AST, Position Pos);
+
+} // namespace clangd
+} // namespace clang
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/launch.json b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/launch.json
new file mode 100644
index 0000000..cd6b87b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/launch.json
@@ -0,0 +1,28 @@
+// A launch configuration that compiles the extension and then opens it inside a new window
+{
+ "version": "0.1.0",
+ "configurations": [
+ {
+ "name": "Launch Extension",
+ "type": "extensionHost",
+ "request": "launch",
+ "runtimeExecutable": "${execPath}",
+ "args": ["--extensionDevelopmentPath=${workspaceRoot}" ],
+ "stopOnEntry": false,
+ "sourceMaps": true,
+ "outFiles": [ "${workspaceRoot}/out/src/**/*.js" ],
+ "preLaunchTask": "npm"
+ },
+ {
+ "name": "Launch Tests",
+ "type": "extensionHost",
+ "request": "launch",
+ "runtimeExecutable": "${execPath}",
+ "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ],
+ "stopOnEntry": false,
+ "sourceMaps": true,
+ "outFiles": [ "${workspaceRoot}/out/test/**/*.js" ],
+ "preLaunchTask": "npm"
+ }
+ ]
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/settings.json b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/settings.json
new file mode 100644
index 0000000..d137133
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/settings.json
@@ -0,0 +1,9 @@
+// Place your settings in this file to overwrite default and user settings.
+{
+ "files.exclude": {
+ "out": false // set this to true to hide the "out" folder with the compiled JS files
+ },
+ "search.exclude": {
+ "out": true // set this to false to include "out" folder in search results
+ }
+}
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/tasks.json b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/tasks.json
new file mode 100644
index 0000000..fb7f662
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/tasks.json
@@ -0,0 +1,30 @@
+// Available variables which can be used inside of strings.
+// ${workspaceRoot}: the root folder of the team
+// ${file}: the current opened file
+// ${fileBasename}: the current opened file's basename
+// ${fileDirname}: the current opened file's dirname
+// ${fileExtname}: the current opened file's extension
+// ${cwd}: the current working directory of the spawned process
+
+// A task runner that calls a custom npm script that compiles the extension.
+{
+ "version": "0.1.0",
+
+ // we want to run npm
+ "command": "npm",
+
+ // the command is a shell script
+ "isShellCommand": true,
+
+ // show the output window only if unrecognized errors occur.
+ "showOutput": "silent",
+
+ // we run the custom script "compile" as defined in package.json
+ "args": ["run", "compile", "--loglevel", "silent"],
+
+ // The tsc compiler is started in watching mode
+ "isWatching": true,
+
+ // use the standard tsc in watch mode problem matcher to find compile problems in the output.
+ "problemMatcher": "$tsc-watch"
+}
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/.vscodeignore b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/.vscodeignore
new file mode 100644
index 0000000..5ff3c19
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/.vscodeignore
@@ -0,0 +1,9 @@
+.vscode/**
+.vscode-test/**
+out/test/**
+test/**
+src/**
+**/*.map
+.gitignore
+tsconfig.json
+vsc-extension-quickstart.md
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/LICENSE b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/LICENSE
new file mode 100644
index 0000000..c558158
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 The LLVM Developers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/README.md b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/README.md
new file mode 100644
index 0000000..f950cb6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/README.md
@@ -0,0 +1,76 @@
+# vscode-clangd
+
+Provides C/C++ language IDE features for VS Code using [clangd](https://clang.llvm.org/extra/clangd.html).
+
+## Usage
+
+`vscode-clangd` provides the features designated by the [Language Server
+Protocol](https://github.com/Microsoft/language-server-protocol), such as
+code completion, code formatting and goto definition.
+
+**Note**: `clangd` is under heavy development, not all LSP features are
+implemented. See [Current Status](https://clang.llvm.org/extra/clangd.html#current-status)
+for details.
+
+To use `vscode-clangd` extension in VS Code, you need to install `vscode-clangd`
+from VS Code extension marketplace.
+
+`vscode-clangd` will attempt to find the `clangd` binary on your `PATH`.
+Alternatively, the `clangd` executable can be specified in your VS Code
+`settings.json` file:
+
+```json
+{
+ "clangd.path": "/absolute/path/to/clangd"
+}
+```
+
+To obtain `clangd` binary, please see the [installing Clangd](https://clang.llvm.org/extra/clangd.html#installing-clangd).
+
+## Development
+
+A guide of developing `vscode-clangd` extension.
+
+### Requirements
+
+* VS Code
+* node.js and npm
+
+### Steps
+
+1. Make sure you disable the installed `vscode-clangd` extension in VS Code.
+2. Make sure you have clangd in /usr/bin/clangd or edit src/extension.ts to
+point to the binary.
+3. In order to start a development instance of VS code extended with this, run:
+
+```bash
+ $ cd /path/to/clang-tools-extra/clangd/clients/clangd-vscode/
+ $ npm install
+ $ code .
+ # When VS Code starts, press <F5>.
+```
+
+## Publish to VS Code Marketplace
+
+New changes to `clangd-vscode` are not released until a new version is published
+to the marketplace.
+
+### Requirements
+
+* Make sure install the `vsce` command (`npm install -g vsce`)
+* `llvm-vs-code-extensions` account
+* Bump the version in `package.json`, and commit the change to upstream
+
+The extension is published under `llvm-vs-code-extensions` account, which is
+currently maintained by clangd developers. If you want to make a new release,
+please contact cfe-dev@lists.llvm.org.
+
+### Steps
+
+```bash
+ $ cd /path/to/clang-tools-extra/clangd/clients/clangd-vscode/
+ # For the first time, you need to login in the account. vsce will ask you for
+ the Personal Access Token, and remember it for future commands.
+ $ vsce login llvm-vs-code-extensions
+ $ vsce publish
+```
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/package.json b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/package.json
new file mode 100644
index 0000000..eeb5112
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/package.json
@@ -0,0 +1,79 @@
+{
+ "name": "vscode-clangd",
+ "displayName": "vscode-clangd",
+ "description": "Clang Language Server",
+ "version": "0.0.6",
+ "publisher": "llvm-vs-code-extensions",
+ "homepage": "https://clang.llvm.org/extra/clangd.html",
+ "engines": {
+ "vscode": "^1.18.0"
+ },
+ "categories": [
+ "Programming Languages",
+ "Linters",
+ "Snippets"
+ ],
+ "keywords": [
+ "C",
+ "C++",
+ "LSP",
+ "Clangd",
+ "LLVM"
+ ],
+ "activationEvents": [
+ "onLanguage:cpp",
+ "onLanguage:c"
+ ],
+ "main": "./out/src/extension",
+ "scripts": {
+ "vscode:prepublish": "tsc -p ./",
+ "compile": "tsc -watch -p ./",
+ "postinstall": "node ./node_modules/vscode/bin/install",
+ "test": "node ./node_modules/vscode/bin/test"
+ },
+ "dependencies": {
+ "vscode-languageclient": "^4.0.0",
+ "vscode-languageserver": "^4.0.0"
+ },
+ "devDependencies": {
+ "typescript": "^2.0.3",
+ "vscode": "^1.1.0",
+ "mocha": "^2.3.3",
+ "@types/node": "^6.0.40",
+ "@types/mocha": "^2.2.32"
+ },
+ "repository": {
+ "type": "svn",
+ "url": "http://llvm.org/svn/llvm-project/clang-tools-extra/trunk/clangd/clients/clangd-vscode/"
+ },
+ "contributes": {
+ "configuration": {
+ "type": "object",
+ "title": "clangd configuration",
+ "properties": {
+ "clangd.path": {
+ "type": "string",
+ "default": "clangd",
+ "description": "The path to clangd executable, e.g.: /usr/bin/clangd"
+ },
+ "clangd.arguments": {
+ "type": "array",
+ "default": [],
+ "items": {
+ "type": "string"
+ },
+ "description": "Arguments for clangd server"
+ },
+ "clangd.syncFileEvents": {
+ "type": "boolean",
+ "default": true,
+ "description": "Whether or not to send file events to clangd (File created, changed or deleted). This can be disabled for performance consideration."
+ },
+ "clangd.trace": {
+ "type": "string",
+ "description": "Names a file that clangd should log a performance trace to, in chrome trace-viewer JSON format."
+ }
+ }
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts
new file mode 100644
index 0000000..a126a19
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts
@@ -0,0 +1,58 @@
+import * as vscode from 'vscode';
+import * as vscodelc from 'vscode-languageclient';
+import { realpathSync } from 'fs';
+
+/**
+ * Method to get workspace configuration option
+ * @param option name of the option (e.g. for clangd.path should be path)
+ * @param defaultValue default value to return if option is not set
+ */
+function getConfig<T>(option: string, defaultValue?: any): T {
+ const config = vscode.workspace.getConfiguration('clangd');
+ return config.get<T>(option, defaultValue);
+}
+
+/**
+ * this method is called when your extension is activate
+ * your extension is activated the very first time the command is executed
+ */
+export function activate(context: vscode.ExtensionContext) {
+ const syncFileEvents = getConfig<boolean>('syncFileEvents', true);
+
+ const clangd: vscodelc.Executable = {
+ command: getConfig<string>('path'),
+ args: getConfig<string[]>('arguments')
+ };
+ const traceFile = getConfig<string>('trace');
+ if (!!traceFile) {
+ const trace = { CLANGD_TRACE: traceFile };
+ clangd.options = { env: { ...process.env, ...trace } };
+ }
+ const serverOptions: vscodelc.ServerOptions = clangd;
+
+ const filePattern: string = '**/*.{' +
+ ['cpp', 'c', 'cc', 'cxx', 'c++', 'm', 'mm', 'h', 'hh', 'hpp', 'hxx', 'inc'].join() + '}';
+ const clientOptions: vscodelc.LanguageClientOptions = {
+ // Register the server for C/C++ files
+ documentSelector: [{ scheme: 'file', pattern: filePattern }],
+ synchronize: !syncFileEvents ? undefined : {
+ fileEvents: vscode.workspace.createFileSystemWatcher(filePattern)
+ },
+ // Resolve symlinks for all files provided by clangd.
+ // This is a workaround for a bazel + clangd issue - bazel produces a symlink tree to build in,
+ // and when navigating to the included file, clangd passes its path inside the symlink tree
+ // rather than its filesystem path.
+ // FIXME: remove this once clangd knows enough about bazel to resolve the
+ // symlinks where needed (or if this causes problems for other workflows).
+ uriConverters: {
+ code2Protocol: (value: vscode.Uri) => value.toString(),
+ protocol2Code: (value: string) =>
+ vscode.Uri.file(realpathSync(vscode.Uri.parse(value).fsPath))
+ }
+ };
+
+ const clangdClient = new vscodelc.LanguageClient('Clang Language Server', serverOptions, clientOptions);
+ console.log('Clang Language Server is now active!');
+
+ const disposable = clangdClient.start();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/test/extension.test.ts b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/test/extension.test.ts
new file mode 100644
index 0000000..de4e068
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/test/extension.test.ts
@@ -0,0 +1,15 @@
+/** The module 'assert' provides assertion methods from node */
+import * as assert from 'assert';
+
+import * as vscode from 'vscode';
+import * as myExtension from '../src/extension';
+
+// TODO: add tests
+suite("Extension Tests", () => {
+
+ // Defines a Mocha unit test
+ test("Something 1", () => {
+ assert.equal(-1, [1, 2, 3].indexOf(5));
+ assert.equal(-1, [1, 2, 3].indexOf(0));
+ });
+});
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/test/index.ts b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/test/index.ts
new file mode 100644
index 0000000..50bae45
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/test/index.ts
@@ -0,0 +1,22 @@
+//
+// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
+//
+// This file is providing the test runner to use when running extension tests.
+// By default the test runner in use is Mocha based.
+//
+// You can provide your own test runner if you want to override it by exporting
+// a function run(testRoot: string, clb: (error:Error) => void) that the extension
+// host can call to run the tests. The test runner is expected to use console.log
+// to report the results back to the caller. When the tests are finished, return
+// a possible error to the callback or null if none.
+
+var testRunner = require('vscode/lib/testrunner');
+
+// You can directly control Mocha options by uncommenting the following lines
+// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
+testRunner.configure({
+ ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
+ useColors: true // colored output from test results
+});
+
+module.exports = testRunner;
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/tsconfig.json b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/tsconfig.json
new file mode 100644
index 0000000..0b05f30
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/tsconfig.json
@@ -0,0 +1,29 @@
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "target": "es6",
+ "outDir": "out",
+ "lib": [
+ "es6",
+ "es2015.core",
+ "es2015.collection",
+ "es2015.generator",
+ "es2015.iterable",
+ "es2015.promise",
+ "es2015.symbol",
+ "es2016.array.include"
+ ],
+ "sourceMap": true,
+ "rootDir": ".",
+ "alwaysStrict": true,
+ "noEmitOnError": true,
+ "noFallthroughCasesInSwitch": true,
+ "noImplicitAny": true,
+ "noImplicitReturns": true,
+ "noImplicitThis": true
+ },
+ "exclude": [
+ "node_modules",
+ ".vscode-test"
+ ]
+}
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/vsc-extension-quickstart.md b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/vsc-extension-quickstart.md
new file mode 100644
index 0000000..24675ec
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/clients/clangd-vscode/vsc-extension-quickstart.md
@@ -0,0 +1,33 @@
+# Toy VS Code Extension for clangd
+
+## What's in the folder
+* This folder contains all of the files necessary for your extension
+* `package.json` - this is the manifest file in which you declare your extension and command.
+The sample plugin registers a command and defines its title and command name. With this information
+VS Code can show the command in the command palette. It doesn’t yet need to load the plugin.
+* `src/extension.ts` - this is the main file where you will provide the implementation of your command.
+The file exports one function, `activate`, which is called the very first time your extension is
+activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`.
+We pass the function containing the implementation of the command as the second parameter to
+`registerCommand`.
+
+## Get up and running straight away
+* press `F5` to open a new window with your extension loaded
+* run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`
+* set breakpoints in your code inside `src/extension.ts` to debug your extension
+* find output from your extension in the debug console
+
+## Make changes
+* you can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`
+* you can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes
+
+## Explore the API
+* you can open the full set of our API when you open the file `node_modules/vscode/vscode.d.ts`
+
+## Run tests
+* open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Launch Tests`
+* press `F5` to run the tests in a new window with your extension loaded
+* see the output of the test result in the debug console
+* make changes to `test/extension.test.ts` or create new test files inside the `test` folder
+ * by convention, the test runner will only consider files matching the name pattern `**.test.ts`
+ * you can create folders inside the `test` folder to structure your tests any way you want
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/fuzzer/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clangd/fuzzer/CMakeLists.txt
new file mode 100644
index 0000000..ca76c97
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/fuzzer/CMakeLists.txt
@@ -0,0 +1,24 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+set(LLVM_LINK_COMPONENTS support)
+
+if(LLVM_USE_SANITIZE_COVERAGE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=fuzzer")
+endif()
+
+add_clang_executable(clangd-fuzzer
+ EXCLUDE_FROM_ALL
+ ClangdFuzzer.cpp
+ )
+
+target_link_libraries(clangd-fuzzer
+ PRIVATE
+ clangBasic
+ clangDaemon
+ clangFormat
+ clangFrontend
+ clangSema
+ clangTooling
+ clangToolingCore
+ ${LLVM_LIB_FUZZING_ENGINE}
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/fuzzer/ClangdFuzzer.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/fuzzer/ClangdFuzzer.cpp
new file mode 100644
index 0000000..86f6107
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/fuzzer/ClangdFuzzer.cpp
@@ -0,0 +1,37 @@
+//===-- ClangdFuzzer.cpp - Fuzz clangd ------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements a function that runs clangd on a single input.
+/// This function is then linked into the Fuzzer library.
+///
+//===----------------------------------------------------------------------===//
+
+#include "ClangdLSPServer.h"
+#include "ClangdServer.h"
+#include "CodeComplete.h"
+#include <sstream>
+#include <stdio.h>
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
+ if (size == 0)
+ return 0;
+
+ clang::clangd::JSONOutput Out(llvm::nulls(), llvm::nulls(),
+ clang::clangd::Logger::Error, nullptr);
+ clang::clangd::CodeCompleteOptions CCOpts;
+ CCOpts.EnableSnippets = false;
+ clang::clangd::ClangdServer::Options Opts;
+
+ // Initialize and run ClangdLSPServer.
+ clang::clangd::ClangdLSPServer LSPServer(Out, CCOpts, llvm::None, Opts);
+ // fmemopen isn't portable, but I think we only run the fuzzer on Linux.
+ LSPServer.run(fmemopen(data, size, "r"));
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/global-symbol-builder/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clangd/global-symbol-builder/CMakeLists.txt
new file mode 100644
index 0000000..c81da16
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/global-symbol-builder/CMakeLists.txt
@@ -0,0 +1,20 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../)
+
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_executable(global-symbol-builder
+ GlobalSymbolBuilderMain.cpp
+ )
+
+target_link_libraries(global-symbol-builder
+ PRIVATE
+ clangAST
+ clangIndex
+ clangDaemon
+ clangBasic
+ clangFrontend
+ clangLex
+ clangTooling
+)
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp
new file mode 100644
index 0000000..0cc0480
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp
@@ -0,0 +1,199 @@
+//===--- GlobalSymbolBuilderMain.cpp -----------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// GlobalSymbolBuilder is a tool to generate YAML-format symbols across the
+// whole project. This tools is for **experimental** only. Don't use it in
+// production code.
+//
+//===---------------------------------------------------------------------===//
+
+#include "index/CanonicalIncludes.h"
+#include "index/Index.h"
+#include "index/Merge.h"
+#include "index/SymbolCollector.h"
+#include "index/SymbolYAML.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Index/IndexDataConsumer.h"
+#include "clang/Index/IndexingAction.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Execution.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace llvm;
+using namespace clang::tooling;
+using clang::clangd::SymbolSlab;
+
+namespace clang {
+namespace clangd {
+namespace {
+
+static llvm::cl::opt<std::string> AssumedHeaderDir(
+ "assume-header-dir",
+ llvm::cl::desc("The index includes header that a symbol is defined in. "
+ "If the absolute path cannot be determined (e.g. an "
+ "in-memory VFS) then the relative path is resolved against "
+ "this directory, which must be absolute. If this flag is "
+ "not given, such headers will have relative paths."),
+ llvm::cl::init(""));
+
+class SymbolIndexActionFactory : public tooling::FrontendActionFactory {
+public:
+ SymbolIndexActionFactory(tooling::ExecutionContext *Ctx) : Ctx(Ctx) {}
+
+ clang::FrontendAction *create() override {
+ // Wraps the index action and reports collected symbols to the execution
+ // context at the end of each translation unit.
+ class WrappedIndexAction : public WrapperFrontendAction {
+ public:
+ WrappedIndexAction(std::shared_ptr<SymbolCollector> C,
+ std::unique_ptr<CanonicalIncludes> Includes,
+ const index::IndexingOptions &Opts,
+ tooling::ExecutionContext *Ctx)
+ : WrapperFrontendAction(
+ index::createIndexingAction(C, Opts, nullptr)),
+ Ctx(Ctx), Collector(C), Includes(std::move(Includes)),
+ PragmaHandler(collectIWYUHeaderMaps(this->Includes.get())) {}
+
+ std::unique_ptr<ASTConsumer>
+ CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
+ CI.getPreprocessor().addCommentHandler(PragmaHandler.get());
+ return WrapperFrontendAction::CreateASTConsumer(CI, InFile);
+ }
+
+ bool BeginInvocation(CompilerInstance &CI) override {
+ // We want all comments, not just the doxygen ones.
+ CI.getLangOpts().CommentOpts.ParseAllComments = true;
+ return WrapperFrontendAction::BeginInvocation(CI);
+ }
+
+ void EndSourceFileAction() override {
+ WrapperFrontendAction::EndSourceFileAction();
+
+ const auto &CI = getCompilerInstance();
+ if (CI.hasDiagnostics() &&
+ CI.getDiagnostics().hasUncompilableErrorOccurred()) {
+ llvm::errs()
+ << "Found uncompilable errors in the translation unit. Igoring "
+ "collected symbols...\n";
+ return;
+ }
+
+ auto Symbols = Collector->takeSymbols();
+ for (const auto &Sym : Symbols) {
+ Ctx->reportResult(Sym.ID.str(), SymbolToYAML(Sym));
+ }
+ }
+
+ private:
+ tooling::ExecutionContext *Ctx;
+ std::shared_ptr<SymbolCollector> Collector;
+ std::unique_ptr<CanonicalIncludes> Includes;
+ std::unique_ptr<CommentHandler> PragmaHandler;
+ };
+
+ index::IndexingOptions IndexOpts;
+ IndexOpts.SystemSymbolFilter =
+ index::IndexingOptions::SystemSymbolFilterKind::All;
+ IndexOpts.IndexFunctionLocals = false;
+ auto CollectorOpts = SymbolCollector::Options();
+ CollectorOpts.FallbackDir = AssumedHeaderDir;
+ CollectorOpts.CollectIncludePath = true;
+ CollectorOpts.CountReferences = true;
+ CollectorOpts.Origin = SymbolOrigin::Static;
+ auto Includes = llvm::make_unique<CanonicalIncludes>();
+ addSystemHeadersMapping(Includes.get());
+ CollectorOpts.Includes = Includes.get();
+ return new WrappedIndexAction(
+ std::make_shared<SymbolCollector>(std::move(CollectorOpts)),
+ std::move(Includes), IndexOpts, Ctx);
+ }
+
+ tooling::ExecutionContext *Ctx;
+};
+
+// Combine occurrences of the same symbol across translation units.
+SymbolSlab mergeSymbols(tooling::ToolResults *Results) {
+ SymbolSlab::Builder UniqueSymbols;
+ llvm::BumpPtrAllocator Arena;
+ Symbol::Details Scratch;
+ Results->forEachResult([&](llvm::StringRef Key, llvm::StringRef Value) {
+ Arena.Reset();
+ llvm::yaml::Input Yin(Value, &Arena);
+ auto Sym = clang::clangd::SymbolFromYAML(Yin, Arena);
+ clang::clangd::SymbolID ID;
+ Key >> ID;
+ if (const auto *Existing = UniqueSymbols.find(ID))
+ UniqueSymbols.insert(mergeSymbol(*Existing, Sym, &Scratch));
+ else
+ UniqueSymbols.insert(Sym);
+ });
+ return std::move(UniqueSymbols).build();
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
+
+int main(int argc, const char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+
+ const char *Overview = R"(
+ This is an **experimental** tool to generate YAML-format project-wide symbols
+ for clangd (global code completion). It would be changed and deprecated
+ eventually. Don't use it in production code!
+
+ Example usage for building index for the whole project using CMake compile
+ commands:
+
+ $ global-symbol-builder --executor=all-TUs compile_commands.json > index.yaml
+
+ Example usage for file sequence index without flags:
+
+ $ global-symbol-builder File1.cpp File2.cpp ... FileN.cpp > index.yaml
+
+ Note: only symbols from header files will be collected.
+ )";
+
+ auto Executor = clang::tooling::createExecutorFromCommandLineArgs(
+ argc, argv, cl::GeneralCategory, Overview);
+
+ if (!Executor) {
+ llvm::errs() << llvm::toString(Executor.takeError()) << "\n";
+ return 1;
+ }
+
+ if (!clang::clangd::AssumedHeaderDir.empty() &&
+ !llvm::sys::path::is_absolute(clang::clangd::AssumedHeaderDir)) {
+ llvm::errs() << "--assume-header-dir must be an absolute path.\n";
+ return 1;
+ }
+
+ // Map phase: emit symbols found in each translation unit.
+ auto Err = Executor->get()->execute(
+ llvm::make_unique<clang::clangd::SymbolIndexActionFactory>(
+ Executor->get()->getExecutionContext()));
+ if (Err) {
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ }
+
+ // Reduce phase: combine symbols using the ID as a key.
+ auto UniqueSymbols =
+ clang::clangd::mergeSymbols(Executor->get()->getToolResults());
+
+ // Output phase: emit YAML for result symbols.
+ SymbolsToYAML(UniqueSymbols, llvm::outs());
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/CanonicalIncludes.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/index/CanonicalIncludes.cpp
new file mode 100644
index 0000000..a3493e3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/CanonicalIncludes.cpp
@@ -0,0 +1,813 @@
+//===-- CanonicalIncludes.h - remap #inclue headers--------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CanonicalIncludes.h"
+#include "../Headers.h"
+#include "clang/Driver/Types.h"
+#include "llvm/Support/Regex.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+const char IWYUPragma[] = "// IWYU pragma: private, include ";
+} // namespace
+
+void CanonicalIncludes::addMapping(llvm::StringRef Path,
+ llvm::StringRef CanonicalPath) {
+ addRegexMapping((llvm::Twine("^") + llvm::Regex::escape(Path) + "$").str(),
+ CanonicalPath);
+}
+
+void CanonicalIncludes::addRegexMapping(llvm::StringRef RE,
+ llvm::StringRef CanonicalPath) {
+ this->RegexHeaderMappingTable.emplace_back(llvm::Regex(RE), CanonicalPath);
+}
+
+void CanonicalIncludes::addSymbolMapping(llvm::StringRef QualifiedName,
+ llvm::StringRef CanonicalPath) {
+ this->SymbolMapping[QualifiedName] = CanonicalPath;
+}
+
+llvm::StringRef
+CanonicalIncludes::mapHeader(llvm::ArrayRef<std::string> Headers,
+ llvm::StringRef QualifiedName) const {
+ assert(!Headers.empty());
+ auto SE = SymbolMapping.find(QualifiedName);
+ if (SE != SymbolMapping.end())
+ return SE->second;
+ std::lock_guard<std::mutex> Lock(RegexMutex);
+ // Find the first header such that the extension is not '.inc', and isn't a
+ // recognized non-header file
+ auto I =
+ std::find_if(Headers.begin(), Headers.end(), [](llvm::StringRef Include) {
+ // Skip .inc file whose including header file should
+ // be #included instead.
+ return !Include.endswith(".inc");
+ });
+ if (I == Headers.end())
+ return Headers[0]; // Fallback to the declaring header.
+ StringRef Header = *I;
+ // If Header is not expected be included (e.g. .cc file), we fall back to
+ // the declaring header.
+ StringRef Ext = llvm::sys::path::extension(Header).trim('.');
+ // Include-able headers must have precompile type. Treat files with
+ // non-recognized extenstions (TY_INVALID) as headers.
+ auto ExtType = driver::types::lookupTypeForExtension(Ext);
+ if ((ExtType != driver::types::TY_INVALID) &&
+ !driver::types::onlyPrecompileType(ExtType))
+ return Headers[0];
+ for (auto &Entry : RegexHeaderMappingTable) {
+#ifndef NDEBUG
+ std::string Dummy;
+ assert(Entry.first.isValid(Dummy) && "Regex should never be invalid!");
+#endif
+ if (Entry.first.match(Header))
+ return Entry.second;
+ }
+ return Header;
+}
+
+std::unique_ptr<CommentHandler>
+collectIWYUHeaderMaps(CanonicalIncludes *Includes) {
+ class PragmaCommentHandler : public clang::CommentHandler {
+ public:
+ PragmaCommentHandler(CanonicalIncludes *Includes) : Includes(Includes) {}
+
+ bool HandleComment(Preprocessor &PP, SourceRange Range) override {
+ StringRef Text =
+ Lexer::getSourceText(CharSourceRange::getCharRange(Range),
+ PP.getSourceManager(), PP.getLangOpts());
+ if (!Text.consume_front(IWYUPragma))
+ return false;
+ // FIXME(ioeric): resolve the header and store actual file path. For now,
+ // we simply assume the written header is suitable to be #included.
+ Includes->addMapping(PP.getSourceManager().getFilename(Range.getBegin()),
+ isLiteralInclude(Text) ? Text.str()
+ : ("\"" + Text + "\"").str());
+ return false;
+ }
+
+ private:
+ CanonicalIncludes *const Includes;
+ };
+ return llvm::make_unique<PragmaCommentHandler>(Includes);
+}
+
+void addSystemHeadersMapping(CanonicalIncludes *Includes) {
+ static const std::vector<std::pair<const char *, const char *>> SymbolMap = {
+ {"std::addressof", "<memory>"},
+ // Map symbols in <iosfwd> to their preferred includes.
+ {"std::basic_filebuf", "<fstream>"},
+ {"std::basic_fstream", "<fstream>"},
+ {"std::basic_ifstream", "<fstream>"},
+ {"std::basic_ofstream", "<fstream>"},
+ {"std::filebuf", "<fstream>"},
+ {"std::fstream", "<fstream>"},
+ {"std::ifstream", "<fstream>"},
+ {"std::ofstream", "<fstream>"},
+ {"std::wfilebuf", "<fstream>"},
+ {"std::wfstream", "<fstream>"},
+ {"std::wifstream", "<fstream>"},
+ {"std::wofstream", "<fstream>"},
+ {"std::basic_ios", "<ios>"},
+ {"std::ios", "<ios>"},
+ {"std::wios", "<ios>"},
+ {"std::basic_iostream", "<iostream>"},
+ {"std::iostream", "<iostream>"},
+ {"std::wiostream", "<iostream>"},
+ {"std::basic_istream", "<istream>"},
+ {"std::istream", "<istream>"},
+ {"std::wistream", "<istream>"},
+ {"std::istreambuf_iterator", "<iterator>"},
+ {"std::ostreambuf_iterator", "<iterator>"},
+ {"std::basic_ostream", "<ostream>"},
+ {"std::ostream", "<ostream>"},
+ {"std::wostream", "<ostream>"},
+ {"std::basic_istringstream", "<sstream>"},
+ {"std::basic_ostringstream", "<sstream>"},
+ {"std::basic_stringbuf", "<sstream>"},
+ {"std::basic_stringstream", "<sstream>"},
+ {"std::istringstream", "<sstream>"},
+ {"std::ostringstream", "<sstream>"},
+ {"std::stringbuf", "<sstream>"},
+ {"std::stringstream", "<sstream>"},
+ {"std::wistringstream", "<sstream>"},
+ {"std::wostringstream", "<sstream>"},
+ {"std::wstringbuf", "<sstream>"},
+ {"std::wstringstream", "<sstream>"},
+ {"std::basic_streambuf", "<streambuf>"},
+ {"std::streambuf", "<streambuf>"},
+ {"std::wstreambuf", "<streambuf>"},
+ {"std::uint_least16_t", "<cstdint>"}, // <type_traits> redeclares these
+ {"std::uint_least32_t", "<cstdint>"},
+ {"std::declval", "<utility>"},
+ };
+ for (const auto &Pair : SymbolMap)
+ Includes->addSymbolMapping(Pair.first, Pair.second);
+
+ static const std::vector<std::pair<const char *, const char *>>
+ SystemHeaderMap = {
+ {"include/__stddef_max_align_t.h$", "<cstddef>"},
+ {"include/__wmmintrin_aes.h$", "<wmmintrin.h>"},
+ {"include/__wmmintrin_pclmul.h$", "<wmmintrin.h>"},
+ {"include/adxintrin.h$", "<immintrin.h>"},
+ {"include/ammintrin.h$", "<ammintrin.h>"},
+ {"include/avx2intrin.h$", "<immintrin.h>"},
+ {"include/avx512bwintrin.h$", "<immintrin.h>"},
+ {"include/avx512cdintrin.h$", "<immintrin.h>"},
+ {"include/avx512dqintrin.h$", "<immintrin.h>"},
+ {"include/avx512erintrin.h$", "<immintrin.h>"},
+ {"include/avx512fintrin.h$", "<immintrin.h>"},
+ {"include/avx512ifmaintrin.h$", "<immintrin.h>"},
+ {"include/avx512ifmavlintrin.h$", "<immintrin.h>"},
+ {"include/avx512pfintrin.h$", "<immintrin.h>"},
+ {"include/avx512vbmiintrin.h$", "<immintrin.h>"},
+ {"include/avx512vbmivlintrin.h$", "<immintrin.h>"},
+ {"include/avx512vlbwintrin.h$", "<immintrin.h>"},
+ {"include/avx512vlcdintrin.h$", "<immintrin.h>"},
+ {"include/avx512vldqintrin.h$", "<immintrin.h>"},
+ {"include/avx512vlintrin.h$", "<immintrin.h>"},
+ {"include/avxintrin.h$", "<immintrin.h>"},
+ {"include/bmi2intrin.h$", "<x86intrin.h>"},
+ {"include/bmiintrin.h$", "<x86intrin.h>"},
+ {"include/emmintrin.h$", "<emmintrin.h>"},
+ {"include/f16cintrin.h$", "<emmintrin.h>"},
+ {"include/float.h$", "<cfloat>"},
+ {"include/fma4intrin.h$", "<x86intrin.h>"},
+ {"include/fmaintrin.h$", "<immintrin.h>"},
+ {"include/fxsrintrin.h$", "<immintrin.h>"},
+ {"include/ia32intrin.h$", "<x86intrin.h>"},
+ {"include/immintrin.h$", "<immintrin.h>"},
+ {"include/inttypes.h$", "<cinttypes>"},
+ {"include/limits.h$", "<climits>"},
+ {"include/lzcntintrin.h$", "<x86intrin.h>"},
+ {"include/mm3dnow.h$", "<mm3dnow.h>"},
+ {"include/mm_malloc.h$", "<mm_malloc.h>"},
+ {"include/mmintrin.h$", "<mmintrin>"},
+ {"include/mwaitxintrin.h$", "<x86intrin.h>"},
+ {"include/pkuintrin.h$", "<immintrin.h>"},
+ {"include/pmmintrin.h$", "<pmmintrin.h>"},
+ {"include/popcntintrin.h$", "<popcntintrin.h>"},
+ {"include/prfchwintrin.h$", "<x86intrin.h>"},
+ {"include/rdseedintrin.h$", "<x86intrin.h>"},
+ {"include/rtmintrin.h$", "<immintrin.h>"},
+ {"include/shaintrin.h$", "<immintrin.h>"},
+ {"include/smmintrin.h$", "<smmintrin.h>"},
+ {"include/stdalign.h$", "<cstdalign>"},
+ {"include/stdarg.h$", "<cstdarg>"},
+ {"include/stdbool.h$", "<cstdbool>"},
+ {"include/stddef.h$", "<cstddef>"},
+ {"include/stdint.h$", "<cstdint>"},
+ {"include/tbmintrin.h$", "<x86intrin.h>"},
+ {"include/tmmintrin.h$", "<tmmintrin.h>"},
+ {"include/wmmintrin.h$", "<wmmintrin.h>"},
+ {"include/x86intrin.h$", "<x86intrin.h>"},
+ {"include/xmmintrin.h$", "<xmmintrin.h>"},
+ {"include/xopintrin.h$", "<x86intrin.h>"},
+ {"include/xsavecintrin.h$", "<immintrin.h>"},
+ {"include/xsaveintrin.h$", "<immintrin.h>"},
+ {"include/xsaveoptintrin.h$", "<immintrin.h>"},
+ {"include/xsavesintrin.h$", "<immintrin.h>"},
+ {"include/xtestintrin.h$", "<immintrin.h>"},
+ {"include/_G_config.h$", "<cstdio>"},
+ {"include/assert.h$", "<cassert>"},
+ {"algorithm$", "<algorithm>"},
+ {"valarray$", "<valarray>"},
+ {"array$", "<array>"},
+ {"atomic$", "<atomic>"},
+ {"backward/auto_ptr.h$", "<memory>"},
+ {"backward/binders.h$", "<string>"},
+ {"bits/algorithmfwd.h$", "<algorithm>"},
+ {"bits/alloc_traits.h$", "<memory>"},
+ {"bits/allocated_ptr.h$", "<memory>"},
+ {"bits/allocator.h$", "<allocator>"},
+ {"bits/atomic_base.h$", "<atomic>"},
+ {"bits/atomic_lockfree_defines.h$", "<exception>"},
+ {"bits/atomic_futex.h$", "<atomic>"},
+ {"bits/basic_ios.h$", "<ios>"},
+ {"bits/basic_ios.tcc$", "<ios>"},
+ {"bits/basic_string.h$", "<string>"},
+ {"bits/basic_string.tcc$", "<string>"},
+ {"bits/char_traits.h$", "<string>"},
+ {"bits/codecvt.h$", "<locale>"},
+ {"bits/concept_check.h$", "<numeric>"},
+ {"bits/cpp_type_traits.h$", "<cmath>"},
+ {"bits/cxxabi_forced.h$", "<cxxabi.h>"},
+ {"bits/deque.tcc$", "<deque>"},
+ {"bits/exception.h$", "<exception>"},
+ {"bits/exception_defines.h$", "<exception>"},
+ {"bits/exception_ptr.h$", "<exception>"},
+ {"bits/forward_list.h$", "<forward_list>"},
+ {"bits/forward_list.tcc$", "<forward_list>"},
+ {"bits/fstream.tcc$", "<fstream>"},
+ {"bits/functexcept.h$", "<list>"},
+ {"bits/functional_hash.h$", "<functional>"},
+ {"bits/gslice.h$", "<valarray>"},
+ {"bits/gslice_array.h$", "<valarray>"},
+ {"bits/hash_bytes.h$", "<typeinfo>"},
+ {"bits/hashtable.h$", "<unordered_set>"},
+ {"bits/hashtable_policy.h$", "<unordered_set>"},
+ {"bits/indirect_array.h$", "<valarray>"},
+ {"bits/invoke.h$", "<functional>"},
+ {"bits/ios_base.h$", "<ios>"},
+ {"bits/istream.tcc$", "<istream>"},
+ {"bits/list.tcc$", "<list>"},
+ {"bits/locale_classes.h$", "<locale>"},
+ {"bits/locale_classes.tcc$", "<locale>"},
+ {"bits/locale_conv.h$", "<locale>"},
+ {"bits/locale_facets.h$", "<locale>"},
+ {"bits/locale_facets.tcc$", "<locale>"},
+ {"bits/locale_facets_nonio.h$", "<locale>"},
+ {"bits/locale_facets_nonio.tcc$", "<locale>"},
+ {"bits/localefwd.h$", "<locale>"},
+ {"bits/mask_array.h$", "<valarray>"},
+ {"bits/memoryfwd.h$", "<memory>"},
+ {"bits/move.h$", "<utility>"},
+ {"bits/nested_exception.h$", "<exception>"},
+ {"bits/ostream.tcc$", "<ostream>"},
+ {"bits/ostream_insert.h$", "<ostream>"},
+ {"bits/parse_numbers.h$", "<chrono>"},
+ {"bits/postypes.h$", "<ios>"},
+ {"bits/predefined_ops.h$", "<algorithm>"},
+ {"bits/ptr_traits.h$", "<memory>"},
+ {"bits/quoted_string.h$", "<iomanip>"},
+ {"bits/random.h$", "<random>"},
+ {"bits/random.tcc$", "<random>"},
+ {"bits/range_access.h$", "<iterator>"},
+ {"bits/refwrap.h$", "<functional>"},
+ {"bits/regex.h$", "<regex>"},
+ {"bits/regex_automaton.h$", "<regex>"},
+ {"bits/regex_compiler.h$", "<regex>"},
+ {"bits/regex_constants.h$", "<regex>"},
+ {"bits/regex_cursor.h$", "<regex>"},
+ {"bits/regex_error.h$", "<regex>"},
+ {"bits/regex_executor.h$", "<regex>"},
+ {"bits/regex_grep_matcher.h$", "<regex>"},
+ {"bits/regex_grep_matcher.tcc$", "<regex>"},
+ {"bits/regex_nfa.h$", "<regex>"},
+ {"bits/regex_scanner.h$", "<regex>"},
+ {"bits/shared_ptr.h$", "<memory>"},
+ {"bits/shared_ptr_base.h$", "<memory>"},
+ {"bits/shared_ptr_atomic.h$", "<atomic>"},
+ {"bits/slice_array.h$", "<valarray>"},
+ {"bits/sstream.tcc$", "<sstream>"},
+ {"bits/std_abs.h$", "<cmath>"},
+ {"bits/std_function.h$", "<functional>"},
+ {"bits/std_mutex.h$", "<mutex>"},
+ {"bits/stl_algo.h$", "<algorithm>"},
+ {"bits/stl_algobase.h$", "<algorithm>"},
+ {"bits/stl_bvector.h$", "<vector>"},
+ {"bits/stl_construct.h$", "<deque>"},
+ {"bits/stl_deque.h$", "<deque>"},
+ {"bits/stl_function.h$", "<functional>"},
+ {"bits/stl_heap.h$", "<heap>"},
+ {"bits/stl_iterator.h$", "<iterator>"},
+ {"bits/stl_iterator_base_funcs.h$", "<iterator>"},
+ {"bits/stl_iterator_base_types.h$", "<iterator>"},
+ {"bits/stl_list.h$", "<list>"},
+ {"bits/stl_map.h$", "<map>"},
+ {"bits/stl_multimap.h$", "<map>"},
+ {"bits/stl_multiset.h$", "<set>"},
+ {"bits/stl_numeric.h$", "<numeric>"},
+ {"bits/stl_pair.h$", "<utility>"},
+ {"bits/stl_queue.h$", "<queue>"},
+ {"bits/stl_raw_storage_iter.h$", "<memory>"},
+ {"bits/stl_relops.h$", "<utility>"},
+ {"bits/stl_set.h$", "<set>"},
+ {"bits/stl_stack.h$", "<stack>"},
+ {"bits/stl_tempbuf.h$", "<memory>"},
+ {"bits/stl_tree.h$", "<map>"},
+ {"bits/stl_uninitialized.h$", "<memory>"},
+ {"bits/stl_vector.h$", "<vector>"},
+ {"bits/stream_iterator.h$", "<iterator>"},
+ {"bits/streambuf.tcc$", "<streambuf>"},
+ {"bits/streambuf_iterator.h$", "<iterator>"},
+ {"bits/stringfwd.h$", "<string>"},
+ {"bits/uniform_int_dist.h$", "<random>"},
+ {"bits/unique_ptr.h$", "<memory>"},
+ {"bits/unordered_map.h$", "<unordered_map>"},
+ {"bits/unordered_set.h$", "<unordered_set>"},
+ {"bits/uses_allocator.h$", "<memory>"},
+ {"bits/valarray_after.h$", "<valarray>"},
+ {"bits/valarray_array.h$", "<valarray>"},
+ {"bits/valarray_array.tcc$", "<valarray>"},
+ {"bits/valarray_before.h$", "<valarray>"},
+ {"bits/vector.tcc$", "<vector>"},
+ {"bitset$", "<bitset>"},
+ {"ccomplex$", "<ccomplex>"},
+ {"cctype$", "<cctype>"},
+ {"cerrno$", "<cerrno>"},
+ {"cfenv$", "<cfenv>"},
+ {"cfloat$", "<cfloat>"},
+ {"chrono$", "<chrono>"},
+ {"cinttypes$", "<cinttypes>"},
+ {"climits$", "<climits>"},
+ {"clocale$", "<clocale>"},
+ {"cmath$", "<cmath>"},
+ {"complex$", "<complex>"},
+ {"complex.h$", "<complex.h>"},
+ {"condition_variable$", "<condition_variable>"},
+ {"csetjmp$", "<csetjmp>"},
+ {"csignal$", "<csignal>"},
+ {"cstdalign$", "<cstdalign>"},
+ {"cstdarg$", "<cstdarg>"},
+ {"cstdbool$", "<cstdbool>"},
+ {"cstdint$", "<cstdint>"},
+ {"cstdio$", "<cstdio>"},
+ {"cstdlib$", "<cstdlib>"},
+ {"cstring$", "<cstring>"},
+ {"ctgmath$", "<ctgmath>"},
+ {"ctime$", "<ctime>"},
+ {"cwchar$", "<cwchar>"},
+ {"cwctype$", "<cwctype>"},
+ {"cxxabi.h$", "<cxxabi.h>"},
+ {"debug/debug.h$", "<numeric>"},
+ {"debug/map.h$", "<map>"},
+ {"debug/multimap.h$", "<multimap>"},
+ {"debug/multiset.h$", "<multiset>"},
+ {"debug/set.h$", "<set>"},
+ {"deque$", "<deque>"},
+ {"exception$", "<exception>"},
+ {"ext/alloc_traits.h$", "<deque>"},
+ {"ext/atomicity.h$", "<memory>"},
+ {"ext/concurrence.h$", "<memory>"},
+ {"ext/new_allocator.h$", "<string>"},
+ {"ext/numeric_traits.h$", "<list>"},
+ {"ext/string_conversions.h$", "<string>"},
+ {"ext/type_traits.h$", "<cmath>"},
+ {"fenv.h$", "<fenv.h>"},
+ {"forward_list$", "<forward_list>"},
+ {"fstream$", "<fstream>"},
+ {"functional$", "<functional>"},
+ {"future$", "<future>"},
+ {"initializer_list$", "<initializer_list>"},
+ {"iomanip$", "<iomanip>"},
+ {"ios$", "<ios>"},
+ {"iosfwd$", "<iosfwd>"},
+ {"iostream$", "<iostream>"},
+ {"istream$", "<istream>"},
+ {"iterator$", "<iterator>"},
+ {"limits$", "<limits>"},
+ {"list$", "<list>"},
+ {"locale$", "<locale>"},
+ {"map$", "<map>"},
+ {"memory$", "<memory>"},
+ {"shared_mutex$", "<shared_mutex>"},
+ {"mutex$", "<mutex>"},
+ {"new$", "<new>"},
+ {"numeric$", "<numeric>"},
+ {"ostream$", "<ostream>"},
+ {"queue$", "<queue>"},
+ {"random$", "<random>"},
+ {"ratio$", "<ratio>"},
+ {"regex$", "<regex>"},
+ {"scoped_allocator$", "<scoped_allocator>"},
+ {"set$", "<set>"},
+ {"sstream$", "<sstream>"},
+ {"stack$", "<stack>"},
+ {"stdexcept$", "<stdexcept>"},
+ {"streambuf$", "<streambuf>"},
+ {"string$", "<string>"},
+ {"system_error$", "<system_error>"},
+ {"tgmath.h$", "<tgmath.h>"},
+ {"thread$", "<thread>"},
+ {"tuple$", "<tuple>"},
+ {"type_traits$", "<type_traits>"},
+ {"typeindex$", "<typeindex>"},
+ {"typeinfo$", "<typeinfo>"},
+ {"unordered_map$", "<unordered_map>"},
+ {"unordered_set$", "<unordered_set>"},
+ {"utility$", "<utility>"},
+ {"valarray$", "<valarray>"},
+ {"vector$", "<vector>"},
+ {"include/complex.h$", "<complex.h>"},
+ {"include/ctype.h$", "<cctype>"},
+ {"include/errno.h$", "<cerrno>"},
+ {"include/fenv.h$", "<fenv.h>"},
+ {"include/inttypes.h$", "<cinttypes>"},
+ {"include/libio.h$", "<cstdio>"},
+ {"include/limits.h$", "<climits>"},
+ {"include/locale.h$", "<clocale>"},
+ {"include/math.h$", "<cmath>"},
+ {"include/setjmp.h$", "<csetjmp>"},
+ {"include/signal.h$", "<csignal>"},
+ {"include/stdint.h$", "<cstdint>"},
+ {"include/stdio.h$", "<cstdio>"},
+ {"include/stdlib.h$", "<cstdlib>"},
+ {"include/string.h$", "<cstring>"},
+ {"include/time.h$", "<ctime>"},
+ {"include/wchar.h$", "<cwchar>"},
+ {"include/wctype.h$", "<cwctype>"},
+ {"bits/cmathcalls.h$", "<complex.h>"},
+ {"bits/errno.h$", "<cerrno>"},
+ {"bits/fenv.h$", "<fenv.h>"},
+ {"bits/huge_val.h$", "<cmath>"},
+ {"bits/huge_valf.h$", "<cmath>"},
+ {"bits/huge_vall.h$", "<cmath>"},
+ {"bits/inf.h$", "<cmath>"},
+ {"bits/local_lim.h$", "<climits>"},
+ {"bits/locale.h$", "<clocale>"},
+ {"bits/mathcalls.h$", "<math.h>"},
+ {"bits/mathdef.h$", "<cmath>"},
+ {"bits/nan.h$", "<cmath>"},
+ {"bits/posix1_lim.h$", "<climits>"},
+ {"bits/posix2_lim.h$", "<climits>"},
+ {"bits/setjmp.h$", "<csetjmp>"},
+ {"bits/sigaction.h$", "<csignal>"},
+ {"bits/sigcontext.h$", "<csignal>"},
+ {"bits/siginfo.h$", "<csignal>"},
+ {"bits/signum.h$", "<csignal>"},
+ {"bits/sigset.h$", "<csignal>"},
+ {"bits/sigstack.h$", "<csignal>"},
+ {"bits/stdio_lim.h$", "<cstdio>"},
+ {"bits/sys_errlist.h$", "<cstdio>"},
+ {"bits/time.h$", "<ctime>"},
+ {"bits/timex.h$", "<ctime>"},
+ {"bits/typesizes.h$", "<cstdio>"},
+ {"bits/wchar.h$", "<cwchar>"},
+ {"bits/wordsize.h$", "<csetjmp>"},
+ {"bits/xopen_lim.h$", "<climits>"},
+ {"include/xlocale.h$", "<cstring>"},
+ {"bits/atomic_word.h$", "<memory>"},
+ {"bits/basic_file.h$", "<fstream>"},
+ {"bits/c\\+\\+allocator.h$", "<string>"},
+ {"bits/c\\+\\+config.h$", "<cstddef>"},
+ {"bits/c\\+\\+io.h$", "<ios>"},
+ {"bits/c\\+\\+locale.h$", "<locale>"},
+ {"bits/cpu_defines.h$", "<iosfwd>"},
+ {"bits/ctype_base.h$", "<locale>"},
+ {"bits/cxxabi_tweaks.h$", "<cxxabi.h>"},
+ {"bits/error_constants.h$", "<system_error>"},
+ {"bits/gthr-default.h$", "<memory>"},
+ {"bits/gthr.h$", "<memory>"},
+ {"bits/opt_random.h$", "<random>"},
+ {"bits/os_defines.h$", "<iosfwd>"},
+ // GNU C headers
+ {"include/aio.h$", "<aio.h>"},
+ {"include/aliases.h$", "<aliases.h>"},
+ {"include/alloca.h$", "<alloca.h>"},
+ {"include/ar.h$", "<ar.h>"},
+ {"include/argp.h$", "<argp.h>"},
+ {"include/argz.h$", "<argz.h>"},
+ {"include/arpa/nameser.h$", "<resolv.h>"},
+ {"include/arpa/nameser_compat.h$", "<resolv.h>"},
+ {"include/byteswap.h$", "<byteswap.h>"},
+ {"include/cpio.h$", "<cpio.h>"},
+ {"include/crypt.h$", "<crypt.h>"},
+ {"include/dirent.h$", "<dirent.h>"},
+ {"include/dlfcn.h$", "<dlfcn.h>"},
+ {"include/elf.h$", "<elf.h>"},
+ {"include/endian.h$", "<endian.h>"},
+ {"include/envz.h$", "<envz.h>"},
+ {"include/err.h$", "<err.h>"},
+ {"include/error.h$", "<error.h>"},
+ {"include/execinfo.h$", "<execinfo.h>"},
+ {"include/fcntl.h$", "<fcntl.h>"},
+ {"include/features.h$", "<features.h>"},
+ {"include/fenv.h$", "<fenv.h>"},
+ {"include/fmtmsg.h$", "<fmtmsg.h>"},
+ {"include/fnmatch.h$", "<fnmatch.h>"},
+ {"include/fstab.h$", "<fstab.h>"},
+ {"include/fts.h$", "<fts.h>"},
+ {"include/ftw.h$", "<ftw.h>"},
+ {"include/gconv.h$", "<gconv.h>"},
+ {"include/getopt.h$", "<getopt.h>"},
+ {"include/glob.h$", "<glob.h>"},
+ {"include/grp.h$", "<grp.h>"},
+ {"include/gshadow.h$", "<gshadow.h>"},
+ {"include/iconv.h$", "<iconv.h>"},
+ {"include/ifaddrs.h$", "<ifaddrs.h>"},
+ {"include/kdb.h$", "<kdb.h>"},
+ {"include/langinfo.h$", "<langinfo.h>"},
+ {"include/libgen.h$", "<libgen.h>"},
+ {"include/libintl.h$", "<libintl.h>"},
+ {"include/link.h$", "<link.h>"},
+ {"include/malloc.h$", "<malloc.h>"},
+ {"include/mcheck.h$", "<mcheck.h>"},
+ {"include/memory.h$", "<memory.h>"},
+ {"include/mntent.h$", "<mntent.h>"},
+ {"include/monetary.h$", "<monetary.h>"},
+ {"include/mqueue.h$", "<mqueue.h>"},
+ {"include/netdb.h$", "<netdb.h>"},
+ {"include/netinet/in.h$", "<netinet/in.h>"},
+ {"include/nl_types.h$", "<nl_types.h>"},
+ {"include/nss.h$", "<nss.h>"},
+ {"include/obstack.h$", "<obstack.h>"},
+ {"include/panel.h$", "<panel.h>"},
+ {"include/paths.h$", "<paths.h>"},
+ {"include/printf.h$", "<printf.h>"},
+ {"include/profile.h$", "<profile.h>"},
+ {"include/pthread.h$", "<pthread.h>"},
+ {"include/pty.h$", "<pty.h>"},
+ {"include/pwd.h$", "<pwd.h>"},
+ {"include/re_comp.h$", "<re_comp.h>"},
+ {"include/regex.h$", "<regex.h>"},
+ {"include/regexp.h$", "<regexp.h>"},
+ {"include/resolv.h$", "<resolv.h>"},
+ {"include/rpc/netdb.h$", "<netdb.h>"},
+ {"include/sched.h$", "<sched.h>"},
+ {"include/search.h$", "<search.h>"},
+ {"include/semaphore.h$", "<semaphore.h>"},
+ {"include/sgtty.h$", "<sgtty.h>"},
+ {"include/shadow.h$", "<shadow.h>"},
+ {"include/spawn.h$", "<spawn.h>"},
+ {"include/stab.h$", "<stab.h>"},
+ {"include/stdc-predef.h$", "<stdc-predef.h>"},
+ {"include/stdio_ext.h$", "<stdio_ext.h>"},
+ {"include/strings.h$", "<strings.h>"},
+ {"include/stropts.h$", "<stropts.h>"},
+ {"include/sudo_plugin.h$", "<sudo_plugin.h>"},
+ {"include/sysexits.h$", "<sysexits.h>"},
+ {"include/tar.h$", "<tar.h>"},
+ {"include/tcpd.h$", "<tcpd.h>"},
+ {"include/term.h$", "<term.h>"},
+ {"include/term_entry.h$", "<term_entry.h>"},
+ {"include/termcap.h$", "<termcap.h>"},
+ {"include/termios.h$", "<termios.h>"},
+ {"include/thread_db.h$", "<thread_db.h>"},
+ {"include/tic.h$", "<tic.h>"},
+ {"include/ttyent.h$", "<ttyent.h>"},
+ {"include/uchar.h$", "<uchar.h>"},
+ {"include/ucontext.h$", "<ucontext.h>"},
+ {"include/ulimit.h$", "<ulimit.h>"},
+ {"include/unctrl.h$", "<unctrl.h>"},
+ {"include/unistd.h$", "<unistd.h>"},
+ {"include/utime.h$", "<utime.h>"},
+ {"include/utmp.h$", "<utmp.h>"},
+ {"include/utmpx.h$", "<utmpx.h>"},
+ {"include/values.h$", "<values.h>"},
+ {"include/wordexp.h$", "<wordexp.h>"},
+ {"fpu_control.h$", "<fpu_control.h>"},
+ {"ieee754.h$", "<ieee754.h>"},
+ {"include/xlocale.h$", "<xlocale.h>"},
+ {"gnu/lib-names.h$", "<gnu/lib-names.h>"},
+ {"gnu/libc-version.h$", "<gnu/libc-version.h>"},
+ {"gnu/option-groups.h$", "<gnu/option-groups.h>"},
+ {"gnu/stubs-32.h$", "<gnu/stubs-32.h>"},
+ {"gnu/stubs-64.h$", "<gnu/stubs-64.h>"},
+ {"gnu/stubs-x32.h$", "<gnu/stubs-x32.h>"},
+ {"include/rpc/auth_des.h$", "<rpc/auth_des.h>"},
+ {"include/rpc/rpc_msg.h$", "<rpc/rpc_msg.h>"},
+ {"include/rpc/pmap_clnt.h$", "<rpc/pmap_clnt.h>"},
+ {"include/rpc/rpc.h$", "<rpc/rpc.h>"},
+ {"include/rpc/types.h$", "<rpc/types.h>"},
+ {"include/rpc/auth_unix.h$", "<rpc/auth_unix.h>"},
+ {"include/rpc/key_prot.h$", "<rpc/key_prot.h>"},
+ {"include/rpc/pmap_prot.h$", "<rpc/pmap_prot.h>"},
+ {"include/rpc/auth.h$", "<rpc/auth.h>"},
+ {"include/rpc/svc_auth.h$", "<rpc/svc_auth.h>"},
+ {"include/rpc/xdr.h$", "<rpc/xdr.h>"},
+ {"include/rpc/pmap_rmt.h$", "<rpc/pmap_rmt.h>"},
+ {"include/rpc/des_crypt.h$", "<rpc/des_crypt.h>"},
+ {"include/rpc/svc.h$", "<rpc/svc.h>"},
+ {"include/rpc/rpc_des.h$", "<rpc/rpc_des.h>"},
+ {"include/rpc/clnt.h$", "<rpc/clnt.h>"},
+ {"include/scsi/scsi.h$", "<scsi/scsi.h>"},
+ {"include/scsi/sg.h$", "<scsi/sg.h>"},
+ {"include/scsi/scsi_ioctl.h$", "<scsi/scsi_ioctl>"},
+ {"include/netrose/rose.h$", "<netrose/rose.h>"},
+ {"include/nfs/nfs.h$", "<nfs/nfs.h>"},
+ {"include/netatalk/at.h$", "<netatalk/at.h>"},
+ {"include/netinet/ether.h$", "<netinet/ether.h>"},
+ {"include/netinet/icmp6.h$", "<netinet/icmp6.h>"},
+ {"include/netinet/if_ether.h$", "<netinet/if_ether.h>"},
+ {"include/netinet/if_fddi.h$", "<netinet/if_fddi.h>"},
+ {"include/netinet/if_tr.h$", "<netinet/if_tr.h>"},
+ {"include/netinet/igmp.h$", "<netinet/igmp.h>"},
+ {"include/netinet/in.h$", "<netinet/in.h>"},
+ {"include/netinet/in_systm.h$", "<netinet/in_systm.h>"},
+ {"include/netinet/ip.h$", "<netinet/ip.h>"},
+ {"include/netinet/ip6.h$", "<netinet/ip6.h>"},
+ {"include/netinet/ip_icmp.h$", "<netinet/ip_icmp.h>"},
+ {"include/netinet/tcp.h$", "<netinet/tcp.h>"},
+ {"include/netinet/udp.h$", "<netinet/udp.h>"},
+ {"include/netrom/netrom.h$", "<netrom/netrom.h>"},
+ {"include/protocols/routed.h$", "<protocols/routed.h>"},
+ {"include/protocols/rwhod.h$", "<protocols/rwhod.h>"},
+ {"include/protocols/talkd.h$", "<protocols/talkd.h>"},
+ {"include/protocols/timed.h$", "<protocols/timed.h>"},
+ {"include/rpcsvc/klm_prot.x$", "<rpcsvc/klm_prot.x>"},
+ {"include/rpcsvc/rstat.h$", "<rpcsvc/rstat.h>"},
+ {"include/rpcsvc/spray.x$", "<rpcsvc/spray.x>"},
+ {"include/rpcsvc/nlm_prot.x$", "<rpcsvc/nlm_prot.x>"},
+ {"include/rpcsvc/nis_callback.x$", "<rpcsvc/nis_callback.x>"},
+ {"include/rpcsvc/yp.h$", "<rpcsvc/yp.h>"},
+ {"include/rpcsvc/yp.x$", "<rpcsvc/yp.x>"},
+ {"include/rpcsvc/nfs_prot.h$", "<rpcsvc/nfs_prot.h>"},
+ {"include/rpcsvc/rex.h$", "<rpcsvc/rex.h>"},
+ {"include/rpcsvc/yppasswd.h$", "<rpcsvc/yppasswd.h>"},
+ {"include/rpcsvc/rex.x$", "<rpcsvc/rex.x>"},
+ {"include/rpcsvc/nis_tags.h$", "<rpcsvc/nis_tags.h>"},
+ {"include/rpcsvc/nis_callback.h$", "<rpcsvc/nis_callback.h>"},
+ {"include/rpcsvc/nfs_prot.x$", "<rpcsvc/nfs_prot.x>"},
+ {"include/rpcsvc/bootparam_prot.x$", "<rpcsvc/bootparam_prot.x>"},
+ {"include/rpcsvc/rusers.x$", "<rpcsvc/rusers.x>"},
+ {"include/rpcsvc/rquota.x$", "<rpcsvc/rquota.x>"},
+ {"include/rpcsvc/nis.h$", "<rpcsvc/nis.h>"},
+ {"include/rpcsvc/nislib.h$", "<rpcsvc/nislib.h>"},
+ {"include/rpcsvc/ypupd.h$", "<rpcsvc/ypupd.h>"},
+ {"include/rpcsvc/bootparam.h$", "<rpcsvc/bootparam.h>"},
+ {"include/rpcsvc/spray.h$", "<rpcsvc/spray.h>"},
+ {"include/rpcsvc/key_prot.h$", "<rpcsvc/key_prot.h>"},
+ {"include/rpcsvc/klm_prot.h$", "<rpcsvc/klm_prot.h>"},
+ {"include/rpcsvc/sm_inter.h$", "<rpcsvc/sm_inter.h>"},
+ {"include/rpcsvc/nlm_prot.h$", "<rpcsvc/nlm_prot.h>"},
+ {"include/rpcsvc/yp_prot.h$", "<rpcsvc/yp_prot.h>"},
+ {"include/rpcsvc/ypclnt.h$", "<rpcsvc/ypclnt.h>"},
+ {"include/rpcsvc/rstat.x$", "<rpcsvc/rstat.x>"},
+ {"include/rpcsvc/rusers.h$", "<rpcsvc/rusers.h>"},
+ {"include/rpcsvc/key_prot.x$", "<rpcsvc/key_prot.x>"},
+ {"include/rpcsvc/sm_inter.x$", "<rpcsvc/sm_inter.x>"},
+ {"include/rpcsvc/rquota.h$", "<rpcsvc/rquota.h>"},
+ {"include/rpcsvc/nis.x$", "<rpcsvc/nis.x>"},
+ {"include/rpcsvc/bootparam_prot.h$", "<rpcsvc/bootparam_prot.h>"},
+ {"include/rpcsvc/mount.h$", "<rpcsvc/mount.h>"},
+ {"include/rpcsvc/mount.x$", "<rpcsvc/mount.x>"},
+ {"include/rpcsvc/nis_object.x$", "<rpcsvc/nis_object.x>"},
+ {"include/rpcsvc/yppasswd.x$", "<rpcsvc/yppasswd.x>"},
+ {"sys/acct.h$", "<sys/acct.h>"},
+ {"sys/auxv.h$", "<sys/auxv.h>"},
+ {"sys/cdefs.h$", "<sys/cdefs.h>"},
+ {"sys/debugreg.h$", "<sys/debugreg.h>"},
+ {"sys/dir.h$", "<sys/dir.h>"},
+ {"sys/elf.h$", "<sys/elf.h>"},
+ {"sys/epoll.h$", "<sys/epoll.h>"},
+ {"sys/eventfd.h$", "<sys/eventfd.h>"},
+ {"sys/fanotify.h$", "<sys/fanotify.h>"},
+ {"sys/file.h$", "<sys/file.h>"},
+ {"sys/fsuid.h$", "<sys/fsuid.h>"},
+ {"sys/gmon.h$", "<sys/gmon.h>"},
+ {"sys/gmon_out.h$", "<sys/gmon_out.h>"},
+ {"sys/inotify.h$", "<sys/inotify.h>"},
+ {"sys/io.h$", "<sys/io.h>"},
+ {"sys/ioctl.h$", "<sys/ioctl.h>"},
+ {"sys/ipc.h$", "<sys/ipc.h>"},
+ {"sys/kd.h$", "<sys/kd.h>"},
+ {"sys/kdaemon.h$", "<sys/kdaemon.h>"},
+ {"sys/klog.h$", "<sys/klog.h>"},
+ {"sys/mman.h$", "<sys/mman.h>"},
+ {"sys/mount.h$", "<sys/mount.h>"},
+ {"sys/msg.h$", "<sys/msg.h>"},
+ {"sys/mtio.h$", "<sys/mtio.h>"},
+ {"sys/param.h$", "<sys/param.h>"},
+ {"sys/pci.h$", "<sys/pci.h>"},
+ {"sys/perm.h$", "<sys/perm.h>"},
+ {"sys/personality.h$", "<sys/personality.h>"},
+ {"sys/poll.h$", "<sys/poll.h>"},
+ {"sys/prctl.h$", "<sys/prctl.h>"},
+ {"sys/procfs.h$", "<sys/procfs.h>"},
+ {"sys/profil.h$", "<sys/profil.h>"},
+ {"sys/ptrace.h$", "<sys/ptrace.h>"},
+ {"sys/queue.h$", "<sys/queue.h>"},
+ {"sys/quota.h$", "<sys/quota.h>"},
+ {"sys/raw.h$", "<sys/raw.h>"},
+ {"sys/reboot.h$", "<sys/reboot.h>"},
+ {"sys/reg.h$", "<sys/reg.h>"},
+ {"sys/resource.h$", "<sys/resource.h>"},
+ {"sys/select.h$", "<sys/select.h>"},
+ {"sys/sem.h$", "<sys/sem.h>"},
+ {"sys/sendfile.h$", "<sys/sendfile.h>"},
+ {"sys/shm.h$", "<sys/shm.h>"},
+ {"sys/signalfd.h$", "<sys/signalfd.h>"},
+ {"sys/socket.h$", "<sys/socket.h>"},
+ {"sys/stat.h$", "<sys/stat.h>"},
+ {"sys/statfs.h$", "<sys/statfs.h>"},
+ {"sys/statvfs.h$", "<sys/statvfs.h>"},
+ {"sys/swap.h$", "<sys/swap.h>"},
+ {"sys/syscall.h$", "<sys/syscall.h>"},
+ {"sys/sysctl.h$", "<sys/sysctl.h>"},
+ {"sys/sysinfo.h$", "<sys/sysinfo.h>"},
+ {"sys/syslog.h$", "<sys/syslog.h>"},
+ {"sys/sysmacros.h$", "<sys/sysmacros.h>"},
+ {"sys/termios.h$", "<sys/termios.h>"},
+ {"sys/time.h$", "<sys/select.h>"},
+ {"sys/timeb.h$", "<sys/timeb.h>"},
+ {"sys/timerfd.h$", "<sys/timerfd.h>"},
+ {"sys/times.h$", "<sys/times.h>"},
+ {"sys/timex.h$", "<sys/timex.h>"},
+ {"sys/ttychars.h$", "<sys/ttychars.h>"},
+ {"sys/ttydefaults.h$", "<sys/ttydefaults.h>"},
+ {"sys/types.h$", "<sys/types.h>"},
+ {"sys/ucontext.h$", "<sys/ucontext.h>"},
+ {"sys/uio.h$", "<sys/uio.h>"},
+ {"sys/un.h$", "<sys/un.h>"},
+ {"sys/user.h$", "<sys/user.h>"},
+ {"sys/ustat.h$", "<sys/ustat.h>"},
+ {"sys/utsname.h$", "<sys/utsname.h>"},
+ {"sys/vlimit.h$", "<sys/vlimit.h>"},
+ {"sys/vm86.h$", "<sys/vm86.h>"},
+ {"sys/vtimes.h$", "<sys/vtimes.h>"},
+ {"sys/wait.h$", "<sys/wait.h>"},
+ {"sys/xattr.h$", "<sys/xattr.h>"},
+ {"bits/epoll.h$", "<sys/epoll.h>"},
+ {"bits/eventfd.h$", "<sys/eventfd.h>"},
+ {"bits/inotify.h$", "<sys/inotify.h>"},
+ {"bits/ipc.h$", "<sys/ipc.h>"},
+ {"bits/ipctypes.h$", "<sys/ipc.h>"},
+ {"bits/mman-linux.h$", "<sys/mman.h>"},
+ {"bits/mman.h$", "<sys/mman.h>"},
+ {"bits/msq.h$", "<sys/msg.h>"},
+ {"bits/resource.h$", "<sys/resource.h>"},
+ {"bits/sem.h$", "<sys/sem.h>"},
+ {"bits/shm.h$", "<sys/shm.h>"},
+ {"bits/signalfd.h$", "<sys/signalfd.h>"},
+ {"bits/statfs.h$", "<sys/statfs.h>"},
+ {"bits/statvfs.h$", "<sys/statvfs.h>"},
+ {"bits/timerfd.h$", "<sys/timerfd.h>"},
+ {"bits/utsname.h$", "<sys/utsname.h>"},
+ {"bits/auxv.h$", "<sys/auxv.h>"},
+ {"bits/byteswap-16.h$", "<byteswap.h>"},
+ {"bits/byteswap.h$", "<byteswap.h>"},
+ {"bits/confname.h$", "<unistd.h>"},
+ {"bits/dirent.h$", "<dirent.h>"},
+ {"bits/dlfcn.h$", "<dlfcn.h>"},
+ {"bits/elfclass.h$", "<link.h>"},
+ {"bits/endian.h$", "<endian.h>"},
+ {"bits/environments.h$", "<unistd.h>"},
+ {"bits/fcntl-linux.h$", "<fcntl.h>"},
+ {"bits/fcntl.h$", "<fcntl.h>"},
+ {"bits/in.h$", "<netinet/in.h>"},
+ {"bits/ioctl-types.h$", "<sys/ioctl.h>"},
+ {"bits/ioctls.h$", "<sys/ioctl.h>"},
+ {"bits/link.h$", "<link.h>"},
+ {"bits/mqueue.h$", "<mqueue.h>"},
+ {"bits/netdb.h$", "<netdb.h>"},
+ {"bits/param.h$", "<sys/param.h>"},
+ {"bits/poll.h$", "<sys/poll.h>"},
+ {"bits/posix_opt.h$", "<bits/posix_opt.h>"},
+ {"bits/pthreadtypes.h$", "<pthread.h>"},
+ {"bits/sched.h$", "<sched.h>"},
+ {"bits/select.h$", "<sys/select.h>"},
+ {"bits/semaphore.h$", "<semaphore.h>"},
+ {"bits/sigthread.h$", "<pthread.h>"},
+ {"bits/sockaddr.h$", "<sys/socket.h>"},
+ {"bits/socket.h$", "<sys/socket.h>"},
+ {"bits/socket_type.h$", "<sys/socket.h>"},
+ {"bits/stab.def$", "<stab.h>"},
+ {"bits/stat.h$", "<sys/stat.h>"},
+ {"bits/stropts.h$", "<stropts.h>"},
+ {"bits/syscall.h$", "<sys/syscall.h>"},
+ {"bits/syslog-path.h$", "<sys/syslog.h>"},
+ {"bits/termios.h$", "<termios.h>"},
+ {"bits/types.h$", "<sys/types.h>"},
+ {"bits/typesizes.h$", "<sys/types.h>"},
+ {"bits/uio.h$", "<sys/uio.h>"},
+ {"bits/ustat.h$", "<sys/ustat.h>"},
+ {"bits/utmp.h$", "<utmp.h>"},
+ {"bits/utmpx.h$", "<utmpx.h>"},
+ {"bits/waitflags.h$", "<sys/wait.h>"},
+ {"bits/waitstatus.h$", "<sys/wait.h>"},
+ {"bits/xtitypes.h$", "<stropts.h>"},
+ };
+ for (const auto &Pair : SystemHeaderMap)
+ Includes->addRegexMapping(Pair.first, Pair.second);
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/CanonicalIncludes.h b/src/third_party/llvm-project/clang-tools-extra/clangd/index/CanonicalIncludes.h
new file mode 100644
index 0000000..a2fdb04
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/CanonicalIncludes.h
@@ -0,0 +1,93 @@
+//===-- CanonicalIncludes.h - remap #include header -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// At indexing time, we decide which file to #included for a symbol.
+// Usually this is the file with the canonical decl, but there are exceptions:
+// - private headers may have pragmas pointing to the matching public header.
+// (These are "IWYU" pragmas, named after the include-what-you-use tool).
+// - the standard library is implemented in many files, without any pragmas.
+// We have a lookup table for common standard library implementations.
+// libstdc++ puts char_traits in bits/char_traits.h, but we #include <string>.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_CANONICALINCLUDES_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_CANONICALINCLUDES_H
+
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Regex.h"
+#include <mutex>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace clangd {
+
+/// Maps a definition location onto an #include file, based on a set of filename
+/// rules.
+/// Only const methods (i.e. mapHeader) in this class are thread safe.
+class CanonicalIncludes {
+public:
+ CanonicalIncludes() = default;
+
+ /// Adds a string-to-string mapping from \p Path to \p CanonicalPath.
+ void addMapping(llvm::StringRef Path, llvm::StringRef CanonicalPath);
+
+ /// Maps all files matching \p RE to \p CanonicalPath
+ void addRegexMapping(llvm::StringRef RE, llvm::StringRef CanonicalPath);
+
+ /// Sets the canonical include for any symbol with \p QualifiedName.
+ /// Symbol mappings take precedence over header mappings.
+ void addSymbolMapping(llvm::StringRef QualifiedName,
+ llvm::StringRef CanonicalPath);
+
+ /// Returns the canonical include for symbol with \p QualifiedName.
+ /// \p Headers is the include stack: Headers.front() is the file declaring the
+ /// symbol, and Headers.back() is the main file.
+ llvm::StringRef mapHeader(llvm::ArrayRef<std::string> Headers,
+ llvm::StringRef QualifiedName) const;
+
+private:
+ // A map from header patterns to header names. This needs to be mutable so
+ // that we can match again a Regex in a const function member.
+ // FIXME(ioeric): All the regexes we have so far are suffix matches. The
+ // performance could be improved by allowing only suffix matches instead of
+ // arbitrary regexes.
+ mutable std::vector<std::pair<llvm::Regex, std::string>>
+ RegexHeaderMappingTable;
+ // A map from fully qualified symbol names to header names.
+ llvm::StringMap<std::string> SymbolMapping;
+ // Guards Regex matching as it's not thread-safe.
+ mutable std::mutex RegexMutex;
+};
+
+/// Returns a CommentHandler that parses pragma comment on include files to
+/// determine when we should include a different header from the header that
+/// directly defines a symbol. Mappinps are registered with \p Includes.
+///
+/// Currently it only supports IWYU private pragma:
+/// https://github.com/include-what-you-use/include-what-you-use/blob/master/docs/IWYUPragmas.md#iwyu-pragma-private
+std::unique_ptr<CommentHandler>
+collectIWYUHeaderMaps(CanonicalIncludes *Includes);
+
+/// Adds mapping for system headers and some special symbols (e.g. STL symbols
+/// in <iosfwd> need to be mapped individually). Approximately, the following
+/// system headers are handled:
+/// - C++ standard library e.g. bits/basic_string.h$ -> <string>
+/// - Posix library e.g. bits/pthreadtypes.h$ -> <pthread.h>
+/// - Compiler extensions, e.g. include/avx512bwintrin.h$ -> <immintrin.h>
+/// The mapping is hardcoded and hand-maintained, so it might not cover all
+/// headers.
+void addSystemHeadersMapping(CanonicalIncludes *Includes);
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_HEADERMAPCOLLECTOR_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/FileIndex.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/index/FileIndex.cpp
new file mode 100644
index 0000000..407e86a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/FileIndex.cpp
@@ -0,0 +1,109 @@
+//===--- FileIndex.cpp - Indexes for files. ------------------------ C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FileIndex.h"
+#include "SymbolCollector.h"
+#include "clang/Index/IndexingAction.h"
+#include "clang/Lex/Preprocessor.h"
+
+namespace clang {
+namespace clangd {
+
+SymbolSlab indexAST(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
+ llvm::ArrayRef<std::string> URISchemes) {
+ SymbolCollector::Options CollectorOpts;
+ // FIXME(ioeric): we might also want to collect include headers. We would need
+ // to make sure all includes are canonicalized (with CanonicalIncludes), which
+ // is not trivial given the current way of collecting symbols: we only have
+ // AST at this point, but we also need preprocessor callbacks (e.g.
+ // CommentHandler for IWYU pragma) to canonicalize includes.
+ CollectorOpts.CollectIncludePath = false;
+ CollectorOpts.CountReferences = false;
+ if (!URISchemes.empty())
+ CollectorOpts.URISchemes = URISchemes;
+ CollectorOpts.Origin = SymbolOrigin::Dynamic;
+
+ SymbolCollector Collector(std::move(CollectorOpts));
+ Collector.setPreprocessor(PP);
+ index::IndexingOptions IndexOpts;
+ // We only need declarations, because we don't count references.
+ IndexOpts.SystemSymbolFilter =
+ index::IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly;
+ IndexOpts.IndexFunctionLocals = false;
+
+ std::vector<const Decl *> TopLevelDecls(
+ AST.getTranslationUnitDecl()->decls().begin(),
+ AST.getTranslationUnitDecl()->decls().end());
+ index::indexTopLevelDecls(AST, TopLevelDecls, Collector, IndexOpts);
+
+ return Collector.takeSymbols();
+}
+
+FileIndex::FileIndex(std::vector<std::string> URISchemes)
+ : URISchemes(std::move(URISchemes)) {}
+
+void FileSymbols::update(PathRef Path, std::unique_ptr<SymbolSlab> Slab) {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ if (!Slab)
+ FileToSlabs.erase(Path);
+ else
+ FileToSlabs[Path] = std::move(Slab);
+}
+
+std::shared_ptr<std::vector<const Symbol *>> FileSymbols::allSymbols() {
+ // The snapshot manages life time of symbol slabs and provides pointers of all
+ // symbols in all slabs.
+ struct Snapshot {
+ std::vector<const Symbol *> Pointers;
+ std::vector<std::shared_ptr<SymbolSlab>> KeepAlive;
+ };
+ auto Snap = std::make_shared<Snapshot>();
+ {
+ std::lock_guard<std::mutex> Lock(Mutex);
+
+ for (const auto &FileAndSlab : FileToSlabs) {
+ Snap->KeepAlive.push_back(FileAndSlab.second);
+ for (const auto &Iter : *FileAndSlab.second)
+ Snap->Pointers.push_back(&Iter);
+ }
+ }
+ auto *Pointers = &Snap->Pointers;
+ // Use aliasing constructor to keep the snapshot alive along with the
+ // pointers.
+ return {std::move(Snap), Pointers};
+}
+
+void FileIndex::update(PathRef Path, ASTContext *AST,
+ std::shared_ptr<Preprocessor> PP) {
+ if (!AST) {
+ FSymbols.update(Path, nullptr);
+ } else {
+ assert(PP);
+ auto Slab = llvm::make_unique<SymbolSlab>();
+ *Slab = indexAST(*AST, PP, URISchemes);
+ FSymbols.update(Path, std::move(Slab));
+ }
+ auto Symbols = FSymbols.allSymbols();
+ Index.build(std::move(Symbols));
+}
+
+bool FileIndex::fuzzyFind(
+ const FuzzyFindRequest &Req,
+ llvm::function_ref<void(const Symbol &)> Callback) const {
+ return Index.fuzzyFind(Req, Callback);
+}
+
+void FileIndex::lookup(
+ const LookupRequest &Req,
+ llvm::function_ref<void(const Symbol &)> Callback) const {
+ Index.lookup(Req, Callback);
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/FileIndex.h b/src/third_party/llvm-project/clang-tools-extra/clangd/index/FileIndex.h
new file mode 100644
index 0000000..1af37d1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/FileIndex.h
@@ -0,0 +1,91 @@
+//===--- FileIndex.h - Index for files. ---------------------------- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// FileIndex implements SymbolIndex for symbols from a set of files. Symbols are
+// maintained at source-file granuality (e.g. with ASTs), and files can be
+// updated dynamically.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_FILEINDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_FILEINDEX_H
+
+#include "../ClangdUnit.h"
+#include "Index.h"
+#include "MemIndex.h"
+#include "clang/Lex/Preprocessor.h"
+
+namespace clang {
+namespace clangd {
+
+/// \brief A container of Symbols from several source files. It can be updated
+/// at source-file granularity, replacing all symbols from one file with a new
+/// set.
+///
+/// This implements a snapshot semantics for symbols in a file. Each update to a
+/// file will create a new snapshot for all symbols in the file. Snapshots are
+/// managed with shared pointers that are shared between this class and the
+/// users. For each file, this class only stores a pointer pointing to the
+/// newest snapshot, and an outdated snapshot is deleted by the last owner of
+/// the snapshot, either this class or the symbol index.
+///
+/// The snapshot semantics keeps critical sections minimal since we only need
+/// locking when we swap or obtain refereces to snapshots.
+class FileSymbols {
+public:
+ /// \brief Updates all symbols in a file. If \p Slab is nullptr, symbols for
+ /// \p Path will be removed.
+ void update(PathRef Path, std::unique_ptr<SymbolSlab> Slab);
+
+ // The shared_ptr keeps the symbols alive
+ std::shared_ptr<std::vector<const Symbol *>> allSymbols();
+
+private:
+ mutable std::mutex Mutex;
+
+ /// \brief Stores the latest snapshots for all active files.
+ llvm::StringMap<std::shared_ptr<SymbolSlab>> FileToSlabs;
+};
+
+/// \brief This manages symbls from files and an in-memory index on all symbols.
+class FileIndex : public SymbolIndex {
+public:
+ /// If URISchemes is empty, the default schemes in SymbolCollector will be
+ /// used.
+ FileIndex(std::vector<std::string> URISchemes = {});
+
+ /// \brief Update symbols in \p Path with symbols in \p AST. If \p AST is
+ /// nullptr, this removes all symbols in the file.
+ /// If \p AST is not null, \p PP cannot be null and it should be the
+ /// preprocessor that was used to build \p AST.
+ void update(PathRef Path, ASTContext *AST, std::shared_ptr<Preprocessor> PP);
+
+ bool
+ fuzzyFind(const FuzzyFindRequest &Req,
+ llvm::function_ref<void(const Symbol &)> Callback) const override;
+
+ void lookup(const LookupRequest &Req,
+ llvm::function_ref<void(const Symbol &)> Callback) const override;
+
+private:
+ FileSymbols FSymbols;
+ MemIndex Index;
+ std::vector<std::string> URISchemes;
+};
+
+/// Retrieves namespace and class level symbols in \p AST.
+/// Exposed to assist in unit tests.
+/// If URISchemes is empty, the default schemes in SymbolCollector will be used.
+SymbolSlab indexAST(ASTContext &AST, std::shared_ptr<Preprocessor> PP,
+ llvm::ArrayRef<std::string> URISchemes = {});
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_FILEINDEX_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/Index.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/index/Index.cpp
new file mode 100644
index 0000000..1ae3d54
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/Index.cpp
@@ -0,0 +1,138 @@
+//===--- Index.cpp -----------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Index.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/SHA1.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolLocation &L) {
+ if (!L)
+ return OS << "(none)";
+ return OS << L.FileURI << "[" << L.Start.Line << ":" << L.Start.Column << "-"
+ << L.End.Line << ":" << L.End.Column << ")";
+}
+
+SymbolID::SymbolID(StringRef USR)
+ : HashValue(SHA1::hash(arrayRefFromStringRef(USR))) {}
+
+raw_ostream &operator<<(raw_ostream &OS, const SymbolID &ID) {
+ OS << toHex(toStringRef(ID.HashValue));
+ return OS;
+}
+
+std::string SymbolID::str() const {
+ std::string ID;
+ llvm::raw_string_ostream OS(ID);
+ OS << *this;
+ return OS.str();
+}
+
+void operator>>(StringRef Str, SymbolID &ID) {
+ std::string HexString = fromHex(Str);
+ assert(HexString.size() == ID.HashValue.size());
+ std::copy(HexString.begin(), HexString.end(), ID.HashValue.begin());
+}
+
+raw_ostream &operator<<(raw_ostream &OS, SymbolOrigin O) {
+ if (O == SymbolOrigin::Unknown)
+ return OS << "unknown";
+ constexpr static char Sigils[] = "ADSM4567";
+ for (unsigned I = 0; I < sizeof(Sigils); ++I)
+ if (static_cast<uint8_t>(O) & 1u << I)
+ OS << Sigils[I];
+ return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const Symbol &S) {
+ return OS << S.Scope << S.Name;
+}
+
+double quality(const Symbol &S) {
+ // This avoids a sharp gradient for tail symbols, and also neatly avoids the
+ // question of whether 0 references means a bad symbol or missing data.
+ if (S.References < 3)
+ return 1;
+ return std::log(S.References);
+}
+
+SymbolSlab::const_iterator SymbolSlab::find(const SymbolID &ID) const {
+ auto It = std::lower_bound(Symbols.begin(), Symbols.end(), ID,
+ [](const Symbol &S, const SymbolID &I) {
+ return S.ID < I;
+ });
+ if (It != Symbols.end() && It->ID == ID)
+ return It;
+ return Symbols.end();
+}
+
+// Copy the underlying data of the symbol into the owned arena.
+static void own(Symbol &S, DenseSet<StringRef> &Strings,
+ BumpPtrAllocator &Arena) {
+ // Intern replaces V with a reference to the same string owned by the arena.
+ auto Intern = [&](StringRef &V) {
+ auto R = Strings.insert(V);
+ if (R.second) { // New entry added to the table, copy the string.
+ *R.first = V.copy(Arena);
+ }
+ V = *R.first;
+ };
+
+ // We need to copy every StringRef field onto the arena.
+ Intern(S.Name);
+ Intern(S.Scope);
+ Intern(S.CanonicalDeclaration.FileURI);
+ Intern(S.Definition.FileURI);
+
+ Intern(S.Signature);
+ Intern(S.CompletionSnippetSuffix);
+
+ if (S.Detail) {
+ // Copy values of StringRefs into arena.
+ auto *Detail = Arena.Allocate<Symbol::Details>();
+ *Detail = *S.Detail;
+ // Intern the actual strings.
+ Intern(Detail->Documentation);
+ Intern(Detail->ReturnType);
+ Intern(Detail->IncludeHeader);
+ // Replace the detail pointer with our copy.
+ S.Detail = Detail;
+ }
+}
+
+void SymbolSlab::Builder::insert(const Symbol &S) {
+ auto R = SymbolIndex.try_emplace(S.ID, Symbols.size());
+ if (R.second) {
+ Symbols.push_back(S);
+ own(Symbols.back(), Strings, Arena);
+ } else {
+ auto &Copy = Symbols[R.first->second] = S;
+ own(Copy, Strings, Arena);
+ }
+}
+
+SymbolSlab SymbolSlab::Builder::build() && {
+ Symbols = {Symbols.begin(), Symbols.end()}; // Force shrink-to-fit.
+ // Sort symbols so the slab can binary search over them.
+ std::sort(Symbols.begin(), Symbols.end(),
+ [](const Symbol &L, const Symbol &R) { return L.ID < R.ID; });
+ // We may have unused strings from overwritten symbols. Build a new arena.
+ BumpPtrAllocator NewArena;
+ DenseSet<StringRef> Strings;
+ for (auto &S : Symbols)
+ own(S, Strings, NewArena);
+ return SymbolSlab(std::move(NewArena), std::move(Symbols));
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/Index.h b/src/third_party/llvm-project/clang-tools-extra/clangd/index/Index.h
new file mode 100644
index 0000000..18ed05f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/Index.h
@@ -0,0 +1,343 @@
+//===--- Index.h ------------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_INDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_INDEX_H
+
+#include "clang/Index/IndexSymbol.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringExtras.h"
+#include <array>
+#include <string>
+
+namespace clang {
+namespace clangd {
+
+struct SymbolLocation {
+ // Specify a position (Line, Column) of symbol. Using Line/Column allows us to
+ // build LSP responses without reading the file content.
+ struct Position {
+ uint32_t Line = 0; // 0-based
+ // Using UTF-16 code units.
+ uint32_t Column = 0; // 0-based
+ bool operator==(const Position& P) const {
+ return Line == P.Line && Column == P.Column;
+ }
+ };
+
+ // The URI of the source file where a symbol occurs.
+ llvm::StringRef FileURI;
+
+ /// The symbol range, using half-open range [Start, End).
+ Position Start;
+ Position End;
+
+ explicit operator bool() const { return !FileURI.empty(); }
+ bool operator==(const SymbolLocation& Loc) const {
+ return std::tie(FileURI, Start, End) ==
+ std::tie(Loc.FileURI, Loc.Start, Loc.End);
+ }
+};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const SymbolLocation &);
+
+// The class identifies a particular C++ symbol (class, function, method, etc).
+//
+// As USRs (Unified Symbol Resolution) could be large, especially for functions
+// with long type arguments, SymbolID is using 160-bits SHA1(USR) values to
+// guarantee the uniqueness of symbols while using a relatively small amount of
+// memory (vs storing USRs directly).
+//
+// SymbolID can be used as key in the symbol indexes to lookup the symbol.
+class SymbolID {
+public:
+ SymbolID() = default;
+ explicit SymbolID(llvm::StringRef USR);
+
+ bool operator==(const SymbolID &Sym) const {
+ return HashValue == Sym.HashValue;
+ }
+ bool operator<(const SymbolID &Sym) const {
+ return HashValue < Sym.HashValue;
+ }
+
+ // Returns a 40-bytes hex encoded string.
+ std::string str() const;
+
+private:
+ static constexpr unsigned HashByteLength = 20;
+
+ friend llvm::hash_code hash_value(const SymbolID &ID) {
+ // We already have a good hash, just return the first bytes.
+ static_assert(sizeof(size_t) <= HashByteLength, "size_t longer than SHA1!");
+ size_t Result;
+ memcpy(&Result, ID.HashValue.data(), sizeof(size_t));
+ return llvm::hash_code(Result);
+ }
+ friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const SymbolID &ID);
+ friend void operator>>(llvm::StringRef Str, SymbolID &ID);
+
+ std::array<uint8_t, HashByteLength> HashValue;
+};
+
+// Write SymbolID into the given stream. SymbolID is encoded as a 40-bytes
+// hex string.
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolID &ID);
+
+// Construct SymbolID from a hex string.
+// The HexStr is required to be a 40-bytes hex string, which is encoded from the
+// "<<" operator.
+void operator>>(llvm::StringRef HexStr, SymbolID &ID);
+
+} // namespace clangd
+} // namespace clang
+namespace llvm {
+// Support SymbolIDs as DenseMap keys.
+template <> struct DenseMapInfo<clang::clangd::SymbolID> {
+ static inline clang::clangd::SymbolID getEmptyKey() {
+ static clang::clangd::SymbolID EmptyKey("EMPTYKEY");
+ return EmptyKey;
+ }
+ static inline clang::clangd::SymbolID getTombstoneKey() {
+ static clang::clangd::SymbolID TombstoneKey("TOMBSTONEKEY");
+ return TombstoneKey;
+ }
+ static unsigned getHashValue(const clang::clangd::SymbolID &Sym) {
+ return hash_value(Sym);
+ }
+ static bool isEqual(const clang::clangd::SymbolID &LHS,
+ const clang::clangd::SymbolID &RHS) {
+ return LHS == RHS;
+ }
+};
+} // namespace llvm
+namespace clang {
+namespace clangd {
+
+// Describes the source of information about a symbol.
+// Mainly useful for debugging, e.g. understanding code completion reuslts.
+// This is a bitfield as information can be combined from several sources.
+enum class SymbolOrigin : uint8_t {
+ Unknown = 0,
+ AST = 1 << 0, // Directly from the AST (indexes should not set this).
+ Dynamic = 1 << 1, // From the dynamic index of opened files.
+ Static = 1 << 2, // From the static, externally-built index.
+ Merge = 1 << 3, // A non-trivial index merge was performed.
+ // Remaining bits reserved for index implementations.
+};
+inline SymbolOrigin operator|(SymbolOrigin A, SymbolOrigin B) {
+ return static_cast<SymbolOrigin>(static_cast<uint8_t>(A) |
+ static_cast<uint8_t>(B));
+}
+inline SymbolOrigin &operator|=(SymbolOrigin &A, SymbolOrigin B) {
+ return A = A | B;
+}
+inline SymbolOrigin operator&(SymbolOrigin A, SymbolOrigin B) {
+ return static_cast<SymbolOrigin>(static_cast<uint8_t>(A) &
+ static_cast<uint8_t>(B));
+}
+raw_ostream &operator<<(raw_ostream &, SymbolOrigin);
+
+// The class presents a C++ symbol, e.g. class, function.
+//
+// WARNING: Symbols do not own much of their underlying data - typically strings
+// are owned by a SymbolSlab. They should be treated as non-owning references.
+// Copies are shallow.
+// When adding new unowned data fields to Symbol, remember to update:
+// - SymbolSlab::Builder in Index.cpp, to copy them to the slab's storage.
+// - mergeSymbol in Merge.cpp, to properly combine two Symbols.
+//
+// A fully documented symbol can be split as:
+// size_type std::map<k, t>::count(const K& key) const
+// | Return | Scope |Name| Signature |
+// We split up these components to allow display flexibility later.
+struct Symbol {
+ // The ID of the symbol.
+ SymbolID ID;
+ // The symbol information, like symbol kind.
+ index::SymbolInfo SymInfo;
+ // The unqualified name of the symbol, e.g. "bar" (for ns::bar).
+ llvm::StringRef Name;
+ // The containing namespace. e.g. "" (global), "ns::" (top-level namespace).
+ llvm::StringRef Scope;
+ // The location of the symbol's definition, if one was found.
+ // This just covers the symbol name (e.g. without class/function body).
+ SymbolLocation Definition;
+ // The location of the preferred declaration of the symbol.
+ // This just covers the symbol name.
+ // This may be the same as Definition.
+ //
+ // A C++ symbol may have multiple declarations, and we pick one to prefer.
+ // * For classes, the canonical declaration should be the definition.
+ // * For non-inline functions, the canonical declaration typically appears
+ // in the ".h" file corresponding to the definition.
+ SymbolLocation CanonicalDeclaration;
+ // The number of translation units that reference this symbol from their main
+ // file. This number is only meaningful if aggregated in an index.
+ unsigned References = 0;
+ /// Whether or not this symbol is meant to be used for the code completion.
+ /// See also isIndexedForCodeCompletion().
+ bool IsIndexedForCodeCompletion = false;
+ /// Where this symbol came from. Usually an index provides a constant value.
+ SymbolOrigin Origin = SymbolOrigin::Unknown;
+ /// A brief description of the symbol that can be appended in the completion
+ /// candidate list. For example, "(X x, Y y) const" is a function signature.
+ llvm::StringRef Signature;
+ /// What to insert when completing this symbol, after the symbol name.
+ /// This is in LSP snippet syntax (e.g. "({$0})" for a no-args function).
+ /// (When snippets are disabled, the symbol name alone is used).
+ llvm::StringRef CompletionSnippetSuffix;
+
+ /// Optional symbol details that are not required to be set. For example, an
+ /// index fuzzy match can return a large number of symbol candidates, and it
+ /// is preferable to send only core symbol information in the batched results
+ /// and have clients resolve full symbol information for a specific candidate
+ /// if needed.
+ struct Details {
+ /// Documentation including comment for the symbol declaration.
+ llvm::StringRef Documentation;
+ /// Type when this symbol is used in an expression. (Short display form).
+ /// e.g. return type of a function, or type of a variable.
+ llvm::StringRef ReturnType;
+ /// This can be either a URI of the header to be #include'd for this symbol,
+ /// or a literal header quoted with <> or "" that is suitable to be included
+ /// directly. When this is a URI, the exact #include path needs to be
+ /// calculated according to the URI scheme.
+ ///
+ /// This is a canonical include for the symbol and can be different from
+ /// FileURI in the CanonicalDeclaration.
+ llvm::StringRef IncludeHeader;
+ };
+
+ // Optional details of the symbol.
+ const Details *Detail = nullptr;
+
+ // FIXME: add all occurrences support.
+ // FIXME: add extra fields for index scoring signals.
+};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Symbol &S);
+
+// Computes query-independent quality score for a Symbol.
+// This currently falls in the range [1, ln(#indexed documents)].
+// FIXME: this should probably be split into symbol -> signals
+// and signals -> score, so it can be reused for Sema completions.
+double quality(const Symbol &S);
+
+// An immutable symbol container that stores a set of symbols.
+// The container will maintain the lifetime of the symbols.
+class SymbolSlab {
+public:
+ using const_iterator = std::vector<Symbol>::const_iterator;
+ using iterator = const_iterator;
+
+ SymbolSlab() = default;
+
+ const_iterator begin() const { return Symbols.begin(); }
+ const_iterator end() const { return Symbols.end(); }
+ const_iterator find(const SymbolID &SymID) const;
+
+ size_t size() const { return Symbols.size(); }
+ // Estimates the total memory usage.
+ size_t bytes() const {
+ return sizeof(*this) + Arena.getTotalMemory() +
+ Symbols.capacity() * sizeof(Symbol);
+ }
+
+ // SymbolSlab::Builder is a mutable container that can 'freeze' to SymbolSlab.
+ // The frozen SymbolSlab will use less memory.
+ class Builder {
+ public:
+ // Adds a symbol, overwriting any existing one with the same ID.
+ // This is a deep copy: underlying strings will be owned by the slab.
+ void insert(const Symbol &S);
+
+ // Returns the symbol with an ID, if it exists. Valid until next insert().
+ const Symbol *find(const SymbolID &ID) {
+ auto I = SymbolIndex.find(ID);
+ return I == SymbolIndex.end() ? nullptr : &Symbols[I->second];
+ }
+
+ // Consumes the builder to finalize the slab.
+ SymbolSlab build() &&;
+
+ private:
+ llvm::BumpPtrAllocator Arena;
+ // Intern table for strings. Contents are on the arena.
+ llvm::DenseSet<llvm::StringRef> Strings;
+ std::vector<Symbol> Symbols;
+ // Values are indices into Symbols vector.
+ llvm::DenseMap<SymbolID, size_t> SymbolIndex;
+ };
+
+private:
+ SymbolSlab(llvm::BumpPtrAllocator Arena, std::vector<Symbol> Symbols)
+ : Arena(std::move(Arena)), Symbols(std::move(Symbols)) {}
+
+ llvm::BumpPtrAllocator Arena; // Owns Symbol data that the Symbols do not.
+ std::vector<Symbol> Symbols; // Sorted by SymbolID to allow lookup.
+};
+
+struct FuzzyFindRequest {
+ /// \brief A query string for the fuzzy find. This is matched against symbols'
+ /// un-qualified identifiers and should not contain qualifiers like "::".
+ std::string Query;
+ /// \brief If this is non-empty, symbols must be in at least one of the scopes
+ /// (e.g. namespaces) excluding nested scopes. For example, if a scope "xyz::"
+ /// is provided, the matched symbols must be defined in namespace xyz but not
+ /// namespace xyz::abc.
+ ///
+ /// The global scope is "", a top level scope is "foo::", etc.
+ std::vector<std::string> Scopes;
+ /// \brief The number of top candidates to return. The index may choose to
+ /// return more than this, e.g. if it doesn't know which candidates are best.
+ size_t MaxCandidateCount = UINT_MAX;
+ /// If set to true, only symbols for completion support will be considered.
+ bool RestrictForCodeCompletion = false;
+ /// Contextually relevant files (e.g. the file we're code-completing in).
+ /// Paths should be absolute.
+ std::vector<std::string> ProximityPaths;
+};
+
+struct LookupRequest {
+ llvm::DenseSet<SymbolID> IDs;
+};
+
+/// \brief Interface for symbol indexes that can be used for searching or
+/// matching symbols among a set of symbols based on names or unique IDs.
+class SymbolIndex {
+public:
+ virtual ~SymbolIndex() = default;
+
+ /// \brief Matches symbols in the index fuzzily and applies \p Callback on
+ /// each matched symbol before returning.
+ /// If returned Symbols are used outside Callback, they must be deep-copied!
+ ///
+ /// Returns true if there may be more results (limited by MaxCandidateCount).
+ virtual bool
+ fuzzyFind(const FuzzyFindRequest &Req,
+ llvm::function_ref<void(const Symbol &)> Callback) const = 0;
+
+ /// Looks up symbols with any of the given symbol IDs and applies \p Callback
+ /// on each matched symbol.
+ /// The returned symbol must be deep-copied if it's used outside Callback.
+ virtual void
+ lookup(const LookupRequest &Req,
+ llvm::function_ref<void(const Symbol &)> Callback) const = 0;
+
+ // FIXME: add interfaces for more index use cases:
+ // - getAllOccurrences(SymbolID);
+};
+
+} // namespace clangd
+} // namespace clang
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_INDEX_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/MemIndex.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/index/MemIndex.cpp
new file mode 100644
index 0000000..1a38386
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/MemIndex.cpp
@@ -0,0 +1,91 @@
+//===--- MemIndex.cpp - Dynamic in-memory symbol index. ----------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===-------------------------------------------------------------------===//
+
+#include "MemIndex.h"
+#include "../FuzzyMatch.h"
+#include "../Logger.h"
+#include <queue>
+
+namespace clang {
+namespace clangd {
+
+void MemIndex::build(std::shared_ptr<std::vector<const Symbol *>> Syms) {
+ llvm::DenseMap<SymbolID, const Symbol *> TempIndex;
+ for (const Symbol *Sym : *Syms)
+ TempIndex[Sym->ID] = Sym;
+
+ // Swap out the old symbols and index.
+ {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ Index = std::move(TempIndex);
+ Symbols = std::move(Syms); // Relase old symbols.
+ }
+}
+
+bool MemIndex::fuzzyFind(
+ const FuzzyFindRequest &Req,
+ llvm::function_ref<void(const Symbol &)> Callback) const {
+ assert(!StringRef(Req.Query).contains("::") &&
+ "There must be no :: in query.");
+
+ std::priority_queue<std::pair<float, const Symbol *>> Top;
+ FuzzyMatcher Filter(Req.Query);
+ bool More = false;
+ {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ for (const auto Pair : Index) {
+ const Symbol *Sym = Pair.second;
+
+ // Exact match against all possible scopes.
+ if (!Req.Scopes.empty() && !llvm::is_contained(Req.Scopes, Sym->Scope))
+ continue;
+ if (Req.RestrictForCodeCompletion && !Sym->IsIndexedForCodeCompletion)
+ continue;
+
+ if (auto Score = Filter.match(Sym->Name)) {
+ Top.emplace(-*Score * quality(*Sym), Sym);
+ if (Top.size() > Req.MaxCandidateCount) {
+ More = true;
+ Top.pop();
+ }
+ }
+ }
+ for (; !Top.empty(); Top.pop())
+ Callback(*Top.top().second);
+ }
+ return More;
+}
+
+void MemIndex::lookup(const LookupRequest &Req,
+ llvm::function_ref<void(const Symbol &)> Callback) const {
+ for (const auto &ID : Req.IDs) {
+ auto I = Index.find(ID);
+ if (I != Index.end())
+ Callback(*I->second);
+ }
+}
+
+std::unique_ptr<SymbolIndex> MemIndex::build(SymbolSlab Slab) {
+ struct Snapshot {
+ SymbolSlab Slab;
+ std::vector<const Symbol *> Pointers;
+ };
+ auto Snap = std::make_shared<Snapshot>();
+ Snap->Slab = std::move(Slab);
+ for (auto &Sym : Snap->Slab)
+ Snap->Pointers.push_back(&Sym);
+ auto S = std::shared_ptr<std::vector<const Symbol *>>(std::move(Snap),
+ &Snap->Pointers);
+ auto MemIdx = llvm::make_unique<MemIndex>();
+ MemIdx->build(std::move(S));
+ return std::move(MemIdx);
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/MemIndex.h b/src/third_party/llvm-project/clang-tools-extra/clangd/index/MemIndex.h
new file mode 100644
index 0000000..3147a6c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/MemIndex.h
@@ -0,0 +1,49 @@
+//===--- MemIndex.h - Dynamic in-memory symbol index. -------------- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_MEMINDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_MEMINDEX_H
+
+#include "Index.h"
+#include <mutex>
+
+namespace clang {
+namespace clangd {
+
+/// \brief This implements an index for a (relatively small) set of symbols that
+/// can be easily managed in memory.
+class MemIndex : public SymbolIndex {
+public:
+ /// \brief (Re-)Build index for `Symbols`. All symbol pointers must remain
+ /// accessible as long as `Symbols` is kept alive.
+ void build(std::shared_ptr<std::vector<const Symbol *>> Symbols);
+
+ /// \brief Build index from a symbol slab.
+ static std::unique_ptr<SymbolIndex> build(SymbolSlab Slab);
+
+ bool
+ fuzzyFind(const FuzzyFindRequest &Req,
+ llvm::function_ref<void(const Symbol &)> Callback) const override;
+
+ virtual void
+ lookup(const LookupRequest &Req,
+ llvm::function_ref<void(const Symbol &)> Callback) const override;
+
+private:
+ std::shared_ptr<std::vector<const Symbol *>> Symbols;
+ // Index is a set of symbols that are deduplicated by symbol IDs.
+ // FIXME: build smarter index structure.
+ llvm::DenseMap<SymbolID, const Symbol *> Index;
+ mutable std::mutex Mutex;
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_MEMINDEX_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/Merge.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/index/Merge.cpp
new file mode 100644
index 0000000..da31f8b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/Merge.cpp
@@ -0,0 +1,128 @@
+//===--- Merge.h ------------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#include "Merge.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/raw_ostream.h"
+namespace clang {
+namespace clangd {
+namespace {
+using namespace llvm;
+
+class MergedIndex : public SymbolIndex {
+ public:
+ MergedIndex(const SymbolIndex *Dynamic, const SymbolIndex *Static)
+ : Dynamic(Dynamic), Static(Static) {}
+
+ // FIXME: Deleted symbols in dirty files are still returned (from Static).
+ // To identify these eliminate these, we should:
+ // - find the generating file from each Symbol which is Static-only
+ // - ask Dynamic if it has that file (needs new SymbolIndex method)
+ // - if so, drop the Symbol.
+ bool fuzzyFind(const FuzzyFindRequest &Req,
+ function_ref<void(const Symbol &)> Callback) const override {
+ // We can't step through both sources in parallel. So:
+ // 1) query all dynamic symbols, slurping results into a slab
+ // 2) query the static symbols, for each one:
+ // a) if it's not in the dynamic slab, yield it directly
+ // b) if it's in the dynamic slab, merge it and yield the result
+ // 3) now yield all the dynamic symbols we haven't processed.
+ bool More = false; // We'll be incomplete if either source was.
+ SymbolSlab::Builder DynB;
+ More |= Dynamic->fuzzyFind(Req, [&](const Symbol &S) { DynB.insert(S); });
+ SymbolSlab Dyn = std::move(DynB).build();
+
+ DenseSet<SymbolID> SeenDynamicSymbols;
+ Symbol::Details Scratch;
+ More |= Static->fuzzyFind(Req, [&](const Symbol &S) {
+ auto DynS = Dyn.find(S.ID);
+ if (DynS == Dyn.end())
+ return Callback(S);
+ SeenDynamicSymbols.insert(S.ID);
+ Callback(mergeSymbol(*DynS, S, &Scratch));
+ });
+ for (const Symbol &S : Dyn)
+ if (!SeenDynamicSymbols.count(S.ID))
+ Callback(S);
+ return More;
+ }
+
+ void
+ lookup(const LookupRequest &Req,
+ llvm::function_ref<void(const Symbol &)> Callback) const override {
+ SymbolSlab::Builder B;
+
+ Dynamic->lookup(Req, [&](const Symbol &S) { B.insert(S); });
+
+ auto RemainingIDs = Req.IDs;
+ Symbol::Details Scratch;
+ Static->lookup(Req, [&](const Symbol &S) {
+ const Symbol *Sym = B.find(S.ID);
+ RemainingIDs.erase(S.ID);
+ if (!Sym)
+ Callback(S);
+ else
+ Callback(mergeSymbol(*Sym, S, &Scratch));
+ });
+ for (const auto &ID : RemainingIDs)
+ if (const Symbol *Sym = B.find(ID))
+ Callback(*Sym);
+ }
+
+private:
+ const SymbolIndex *Dynamic, *Static;
+};
+} // namespace
+
+Symbol
+mergeSymbol(const Symbol &L, const Symbol &R, Symbol::Details *Scratch) {
+ assert(L.ID == R.ID);
+ // We prefer information from TUs that saw the definition.
+ // Classes: this is the def itself. Functions: hopefully the header decl.
+ // If both did (or both didn't), continue to prefer L over R.
+ bool PreferR = R.Definition && !L.Definition;
+ Symbol S = PreferR ? R : L; // The target symbol we're merging into.
+ const Symbol &O = PreferR ? L : R; // The "other" less-preferred symbol.
+
+ // For each optional field, fill it from O if missing in S.
+ // (It might be missing in O too, but that's a no-op).
+ if (!S.Definition)
+ S.Definition = O.Definition;
+ if (!S.CanonicalDeclaration)
+ S.CanonicalDeclaration = O.CanonicalDeclaration;
+ S.References += O.References;
+ if (S.Signature == "")
+ S.Signature = O.Signature;
+ if (S.CompletionSnippetSuffix == "")
+ S.CompletionSnippetSuffix = O.CompletionSnippetSuffix;
+
+ if (O.Detail) {
+ if (S.Detail) {
+ // Copy into scratch space so we can merge.
+ *Scratch = *S.Detail;
+ if (Scratch->Documentation == "")
+ Scratch->Documentation = O.Detail->Documentation;
+ if (Scratch->ReturnType == "")
+ Scratch->ReturnType = O.Detail->ReturnType;
+ if (Scratch->IncludeHeader == "")
+ Scratch->IncludeHeader = O.Detail->IncludeHeader;
+ S.Detail = Scratch;
+ } else
+ S.Detail = O.Detail;
+ }
+
+ S.Origin |= O.Origin | SymbolOrigin::Merge;
+ return S;
+}
+
+std::unique_ptr<SymbolIndex> mergeIndex(const SymbolIndex *Dynamic,
+ const SymbolIndex *Static) {
+ return llvm::make_unique<MergedIndex>(Dynamic, Static);
+}
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/Merge.h b/src/third_party/llvm-project/clang-tools-extra/clangd/index/Merge.h
new file mode 100644
index 0000000..b9b58fd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/Merge.h
@@ -0,0 +1,29 @@
+//===--- Merge.h ------------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_MERGE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_MERGE_H
+#include "Index.h"
+namespace clang {
+namespace clangd {
+
+// Merge symbols L and R, preferring data from L in case of conflict.
+// The two symbols must have the same ID.
+// Returned symbol may contain data owned by either source.
+Symbol mergeSymbol(const Symbol &L, const Symbol &R, Symbol::Details *Scratch);
+
+// mergedIndex returns a composite index based on two provided Indexes:
+// - the Dynamic index covers few files, but is relatively up-to-date.
+// - the Static index covers a bigger set of files, but is relatively stale.
+// The returned index attempts to combine results, and avoid duplicates.
+std::unique_ptr<SymbolIndex> mergeIndex(const SymbolIndex *Dynamic,
+ const SymbolIndex *Static);
+
+} // namespace clangd
+} // namespace clang
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/SymbolCollector.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/index/SymbolCollector.cpp
new file mode 100644
index 0000000..5c80f38
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -0,0 +1,518 @@
+//===--- SymbolCollector.cpp -------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolCollector.h"
+#include "../AST.h"
+#include "../CodeComplete.h"
+#include "../CodeCompletionStrings.h"
+#include "../Logger.h"
+#include "../SourceCode.h"
+#include "../URI.h"
+#include "CanonicalIncludes.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Index/IndexSymbol.h"
+#include "clang/Index/USRGeneration.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+
+namespace clang {
+namespace clangd {
+
+namespace {
+/// If \p ND is a template specialization, returns the described template.
+/// Otherwise, returns \p ND.
+const NamedDecl &getTemplateOrThis(const NamedDecl &ND) {
+ if (auto T = ND.getDescribedTemplate())
+ return *T;
+ return ND;
+}
+
+// Returns a URI of \p Path. Firstly, this makes the \p Path absolute using the
+// current working directory of the given SourceManager if the Path is not an
+// absolute path. If failed, this resolves relative paths against \p FallbackDir
+// to get an absolute path. Then, this tries creating an URI for the absolute
+// path with schemes specified in \p Opts. This returns an URI with the first
+// working scheme, if there is any; otherwise, this returns None.
+//
+// The Path can be a path relative to the build directory, or retrieved from
+// the SourceManager.
+llvm::Optional<std::string> toURI(const SourceManager &SM, StringRef Path,
+ const SymbolCollector::Options &Opts) {
+ llvm::SmallString<128> AbsolutePath(Path);
+ if (std::error_code EC =
+ SM.getFileManager().getVirtualFileSystem()->makeAbsolute(
+ AbsolutePath))
+ log("Warning: could not make absolute file: {0}", EC.message());
+ if (llvm::sys::path::is_absolute(AbsolutePath)) {
+ // Handle the symbolic link path case where the current working directory
+ // (getCurrentWorkingDirectory) is a symlink./ We always want to the real
+ // file path (instead of the symlink path) for the C++ symbols.
+ //
+ // Consider the following example:
+ //
+ // src dir: /project/src/foo.h
+ // current working directory (symlink): /tmp/build -> /project/src/
+ //
+ // The file path of Symbol is "/project/src/foo.h" instead of
+ // "/tmp/build/foo.h"
+ if (const DirectoryEntry *Dir = SM.getFileManager().getDirectory(
+ llvm::sys::path::parent_path(AbsolutePath.str()))) {
+ StringRef DirName = SM.getFileManager().getCanonicalName(Dir);
+ SmallString<128> AbsoluteFilename;
+ llvm::sys::path::append(AbsoluteFilename, DirName,
+ llvm::sys::path::filename(AbsolutePath.str()));
+ AbsolutePath = AbsoluteFilename;
+ }
+ } else if (!Opts.FallbackDir.empty()) {
+ llvm::sys::fs::make_absolute(Opts.FallbackDir, AbsolutePath);
+ }
+
+ llvm::sys::path::remove_dots(AbsolutePath, /*remove_dot_dot=*/true);
+
+ std::string ErrMsg;
+ for (const auto &Scheme : Opts.URISchemes) {
+ auto U = URI::create(AbsolutePath, Scheme);
+ if (U)
+ return U->toString();
+ ErrMsg += llvm::toString(U.takeError()) + "\n";
+ }
+ log("Failed to create an URI for file {0}: {1}", AbsolutePath, ErrMsg);
+ return llvm::None;
+}
+
+// All proto generated headers should start with this line.
+static const char *PROTO_HEADER_COMMENT =
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!";
+
+// Checks whether the decl is a private symbol in a header generated by
+// protobuf compiler.
+// To identify whether a proto header is actually generated by proto compiler,
+// we check whether it starts with PROTO_HEADER_COMMENT.
+// FIXME: make filtering extensible when there are more use cases for symbol
+// filters.
+bool isPrivateProtoDecl(const NamedDecl &ND) {
+ const auto &SM = ND.getASTContext().getSourceManager();
+ auto Loc = findNameLoc(&ND);
+ auto FileName = SM.getFilename(Loc);
+ if (!FileName.endswith(".proto.h") && !FileName.endswith(".pb.h"))
+ return false;
+ auto FID = SM.getFileID(Loc);
+ // Double check that this is an actual protobuf header.
+ if (!SM.getBufferData(FID).startswith(PROTO_HEADER_COMMENT))
+ return false;
+
+ // ND without identifier can be operators.
+ if (ND.getIdentifier() == nullptr)
+ return false;
+ auto Name = ND.getIdentifier()->getName();
+ if (!Name.contains('_'))
+ return false;
+ // Nested proto entities (e.g. Message::Nested) have top-level decls
+ // that shouldn't be used (Message_Nested). Ignore them completely.
+ // The nested entities are dangling type aliases, we may want to reconsider
+ // including them in the future.
+ // For enum constants, SOME_ENUM_CONSTANT is not private and should be
+ // indexed. Outer_INNER is private. This heuristic relies on naming style, it
+ // will include OUTER_INNER and exclude some_enum_constant.
+ // FIXME: the heuristic relies on naming style (i.e. no underscore in
+ // user-defined names) and can be improved.
+ return (ND.getKind() != Decl::EnumConstant) ||
+ std::any_of(Name.begin(), Name.end(), islower);
+}
+
+// We only collect #include paths for symbols that are suitable for global code
+// completion, except for namespaces since #include path for a namespace is hard
+// to define.
+bool shouldCollectIncludePath(index::SymbolKind Kind) {
+ using SK = index::SymbolKind;
+ switch (Kind) {
+ case SK::Macro:
+ case SK::Enum:
+ case SK::Struct:
+ case SK::Class:
+ case SK::Union:
+ case SK::TypeAlias:
+ case SK::Using:
+ case SK::Function:
+ case SK::Variable:
+ case SK::EnumConstant:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/// Gets a canonical include (URI of the header or <header> or "header") for
+/// header of \p Loc.
+/// Returns None if fails to get include header for \p Loc.
+llvm::Optional<std::string>
+getIncludeHeader(llvm::StringRef QName, const SourceManager &SM,
+ SourceLocation Loc, const SymbolCollector::Options &Opts) {
+ std::vector<std::string> Headers;
+ // Collect the #include stack.
+ while (true) {
+ if (!Loc.isValid())
+ break;
+ auto FilePath = SM.getFilename(Loc);
+ if (FilePath.empty())
+ break;
+ Headers.push_back(FilePath);
+ if (SM.isInMainFile(Loc))
+ break;
+ Loc = SM.getIncludeLoc(SM.getFileID(Loc));
+ }
+ if (Headers.empty())
+ return llvm::None;
+ llvm::StringRef Header = Headers[0];
+ if (Opts.Includes) {
+ Header = Opts.Includes->mapHeader(Headers, QName);
+ if (Header.startswith("<") || Header.startswith("\""))
+ return Header.str();
+ }
+ return toURI(SM, Header, Opts);
+}
+
+// Return the symbol location of the token at \p Loc.
+llvm::Optional<SymbolLocation>
+getTokenLocation(SourceLocation TokLoc, const SourceManager &SM,
+ const SymbolCollector::Options &Opts,
+ const clang::LangOptions &LangOpts,
+ std::string &FileURIStorage) {
+ auto U = toURI(SM, SM.getFilename(TokLoc), Opts);
+ if (!U)
+ return llvm::None;
+ FileURIStorage = std::move(*U);
+ SymbolLocation Result;
+ Result.FileURI = FileURIStorage;
+ auto TokenLength = clang::Lexer::MeasureTokenLength(TokLoc, SM, LangOpts);
+
+ auto CreatePosition = [&SM](SourceLocation Loc) {
+ auto LSPLoc = sourceLocToPosition(SM, Loc);
+ SymbolLocation::Position Pos;
+ Pos.Line = LSPLoc.line;
+ Pos.Column = LSPLoc.character;
+ return Pos;
+ };
+
+ Result.Start = CreatePosition(TokLoc);
+ auto EndLoc = TokLoc.getLocWithOffset(TokenLength);
+ Result.End = CreatePosition(EndLoc);
+
+ return std::move(Result);
+}
+
+// Checks whether \p ND is a definition of a TagDecl (class/struct/enum/union)
+// in a header file, in which case clangd would prefer to use ND as a canonical
+// declaration.
+// FIXME: handle symbol types that are not TagDecl (e.g. functions), if using
+// the first seen declaration as canonical declaration is not a good enough
+// heuristic.
+bool isPreferredDeclaration(const NamedDecl &ND, index::SymbolRoleSet Roles) {
+ using namespace clang::ast_matchers;
+ return (Roles & static_cast<unsigned>(index::SymbolRole::Definition)) &&
+ llvm::isa<TagDecl>(&ND) &&
+ match(decl(isExpansionInMainFile()), ND, ND.getASTContext()).empty();
+}
+
+} // namespace
+
+SymbolCollector::SymbolCollector(Options Opts) : Opts(std::move(Opts)) {}
+
+void SymbolCollector::initialize(ASTContext &Ctx) {
+ ASTCtx = &Ctx;
+ CompletionAllocator = std::make_shared<GlobalCodeCompletionAllocator>();
+ CompletionTUInfo =
+ llvm::make_unique<CodeCompletionTUInfo>(CompletionAllocator);
+}
+
+bool SymbolCollector::shouldCollectSymbol(const NamedDecl &ND,
+ ASTContext &ASTCtx,
+ const Options &Opts) {
+ using namespace clang::ast_matchers;
+ if (ND.isImplicit())
+ return false;
+ // Skip anonymous declarations, e.g (anonymous enum/class/struct).
+ if (ND.getDeclName().isEmpty())
+ return false;
+
+ // FIXME: figure out a way to handle internal linkage symbols (e.g. static
+ // variables, function) defined in the .cc files. Also we skip the symbols
+ // in anonymous namespace as the qualifier names of these symbols are like
+ // `foo::<anonymous>::bar`, which need a special handling.
+ // In real world projects, we have a relatively large set of header files
+ // that define static variables (like "static const int A = 1;"), we still
+ // want to collect these symbols, although they cause potential ODR
+ // violations.
+ if (ND.isInAnonymousNamespace())
+ return false;
+
+ // We want most things but not "local" symbols such as symbols inside
+ // FunctionDecl, BlockDecl, ObjCMethodDecl and OMPDeclareReductionDecl.
+ // FIXME: Need a matcher for ExportDecl in order to include symbols declared
+ // within an export.
+ auto InNonLocalContext = hasDeclContext(anyOf(
+ translationUnitDecl(), namespaceDecl(), linkageSpecDecl(), recordDecl(),
+ enumDecl(), objcProtocolDecl(), objcInterfaceDecl(), objcCategoryDecl(),
+ objcCategoryImplDecl(), objcImplementationDecl()));
+ // Don't index template specializations and expansions in main files.
+ auto IsSpecialization =
+ anyOf(functionDecl(isExplicitTemplateSpecialization()),
+ cxxRecordDecl(isExplicitTemplateSpecialization()),
+ varDecl(isExplicitTemplateSpecialization()));
+ if (match(decl(allOf(unless(isExpansionInMainFile()), InNonLocalContext,
+ unless(IsSpecialization))),
+ ND, ASTCtx)
+ .empty())
+ return false;
+
+ // Avoid indexing internal symbols in protobuf generated headers.
+ if (isPrivateProtoDecl(ND))
+ return false;
+ return true;
+}
+
+// Always return true to continue indexing.
+bool SymbolCollector::handleDeclOccurence(
+ const Decl *D, index::SymbolRoleSet Roles,
+ ArrayRef<index::SymbolRelation> Relations, SourceLocation Loc,
+ index::IndexDataConsumer::ASTNodeInfo ASTNode) {
+ assert(ASTCtx && PP.get() && "ASTContext and Preprocessor must be set.");
+ assert(CompletionAllocator && CompletionTUInfo);
+ assert(ASTNode.OrigD);
+ // If OrigD is an declaration associated with a friend declaration and it's
+ // not a definition, skip it. Note that OrigD is the occurrence that the
+ // collector is currently visiting.
+ if ((ASTNode.OrigD->getFriendObjectKind() !=
+ Decl::FriendObjectKind::FOK_None) &&
+ !(Roles & static_cast<unsigned>(index::SymbolRole::Definition)))
+ return true;
+ // A declaration created for a friend declaration should not be used as the
+ // canonical declaration in the index. Use OrigD instead, unless we've already
+ // picked a replacement for D
+ if (D->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None)
+ D = CanonicalDecls.try_emplace(D, ASTNode.OrigD).first->second;
+ const NamedDecl *ND = llvm::dyn_cast<NamedDecl>(D);
+ if (!ND)
+ return true;
+
+ // Mark D as referenced if this is a reference coming from the main file.
+ // D may not be an interesting symbol, but it's cheaper to check at the end.
+ auto &SM = ASTCtx->getSourceManager();
+ if (Opts.CountReferences &&
+ (Roles & static_cast<unsigned>(index::SymbolRole::Reference)) &&
+ SM.getFileID(SM.getSpellingLoc(Loc)) == SM.getMainFileID())
+ ReferencedDecls.insert(ND);
+
+ // Don't continue indexing if this is a mere reference.
+ if (!(Roles & static_cast<unsigned>(index::SymbolRole::Declaration) ||
+ Roles & static_cast<unsigned>(index::SymbolRole::Definition)))
+ return true;
+ if (!shouldCollectSymbol(*ND, *ASTCtx, Opts))
+ return true;
+
+ llvm::SmallString<128> USR;
+ if (index::generateUSRForDecl(ND, USR))
+ return true;
+ SymbolID ID(USR);
+
+ const NamedDecl &OriginalDecl = *cast<NamedDecl>(ASTNode.OrigD);
+ const Symbol *BasicSymbol = Symbols.find(ID);
+ if (!BasicSymbol) // Regardless of role, ND is the canonical declaration.
+ BasicSymbol = addDeclaration(*ND, std::move(ID));
+ else if (isPreferredDeclaration(OriginalDecl, Roles))
+ // If OriginalDecl is preferred, replace the existing canonical
+ // declaration (e.g. a class forward declaration). There should be at most
+ // one duplicate as we expect to see only one preferred declaration per
+ // TU, because in practice they are definitions.
+ BasicSymbol = addDeclaration(OriginalDecl, std::move(ID));
+
+ if (Roles & static_cast<unsigned>(index::SymbolRole::Definition))
+ addDefinition(OriginalDecl, *BasicSymbol);
+ return true;
+}
+
+bool SymbolCollector::handleMacroOccurence(const IdentifierInfo *Name,
+ const MacroInfo *MI,
+ index::SymbolRoleSet Roles,
+ SourceLocation Loc) {
+ if (!Opts.CollectMacro)
+ return true;
+ assert(PP.get());
+
+ const auto &SM = PP->getSourceManager();
+ if (SM.isInMainFile(SM.getExpansionLoc(MI->getDefinitionLoc())))
+ return true;
+ // Header guards are not interesting in index. Builtin macros don't have
+ // useful locations and are not needed for code completions.
+ if (MI->isUsedForHeaderGuard() || MI->isBuiltinMacro())
+ return true;
+
+ // Mark the macro as referenced if this is a reference coming from the main
+ // file. The macro may not be an interesting symbol, but it's cheaper to check
+ // at the end.
+ if (Opts.CountReferences &&
+ (Roles & static_cast<unsigned>(index::SymbolRole::Reference)) &&
+ SM.getFileID(SM.getSpellingLoc(Loc)) == SM.getMainFileID())
+ ReferencedMacros.insert(Name);
+ // Don't continue indexing if this is a mere reference.
+ // FIXME: remove macro with ID if it is undefined.
+ if (!(Roles & static_cast<unsigned>(index::SymbolRole::Declaration) ||
+ Roles & static_cast<unsigned>(index::SymbolRole::Definition)))
+ return true;
+
+ llvm::SmallString<128> USR;
+ if (index::generateUSRForMacro(Name->getName(), MI->getDefinitionLoc(), SM,
+ USR))
+ return true;
+ SymbolID ID(USR);
+
+ // Only collect one instance in case there are multiple.
+ if (Symbols.find(ID) != nullptr)
+ return true;
+
+ Symbol S;
+ S.ID = std::move(ID);
+ S.Name = Name->getName();
+ S.IsIndexedForCodeCompletion = true;
+ S.SymInfo = index::getSymbolInfoForMacro(*MI);
+ std::string FileURI;
+ if (auto DeclLoc = getTokenLocation(MI->getDefinitionLoc(), SM, Opts,
+ PP->getLangOpts(), FileURI))
+ S.CanonicalDeclaration = *DeclLoc;
+
+ CodeCompletionResult SymbolCompletion(Name);
+ const auto *CCS = SymbolCompletion.CreateCodeCompletionStringForMacro(
+ *PP, *CompletionAllocator, *CompletionTUInfo);
+ std::string Signature;
+ std::string SnippetSuffix;
+ getSignature(*CCS, &Signature, &SnippetSuffix);
+
+ std::string Include;
+ if (Opts.CollectIncludePath && shouldCollectIncludePath(S.SymInfo.Kind)) {
+ if (auto Header =
+ getIncludeHeader(Name->getName(), SM,
+ SM.getExpansionLoc(MI->getDefinitionLoc()), Opts))
+ Include = std::move(*Header);
+ }
+ S.Signature = Signature;
+ S.CompletionSnippetSuffix = SnippetSuffix;
+ Symbol::Details Detail;
+ Detail.IncludeHeader = Include;
+ S.Detail = &Detail;
+ Symbols.insert(S);
+ return true;
+}
+
+void SymbolCollector::finish() {
+ // At the end of the TU, add 1 to the refcount of all referenced symbols.
+ auto IncRef = [this](const SymbolID &ID) {
+ if (const auto *S = Symbols.find(ID)) {
+ Symbol Inc = *S;
+ ++Inc.References;
+ Symbols.insert(Inc);
+ }
+ };
+ for (const NamedDecl *ND : ReferencedDecls) {
+ llvm::SmallString<128> USR;
+ if (!index::generateUSRForDecl(ND, USR))
+ IncRef(SymbolID(USR));
+ }
+ if (Opts.CollectMacro) {
+ assert(PP);
+ for (const IdentifierInfo *II : ReferencedMacros) {
+ llvm::SmallString<128> USR;
+ if (const auto *MI = PP->getMacroDefinition(II).getMacroInfo())
+ if (!index::generateUSRForMacro(II->getName(), MI->getDefinitionLoc(),
+ PP->getSourceManager(), USR))
+ IncRef(SymbolID(USR));
+ }
+ }
+ ReferencedDecls.clear();
+ ReferencedMacros.clear();
+}
+
+const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND,
+ SymbolID ID) {
+ auto &Ctx = ND.getASTContext();
+ auto &SM = Ctx.getSourceManager();
+
+ Symbol S;
+ S.ID = std::move(ID);
+ std::string QName = printQualifiedName(ND);
+ std::tie(S.Scope, S.Name) = splitQualifiedName(QName);
+ // FIXME: this returns foo:bar: for objective-C methods, we prefer only foo:
+ // for consistency with CodeCompletionString and a clean name/signature split.
+
+ S.IsIndexedForCodeCompletion = isIndexedForCodeCompletion(ND, Ctx);
+ S.SymInfo = index::getSymbolInfo(&ND);
+ std::string FileURI;
+ if (auto DeclLoc = getTokenLocation(findNameLoc(&ND), SM, Opts,
+ ASTCtx->getLangOpts(), FileURI))
+ S.CanonicalDeclaration = *DeclLoc;
+
+ // Add completion info.
+ // FIXME: we may want to choose a different redecl, or combine from several.
+ assert(ASTCtx && PP.get() && "ASTContext and Preprocessor must be set.");
+ // We use the primary template, as clang does during code completion.
+ CodeCompletionResult SymbolCompletion(&getTemplateOrThis(ND), 0);
+ const auto *CCS = SymbolCompletion.CreateCodeCompletionString(
+ *ASTCtx, *PP, CodeCompletionContext::CCC_Name, *CompletionAllocator,
+ *CompletionTUInfo,
+ /*IncludeBriefComments*/ false);
+ std::string Signature;
+ std::string SnippetSuffix;
+ getSignature(*CCS, &Signature, &SnippetSuffix);
+ std::string Documentation =
+ formatDocumentation(*CCS, getDocComment(Ctx, SymbolCompletion,
+ /*CommentsFromHeaders=*/true));
+ std::string ReturnType = getReturnType(*CCS);
+
+ std::string Include;
+ if (Opts.CollectIncludePath && shouldCollectIncludePath(S.SymInfo.Kind)) {
+ // Use the expansion location to get the #include header since this is
+ // where the symbol is exposed.
+ if (auto Header = getIncludeHeader(
+ QName, SM, SM.getExpansionLoc(ND.getLocation()), Opts))
+ Include = std::move(*Header);
+ }
+ S.Signature = Signature;
+ S.CompletionSnippetSuffix = SnippetSuffix;
+ Symbol::Details Detail;
+ Detail.Documentation = Documentation;
+ Detail.ReturnType = ReturnType;
+ Detail.IncludeHeader = Include;
+ S.Detail = &Detail;
+
+ S.Origin = Opts.Origin;
+ Symbols.insert(S);
+ return Symbols.find(S.ID);
+}
+
+void SymbolCollector::addDefinition(const NamedDecl &ND,
+ const Symbol &DeclSym) {
+ if (DeclSym.Definition)
+ return;
+ // If we saw some forward declaration, we end up copying the symbol.
+ // This is not ideal, but avoids duplicating the "is this a definition" check
+ // in clang::index. We should only see one definition.
+ Symbol S = DeclSym;
+ std::string FileURI;
+ if (auto DefLoc = getTokenLocation(findNameLoc(&ND),
+ ND.getASTContext().getSourceManager(),
+ Opts, ASTCtx->getLangOpts(), FileURI))
+ S.Definition = *DefLoc;
+ Symbols.insert(S);
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/SymbolCollector.h b/src/third_party/llvm-project/clang-tools-extra/clangd/index/SymbolCollector.h
new file mode 100644
index 0000000..bc882e4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/SymbolCollector.h
@@ -0,0 +1,114 @@
+//===--- SymbolCollector.h ---------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CanonicalIncludes.h"
+#include "Index.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/Index/IndexDataConsumer.h"
+#include "clang/Index/IndexSymbol.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+
+namespace clang {
+namespace clangd {
+
+/// \brief Collect declarations (symbols) from an AST.
+/// It collects most declarations except:
+/// - Implicit declarations
+/// - Anonymous declarations (anonymous enum/class/struct, etc)
+/// - Declarations in anonymous namespaces
+/// - Local declarations (in function bodies, blocks, etc)
+/// - Declarations in main files
+/// - Template specializations
+/// - Library-specific private declarations (e.g. private declaration generated
+/// by protobuf compiler)
+///
+/// See also shouldCollectSymbol(...).
+///
+/// Clients (e.g. clangd) can use SymbolCollector together with
+/// index::indexTopLevelDecls to retrieve all symbols when the source file is
+/// changed.
+class SymbolCollector : public index::IndexDataConsumer {
+public:
+ struct Options {
+ /// When symbol paths cannot be resolved to absolute paths (e.g. files in
+ /// VFS that does not have absolute path), combine the fallback directory
+ /// with symbols' paths to get absolute paths. This must be an absolute
+ /// path.
+ std::string FallbackDir;
+ /// Specifies URI schemes that can be used to generate URIs for file paths
+ /// in symbols. The list of schemes will be tried in order until a working
+ /// scheme is found. If no scheme works, symbol location will be dropped.
+ std::vector<std::string> URISchemes = {"file"};
+ bool CollectIncludePath = false;
+ /// If set, this is used to map symbol #include path to a potentially
+ /// different #include path.
+ const CanonicalIncludes *Includes = nullptr;
+ // Populate the Symbol.References field.
+ bool CountReferences = false;
+ // Every symbol collected will be stamped with this origin.
+ SymbolOrigin Origin = SymbolOrigin::Unknown;
+ /// Collect macros.
+ /// Note that SymbolCollector must be run with preprocessor in order to
+ /// collect macros. For example, `indexTopLevelDecls` will not index any
+ /// macro even if this is true.
+ bool CollectMacro = false;
+ };
+
+ SymbolCollector(Options Opts);
+
+ /// Returns true is \p ND should be collected.
+ /// AST matchers require non-const ASTContext.
+ static bool shouldCollectSymbol(const NamedDecl &ND, ASTContext &ASTCtx,
+ const Options &Opts);
+
+ void initialize(ASTContext &Ctx) override;
+
+ void setPreprocessor(std::shared_ptr<Preprocessor> PP) override {
+ this->PP = std::move(PP);
+ }
+
+ bool
+ handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
+ ArrayRef<index::SymbolRelation> Relations,
+ SourceLocation Loc,
+ index::IndexDataConsumer::ASTNodeInfo ASTNode) override;
+
+ bool handleMacroOccurence(const IdentifierInfo *Name, const MacroInfo *MI,
+ index::SymbolRoleSet Roles,
+ SourceLocation Loc) override;
+
+ SymbolSlab takeSymbols() { return std::move(Symbols).build(); }
+
+ void finish() override;
+
+private:
+ const Symbol *addDeclaration(const NamedDecl &, SymbolID);
+ void addDefinition(const NamedDecl &, const Symbol &DeclSymbol);
+
+ // All Symbols collected from the AST.
+ SymbolSlab::Builder Symbols;
+ ASTContext *ASTCtx;
+ std::shared_ptr<Preprocessor> PP;
+ std::shared_ptr<GlobalCodeCompletionAllocator> CompletionAllocator;
+ std::unique_ptr<CodeCompletionTUInfo> CompletionTUInfo;
+ Options Opts;
+ // Symbols referenced from the current TU, flushed on finish().
+ llvm::DenseSet<const NamedDecl *> ReferencedDecls;
+ llvm::DenseSet<const IdentifierInfo *> ReferencedMacros;
+ // Maps canonical declaration provided by clang to canonical declaration for
+ // an index symbol, if clangd prefers a different declaration than that
+ // provided by clang. For example, friend declaration might be considered
+ // canonical by clang but should not be considered canonical in the index
+ // unless it's a definition.
+ llvm::DenseMap<const Decl *, const Decl *> CanonicalDecls;
+};
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/SymbolYAML.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/index/SymbolYAML.cpp
new file mode 100644
index 0000000..1701b5a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/SymbolYAML.cpp
@@ -0,0 +1,207 @@
+//===--- SymbolYAML.cpp ------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolYAML.h"
+#include "Index.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+
+LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(clang::clangd::Symbol)
+
+namespace llvm {
+namespace yaml {
+
+using clang::clangd::Symbol;
+using clang::clangd::SymbolID;
+using clang::clangd::SymbolLocation;
+using clang::index::SymbolInfo;
+using clang::index::SymbolLanguage;
+using clang::index::SymbolKind;
+
+// Helper to (de)serialize the SymbolID. We serialize it as a hex string.
+struct NormalizedSymbolID {
+ NormalizedSymbolID(IO &) {}
+ NormalizedSymbolID(IO &, const SymbolID& ID) {
+ llvm::raw_string_ostream OS(HexString);
+ OS << ID;
+ }
+
+ SymbolID denormalize(IO&) {
+ SymbolID ID;
+ HexString >> ID;
+ return ID;
+ }
+
+ std::string HexString;
+};
+
+template <> struct MappingTraits<SymbolLocation::Position> {
+ static void mapping(IO &IO, SymbolLocation::Position &Value) {
+ IO.mapRequired("Line", Value.Line);
+ IO.mapRequired("Column", Value.Column);
+ }
+};
+
+template <> struct MappingTraits<SymbolLocation> {
+ static void mapping(IO &IO, SymbolLocation &Value) {
+ IO.mapRequired("FileURI", Value.FileURI);
+ IO.mapRequired("Start", Value.Start);
+ IO.mapRequired("End", Value.End);
+ }
+};
+
+template <> struct MappingTraits<SymbolInfo> {
+ static void mapping(IO &io, SymbolInfo &SymInfo) {
+ // FIXME: expose other fields?
+ io.mapRequired("Kind", SymInfo.Kind);
+ io.mapRequired("Lang", SymInfo.Lang);
+ }
+};
+
+template <> struct MappingTraits<Symbol::Details> {
+ static void mapping(IO &io, Symbol::Details &Detail) {
+ io.mapOptional("Documentation", Detail.Documentation);
+ io.mapOptional("ReturnType", Detail.ReturnType);
+ io.mapOptional("IncludeHeader", Detail.IncludeHeader);
+ }
+};
+
+// A YamlIO normalizer for fields of type "const T*" allocated on an arena.
+// Normalizes to Optional<T>, so traits should be provided for T.
+template <typename T> struct ArenaPtr {
+ ArenaPtr(IO &) {}
+ ArenaPtr(IO &, const T *D) {
+ if (D)
+ Opt = *D;
+ }
+
+ const T *denormalize(IO &IO) {
+ assert(IO.getContext() && "Expecting an arena (as context) to allocate "
+ "data for read symbols.");
+ if (!Opt)
+ return nullptr;
+ return new (*static_cast<llvm::BumpPtrAllocator *>(IO.getContext()))
+ T(std::move(*Opt)); // Allocate a copy of Opt on the arena.
+ }
+
+ llvm::Optional<T> Opt;
+};
+
+template <> struct MappingTraits<Symbol> {
+ static void mapping(IO &IO, Symbol &Sym) {
+ MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, Sym.ID);
+ MappingNormalization<ArenaPtr<Symbol::Details>, const Symbol::Details *>
+ NDetail(IO, Sym.Detail);
+ IO.mapRequired("ID", NSymbolID->HexString);
+ IO.mapRequired("Name", Sym.Name);
+ IO.mapRequired("Scope", Sym.Scope);
+ IO.mapRequired("SymInfo", Sym.SymInfo);
+ IO.mapOptional("CanonicalDeclaration", Sym.CanonicalDeclaration,
+ SymbolLocation());
+ IO.mapOptional("Definition", Sym.Definition, SymbolLocation());
+ IO.mapOptional("References", Sym.References, 0u);
+ IO.mapOptional("IsIndexedForCodeCompletion", Sym.IsIndexedForCodeCompletion,
+ false);
+ IO.mapOptional("Signature", Sym.Signature);
+ IO.mapOptional("CompletionSnippetSuffix", Sym.CompletionSnippetSuffix);
+ IO.mapOptional("Detail", NDetail->Opt);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<SymbolLanguage> {
+ static void enumeration(IO &IO, SymbolLanguage &Value) {
+ IO.enumCase(Value, "C", SymbolLanguage::C);
+ IO.enumCase(Value, "Cpp", SymbolLanguage::CXX);
+ IO.enumCase(Value, "ObjC", SymbolLanguage::ObjC);
+ IO.enumCase(Value, "Swift", SymbolLanguage::Swift);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<SymbolKind> {
+ static void enumeration(IO &IO, SymbolKind &Value) {
+#define DEFINE_ENUM(name) IO.enumCase(Value, #name, SymbolKind::name)
+
+ DEFINE_ENUM(Unknown);
+ DEFINE_ENUM(Function);
+ DEFINE_ENUM(Module);
+ DEFINE_ENUM(Namespace);
+ DEFINE_ENUM(NamespaceAlias);
+ DEFINE_ENUM(Macro);
+ DEFINE_ENUM(Enum);
+ DEFINE_ENUM(Struct);
+ DEFINE_ENUM(Class);
+ DEFINE_ENUM(Protocol);
+ DEFINE_ENUM(Extension);
+ DEFINE_ENUM(Union);
+ DEFINE_ENUM(TypeAlias);
+ DEFINE_ENUM(Function);
+ DEFINE_ENUM(Variable);
+ DEFINE_ENUM(Field);
+ DEFINE_ENUM(EnumConstant);
+ DEFINE_ENUM(InstanceMethod);
+ DEFINE_ENUM(ClassMethod);
+ DEFINE_ENUM(StaticMethod);
+ DEFINE_ENUM(InstanceProperty);
+ DEFINE_ENUM(ClassProperty);
+ DEFINE_ENUM(StaticProperty);
+ DEFINE_ENUM(Constructor);
+ DEFINE_ENUM(Destructor);
+ DEFINE_ENUM(ConversionFunction);
+ DEFINE_ENUM(Parameter);
+ DEFINE_ENUM(Using);
+
+#undef DEFINE_ENUM
+ }
+};
+
+} // namespace yaml
+} // namespace llvm
+
+namespace clang {
+namespace clangd {
+
+SymbolSlab symbolsFromYAML(llvm::StringRef YAMLContent) {
+ // Store data of pointer fields (excl. `StringRef`) like `Detail`.
+ llvm::BumpPtrAllocator Arena;
+ llvm::yaml::Input Yin(YAMLContent, &Arena);
+ std::vector<Symbol> S;
+ Yin >> S;
+
+ SymbolSlab::Builder Syms;
+ for (auto &Sym : S)
+ Syms.insert(Sym);
+ return std::move(Syms).build();
+}
+
+Symbol SymbolFromYAML(llvm::yaml::Input &Input, llvm::BumpPtrAllocator &Arena) {
+ // We could grab Arena out of Input, but it'd be a huge hazard for callers.
+ assert(Input.getContext() == &Arena);
+ Symbol S;
+ Input >> S;
+ return S;
+}
+
+void SymbolsToYAML(const SymbolSlab& Symbols, llvm::raw_ostream &OS) {
+ llvm::yaml::Output Yout(OS);
+ for (Symbol S : Symbols) // copy: Yout<< requires mutability.
+ Yout << S;
+}
+
+std::string SymbolToYAML(Symbol Sym) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ llvm::yaml::Output Yout(OS);
+ Yout << Sym;
+ return OS.str();
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/SymbolYAML.h b/src/third_party/llvm-project/clang-tools-extra/clangd/index/SymbolYAML.h
new file mode 100644
index 0000000..726af6c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/SymbolYAML.h
@@ -0,0 +1,48 @@
+//===--- SymbolYAML.h --------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// SymbolYAML provides facilities to convert Symbol to YAML, and vice versa.
+// The YAML format of Symbol is designed for simplicity and experiment, but
+// isn't a suitable/efficient store.
+//
+// This is for **experimental** only. Don't use it in the production code.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOL_FROM_YAML_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOL_FROM_YAML_H
+
+#include "Index.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace clangd {
+
+// Read symbols from a YAML-format string.
+SymbolSlab symbolsFromYAML(llvm::StringRef YAMLContent);
+
+// Read one symbol from a YAML-stream.
+// The arena must be the Input's context! (i.e. yaml::Input Input(Text, &Arena))
+// The returned symbol is backed by both Input and Arena.
+Symbol SymbolFromYAML(llvm::yaml::Input &Input, llvm::BumpPtrAllocator &Arena);
+
+// Convert a single symbol to YAML-format string.
+// The YAML result is safe to concatenate.
+std::string SymbolToYAML(Symbol Sym);
+
+// Convert symbols to a YAML-format string.
+// The YAML result is safe to concatenate if you have multiple symbol slabs.
+void SymbolsToYAML(const SymbolSlab &Symbols, llvm::raw_ostream &OS);
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOL_FROM_YAML_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Iterator.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Iterator.cpp
new file mode 100644
index 0000000..25107f9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Iterator.cpp
@@ -0,0 +1,244 @@
+//===--- Iterator.cpp - Query Symbol Retrieval ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Iterator.h"
+#include <algorithm>
+#include <cassert>
+#include <numeric>
+
+namespace clang {
+namespace clangd {
+namespace dex {
+
+namespace {
+
+/// Implements Iterator over a PostingList. DocumentIterator is the most basic
+/// iterator: it doesn't have any children (hence it is the leaf of iterator
+/// tree) and is simply a wrapper around PostingList::const_iterator.
+class DocumentIterator : public Iterator {
+public:
+ DocumentIterator(PostingListRef Documents)
+ : Documents(Documents), Index(std::begin(Documents)) {}
+
+ bool reachedEnd() const override { return Index == std::end(Documents); }
+
+ /// Advances cursor to the next item.
+ void advance() override {
+ assert(!reachedEnd() && "DocumentIterator can't advance at the end.");
+ ++Index;
+ }
+
+ /// Applies binary search to advance cursor to the next item with DocID equal
+ /// or higher than the given one.
+ void advanceTo(DocID ID) override {
+ assert(!reachedEnd() && "DocumentIterator can't advance at the end.");
+ Index = std::lower_bound(Index, std::end(Documents), ID);
+ }
+
+ DocID peek() const override {
+ assert(!reachedEnd() && "DocumentIterator can't call peek() at the end.");
+ return *Index;
+ }
+
+ llvm::raw_ostream &dump(llvm::raw_ostream &OS) const override {
+ OS << '[';
+ auto Separator = "";
+ for (const auto &ID : Documents) {
+ OS << Separator << ID;
+ Separator = ", ";
+ }
+ OS << ']';
+ return OS;
+ }
+
+private:
+ PostingListRef Documents;
+ PostingListRef::const_iterator Index;
+};
+
+/// Implements Iterator over the intersection of other iterators.
+///
+/// AndIterator iterates through common items among all children. It becomes
+/// exhausted as soon as any child becomes exhausted. After each mutation, the
+/// iterator restores the invariant: all children must point to the same item.
+class AndIterator : public Iterator {
+public:
+ AndIterator(std::vector<std::unique_ptr<Iterator>> AllChildren)
+ : Children(std::move(AllChildren)) {
+ assert(!Children.empty() && "AndIterator should have at least one child.");
+ // Establish invariants.
+ sync();
+ }
+
+ bool reachedEnd() const override { return ReachedEnd; }
+
+ /// Advances all children to the next common item.
+ void advance() override {
+ assert(!reachedEnd() && "AndIterator can't call advance() at the end.");
+ Children.front()->advance();
+ sync();
+ }
+
+ /// Advances all children to the next common item with DocumentID >= ID.
+ void advanceTo(DocID ID) override {
+ assert(!reachedEnd() && "AndIterator can't call advanceTo() at the end.");
+ Children.front()->advanceTo(ID);
+ sync();
+ }
+
+ DocID peek() const override { return Children.front()->peek(); }
+
+ llvm::raw_ostream &dump(llvm::raw_ostream &OS) const override {
+ OS << "(& ";
+ auto Separator = "";
+ for (const auto &Child : Children) {
+ OS << Separator << *Child;
+ Separator = " ";
+ }
+ OS << ')';
+ return OS;
+ }
+
+private:
+ /// Restores class invariants: each child will point to the same element after
+ /// sync.
+ void sync() {
+ ReachedEnd |= Children.front()->reachedEnd();
+ if (ReachedEnd)
+ return;
+ auto SyncID = Children.front()->peek();
+ // Indicates whether any child needs to be advanced to new SyncID.
+ bool NeedsAdvance = false;
+ do {
+ NeedsAdvance = false;
+ for (auto &Child : Children) {
+ Child->advanceTo(SyncID);
+ ReachedEnd |= Child->reachedEnd();
+ // If any child reaches end And iterator can not match any other items.
+ // In this case, just terminate the process.
+ if (ReachedEnd)
+ return;
+ // If any child goes beyond given ID (i.e. ID is not the common item),
+ // all children should be advanced to the next common item.
+ // FIXME(kbobyrev): This is not a very optimized version; after costs
+ // are introduced, cycle should break whenever ID exceeds current one
+ // and cheapest children should be advanced over again.
+ if (Child->peek() > SyncID) {
+ SyncID = Child->peek();
+ NeedsAdvance = true;
+ }
+ }
+ } while (NeedsAdvance);
+ }
+
+ /// AndIterator owns its children and ensures that all of them point to the
+ /// same element. As soon as one child gets exhausted, AndIterator can no
+ /// longer advance and has reached its end.
+ std::vector<std::unique_ptr<Iterator>> Children;
+ /// Indicates whether any child is exhausted. It is cheaper to maintain and
+ /// update the field, rather than traversing the whole subtree in each
+ /// reachedEnd() call.
+ bool ReachedEnd = false;
+};
+
+/// Implements Iterator over the union of other iterators.
+///
+/// OrIterator iterates through all items which can be pointed to by at least
+/// one child. To preserve the sorted order, this iterator always advances the
+/// child with smallest Child->peek() value. OrIterator becomes exhausted as
+/// soon as all of its children are exhausted.
+class OrIterator : public Iterator {
+public:
+ OrIterator(std::vector<std::unique_ptr<Iterator>> AllChildren)
+ : Children(std::move(AllChildren)) {
+ assert(Children.size() > 0 && "Or Iterator must have at least one child.");
+ }
+
+ /// Returns true if all children are exhausted.
+ bool reachedEnd() const override {
+ return std::all_of(begin(Children), end(Children),
+ [](const std::unique_ptr<Iterator> &Child) {
+ return Child->reachedEnd();
+ });
+ }
+
+ /// Moves each child pointing to the smallest DocID to the next item.
+ void advance() override {
+ assert(!reachedEnd() &&
+ "OrIterator must have at least one child to advance().");
+ const auto SmallestID = peek();
+ for (const auto &Child : Children)
+ if (!Child->reachedEnd() && Child->peek() == SmallestID)
+ Child->advance();
+ }
+
+ /// Advances each child to the next existing element with DocumentID >= ID.
+ void advanceTo(DocID ID) override {
+ assert(!reachedEnd() && "Can't advance iterator after it reached the end.");
+ for (const auto &Child : Children)
+ if (!Child->reachedEnd())
+ Child->advanceTo(ID);
+ }
+
+ /// Returns the element under cursor of the child with smallest Child->peek()
+ /// value.
+ DocID peek() const override {
+ assert(!reachedEnd() &&
+ "OrIterator must have at least one child to peek().");
+ DocID Result = std::numeric_limits<DocID>::max();
+
+ for (const auto &Child : Children)
+ if (!Child->reachedEnd())
+ Result = std::min(Result, Child->peek());
+
+ return Result;
+ }
+
+ llvm::raw_ostream &dump(llvm::raw_ostream &OS) const override {
+ OS << "(| ";
+ auto Separator = "";
+ for (const auto &Child : Children) {
+ OS << Separator << *Child;
+ Separator = " ";
+ }
+ OS << ')';
+ return OS;
+ }
+
+private:
+ // FIXME(kbobyrev): Would storing Children in min-heap be faster?
+ std::vector<std::unique_ptr<Iterator>> Children;
+};
+
+} // end namespace
+
+std::vector<DocID> consume(Iterator &It) {
+ std::vector<DocID> Result;
+ for (; !It.reachedEnd(); It.advance())
+ Result.push_back(It.peek());
+ return Result;
+}
+
+std::unique_ptr<Iterator> create(PostingListRef Documents) {
+ return llvm::make_unique<DocumentIterator>(Documents);
+}
+
+std::unique_ptr<Iterator>
+createAnd(std::vector<std::unique_ptr<Iterator>> Children) {
+ return llvm::make_unique<AndIterator>(move(Children));
+}
+
+std::unique_ptr<Iterator>
+createOr(std::vector<std::unique_ptr<Iterator>> Children) {
+ return llvm::make_unique<OrIterator>(move(Children));
+}
+
+} // namespace dex
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Iterator.h b/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Iterator.h
new file mode 100644
index 0000000..f6270f1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Iterator.h
@@ -0,0 +1,152 @@
+//===--- Iterator.h - Query Symbol Retrieval --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Symbol index queries consist of specific requirements for the requested
+// symbol, such as high fuzzy matching score, scope, type etc. The lists of all
+// symbols matching some criteria (e.g. belonging to "clang::clangd::" scope)
+// are expressed in a form of Search Tokens which are stored in the inverted
+// index. Inverted index maps these tokens to the posting lists - sorted ( by
+// symbol quality) sequences of symbol IDs matching the token, e.g. scope token
+// "clangd::clangd::" is mapped to the list of IDs of all symbols which are
+// declared in this namespace. Search queries are build from a set of
+// requirements which can be combined with each other forming the query trees.
+// The leafs of such trees are posting lists, and the nodes are operations on
+// these posting lists, e.g. intersection or union. Efficient processing of
+// these multi-level queries is handled by Iterators. Iterators advance through
+// all leaf posting lists producing the result of search query, which preserves
+// the sorted order of IDs. Having the resulting IDs sorted is important,
+// because it allows receiving a certain number of the most valuable items (e.g.
+// symbols with highest quality which was the sorting key in the first place)
+// without processing all items with requested properties (this might not be
+// computationally effective if search request is not very restrictive).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_DEX_ITERATOR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_DEX_ITERATOR_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+namespace clang {
+namespace clangd {
+namespace dex {
+
+/// Symbol position in the list of all index symbols sorted by a pre-computed
+/// symbol quality.
+using DocID = uint32_t;
+/// Contains sorted sequence of DocIDs all of which belong to symbols matching
+/// certain criteria, i.e. containing a Search Token. PostingLists are values
+/// for the inverted index.
+using PostingList = std::vector<DocID>;
+/// Immutable reference to PostingList object.
+using PostingListRef = llvm::ArrayRef<DocID>;
+
+/// Iterator is the interface for Query Tree node. The simplest type of Iterator
+/// is DocumentIterator which is simply a wrapper around PostingList iterator
+/// and serves as the Query Tree leaf. More sophisticated examples of iterators
+/// can manage intersection, union of the elements produced by other iterators
+/// (their children) to form a multi-level Query Tree. The interface is designed
+/// to be extensible in order to support multiple types of iterators.
+class Iterator {
+ // FIXME(kbobyrev): Provide callback for matched documents.
+ // FIXME(kbobyrev): Implement new types of iterators: Label, Boost (with
+ // scoring), Limit.
+ // FIXME(kbobyrev): Implement iterator cost, an estimate of advance() calls
+ // before iterator exhaustion.
+public:
+ /// Returns true if all valid DocIDs were processed and hence the iterator is
+ /// exhausted.
+ virtual bool reachedEnd() const = 0;
+ /// Moves to next valid DocID. If it doesn't exist, the iterator is exhausted
+ /// and proceeds to the END.
+ ///
+ /// Note: reachedEnd() must be false.
+ virtual void advance() = 0;
+ /// Moves to the first valid DocID which is equal or higher than given ID. If
+ /// it doesn't exist, the iterator is exhausted and proceeds to the END.
+ ///
+ /// Note: reachedEnd() must be false.
+ virtual void advanceTo(DocID ID) = 0;
+ /// Returns the current element this iterator points to.
+ ///
+ /// Note: reachedEnd() must be false.
+ virtual DocID peek() const = 0;
+
+ virtual ~Iterator() {}
+
+ /// Prints a convenient human-readable iterator representation by recursively
+ /// dumping iterators in the following format:
+ ///
+ /// (Type Child1 Child2 ...)
+ ///
+ /// Where Type is the iterator type representation: "&" for And, "|" for Or,
+ /// ChildN is N-th iterator child. Raw iterators over PostingList are
+ /// represented as "[ID1, ID2, ...]" where IDN is N-th PostingList entry.
+ friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ const Iterator &Iterator) {
+ return Iterator.dump(OS);
+ }
+
+private:
+ virtual llvm::raw_ostream &dump(llvm::raw_ostream &OS) const = 0;
+};
+
+/// Exhausts given iterator and returns all processed DocIDs. The result
+/// contains sorted DocumentIDs.
+std::vector<DocID> consume(Iterator &It);
+
+/// Returns a document iterator over given PostingList.
+std::unique_ptr<Iterator> create(PostingListRef Documents);
+
+/// Returns AND Iterator which performs the intersection of the PostingLists of
+/// its children.
+std::unique_ptr<Iterator>
+createAnd(std::vector<std::unique_ptr<Iterator>> Children);
+
+/// Returns OR Iterator which performs the union of the PostingLists of its
+/// children.
+std::unique_ptr<Iterator>
+createOr(std::vector<std::unique_ptr<Iterator>> Children);
+
+/// This allows createAnd(create(...), create(...)) syntax.
+template <typename... Args> std::unique_ptr<Iterator> createAnd(Args... args) {
+ std::vector<std::unique_ptr<Iterator>> Children;
+ populateChildren(Children, args...);
+ return createAnd(move(Children));
+}
+
+/// This allows createOr(create(...), create(...)) syntax.
+template <typename... Args> std::unique_ptr<Iterator> createOr(Args... args) {
+ std::vector<std::unique_ptr<Iterator>> Children;
+ populateChildren(Children, args...);
+ return createOr(move(Children));
+}
+
+template <typename HeadT, typename... TailT>
+void populateChildren(std::vector<std::unique_ptr<Iterator>> &Children,
+ HeadT &Head, TailT &... Tail) {
+ Children.push_back(move(Head));
+ populateChildren(Children, Tail...);
+}
+
+template <typename HeadT>
+void populateChildren(std::vector<std::unique_ptr<Iterator>> &Children,
+ HeadT &Head) {
+ Children.push_back(move(Head));
+}
+
+} // namespace dex
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Token.h b/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Token.h
new file mode 100644
index 0000000..33a16d3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Token.h
@@ -0,0 +1,112 @@
+//===--- Token.h - Symbol Search primitive ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Token objects represent a characteristic of a symbol, which can be used to
+// perform efficient search. Tokens are keys for inverted index which are mapped
+// to the corresponding posting lists.
+//
+// The symbol std::cout might have the tokens:
+// * Scope "std::"
+// * Trigram "cou"
+// * Trigram "out"
+// * Type "std::ostream"
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_DEX_TOKEN_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_DEX_TOKEN_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace clangd {
+namespace dex {
+
+/// A Token represents an attribute of a symbol, such as a particular trigram
+/// present in the name (used for fuzzy search).
+///
+/// Tokens can be used to perform more sophisticated search queries by
+/// constructing complex iterator trees.
+struct Token {
+ /// Kind specifies Token type which defines semantics for the internal
+ /// representation. Each Kind has different representation stored in Data
+ /// field.
+ enum class Kind {
+ /// Represents trigram used for fuzzy search of unqualified symbol names.
+ ///
+ /// Data contains 3 bytes with trigram contents.
+ Trigram,
+ /// Scope primitives, e.g. "symbol belongs to namespace foo::bar".
+ ///
+ /// Data stroes full scope name , e.g. "foo::bar::baz::" or "" (for global
+ /// scope).
+ Scope,
+ /// Internal Token type for invalid/special tokens, e.g. empty tokens for
+ /// llvm::DenseMap.
+ Sentinel,
+ /// FIXME(kbobyrev): Add other Token Kinds
+ /// * Path with full or relative path to the directory in which symbol is
+ /// defined
+ /// * Type with qualified type name or its USR
+ };
+
+ Token(Kind TokenKind, llvm::StringRef Data)
+ : Data(Data), TokenKind(TokenKind) {}
+
+ bool operator==(const Token &Other) const {
+ return TokenKind == Other.TokenKind && Data == Other.Data;
+ }
+
+ /// Representation which is unique among Token with the same Kind.
+ std::string Data;
+ Kind TokenKind;
+
+ friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Token &T) {
+ return OS << T.Data;
+ }
+
+private:
+ friend llvm::hash_code hash_value(const Token &Token) {
+ return llvm::hash_combine(static_cast<int>(Token.TokenKind), Token.Data);
+ }
+};
+
+} // namespace dex
+} // namespace clangd
+} // namespace clang
+
+namespace llvm {
+
+// Support Tokens as DenseMap keys.
+template <> struct DenseMapInfo<clang::clangd::dex::Token> {
+ static inline clang::clangd::dex::Token getEmptyKey() {
+ return {clang::clangd::dex::Token::Kind::Sentinel, "EmptyKey"};
+ }
+
+ static inline clang::clangd::dex::Token getTombstoneKey() {
+ return {clang::clangd::dex::Token::Kind::Sentinel, "TombstoneKey"};
+ }
+
+ static unsigned getHashValue(const clang::clangd::dex::Token &Tag) {
+ return hash_value(Tag);
+ }
+
+ static bool isEqual(const clang::clangd::dex::Token &LHS,
+ const clang::clangd::dex::Token &RHS) {
+ return LHS == RHS;
+ }
+};
+
+} // namespace llvm
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Trigram.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Trigram.cpp
new file mode 100644
index 0000000..549093d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Trigram.cpp
@@ -0,0 +1,132 @@
+//===--- Trigram.cpp - Trigram generation for Fuzzy Matching ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Trigram.h"
+#include "../../FuzzyMatch.h"
+#include "Token.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringExtras.h"
+
+#include <cctype>
+#include <queue>
+#include <string>
+
+using namespace llvm;
+
+namespace clang {
+namespace clangd {
+namespace dex {
+
+// FIXME(kbobyrev): Deal with short symbol symbol names. A viable approach would
+// be generating unigrams and bigrams here, too. This would prevent symbol index
+// from applying fuzzy matching on a tremendous number of symbols and allow
+// supplementary retrieval for short queries.
+//
+// Short names (total segment length <3 characters) are currently ignored.
+std::vector<Token> generateIdentifierTrigrams(llvm::StringRef Identifier) {
+ // Apply fuzzy matching text segmentation.
+ std::vector<CharRole> Roles(Identifier.size());
+ calculateRoles(Identifier,
+ llvm::makeMutableArrayRef(Roles.data(), Identifier.size()));
+
+ std::string LowercaseIdentifier = Identifier.lower();
+
+ // For each character, store indices of the characters to which fuzzy matching
+ // algorithm can jump. There are 3 possible variants:
+ //
+ // * Next Tail - next character from the same segment
+ // * Next Head - front character of the next segment
+ // * Skip-1-Next Head - front character of the skip-1-next segment
+ //
+ // Next stores tuples of three indices in the presented order, if a variant is
+ // not available then 0 is stored.
+ std::vector<std::array<unsigned, 3>> Next(LowercaseIdentifier.size());
+ unsigned NextTail = 0, NextHead = 0, NextNextHead = 0;
+ for (int I = LowercaseIdentifier.size() - 1; I >= 0; --I) {
+ Next[I] = {{NextTail, NextHead, NextNextHead}};
+ NextTail = Roles[I] == Tail ? I : 0;
+ if (Roles[I] == Head) {
+ NextNextHead = NextHead;
+ NextHead = I;
+ }
+ }
+
+ DenseSet<Token> UniqueTrigrams;
+ std::array<char, 4> Chars;
+ for (size_t I = 0; I < LowercaseIdentifier.size(); ++I) {
+ // Skip delimiters.
+ if (Roles[I] != Head && Roles[I] != Tail)
+ continue;
+ for (const unsigned J : Next[I]) {
+ if (!J)
+ continue;
+ for (const unsigned K : Next[J]) {
+ if (!K)
+ continue;
+ Chars = {{LowercaseIdentifier[I], LowercaseIdentifier[J],
+ LowercaseIdentifier[K], 0}};
+ auto Trigram = Token(Token::Kind::Trigram, Chars.data());
+ // Push unique trigrams to the result.
+ if (!UniqueTrigrams.count(Trigram)) {
+ UniqueTrigrams.insert(Trigram);
+ }
+ }
+ }
+ }
+
+ std::vector<Token> Result;
+ for (const auto &Trigram : UniqueTrigrams)
+ Result.push_back(Trigram);
+
+ return Result;
+}
+
+// FIXME(kbobyrev): Similarly, to generateIdentifierTrigrams, this ignores short
+// inputs (total segment length <3 characters).
+std::vector<Token> generateQueryTrigrams(llvm::StringRef Query) {
+ // Apply fuzzy matching text segmentation.
+ std::vector<CharRole> Roles(Query.size());
+ calculateRoles(Query, llvm::makeMutableArrayRef(Roles.data(), Query.size()));
+
+ std::string LowercaseQuery = Query.lower();
+
+ DenseSet<Token> UniqueTrigrams;
+ std::deque<char> Chars;
+
+ for (size_t I = 0; I < LowercaseQuery.size(); ++I) {
+ // If current symbol is delimiter, just skip it.
+ if (Roles[I] != Head && Roles[I] != Tail)
+ continue;
+
+ Chars.push_back(LowercaseQuery[I]);
+
+ if (Chars.size() > 3)
+ Chars.pop_front();
+ if (Chars.size() == 3) {
+ auto Trigram =
+ Token(Token::Kind::Trigram, std::string(begin(Chars), end(Chars)));
+ // Push unique trigrams to the result.
+ if (!UniqueTrigrams.count(Trigram)) {
+ UniqueTrigrams.insert(Trigram);
+ }
+ }
+ }
+
+ std::vector<Token> Result;
+ for (const auto &Trigram : UniqueTrigrams)
+ Result.push_back(Trigram);
+
+ return Result;
+}
+
+} // namespace dex
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Trigram.h b/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Trigram.h
new file mode 100644
index 0000000..0e21c7d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/index/dex/Trigram.h
@@ -0,0 +1,62 @@
+//===--- Trigram.h - Trigram generation for Fuzzy Matching ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Trigrams are attributes of the symbol unqualified name used to effectively
+// extract symbols which can be fuzzy-matched given user query from the inverted
+// index. To match query with the extracted set of trigrams Q, the set of
+// generated trigrams T for identifier (unqualified symbol name) should contain
+// all items of Q, i.e. Q ⊆ T.
+//
+// Trigram sets extracted from unqualified name and from query are different:
+// the set of query trigrams only contains consecutive sequences of three
+// characters (which is only a subset of all trigrams generated for an
+// identifier).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_DEX_TRIGRAM_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_DEX_TRIGRAM_H
+
+#include "Token.h"
+
+#include <string>
+
+namespace clang {
+namespace clangd {
+namespace dex {
+
+/// Returns list of unique fuzzy-search trigrams from unqualified symbol.
+///
+/// First, given Identifier (unqualified symbol name) is segmented using
+/// FuzzyMatch API and lowercased. After segmentation, the following technique
+/// is applied for generating trigrams: for each letter or digit in the input
+/// string the algorithms looks for the possible next and skip-1-next symbols
+/// which can be jumped to during fuzzy matching. Each combination of such three
+/// symbols is inserted into the result.
+///
+/// Trigrams can start at any character in the input. Then we can choose to move
+/// to the next character, move to the start of the next segment, or skip over a
+/// segment.
+///
+/// Note: the returned list of trigrams does not have duplicates, if any trigram
+/// belongs to more than one class it is only inserted once.
+std::vector<Token> generateIdentifierTrigrams(llvm::StringRef Identifier);
+
+/// Returns list of unique fuzzy-search trigrams given a query.
+///
+/// Query is segmented using FuzzyMatch API and downcasted to lowercase. Then,
+/// the simplest trigrams - sequences of three consecutive letters and digits
+/// are extracted and returned after deduplication.
+std::vector<Token> generateQueryTrigrams(llvm::StringRef Query);
+
+} // namespace dex
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/tool/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/clangd/tool/CMakeLists.txt
new file mode 100644
index 0000000..c188761
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/tool/CMakeLists.txt
@@ -0,0 +1,20 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+add_clang_tool(clangd
+ ClangdMain.cpp
+ )
+
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+target_link_libraries(clangd
+ PRIVATE
+ clangBasic
+ clangDaemon
+ clangFormat
+ clangFrontend
+ clangSema
+ clangTooling
+ clangToolingCore
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/clangd/tool/ClangdMain.cpp b/src/third_party/llvm-project/clang-tools-extra/clangd/tool/ClangdMain.cpp
new file mode 100644
index 0000000..95ffdfa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -0,0 +1,298 @@
+//===--- ClangdMain.cpp - clangd server loop ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangdLSPServer.h"
+#include "JSONRPCDispatcher.h"
+#include "Path.h"
+#include "Trace.h"
+#include "index/SymbolYAML.h"
+#include "clang/Basic/Version.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>
+
+using namespace clang;
+using namespace clang::clangd;
+
+namespace {
+enum class PCHStorageFlag { Disk, Memory };
+
+// Build an in-memory static index for global symbols from a YAML-format file.
+// The size of global symbols should be relatively small, so that all symbols
+// can be managed in memory.
+std::unique_ptr<SymbolIndex> buildStaticIndex(llvm::StringRef YamlSymbolFile) {
+ auto Buffer = llvm::MemoryBuffer::getFile(YamlSymbolFile);
+ if (!Buffer) {
+ llvm::errs() << "Can't open " << YamlSymbolFile << "\n";
+ return nullptr;
+ }
+ auto Slab = symbolsFromYAML(Buffer.get()->getBuffer());
+ SymbolSlab::Builder SymsBuilder;
+ for (auto Sym : Slab)
+ SymsBuilder.insert(Sym);
+
+ return MemIndex::build(std::move(SymsBuilder).build());
+}
+} // namespace
+
+static llvm::cl::opt<Path> CompileCommandsDir(
+ "compile-commands-dir",
+ llvm::cl::desc("Specify a path to look for compile_commands.json. If path "
+ "is invalid, clangd will look in the current directory and "
+ "parent paths of each source file."));
+
+static llvm::cl::opt<unsigned>
+ WorkerThreadsCount("j",
+ llvm::cl::desc("Number of async workers used by clangd"),
+ llvm::cl::init(getDefaultAsyncThreadsCount()));
+
+// FIXME: also support "plain" style where signatures are always omitted.
+enum CompletionStyleFlag {
+ Detailed,
+ Bundled,
+};
+static llvm::cl::opt<CompletionStyleFlag> CompletionStyle(
+ "completion-style",
+ llvm::cl::desc("Granularity of code completion suggestions"),
+ llvm::cl::values(
+ clEnumValN(Detailed, "detailed",
+ "One completion item for each semantically distinct "
+ "completion, with full type information."),
+ clEnumValN(Bundled, "bundled",
+ "Similar completion items (e.g. function overloads) are "
+ "combined. Type information shown where possible.")),
+ llvm::cl::init(Detailed));
+
+// FIXME: Flags are the wrong mechanism for user preferences.
+// We should probably read a dotfile or similar.
+static llvm::cl::opt<bool> IncludeIneligibleResults(
+ "include-ineligible-results",
+ llvm::cl::desc(
+ "Include ineligible completion results (e.g. private members)"),
+ llvm::cl::init(clangd::CodeCompleteOptions().IncludeIneligibleResults),
+ llvm::cl::Hidden);
+
+static llvm::cl::opt<JSONStreamStyle> InputStyle(
+ "input-style", llvm::cl::desc("Input JSON stream encoding"),
+ llvm::cl::values(
+ clEnumValN(JSONStreamStyle::Standard, "standard", "usual LSP protocol"),
+ clEnumValN(JSONStreamStyle::Delimited, "delimited",
+ "messages delimited by --- lines, with # comment support")),
+ llvm::cl::init(JSONStreamStyle::Standard));
+
+static llvm::cl::opt<bool>
+ PrettyPrint("pretty", llvm::cl::desc("Pretty-print JSON output"),
+ llvm::cl::init(false));
+
+static llvm::cl::opt<Logger::Level> LogLevel(
+ "log", llvm::cl::desc("Verbosity of log messages written to stderr"),
+ llvm::cl::values(clEnumValN(Logger::Error, "error", "Error messages only"),
+ clEnumValN(Logger::Info, "info",
+ "High level execution tracing"),
+ clEnumValN(Logger::Debug, "verbose", "Low level details")),
+ llvm::cl::init(Logger::Info));
+
+static llvm::cl::opt<bool> Test(
+ "lit-test",
+ llvm::cl::desc(
+ "Abbreviation for -input-style=delimited -pretty -run-synchronously. "
+ "Intended to simplify lit tests."),
+ llvm::cl::init(false), llvm::cl::Hidden);
+
+static llvm::cl::opt<PCHStorageFlag> PCHStorage(
+ "pch-storage",
+ llvm::cl::desc("Storing PCHs in memory increases memory usages, but may "
+ "improve performance"),
+ llvm::cl::values(
+ clEnumValN(PCHStorageFlag::Disk, "disk", "store PCHs on disk"),
+ clEnumValN(PCHStorageFlag::Memory, "memory", "store PCHs in memory")),
+ llvm::cl::init(PCHStorageFlag::Disk));
+
+static llvm::cl::opt<int> LimitResults(
+ "limit-results",
+ llvm::cl::desc("Limit the number of results returned by clangd. "
+ "0 means no limit."),
+ llvm::cl::init(100));
+
+static llvm::cl::opt<bool> RunSynchronously(
+ "run-synchronously",
+ llvm::cl::desc("Parse on main thread. If set, -j is ignored"),
+ llvm::cl::init(false), llvm::cl::Hidden);
+
+static llvm::cl::opt<Path>
+ ResourceDir("resource-dir",
+ llvm::cl::desc("Directory for system clang headers"),
+ llvm::cl::init(""), llvm::cl::Hidden);
+
+static llvm::cl::opt<Path> InputMirrorFile(
+ "input-mirror-file",
+ llvm::cl::desc(
+ "Mirror all LSP input to the specified file. Useful for debugging."),
+ llvm::cl::init(""), llvm::cl::Hidden);
+
+static llvm::cl::opt<bool> EnableIndex(
+ "index",
+ llvm::cl::desc("Enable index-based features such as global code completion "
+ "and searching for symbols."
+ "Clang uses an index built from symbols in opened files"),
+ llvm::cl::init(true));
+
+static llvm::cl::opt<bool>
+ ShowOrigins("debug-origin",
+ llvm::cl::desc("Show origins of completion items"),
+ llvm::cl::init(clangd::CodeCompleteOptions().ShowOrigins),
+ llvm::cl::Hidden);
+
+static llvm::cl::opt<bool> HeaderInsertionDecorators(
+ "header-insertion-decorators",
+ llvm::cl::desc("Prepend a circular dot or space before the completion "
+ "label, depending on wether "
+ "an include line will be inserted or not."),
+ llvm::cl::init(true));
+
+static llvm::cl::opt<Path> YamlSymbolFile(
+ "yaml-symbol-file",
+ llvm::cl::desc(
+ "YAML-format global symbol file to build the static index. Clangd will "
+ "use the static index for global code completion.\n"
+ "WARNING: This option is experimental only, and will be removed "
+ "eventually. Don't rely on it."),
+ llvm::cl::init(""), llvm::cl::Hidden);
+
+int main(int argc, char *argv[]) {
+ llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+ llvm::cl::SetVersionPrinter([](llvm::raw_ostream &OS) {
+ OS << clang::getClangToolFullVersion("clangd") << "\n";
+ });
+ llvm::cl::ParseCommandLineOptions(
+ argc, argv,
+ "clangd is a language server that provides IDE-like features to editors. "
+ "\n\nIt should be used via an editor plugin rather than invoked directly."
+ "For more information, see:"
+ "\n\thttps://clang.llvm.org/extra/clangd.html"
+ "\n\thttps://microsoft.github.io/language-server-protocol/");
+ if (Test) {
+ RunSynchronously = true;
+ InputStyle = JSONStreamStyle::Delimited;
+ PrettyPrint = true;
+ }
+
+ if (!RunSynchronously && WorkerThreadsCount == 0) {
+ llvm::errs() << "A number of worker threads cannot be 0. Did you mean to "
+ "specify -run-synchronously?";
+ return 1;
+ }
+
+ if (RunSynchronously) {
+ if (WorkerThreadsCount.getNumOccurrences())
+ llvm::errs() << "Ignoring -j because -run-synchronously is set.\n";
+ WorkerThreadsCount = 0;
+ }
+
+ // Validate command line arguments.
+ llvm::Optional<llvm::raw_fd_ostream> InputMirrorStream;
+ if (!InputMirrorFile.empty()) {
+ std::error_code EC;
+ InputMirrorStream.emplace(InputMirrorFile, /*ref*/ EC,
+ llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write);
+ if (EC) {
+ InputMirrorStream.reset();
+ llvm::errs() << "Error while opening an input mirror file: "
+ << EC.message();
+ }
+ }
+
+ // Setup tracing facilities if CLANGD_TRACE is set. In practice enabling a
+ // trace flag in your editor's config is annoying, launching with
+ // `CLANGD_TRACE=trace.json vim` is easier.
+ llvm::Optional<llvm::raw_fd_ostream> TraceStream;
+ std::unique_ptr<trace::EventTracer> Tracer;
+ if (auto *TraceFile = getenv("CLANGD_TRACE")) {
+ std::error_code EC;
+ TraceStream.emplace(TraceFile, /*ref*/ EC,
+ llvm::sys::fs::FA_Read | llvm::sys::fs::FA_Write);
+ if (EC) {
+ TraceStream.reset();
+ llvm::errs() << "Error while opening trace file " << TraceFile << ": "
+ << EC.message();
+ } else {
+ Tracer = trace::createJSONTracer(*TraceStream, PrettyPrint);
+ }
+ }
+
+ llvm::Optional<trace::Session> TracingSession;
+ if (Tracer)
+ TracingSession.emplace(*Tracer);
+
+ JSONOutput Out(llvm::outs(), llvm::errs(), LogLevel,
+ InputMirrorStream ? InputMirrorStream.getPointer() : nullptr,
+ PrettyPrint);
+
+ clangd::LoggingSession LoggingSession(Out);
+
+ // If --compile-commands-dir arg was invoked, check value and override default
+ // path.
+ llvm::Optional<Path> CompileCommandsDirPath;
+ if (CompileCommandsDir.empty()) {
+ CompileCommandsDirPath = llvm::None;
+ } else if (!llvm::sys::path::is_absolute(CompileCommandsDir) ||
+ !llvm::sys::fs::exists(CompileCommandsDir)) {
+ llvm::errs() << "Path specified by --compile-commands-dir either does not "
+ "exist or is not an absolute "
+ "path. The argument will be ignored.\n";
+ CompileCommandsDirPath = llvm::None;
+ } else {
+ CompileCommandsDirPath = CompileCommandsDir;
+ }
+
+ ClangdServer::Options Opts;
+ switch (PCHStorage) {
+ case PCHStorageFlag::Memory:
+ Opts.StorePreamblesInMemory = true;
+ break;
+ case PCHStorageFlag::Disk:
+ Opts.StorePreamblesInMemory = false;
+ break;
+ }
+ if (!ResourceDir.empty())
+ Opts.ResourceDir = ResourceDir;
+ Opts.BuildDynamicSymbolIndex = EnableIndex;
+ std::unique_ptr<SymbolIndex> StaticIdx;
+ if (EnableIndex && !YamlSymbolFile.empty()) {
+ StaticIdx = buildStaticIndex(YamlSymbolFile);
+ Opts.StaticIndex = StaticIdx.get();
+ }
+ Opts.AsyncThreadsCount = WorkerThreadsCount;
+
+ clangd::CodeCompleteOptions CCOpts;
+ CCOpts.IncludeIneligibleResults = IncludeIneligibleResults;
+ CCOpts.Limit = LimitResults;
+ CCOpts.BundleOverloads = CompletionStyle != Detailed;
+ CCOpts.ShowOrigins = ShowOrigins;
+ if (!HeaderInsertionDecorators) {
+ CCOpts.IncludeIndicator.Insert.clear();
+ CCOpts.IncludeIndicator.NoInsert.clear();
+ }
+
+ // Initialize and run ClangdLSPServer.
+ ClangdLSPServer LSPServer(Out, CCOpts, CompileCommandsDirPath, Opts);
+ constexpr int NoShutdownRequestErrorCode = 1;
+ llvm::set_thread_name("clangd.main");
+ // Change stdin to binary to not lose \r\n on windows.
+ llvm::sys::ChangeStdinToBinary();
+ return LSPServer.run(stdin, InputStyle) ? 0 : NoShutdownRequestErrorCode;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/docs/CMakeLists.txt
new file mode 100644
index 0000000..8f442e1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/CMakeLists.txt
@@ -0,0 +1,102 @@
+if (DOXYGEN_FOUND)
+ if (LLVM_ENABLE_DOXYGEN)
+ set(abs_srcdir ${CMAKE_CURRENT_SOURCE_DIR})
+ set(abs_builddir ${CMAKE_CURRENT_BINARY_DIR})
+
+ if (HAVE_DOT)
+ set(DOT ${LLVM_PATH_DOT})
+ endif()
+
+ if (LLVM_DOXYGEN_EXTERNAL_SEARCH)
+ set(enable_searchengine "YES")
+ set(searchengine_url "${LLVM_DOXYGEN_SEARCHENGINE_URL}")
+ set(enable_server_based_search "YES")
+ set(enable_external_search "YES")
+ set(extra_search_mappings "${LLVM_DOXYGEN_SEARCH_MAPPINGS}")
+ else()
+ set(enable_searchengine "NO")
+ set(searchengine_url "")
+ set(enable_server_based_search "NO")
+ set(enable_external_search "NO")
+ set(extra_search_mappings "")
+ endif()
+
+ # If asked, configure doxygen for the creation of a Qt Compressed Help file.
+ if (LLVM_ENABLE_DOXYGEN_QT_HELP)
+ set(CLANG_TOOLS_DOXYGEN_QCH_FILENAME "org.llvm.clang.qch" CACHE STRING
+ "Filename of the Qt Compressed help file")
+ set(CLANG_TOOLS_DOXYGEN_QHP_NAMESPACE "org.llvm.clang" CACHE STRING
+ "Namespace under which the intermediate Qt Help Project file lives")
+ set(CLANG_TOOLS_DOXYGEN_QHP_CUST_FILTER_NAME "Clang ${CLANG_VERSION}" CACHE STRING
+ "See http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-filters")
+ set(CLANG_TOOLS_DOXYGEN_QHP_CUST_FILTER_ATTRS "Clang,${CLANG_VERSION}" CACHE STRING
+ "See http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes")
+ set(clang_tools_doxygen_generate_qhp "YES")
+ set(clang_tools_doxygen_qch_filename "${CLANG_DOXYGEN_QCH_FILENAME}")
+ set(clang_tools_doxygen_qhp_namespace "${CLANG_DOXYGEN_QHP_NAMESPACE}")
+ set(clang_tools_doxygen_qhelpgenerator_path "${LLVM_DOXYGEN_QHELPGENERATOR_PATH}")
+ set(clang_tools_doxygen_qhp_cust_filter_name "${CLANG_DOXYGEN_QHP_CUST_FILTER_NAME}")
+ set(clang_tools_doxygen_qhp_cust_filter_attrs "${CLANG_DOXYGEN_QHP_CUST_FILTER_ATTRS}")
+ else()
+ set(clang_tools_doxygen_generate_qhp "NO")
+ set(clang_tools_doxygen_qch_filename "")
+ set(clang_tools_doxygen_qhp_namespace "")
+ set(clang_tools_doxygen_qhelpgenerator_path "")
+ set(clang_tools_doxygen_qhp_cust_filter_name "")
+ set(clang_tools_doxygen_qhp_cust_filter_attrs "")
+ endif()
+
+ option(LLVM_DOXYGEN_SVG
+ "Use svg instead of png files for doxygen graphs." OFF)
+ if (LLVM_DOXYGEN_SVG)
+ set(DOT_IMAGE_FORMAT "svg")
+ else()
+ set(DOT_IMAGE_FORMAT "png")
+ endif()
+
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxygen.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg @ONLY)
+
+ set(abs_top_srcdir)
+ set(abs_top_builddir)
+ set(DOT)
+ set(enable_searchengine)
+ set(searchengine_url)
+ set(enable_server_based_search)
+ set(enable_external_search)
+ set(extra_search_mappings)
+ set(clang_tools_doxygen_generate_qhp)
+ set(clang_tools_doxygen_qch_filename)
+ set(clang_tools_doxygen_qhp_namespace)
+ set(clang_tools_doxygen_qhelpgenerator_path)
+ set(clang_tools_doxygen_qhp_cust_filter_name)
+ set(clang_tools_doxygen_qhp_cust_filter_attrs)
+ set(DOT_IMAGE_FORMAT)
+
+ add_custom_target(doxygen-clang-tools
+ COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Generating clang doxygen documentation." VERBATIM)
+
+ if (LLVM_BUILD_DOCS)
+ add_dependencies(doxygen doxygen-clang-tools)
+ endif()
+
+ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
+ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doxygen/html
+ DESTINATION docs/html)
+ endif()
+ endif()
+endif()
+
+if (LLVM_ENABLE_SPHINX)
+ include(AddSphinxTarget)
+ if (SPHINX_FOUND)
+ if (${SPHINX_OUTPUT_HTML})
+ add_sphinx_target(html clang-tools)
+ endif()
+ if (${SPHINX_OUTPUT_MAN})
+ add_sphinx_target(man clang-tools)
+ endif()
+ endif()
+endif()
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/ModularizeUsage.rst b/src/third_party/llvm-project/clang-tools-extra/docs/ModularizeUsage.rst
new file mode 100644
index 0000000..9f01165
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/ModularizeUsage.rst
@@ -0,0 +1,98 @@
+================
+Modularize Usage
+================
+
+``modularize [<modularize-options>] [<module-map>|<include-files-list>]*
+[<front-end-options>...]``
+
+``<modularize-options>`` is a place-holder for options
+specific to modularize, which are described below in
+`Modularize Command Line Options`.
+
+``<module-map>`` specifies the path of a file name for an
+existing module map. The module map must be well-formed in
+terms of syntax. Modularize will extract the header file names
+from the map. Only normal headers are checked, assuming headers
+marked "private", "textual", or "exclude" are not to be checked
+as a top-level include, assuming they either are included by
+other headers which are checked, or they are not suitable for
+modules.
+
+``<include-files-list>`` specifies the path of a file name for a
+file containing the newline-separated list of headers to check
+with respect to each other. Lines beginning with '#' and empty
+lines are ignored. Header file names followed by a colon and
+other space-separated file names will include those extra files
+as dependencies. The file names can be relative or full paths,
+but must be on the same line. For example::
+
+ header1.h
+ header2.h
+ header3.h: header1.h header2.h
+
+Note that unless a ``-prefix (header path)`` option is specified,
+non-absolute file paths in the header list file will be relative
+to the header list file directory. Use -prefix to specify a different
+directory.
+
+``<front-end-options>`` is a place-holder for regular Clang
+front-end arguments, which must follow the <include-files-list>.
+Note that by default, modularize assumes .h files
+contain C++ source, so if you are using a different language,
+you might need to use a ``-x`` option to tell Clang that the
+header contains another language, i.e.: ``-x c``
+
+Note also that because modularize does not use the clang driver,
+you will likely need to pass in additional compiler front-end
+arguments to match those passed in by default by the driver.
+
+Modularize Command Line Options
+===============================
+
+.. option:: -prefix=<header-path>
+
+ Prepend the given path to non-absolute file paths in the header list file.
+ By default, headers are assumed to be relative to the header list file
+ directory. Use ``-prefix`` to specify a different directory.
+
+.. option:: -module-map-path=<module-map-path>
+
+ Generate a module map and output it to the given file. See the description
+ in :ref:`module-map-generation`.
+
+.. option:: -problem-files-list=<problem-files-list-file-name>
+
+ For use only with module map assistant. Input list of files that
+ have problems with respect to modules. These will still be
+ included in the generated module map, but will be marked as
+ "excluded" headers.
+
+.. option:: -root-module=<root-name>
+
+ Put modules generated by the -module-map-path option in an enclosing
+ module with the given name. See the description in :ref:`module-map-generation`.
+
+.. option:: -block-check-header-list-only
+
+ Limit the #include-inside-extern-or-namespace-block
+ check to only those headers explicitly listed in the header list.
+ This is a work-around for avoiding error messages for private includes that
+ purposefully get included inside blocks.
+
+.. option:: -no-coverage-check
+
+ Don't do the coverage check for a module map.
+
+.. option:: -coverage-check-only
+
+ Only do the coverage check for a module map.
+
+.. option:: -display-file-lists
+
+ Display lists of good files (no compile errors), problem files,
+ and a combined list with problem files preceded by a '#'.
+ This can be used to quickly determine which files have problems.
+ The latter combined list might be useful in starting to modularize
+ a set of headers. You can start with a full list of headers,
+ use -display-file-lists option, and then use the combined list as
+ your intermediate list, uncommenting-out headers as you fix them.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/README.txt b/src/third_party/llvm-project/clang-tools-extra/docs/README.txt
new file mode 100644
index 0000000..4b60777
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/README.txt
@@ -0,0 +1,11 @@
+-------------------------------------------------------------
+Documentation for the tools of clang-tools-extra repo project
+-------------------------------------------------------------
+
+Sphinx and doxygen documentation is generated by executing make.
+
+Sphinx html files can be generated separately using make html.
+
+Doxygen html files can also be generated using make doxygen.
+
+The generated documentation will be placed in _build/html.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/ReleaseNotes.rst b/src/third_party/llvm-project/clang-tools-extra/docs/ReleaseNotes.rst
new file mode 100644
index 0000000..157db97
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/ReleaseNotes.rst
@@ -0,0 +1,245 @@
+=====================================
+Extra Clang Tools 7.0.0 Release Notes
+=====================================
+
+.. contents::
+ :local:
+ :depth: 3
+
+Written by the `LLVM Team <https://llvm.org/>`_
+
+
+Introduction
+============
+
+This document contains the release notes for the Extra Clang Tools, part of the
+Clang release 7.0.0. Here we describe the status of the Extra Clang Tools in
+some detail, including major improvements from the previous release and new
+feature work. All LLVM releases may be downloaded from the `LLVM releases web
+site <https://llvm.org/releases/>`_.
+
+For more information about Clang or LLVM, including information about
+the latest release, please see the `Clang Web Site <https://clang.llvm.org>`_ or
+the `LLVM Web Site <https://llvm.org>`_.
+
+What's New in Extra Clang Tools 7.0.0?
+======================================
+
+Some of the major new features and improvements to Extra Clang Tools are listed
+here. Generic improvements to Extra Clang Tools as a whole or to its underlying
+infrastructure are described first, followed by tool-specific sections.
+
+Improvements to clang-tidy
+--------------------------
+
+- The checks profiling info can now be stored as JSON files for futher
+ post-processing and analysis.
+
+- New module `abseil` for checks related to the `Abseil <https://abseil.io>`_
+ library.
+
+- New module ``portability``.
+
+- New module ``zircon`` for checks related to Fuchsia's Zircon kernel.
+
+- New :doc:`abseil-string-find-startswith
+ <clang-tidy/checks/abseil-string-find-startswith>` check.
+
+ Checks whether a ``std::string::find()`` result is compared with 0, and
+ suggests replacing with ``absl::StartsWith()``.
+
+- New :doc:`android-comparison-in-temp-failure-retry
+ <clang-tidy/checks/android-comparison-in-temp-failure-retry>` check.
+
+ Diagnoses comparisons that appear to be incorrectly placed in the argument to
+ the ``TEMP_FAILURE_RETRY`` macro.
+
+- New :doc:`bugprone-exception-escape
+ <clang-tidy/checks/bugprone-exception-escape>` check
+
+ Finds functions which may throw an exception directly or indirectly, but they
+ should not.
+
+- New :doc:`bugprone-parent-virtual-call
+ <clang-tidy/checks/bugprone-parent-virtual-call>` check.
+
+ Detects and fixes calls to grand-...parent virtual methods instead of calls
+ to overridden parent's virtual methods.
+
+- New :doc:`bugprone-terminating-continue
+ <clang-tidy/checks/bugprone-terminating-continue>` check
+
+ Checks if a ``continue`` statement terminates the loop.
+
+- New :doc:`bugprone-throw-keyword-missing
+ <clang-tidy/checks/bugprone-throw-keyword-missing>` check.
+
+ Diagnoses when a temporary object that appears to be an exception is
+ constructed but not thrown.
+
+- New :doc:`bugprone-unused-return-value
+ <clang-tidy/checks/bugprone-unused-return-value>` check.
+
+ Warns on unused function return values.
+
+- New :doc:`cert-msc32-c
+ <clang-tidy/checks/cert-msc32-c>` check
+
+ Detects inappropriate seeding of ``srand()`` function.
+
+- New :doc:`cert-msc51-cpp
+ <clang-tidy/checks/cert-msc51-cpp>` check
+
+ Detects inappropriate seeding of C++ random generators and C ``srand()`` function.
+
+- New :doc:`cppcoreguidelines-avoid-goto
+ <clang-tidy/checks/cppcoreguidelines-avoid-goto>` check.
+
+ The usage of ``goto`` for control flow is error prone and should be replaced
+ with looping constructs. Every backward jump is rejected. Forward jumps are
+ only allowed in nested loops.
+
+- New :doc:`cppcoreguidelines-narrowing-conversions
+ <clang-tidy/checks/cppcoreguidelines-narrowing-conversions>` check
+
+ Checks for narrowing conversions, e.g. ``int i = 0; i += 0.1;``.
+
+- New :doc:`fuchsia-multiple-inheritance
+ <clang-tidy/checks/fuchsia-multiple-inheritance>` check.
+
+ Warns if a class inherits from multiple classes that are not pure virtual.
+
+- New `fuchsia-restrict-system-includes
+ <https://clang.llvm.org/extra/clang-tidy/checks/fuchsia-restrict-system-includes.html>`_ check
+
+ Checks for allowed system includes and suggests removal of any others.
+
+- New `fuchsia-statically-constructed-objects
+ <https://clang.llvm.org/extra/clang-tidy/checks/fuchsia-statically-constructed-objects.html>`_ check
+
+ Warns if global, non-trivial objects with static storage are constructed,
+ unless the object is statically initialized with a ``constexpr`` constructor
+ or has no explicit constructor.
+
+- New :doc:`fuchsia-trailing-return
+ <clang-tidy/checks/fuchsia-trailing-return>` check.
+
+ Functions that have trailing returns are disallowed, except for those
+ using ``decltype`` specifiers and lambda with otherwise unutterable
+ return types.
+
+- New :doc:`hicpp-multiway-paths-covered
+ <clang-tidy/checks/hicpp-multiway-paths-covered>` check.
+
+ Checks on ``switch`` and ``if`` - ``else if`` constructs that do not cover all possible code paths.
+
+- New :doc:`modernize-use-uncaught-exceptions
+ <clang-tidy/checks/modernize-use-uncaught-exceptions>` check.
+
+ Finds and replaces deprecated uses of ``std::uncaught_exception`` to
+ ``std::uncaught_exceptions``.
+
+- New :doc:`portability-simd-intrinsics
+ <clang-tidy/checks/portability-simd-intrinsics>` check.
+
+ Warns or suggests alternatives if SIMD intrinsics are used which can be replaced by
+ ``std::experimental::simd`` operations.
+
+- New :doc:`readability-simplify-subscript-expr
+ <clang-tidy/checks/readability-simplify-subscript-expr>` check.
+
+ Simplifies subscript expressions like ``s.data()[i]`` into ``s[i]``.
+
+- New :doc:`zircon-temporary-objects
+ <clang-tidy/checks/zircon-temporary-objects>` check.
+
+ Warns on construction of specific temporary objects in the Zircon kernel.
+
+- Added the missing bitwise assignment operations to
+ :doc:`hicpp-signed-bitwise <clang-tidy/checks/hicpp-signed-bitwise>`.
+
+- New option `MinTypeNameLength` for :doc:`modernize-use-auto
+ <clang-tidy/checks/modernize-use-auto>` check to limit the minimal length of
+ type names to be replaced with ``auto``. Use to skip replacing short type
+ names like ``int``/``bool`` with ``auto``. Default value is 5 which means
+ replace types with the name length >= 5 letters only (ex. ``double``,
+ ``unsigned``).
+
+- Add `VariableThreshold` option to :doc:`readability-function-size
+ <clang-tidy/checks/readability-function-size>` check.
+
+ Flags functions that have more than a specified number of variables declared
+ in the body.
+
+- The `AnalyzeTemporaryDtors` option was removed, since the corresponding
+ `cfg-temporary-dtors` option of the Static Analyzer now defaults to `true`.
+
+- New alias :doc:`fuchsia-header-anon-namespaces
+ <clang-tidy/checks/fuchsia-header-anon-namespaces>` to :doc:`google-build-namespaces
+ <clang-tidy/checks/google-build-namespaces>`
+ added.
+
+- New alias :doc:`hicpp-avoid-goto
+ <clang-tidy/checks/hicpp-avoid-goto>` to :doc:`cppcoreguidelines-avoid-goto
+ <clang-tidy/checks/cppcoreguidelines-avoid-goto>`
+ added.
+
+- Removed the `google-readability-redundant-smartptr-get` alias of the
+ :doc:`readability-redundant-smartptr-get
+ <clang-tidy/checks/readability-redundant-smartptr-get>` check.
+
+- The 'misc-forwarding-reference-overload' check was renamed to :doc:`bugprone-forwarding-reference-overload
+ <clang-tidy/checks/bugprone-forwarding-reference-overload>`
+
+- The 'misc-incorrect-roundings' check was renamed to :doc:`bugprone-incorrect-roundings
+ <clang-tidy/checks/bugprone-incorrect-roundings>`
+
+- The 'misc-lambda-function-name' check was renamed to :doc:`bugprone-lambda-function-name
+ <clang-tidy/checks/bugprone-lambda-function-name>`
+
+- The 'misc-macro-parentheses' check was renamed to :doc:`bugprone-macro-parentheses
+ <clang-tidy/checks/bugprone-macro-parentheses>`
+
+- The 'misc-macro-repeated-side-effects' check was renamed to :doc:`bugprone-macro-repeated-side-effects
+ <clang-tidy/checks/bugprone-macro-repeated-side-effects>`
+
+- The 'misc-misplaced-widening-cast' check was renamed to :doc:`bugprone-misplaced-widening-cast
+ <clang-tidy/checks/bugprone-misplaced-widening-cast>`
+
+- The 'misc-sizeof-container' check was renamed to :doc:`bugprone-sizeof-container
+ <clang-tidy/checks/bugprone-sizeof-container>`
+
+- The 'misc-sizeof-expression' check was renamed to :doc:`bugprone-sizeof-expression
+ <clang-tidy/checks/bugprone-sizeof-expression>`
+
+- The 'misc-string-compare' check was renamed to :doc:`readability-string-compare
+ <clang-tidy/checks/readability-string-compare>`
+
+- The 'misc-string-integer-assignment' check was renamed to :doc:`bugprone-string-integer-assignment
+ <clang-tidy/checks/bugprone-string-integer-assignment>`
+
+- The 'misc-string-literal-with-embedded-nul' check was renamed to :doc:`bugprone-string-literal-with-embedded-nul
+ <clang-tidy/checks/bugprone-string-literal-with-embedded-nul>`
+
+- The 'misc-suspicious-enum-usage' check was renamed to :doc:`bugprone-suspicious-enum-usage
+ <clang-tidy/checks/bugprone-suspicious-enum-usage>`
+
+- The 'misc-suspicious-missing-comma' check was renamed to :doc:`bugprone-suspicious-missing-comma
+ <clang-tidy/checks/bugprone-suspicious-missing-comma>`
+
+- The 'misc-suspicious-semicolon' check was renamed to :doc:`bugprone-suspicious-semicolon
+ <clang-tidy/checks/bugprone-suspicious-semicolon>`
+
+- The 'misc-suspicious-string-compare' check was renamed to :doc:`bugprone-suspicious-string-compare
+ <clang-tidy/checks/bugprone-suspicious-string-compare>`
+
+- The 'misc-swapped-arguments' check was renamed to :doc:`bugprone-swapped-arguments
+ <clang-tidy/checks/bugprone-swapped-arguments>`
+
+- The 'misc-undelegated-constructor' check was renamed to :doc:`bugprone-undelegated-constructor
+ <clang-tidy/checks/bugprone-undelegated-constructor>`
+
+- The 'misc-unused-raii' check was renamed to :doc:`bugprone-unused-raii
+ <clang-tidy/checks/bugprone-unused-raii>`
+
+- The 'google-runtime-member-string-references' check was removed.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-doc.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-doc.rst
new file mode 100644
index 0000000..f891b71
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-doc.rst
@@ -0,0 +1,65 @@
+===================
+Clang-Doc
+===================
+
+.. contents::
+
+.. toctree::
+ :maxdepth: 1
+
+:program:`clang-doc` is a tool for generating C and C++ documenation from
+source code and comments.
+
+The tool is in a very early development stage, so you might encounter bugs and
+crashes. Submitting reports with information about how to reproduce the issue
+to `the LLVM bugtracker <https://llvm.org/bugs>`_ will definitely help the
+project. If you have any ideas or suggestions, please to put a feature request
+there.
+
+Use
+=====
+
+:program:`clang-doc` is a `LibTooling
+<http://clang.llvm.org/docs/LibTooling.html>`_-based tool, and so requires a
+compile command database for your project (for an example of how to do this
+see `How To Setup Tooling For LLVM
+<http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html>`_).
+
+The tool can be used on a single file or multiple files as defined in
+the compile commands database:
+
+.. code-block:: console
+
+ $ clang-doc /path/to/file.cpp -p /path/to/compile/commands
+
+This generates an intermediate representation of the declarations and their
+associated information in the specified TUs, serialized to LLVM bitcode.
+
+As currently implemented, the tool is only able to parse TUs that can be
+stored in-memory. Future additions will extend the current framework to use
+map-reduce frameworks to allow for use with large codebases.
+
+:program:`clang-doc` offers the following options:
+
+.. code-block:: console
+
+ $ clang-doc --help
+ USAGE: clang-doc [options] <source0> [... <sourceN>]
+
+ OPTIONS:
+
+ Generic Options:
+
+ -help - Display available options (-help-hidden for more)
+ -help-list - Display list of available options (-help-list-hidden for more)
+ -version - Display the version of this program
+
+ clang-doc options:
+
+ -doxygen - Use only doxygen-style comments to generate docs.
+ -dump - Dump intermediate results to bitcode file.
+ -extra-arg=<string> - Additional argument to append to the compiler command line
+ -extra-arg-before=<string> - Additional argument to prepend to the compiler command line
+ -omit-filenames - Omit filenames in output.
+ -output=<string> - Directory for outputting generated files.
+ -p=<string> - Build path
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-modernize.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-modernize.rst
new file mode 100644
index 0000000..0a42961
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-modernize.rst
@@ -0,0 +1,4 @@
+:orphan:
+
+All :program:`clang-modernize` transforms have moved to :doc:`clang-tidy/index`
+(see the ``modernize`` module).
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-rename.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-rename.rst
new file mode 100644
index 0000000..f622779
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-rename.rst
@@ -0,0 +1,166 @@
+============
+Clang-Rename
+============
+
+.. contents::
+
+See also:
+
+.. toctree::
+ :maxdepth: 1
+
+
+:program:`clang-rename` is a C++ refactoring tool. Its purpose is to perform
+efficient renaming actions in large-scale projects such as renaming classes,
+functions, variables, arguments, namespaces etc.
+
+The tool is in a very early development stage, so you might encounter bugs and
+crashes. Submitting reports with information about how to reproduce the issue
+to `the LLVM bugtracker <https://llvm.org/bugs>`_ will definitely help the
+project. If you have any ideas or suggestions, you might want to put a feature
+request there.
+
+Using Clang-Rename
+==================
+
+:program:`clang-rename` is a `LibTooling
+<http://clang.llvm.org/docs/LibTooling.html>`_-based tool, and it's easier to
+work with if you set up a compile command database for your project (for an
+example of how to do this see `How To Setup Tooling For LLVM
+<http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html>`_). You can also
+specify compilation options on the command line after `--`:
+
+.. code-block:: console
+
+ $ clang-rename -offset=42 -new-name=foo test.cpp -- -Imy_project/include -DMY_DEFINES ...
+
+
+To get an offset of a symbol in a file run
+
+.. code-block:: console
+
+ $ grep -FUbo 'foo' file.cpp
+
+
+The tool currently supports renaming actions inside a single translation unit
+only. It is planned to extend the tool's functionality to support multi-TU
+renaming actions in the future.
+
+:program:`clang-rename` also aims to be easily integrated into popular text
+editors, such as Vim and Emacs, and improve the workflow of users.
+
+Although a command line interface exists, it is highly recommended to use the
+text editor interface instead for better experience.
+
+You can also identify one or more symbols to be renamed by giving the fully
+qualified name:
+
+.. code-block:: console
+
+ $ clang-rename -qualified-name=foo -new-name=bar test.cpp
+
+Renaming multiple symbols at once is supported, too. However,
+:program:`clang-rename` doesn't accept both `-offset` and `-qualified-name` at
+the same time. So, you can either specify multiple `-offset` or
+`-qualified-name`.
+
+.. code-block:: console
+
+ $ clang-rename -offset=42 -new-name=bar1 -offset=150 -new-name=bar2 test.cpp
+
+or
+
+.. code-block:: console
+
+ $ clang-rename -qualified-name=foo1 -new-name=bar1 -qualified-name=foo2 -new-name=bar2 test.cpp
+
+
+Alternatively, {offset | qualified-name} / new-name pairs can be put into a YAML
+file:
+
+.. code-block:: yaml
+
+ ---
+ - Offset: 42
+ NewName: bar1
+ - Offset: 150
+ NewName: bar2
+ ...
+
+or
+
+.. code-block:: yaml
+
+ ---
+ - QualifiedName: foo1
+ NewName: bar1
+ - QualifiedName: foo2
+ NewName: bar2
+ ...
+
+That way you can avoid spelling out all the names as command line arguments:
+
+.. code-block:: console
+
+ $ clang-rename -input=test.yaml test.cpp
+
+:program:`clang-rename` offers the following options:
+
+.. code-block:: console
+
+ $ clang-rename --help
+ USAGE: clang-rename [subcommand] [options] <source0> [... <sourceN>]
+
+ OPTIONS:
+
+ Generic Options:
+
+ -help - Display available options (-help-hidden for more)
+ -help-list - Display list of available options (-help-list-hidden for more)
+ -version - Display the version of this program
+
+ clang-rename common options:
+
+ -export-fixes=<filename> - YAML file to store suggested fixes in.
+ -extra-arg=<string> - Additional argument to append to the compiler command line
+ -extra-arg-before=<string> - Additional argument to prepend to the compiler command line
+ -force - Ignore nonexistent qualified names.
+ -i - Overwrite edited <file>s.
+ -input=<string> - YAML file to load oldname-newname pairs from.
+ -new-name=<string> - The new name to change the symbol to.
+ -offset=<uint> - Locates the symbol by offset as opposed to <line>:<column>.
+ -p=<string> - Build path
+ -pl - Print the locations affected by renaming to stderr.
+ -pn - Print the found symbol's name prior to renaming to stderr.
+ -qualified-name=<string> - The fully qualified name of the symbol.
+
+Vim Integration
+===============
+
+You can call :program:`clang-rename` directly from Vim! To set up
+:program:`clang-rename` integration for Vim see
+`clang-rename/tool/clang-rename.py
+<http://reviews.llvm.org/diffusion/L/browse/clang-tools-extra/trunk/clang-rename/tool/clang-rename.py>`_.
+
+Please note that **you have to save all buffers, in which the replacement will
+happen before running the tool**.
+
+Once installed, you can point your cursor to symbols you want to rename, press
+`<leader>cr` and type new desired name. The `<leader> key
+<http://vim.wikia.com/wiki/Mapping_keys_in_Vim_-_Tutorial_(Part_3)#Map_leader>`_
+is a reference to a specific key defined by the mapleader variable and is bound
+to backslash by default.
+
+Emacs Integration
+=================
+
+You can also use :program:`clang-rename` while using Emacs! To set up
+:program:`clang-rename` integration for Emacs see
+`clang-rename/tool/clang-rename.el
+<http://reviews.llvm.org/diffusion/L/browse/clang-tools-extra/trunk/clang-rename/tool/clang-rename.el>`_.
+
+Once installed, you can point your cursor to symbols you want to rename, press
+`M-X`, type `clang-rename` and new desired name.
+
+Please note that **you have to save all buffers, in which the replacement will
+happen before running the tool**.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy.rst
new file mode 100644
index 0000000..bcd2bf1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy.rst
@@ -0,0 +1,6 @@
+:orphan:
+
+.. meta::
+ :http-equiv=refresh: 0;URL='clang-tidy/'
+
+clang-tidy documentation has moved here: http://clang.llvm.org/extra/clang-tidy/
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/abseil-string-find-startswith.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/abseil-string-find-startswith.rst
new file mode 100644
index 0000000..43f35ac
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/abseil-string-find-startswith.rst
@@ -0,0 +1,41 @@
+.. title:: clang-tidy - abseil-string-find-startswith
+
+abseil-string-find-startswith
+=============================
+
+Checks whether a ``std::string::find()`` result is compared with 0, and
+suggests replacing with ``absl::StartsWith()``. This is both a readability and
+performance issue.
+
+.. code-block:: c++
+
+ string s = "...";
+ if (s.find("Hello World") == 0) { /* do something */ }
+
+becomes
+
+
+.. code-block:: c++
+
+ string s = "...";
+ if (absl::StartsWith(s, "Hello World")) { /* do something */ }
+
+
+Options
+-------
+
+.. option:: StringLikeClasses
+
+ Semicolon-separated list of names of string-like classes. By default only
+ ``std::basic_string`` is considered. The list of methods to considered is
+ fixed.
+
+.. option:: IncludeStyle
+
+ A string specifying which include-style is used, `llvm` or `google`. Default
+ is `llvm`.
+
+.. option:: AbseilStringsMatchHeader
+
+ The location of Abseil's ``strings/match.h``. Defaults to
+ ``absl/strings/match.h``.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-accept.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-accept.rst
new file mode 100644
index 0000000..58ce05f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-accept.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - android-cloexec-accept
+
+android-cloexec-accept
+======================
+
+The usage of ``accept()`` is not recommended, it's better to use ``accept4()``.
+Without this flag, an opened sensitive file descriptor would remain open across
+a fork+exec to a lower-privileged SELinux domain.
+
+Examples:
+
+.. code-block:: c++
+
+ accept(sockfd, addr, addrlen);
+
+ // becomes
+
+ accept4(sockfd, addr, addrlen, SOCK_CLOEXEC);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-accept4.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-accept4.rst
new file mode 100644
index 0000000..1633395
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-accept4.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - android-cloexec-accept4
+
+android-cloexec-accept4
+=======================
+
+``accept4()`` should include ``SOCK_CLOEXEC`` in its type argument to avoid the
+file descriptor leakage. Without this flag, an opened sensitive file would
+remain open across a fork+exec to a lower-privileged SELinux domain.
+
+Examples:
+
+.. code-block:: c++
+
+ accept4(sockfd, addr, addrlen, SOCK_NONBLOCK);
+
+ // becomes
+
+ accept4(sockfd, addr, addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-creat.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-creat.rst
new file mode 100644
index 0000000..d2892a0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-creat.rst
@@ -0,0 +1,16 @@
+.. title:: clang-tidy - android-cloexec-creat
+
+android-cloexec-creat
+=====================
+
+The usage of ``creat()`` is not recommended, it's better to use ``open()``.
+
+Examples:
+
+.. code-block:: c++
+
+ int fd = creat(path, mode);
+
+ // becomes
+
+ int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-dup.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-dup.rst
new file mode 100644
index 0000000..d287a65
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-dup.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - android-cloexec-dup
+
+android-cloexec-dup
+===================
+
+The usage of ``dup()`` is not recommended, it's better to use ``fcntl()``,
+which can set the close-on-exec flag. Otherwise, an opened sensitive file would
+remain open across a fork+exec to a lower-privileged SELinux domain.
+
+Examples:
+
+.. code-block:: c++
+
+ int fd = dup(oldfd);
+
+ // becomes
+
+ int fd = fcntl(oldfd, F_DUPFD_CLOEXEC);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-epoll-create.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-epoll-create.rst
new file mode 100644
index 0000000..98f0f6c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-epoll-create.rst
@@ -0,0 +1,17 @@
+.. title:: clang-tidy - android-cloexec-epoll-create
+
+android-cloexec-epoll-create
+============================
+
+The usage of ``epoll_create()`` is not recommended, it's better to use
+``epoll_create1()``, which allows close-on-exec.
+
+Examples:
+
+.. code-block:: c++
+
+ epoll_create(size);
+
+ // becomes
+
+ epoll_create1(EPOLL_CLOEXEC);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-epoll-create1.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-epoll-create1.rst
new file mode 100644
index 0000000..7e7c4ad
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-epoll-create1.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - android-cloexec-epoll-create1
+
+android-cloexec-epoll-create1
+=============================
+
+``epoll_create1()`` should include ``EPOLL_CLOEXEC`` in its type argument to
+avoid the file descriptor leakage. Without this flag, an opened sensitive file
+would remain open across a fork+exec to a lower-privileged SELinux domain.
+
+Examples:
+
+.. code-block:: c++
+
+ epoll_create1(0);
+
+ // becomes
+
+ epoll_create1(EPOLL_CLOEXEC);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-fopen.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-fopen.rst
new file mode 100644
index 0000000..0552969
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-fopen.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - android-cloexec-fopen
+
+android-cloexec-fopen
+=====================
+
+``fopen()`` should include ``e`` in their mode string; so ``re`` would be
+valid. This is equivalent to having set ``FD_CLOEXEC on`` that descriptor.
+
+Examples:
+
+.. code-block:: c++
+
+ fopen("fn", "r");
+
+ // becomes
+
+ fopen("fn", "re");
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-inotify-init.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-inotify-init.rst
new file mode 100644
index 0000000..cee4c7b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-inotify-init.rst
@@ -0,0 +1,17 @@
+.. title:: clang-tidy - android-cloexec-inotify-init
+
+android-cloexec-inotify-init
+============================
+
+The usage of ``inotify_init()`` is not recommended, it's better to use
+``inotify_init1()``.
+
+Examples:
+
+.. code-block:: c++
+
+ inotify_init();
+
+ // becomes
+
+ inotify_init1(IN_CLOEXEC);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-inotify-init1.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-inotify-init1.rst
new file mode 100644
index 0000000..827598c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-inotify-init1.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - android-cloexec-inotify-init1
+
+android-cloexec-inotify-init1
+=============================
+
+``inotify_init1()`` should include ``IN_CLOEXEC`` in its type argument to avoid the
+file descriptor leakage. Without this flag, an opened sensitive file would
+remain open across a fork+exec to a lower-privileged SELinux domain.
+
+Examples:
+
+.. code-block:: c++
+
+ inotify_init1(IN_NONBLOCK);
+
+ // becomes
+
+ inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-memfd-create.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-memfd-create.rst
new file mode 100644
index 0000000..a45321d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-memfd-create.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - android-cloexec-memfd-create
+
+android-cloexec-memfd-create
+============================
+
+``memfd_create()`` should include ``MFD_CLOEXEC`` in its type argument to avoid
+the file descriptor leakage. Without this flag, an opened sensitive file would
+remain open across a fork+exec to a lower-privileged SELinux domain.
+
+Examples:
+
+.. code-block:: c++
+
+ memfd_create(name, MFD_ALLOW_SEALING);
+
+ // becomes
+
+ memfd_create(name, MFD_ALLOW_SEALING | MFD_CLOEXEC);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-open.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-open.rst
new file mode 100644
index 0000000..ee3e4b5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-open.rst
@@ -0,0 +1,24 @@
+.. title:: clang-tidy - android-cloexec-open
+
+android-cloexec-open
+====================
+
+A common source of security bugs is code that opens a file without using the
+``O_CLOEXEC`` flag. Without that flag, an opened sensitive file would remain
+open across a fork+exec to a lower-privileged SELinux domain, leaking that
+sensitive data. Open-like functions including ``open()``, ``openat()``, and
+``open64()`` should include ``O_CLOEXEC`` in their flags argument.
+
+Examples:
+
+.. code-block:: c++
+
+ open("filename", O_RDWR);
+ open64("filename", O_RDWR);
+ openat(0, "filename", O_RDWR);
+
+ // becomes
+
+ open("filename", O_RDWR | O_CLOEXEC);
+ open64("filename", O_RDWR | O_CLOEXEC);
+ openat(0, "filename", O_RDWR | O_CLOEXEC);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-socket.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-socket.rst
new file mode 100644
index 0000000..10b1976
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-cloexec-socket.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - android-cloexec-socket
+
+android-cloexec-socket
+======================
+
+``socket()`` should include ``SOCK_CLOEXEC`` in its type argument to avoid the
+file descriptor leakage. Without this flag, an opened sensitive file would
+remain open across a fork+exec to a lower-privileged SELinux domain.
+
+Examples:
+
+.. code-block:: c++
+
+ socket(domain, type, SOCK_STREAM);
+
+ // becomes
+
+ socket(domain, type, SOCK_STREAM | SOCK_CLOEXEC);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-comparison-in-temp-failure-retry.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-comparison-in-temp-failure-retry.rst
new file mode 100644
index 0000000..e4de4b0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/android-comparison-in-temp-failure-retry.rst
@@ -0,0 +1,36 @@
+.. title:: clang-tidy - android-comparison-in-temp-failure-retry
+
+android-comparison-in-temp-failure-retry
+========================================
+
+Diagnoses comparisons that appear to be incorrectly placed in the argument to
+the ``TEMP_FAILURE_RETRY`` macro. Having such a use is incorrect in the vast
+majority of cases, and will often silently defeat the purpose of the
+``TEMP_FAILURE_RETRY`` macro.
+
+For context, ``TEMP_FAILURE_RETRY`` is `a convenience macro
+<https://www.gnu.org/software/libc/manual/html_node/Interrupted-Primitives.html>`_
+provided by both glibc and Bionic. Its purpose is to repeatedly run a syscall
+until it either succeeds, or fails for reasons other than being interrupted.
+
+Example buggy usage looks like:
+
+.. code-block:: c
+
+ char cs[1];
+ while (TEMP_FAILURE_RETRY(read(STDIN_FILENO, cs, sizeof(cs)) != 0)) {
+ // Do something with cs.
+ }
+
+Because TEMP_FAILURE_RETRY will check for whether the result *of the comparison*
+is ``-1``, and retry if so.
+
+If you encounter this, the fix is simple: lift the comparison out of the
+``TEMP_FAILURE_RETRY`` argument, like so:
+
+.. code-block:: c
+
+ char cs[1];
+ while (TEMP_FAILURE_RETRY(read(STDIN_FILENO, cs, sizeof(cs))) != 0) {
+ // Do something with cs.
+ }
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/boost-use-to-string.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/boost-use-to-string.rst
new file mode 100644
index 0000000..ebeb829
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/boost-use-to-string.rst
@@ -0,0 +1,22 @@
+.. title:: clang-tidy - boost-use-to-string
+
+boost-use-to-string
+===================
+
+This check finds conversion from integer type like ``int`` to ``std::string`` or
+``std::wstring`` using ``boost::lexical_cast``, and replace it with calls to
+``std::to_string`` and ``std::to_wstring``.
+
+It doesn't replace conversion from floating points despite the ``to_string``
+overloads, because it would change the behaviour.
+
+
+ .. code-block:: c++
+
+ auto str = boost::lexical_cast<std::string>(42);
+ auto wstr = boost::lexical_cast<std::wstring>(2137LL);
+
+ // Will be changed to
+ auto str = std::to_string(42);
+ auto wstr = std::to_wstring(2137LL);
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-argument-comment.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-argument-comment.rst
new file mode 100644
index 0000000..5f7e5f0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-argument-comment.rst
@@ -0,0 +1,29 @@
+.. title:: clang-tidy - bugprone-argument-comment
+
+bugprone-argument-comment
+=========================
+
+Checks that argument comments match parameter names.
+
+The check understands argument comments in the form ``/*parameter_name=*/``
+that are placed right before the argument.
+
+.. code-block:: c++
+
+ void f(bool foo);
+
+ ...
+
+ f(/*bar=*/true);
+ // warning: argument name 'bar' in comment does not match parameter name 'foo'
+
+The check tries to detect typos and suggest automated fixes for them.
+
+Options
+-------
+
+.. option:: StrictMode
+
+ When zero (default value), the check will ignore leading and trailing
+ underscores and case when comparing names -- otherwise they are taken into
+ account.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-assert-side-effect.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-assert-side-effect.rst
new file mode 100644
index 0000000..dc7a3c9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-assert-side-effect.rst
@@ -0,0 +1,23 @@
+.. title:: clang-tidy - bugprone-assert-side-effect
+
+bugprone-assert-side-effect
+===========================
+
+Finds ``assert()`` with side effect.
+
+The condition of ``assert()`` is evaluated only in debug builds so a
+condition with side effect can cause different behavior in debug / release
+builds.
+
+Options
+-------
+
+.. option:: AssertMacros
+
+ A comma-separated list of the names of assert macros to be checked.
+
+.. option:: CheckFunctionCalls
+
+ Whether to treat non-const member and non-member functions as they produce
+ side effects. Disabled by default because it can increase the number of false
+ positive warnings.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-bool-pointer-implicit-conversion.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-bool-pointer-implicit-conversion.rst
new file mode 100644
index 0000000..e42ee5f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-bool-pointer-implicit-conversion.rst
@@ -0,0 +1,16 @@
+.. title:: clang-tidy - bugprone-bool-pointer-implicit-conversion
+
+bugprone-bool-pointer-implicit-conversion
+=========================================
+
+Checks for conditions based on implicit conversion from a ``bool`` pointer to
+``bool``.
+
+Example:
+
+.. code-block:: c++
+
+ bool *p;
+ if (p) {
+ // Never used in a pointer-specific way.
+ }
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-copy-constructor-init.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-copy-constructor-init.rst
new file mode 100644
index 0000000..a2b39bc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-copy-constructor-init.rst
@@ -0,0 +1,29 @@
+.. title:: clang-tidy - bugprone-copy-constructor-init
+
+bugprone-copy-constructor-init
+==============================
+
+Finds copy constructors where the constructor doesn't call
+the copy constructor of the base class.
+
+.. code-block:: c++
+
+ class Copyable {
+ public:
+ Copyable() = default;
+ Copyable(const Copyable &) = default;
+ };
+ class X2 : public Copyable {
+ X2(const X2 &other) {} // Copyable(other) is missing
+ };
+
+Also finds copy constructors where the constructor of
+the base class don't have parameter.
+
+.. code-block:: c++
+
+ class X4 : public Copyable {
+ X4(const X4 &other) : Copyable() {} // other is missing
+ };
+
+The check also suggests a fix-its in some cases.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-dangling-handle.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-dangling-handle.rst
new file mode 100644
index 0000000..8c2c316
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-dangling-handle.rst
@@ -0,0 +1,38 @@
+.. title:: clang-tidy - bugprone-dangling-handle
+
+bugprone-dangling-handle
+========================
+
+Detect dangling references in value handles like
+``std::experimental::string_view``.
+These dangling references can be a result of constructing handles from temporary
+values, where the temporary is destroyed soon after the handle is created.
+
+Examples:
+
+.. code-block:: c++
+
+ string_view View = string(); // View will dangle.
+ string A;
+ View = A + "A"; // still dangle.
+
+ vector<string_view> V;
+ V.push_back(string()); // V[0] is dangling.
+ V.resize(3, string()); // V[1] and V[2] will also dangle.
+
+ string_view f() {
+ // All these return values will dangle.
+ return string();
+ string S;
+ return S;
+ char Array[10]{};
+ return Array;
+ }
+
+Options
+-------
+
+.. option:: HandleClasses
+
+ A semicolon-separated list of class names that should be treated as handles.
+ By default only ``std::experimental::basic_string_view`` is considered.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-exception-escape.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-exception-escape.rst
new file mode 100644
index 0000000..e9653a7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-exception-escape.rst
@@ -0,0 +1,39 @@
+.. title:: clang-tidy - bugprone-exception-escape
+
+bugprone-exception-escape
+=========================
+
+Finds functions which may throw an exception directly or indirectly, but they
+should not. The functions which should not throw exceptions are the following:
+* Destructors
+* Move constructors
+* Move assignment operators
+* The ``main()`` functions
+* ``swap()`` functions
+* Functions marked with ``throw()`` or ``noexcept``
+* Other functions given as option
+
+A destructor throwing an exception may result in undefined behavior, resource
+leaks or unexpected termination of the program. Throwing move constructor or
+move assignment also may result in undefined behavior or resource leak. The
+``swap()`` operations expected to be non throwing most of the cases and they
+are always possible to implement in a non throwing way. Non throwing ``swap()``
+operations are also used to create move operations. A throwing ``main()``
+function also results in unexpected termination.
+
+WARNING! This check may be expensive on large source files.
+
+Options
+-------
+
+.. option:: FunctionsThatShouldNotThrow
+
+ Comma separated list containing function names which should not throw. An
+ example value for this parameter can be ``WinMain`` which adds function
+ ``WinMain()`` in the Windows API to the list of the funcions which should
+ not throw. Default value is an empty string.
+
+.. option:: IgnoredExceptions
+
+ Comma separated list containing type names which are not counted as thrown
+ exceptions in the check. Default value is an empty string.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-fold-init-type.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-fold-init-type.rst
new file mode 100644
index 0000000..ebe3d22
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-fold-init-type.rst
@@ -0,0 +1,27 @@
+.. title:: clang-tidy - bugprone-fold-init-type
+
+bugprone-fold-init-type
+=======================
+
+The check flags type mismatches in
+`folds <https://en.wikipedia.org/wiki/Fold_(higher-order_function)>`_
+like ``std::accumulate`` that might result in loss of precision.
+``std::accumulate`` folds an input range into an initial value using the type of
+the latter, with ``operator+`` by default. This can cause loss of precision
+through:
+
+- Truncation: The following code uses a floating point range and an int
+ initial value, so trucation wil happen at every application of ``operator+``
+ and the result will be `0`, which might not be what the user expected.
+
+.. code-block:: c++
+
+ auto a = {0.5f, 0.5f, 0.5f, 0.5f};
+ return std::accumulate(std::begin(a), std::end(a), 0);
+
+- Overflow: The following code also returns `0`.
+
+.. code-block:: c++
+
+ auto a = {65536LL * 65536 * 65536};
+ return std::accumulate(std::begin(a), std::end(a), 0);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-forward-declaration-namespace.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-forward-declaration-namespace.rst
new file mode 100644
index 0000000..99ecb63
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-forward-declaration-namespace.rst
@@ -0,0 +1,20 @@
+.. title:: clang-tidy - bugprone-forward-declaration-namespace
+
+bugprone-forward-declaration-namespace
+======================================
+
+Checks if an unused forward declaration is in a wrong namespace.
+
+The check inspects all unused forward declarations and checks if there is any
+declaration/definition with the same name existing, which could indicate that
+the forward declaration is in a potentially wrong namespace.
+
+.. code-block:: c++
+
+ namespace na { struct A; }
+ namespace nb { struct A {}; }
+ nb::A a;
+ // warning : no definition found for 'A', but a definition with the same name
+ // 'A' found in another namespace 'nb::'
+
+This check can only generate warnings, but it can't suggest a fix at this point.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-forwarding-reference-overload.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-forwarding-reference-overload.rst
new file mode 100644
index 0000000..ddf69dc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-forwarding-reference-overload.rst
@@ -0,0 +1,49 @@
+.. title:: clang-tidy - bugprone-forwarding-reference-overload
+
+bugprone-forwarding-reference-overload
+======================================
+
+The check looks for perfect forwarding constructors that can hide copy or move
+constructors. If a non const lvalue reference is passed to the constructor, the
+forwarding reference parameter will be a better match than the const reference
+parameter of the copy constructor, so the perfect forwarding constructor will be
+called, which can be confusing.
+For detailed description of this issue see: Scott Meyers, Effective Modern C++,
+Item 26.
+
+Consider the following example:
+
+ .. code-block:: c++
+
+ class Person {
+ public:
+ // C1: perfect forwarding ctor
+ template<typename T>
+ explicit Person(T&& n) {}
+
+ // C2: perfect forwarding ctor with parameter default value
+ template<typename T>
+ explicit Person(T&& n, int x = 1) {}
+
+ // C3: perfect forwarding ctor guarded with enable_if
+ template<typename T, typename X = enable_if_t<is_special<T>,void>>
+ explicit Person(T&& n) {}
+
+ // (possibly compiler generated) copy ctor
+ Person(const Person& rhs);
+ };
+
+The check warns for constructors C1 and C2, because those can hide copy and move
+constructors. We suppress warnings if the copy and the move constructors are both
+disabled (deleted or private), because there is nothing the perfect forwarding
+constructor could hide in this case. We also suppress warnings for constructors
+like C3 that are guarded with an enable_if, assuming the programmer was aware of
+the possible hiding.
+
+Background
+----------
+
+For deciding whether a constructor is guarded with enable_if, we consider the
+default values of the type parameters and the types of the constructor
+parameters. If any part of these types is std::enable_if or std::enable_if_t, we
+assume the constructor is guarded.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-inaccurate-erase.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-inaccurate-erase.rst
new file mode 100644
index 0000000..7df47b0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-inaccurate-erase.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - bugprone-inaccurate-erase
+
+bugprone-inaccurate-erase
+=========================
+
+
+Checks for inaccurate use of the ``erase()`` method.
+
+Algorithms like ``remove()`` do not actually remove any element from the
+container but return an iterator to the first redundant element at the end
+of the container. These redundant elements must be removed using the
+``erase()`` method. This check warns when not all of the elements will be
+removed due to using an inappropriate overload.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-incorrect-roundings.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-incorrect-roundings.rst
new file mode 100644
index 0000000..0a5047a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-incorrect-roundings.rst
@@ -0,0 +1,16 @@
+.. title:: clang-tidy - bugprone-incorrect-roundings
+
+bugprone-incorrect-roundings
+============================
+
+Checks the usage of patterns known to produce incorrect rounding.
+Programmers often use::
+
+ (int)(double_expression + 0.5)
+
+to round the double expression to an integer. The problem with this:
+
+1. It is unnecessarily slow.
+2. It is incorrect. The number 0.499999975 (smallest representable float
+ number below 0.5) rounds to 1.0. Even worse behavior for negative
+ numbers where both -0.5f and -1.4f both round to 0.0.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-integer-division.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-integer-division.rst
new file mode 100644
index 0000000..2c82e6f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-integer-division.rst
@@ -0,0 +1,39 @@
+.. title:: clang-tidy - bugprone-integer-division
+
+bugprone-integer-division
+=========================
+
+Finds cases where integer division in a floating point context is likely to
+cause unintended loss of precision.
+
+No reports are made if divisions are part of the following expressions:
+
+- operands of operators expecting integral or bool types,
+- call expressions of integral or bool types, and
+- explicit cast expressions to integral or bool types,
+
+as these are interpreted as signs of deliberateness from the programmer.
+
+Examples:
+
+.. code-block:: c++
+
+ float floatFunc(float);
+ int intFunc(int);
+ double d;
+ int i = 42;
+
+ // Warn, floating-point values expected.
+ d = 32 * 8 / (2 + i);
+ d = 8 * floatFunc(1 + 7 / 2);
+ d = i / (1 << 4);
+
+ // OK, no integer division.
+ d = 32 * 8.0 / (2 + i);
+ d = 8 * floatFunc(1 + 7.0 / 2);
+ d = (double)i / (1 << 4);
+
+ // OK, there are signs of deliberateness.
+ d = 1 << (i / 2);
+ d = 9 + intFunc(6 * i / 32);
+ d = (int)(i / 32) - 8;
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-lambda-function-name.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-lambda-function-name.rst
new file mode 100644
index 0000000..683977a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-lambda-function-name.rst
@@ -0,0 +1,27 @@
+.. title:: clang-tidy - bugprone-lambda-function-name
+
+bugprone-lambda-function-name
+=============================
+
+Checks for attempts to get the name of a function from within a lambda
+expression. The name of a lambda is always something like ``operator()``, which
+is almost never what was intended.
+
+Example:
+
+.. code-block:: c++
+
+ void FancyFunction() {
+ [] { printf("Called from %s\n", __func__); }();
+ [] { printf("Now called from %s\n", __FUNCTION__); }();
+ }
+
+Output::
+
+ Called from operator()
+ Now called from operator()
+
+Likely intended output::
+
+ Called from FancyFunction
+ Now called from FancyFunction
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-macro-parentheses.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-macro-parentheses.rst
new file mode 100644
index 0000000..f827080
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-macro-parentheses.rst
@@ -0,0 +1,19 @@
+.. title:: clang-tidy - bugprone-macro-parentheses
+
+bugprone-macro-parentheses
+==========================
+
+
+Finds macros that can have unexpected behaviour due to missing parentheses.
+
+Macros are expanded by the preprocessor as-is. As a result, there can be
+unexpected behaviour; operators may be evaluated in unexpected order and
+unary operators may become binary operators, etc.
+
+When the replacement list has an expression, it is recommended to surround
+it with parentheses. This ensures that the macro result is evaluated
+completely before it is used.
+
+It is also recommended to surround macro arguments in the replacement list
+with parentheses. This ensures that the argument value is calculated
+properly.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-macro-repeated-side-effects.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-macro-repeated-side-effects.rst
new file mode 100644
index 0000000..15dfdca
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-macro-repeated-side-effects.rst
@@ -0,0 +1,7 @@
+.. title:: clang-tidy - bugprone-macro-repeated-side-effects
+
+bugprone-macro-repeated-side-effects
+====================================
+
+
+Checks for repeated argument with side effects in macros.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-misplaced-operator-in-strlen-in-alloc.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-misplaced-operator-in-strlen-in-alloc.rst
new file mode 100644
index 0000000..e6ff2fe
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-misplaced-operator-in-strlen-in-alloc.rst
@@ -0,0 +1,57 @@
+.. title:: clang-tidy - bugprone-misplaced-operator-in-strlen-in-alloc
+
+bugprone-misplaced-operator-in-strlen-in-alloc
+==============================================
+
+Finds cases where ``1`` is added to the string in the argument to ``strlen()``,
+``strnlen()``, ``strnlen_s()``, ``wcslen()``, ``wcsnlen()``, and ``wcsnlen_s()``
+instead of the result and the value is used as an argument to a memory
+allocation function (``malloc()``, ``calloc()``, ``realloc()``, ``alloca()``) or
+the ``new[]`` operator in `C++`. The check detects error cases even if one of
+these functions (except the ``new[]`` operator) is called by a constant function
+pointer. Cases where ``1`` is added both to the parameter and the result of the
+``strlen()``-like function are ignored, as are cases where the whole addition is
+surrounded by extra parentheses.
+
+`C` example code:
+
+.. code-block:: c
+
+ void bad_malloc(char *str) {
+ char *c = (char*) malloc(strlen(str + 1));
+ }
+
+
+The suggested fix is to add ``1`` to the return value of ``strlen()`` and not
+to its argument. In the example above the fix would be
+
+.. code-block:: c
+
+ char *c = (char*) malloc(strlen(str) + 1);
+
+
+`C++` example code:
+
+.. code-block:: c++
+
+ void bad_new(char *str) {
+ char *c = new char[strlen(str + 1)];
+ }
+
+
+As in the `C` code with the ``malloc()`` function, the suggested fix is to
+add ``1`` to the return value of ``strlen()`` and not to its argument. In the
+example above the fix would be
+
+.. code-block:: c++
+
+ char *c = new char[strlen(str) + 1];
+
+
+Example for silencing the diagnostic:
+
+.. code-block:: c
+
+ void bad_malloc(char *str) {
+ char *c = (char*) malloc(strlen((str + 1)));
+ }
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-misplaced-widening-cast.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-misplaced-widening-cast.rst
new file mode 100644
index 0000000..f42be76
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-misplaced-widening-cast.rst
@@ -0,0 +1,65 @@
+.. title:: clang-tidy - bugprone-misplaced-widening-cast
+
+bugprone-misplaced-widening-cast
+================================
+
+This check will warn when there is a cast of a calculation result to a bigger
+type. If the intention of the cast is to avoid loss of precision then the cast
+is misplaced, and there can be loss of precision. Otherwise the cast is
+ineffective.
+
+Example code:
+
+.. code-block:: c++
+
+ long f(int x) {
+ return (long)(x * 1000);
+ }
+
+The result ``x * 1000`` is first calculated using ``int`` precision. If the
+result exceeds ``int`` precision there is loss of precision. Then the result is
+casted to ``long``.
+
+If there is no loss of precision then the cast can be removed or you can
+explicitly cast to ``int`` instead.
+
+If you want to avoid loss of precision then put the cast in a proper location,
+for instance:
+
+.. code-block:: c++
+
+ long f(int x) {
+ return (long)x * 1000;
+ }
+
+Implicit casts
+--------------
+
+Forgetting to place the cast at all is at least as dangerous and at least as
+common as misplacing it. If :option:`CheckImplicitCasts` is enabled the check
+also detects these cases, for instance:
+
+.. code-block:: c++
+
+ long f(int x) {
+ return x * 1000;
+ }
+
+Floating point
+--------------
+
+Currently warnings are only written for integer conversion. No warning is
+written for this code:
+
+.. code-block:: c++
+
+ double f(float x) {
+ return (double)(x * 10.0f);
+ }
+
+Options
+-------
+
+.. option:: CheckImplicitCasts
+
+ If non-zero, enables detection of implicit casts. Default is non-zero.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-move-forwarding-reference.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-move-forwarding-reference.rst
new file mode 100644
index 0000000..3b57d50
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-move-forwarding-reference.rst
@@ -0,0 +1,60 @@
+.. title:: clang-tidy - bugprone-move-forwarding-reference
+
+bugprone-move-forwarding-reference
+==================================
+
+Warns if ``std::move`` is called on a forwarding reference, for example:
+
+ .. code-block:: c++
+
+ template <typename T>
+ void foo(T&& t) {
+ bar(std::move(t));
+ }
+
+`Forwarding references
+<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4164.pdf>`_ should
+typically be passed to ``std::forward`` instead of ``std::move``, and this is
+the fix that will be suggested.
+
+(A forwarding reference is an rvalue reference of a type that is a deduced
+function template argument.)
+
+In this example, the suggested fix would be
+
+ .. code-block:: c++
+
+ bar(std::forward<T>(t));
+
+Background
+----------
+
+Code like the example above is sometimes written with the expectation that
+``T&&`` will always end up being an rvalue reference, no matter what type is
+deduced for ``T``, and that it is therefore not possible to pass an lvalue to
+``foo()``. However, this is not true. Consider this example:
+
+ .. code-block:: c++
+
+ std::string s = "Hello, world";
+ foo(s);
+
+This code compiles and, after the call to ``foo()``, ``s`` is left in an
+indeterminate state because it has been moved from. This may be surprising to
+the caller of ``foo()`` because no ``std::move`` was used when calling
+``foo()``.
+
+The reason for this behavior lies in the special rule for template argument
+deduction on function templates like ``foo()`` -- i.e. on function templates
+that take an rvalue reference argument of a type that is a deduced function
+template argument. (See section [temp.deduct.call]/3 in the C++11 standard.)
+
+If ``foo()`` is called on an lvalue (as in the example above), then ``T`` is
+deduced to be an lvalue reference. In the example, ``T`` is deduced to be
+``std::string &``. The type of the argument ``t`` therefore becomes
+``std::string& &&``; by the reference collapsing rules, this collapses to
+``std::string&``.
+
+This means that the ``foo(s)`` call passes ``s`` as an lvalue reference, and
+``foo()`` ends up moving ``s`` and thereby placing it into an indeterminate
+state.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-multiple-statement-macro.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-multiple-statement-macro.rst
new file mode 100644
index 0000000..708dc95
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-multiple-statement-macro.rst
@@ -0,0 +1,16 @@
+.. title:: clang-tidy - bugprone-multiple-statement-macro
+
+bugprone-multiple-statement-macro
+=================================
+
+Detect multiple statement macros that are used in unbraced conditionals. Only
+the first statement of the macro will be inside the conditional and the other
+ones will be executed unconditionally.
+
+Example:
+
+.. code-block:: c++
+
+ #define INCREMENT_TWO(x, y) (x)++; (y)++
+ if (do_increment)
+ INCREMENT_TWO(a, b); // (b)++ will be executed unconditionally.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-parent-virtual-call.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
new file mode 100755
index 0000000..e1021b1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-parent-virtual-call.rst
@@ -0,0 +1,23 @@
+.. title:: clang-tidy - bugprone-parent-virtual-call
+
+bugprone-parent-virtual-call
+============================
+
+Detects and fixes calls to grand-...parent virtual methods instead of calls
+to overridden parent's virtual methods.
+
+.. code-block:: c++
+
+ class A {
+ int virtual foo() {...}
+ };
+
+ class B: public A {
+ int foo() override {...}
+ };
+
+ class C: public B {
+ int foo() override { A::foo(); }
+ // ^^^^^^^^
+ // warning: qualified name A::foo refers to a member overridden in subclass; did you mean 'B'? [bugprone-parent-virtual-call]
+ };
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-sizeof-container.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-sizeof-container.rst
new file mode 100644
index 0000000..fb2f0b2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-sizeof-container.rst
@@ -0,0 +1,26 @@
+.. title:: clang-tidy - bugprone-sizeof-container
+
+bugprone-sizeof-container
+=========================
+
+The check finds usages of ``sizeof`` on expressions of STL container types. Most
+likely the user wanted to use ``.size()`` instead.
+
+All class/struct types declared in namespace ``std::`` having a const ``size()``
+method are considered containers, with the exception of ``std::bitset`` and
+``std::array``.
+
+Examples:
+
+.. code-block:: c++
+
+ std::string s;
+ int a = 47 + sizeof(s); // warning: sizeof() doesn't return the size of the container. Did you mean .size()?
+
+ int b = sizeof(std::string); // no warning, probably intended.
+
+ std::string array_of_strings[10];
+ int c = sizeof(array_of_strings) / sizeof(array_of_strings[0]); // no warning, definitely intended.
+
+ std::array<int, 3> std_array;
+ int d = sizeof(std_array); // no warning, probably intended.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-sizeof-expression.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-sizeof-expression.rst
new file mode 100644
index 0000000..b58deaa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-sizeof-expression.rst
@@ -0,0 +1,189 @@
+.. title:: clang-tidy - bugprone-sizeof-expression
+
+bugprone-sizeof-expression
+==========================
+
+The check finds usages of ``sizeof`` expressions which are most likely errors.
+
+The ``sizeof`` operator yields the size (in bytes) of its operand, which may be
+an expression or the parenthesized name of a type. Misuse of this operator may
+be leading to errors and possible software vulnerabilities.
+
+Suspicious usage of 'sizeof(K)'
+-------------------------------
+
+A common mistake is to query the ``sizeof`` of an integer literal. This is
+equivalent to query the size of its type (probably ``int``). The intent of the
+programmer was probably to simply get the integer and not its size.
+
+.. code-block:: c++
+
+ #define BUFLEN 42
+ char buf[BUFLEN];
+ memset(buf, 0, sizeof(BUFLEN)); // sizeof(42) ==> sizeof(int)
+
+Suspicious usage of 'sizeof(expr)'
+----------------------------------
+
+In cases, where there is an enum or integer to represent a type, a common
+mistake is to query the ``sizeof`` on the integer or enum that represents the
+type that should be used by ``sizeof``. This results in the size of the integer
+and not of the type the integer represents:
+
+.. code-block:: c++
+
+ enum data_type {
+ FLOAT_TYPE,
+ DOUBLE_TYPE
+ };
+
+ struct data {
+ data_type type;
+ void* buffer;
+ data_type get_type() {
+ return type;
+ }
+ };
+
+ void f(data d, int numElements) {
+ // should be sizeof(float) or sizeof(double), depending on d.get_type()
+ int numBytes = numElements * sizeof(d.get_type());
+ ...
+ }
+
+
+Suspicious usage of 'sizeof(this)'
+----------------------------------
+
+The ``this`` keyword is evaluated to a pointer to an object of a given type.
+The expression ``sizeof(this)`` is returning the size of a pointer. The
+programmer most likely wanted the size of the object and not the size of the
+pointer.
+
+.. code-block:: c++
+
+ class Point {
+ [...]
+ size_t size() { return sizeof(this); } // should probably be sizeof(*this)
+ [...]
+ };
+
+Suspicious usage of 'sizeof(char*)'
+-----------------------------------
+
+There is a subtle difference between declaring a string literal with
+``char* A = ""`` and ``char A[] = ""``. The first case has the type ``char*``
+instead of the aggregate type ``char[]``. Using ``sizeof`` on an object declared
+with ``char*`` type is returning the size of a pointer instead of the number of
+characters (bytes) in the string literal.
+
+.. code-block:: c++
+
+ const char* kMessage = "Hello World!"; // const char kMessage[] = "...";
+ void getMessage(char* buf) {
+ memcpy(buf, kMessage, sizeof(kMessage)); // sizeof(char*)
+ }
+
+Suspicious usage of 'sizeof(A*)'
+--------------------------------
+
+A common mistake is to compute the size of a pointer instead of its pointee.
+These cases may occur because of explicit cast or implicit conversion.
+
+.. code-block:: c++
+
+ int A[10];
+ memset(A, 0, sizeof(A + 0));
+
+ struct Point point;
+ memset(point, 0, sizeof(&point));
+
+Suspicious usage of 'sizeof(...)/sizeof(...)'
+---------------------------------------------
+
+Dividing ``sizeof`` expressions is typically used to retrieve the number of
+elements of an aggregate. This check warns on incompatible or suspicious cases.
+
+In the following example, the entity has 10-bytes and is incompatible with the
+type ``int`` which has 4 bytes.
+
+.. code-block:: c++
+
+ char buf[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // sizeof(buf) => 10
+ void getMessage(char* dst) {
+ memcpy(dst, buf, sizeof(buf) / sizeof(int)); // sizeof(int) => 4 [incompatible sizes]
+ }
+
+In the following example, the expression ``sizeof(Values)`` is returning the
+size of ``char*``. One can easily be fooled by its declaration, but in parameter
+declaration the size '10' is ignored and the function is receiving a ``char*``.
+
+.. code-block:: c++
+
+ char OrderedValues[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ return CompareArray(char Values[10]) {
+ return memcmp(OrderedValues, Values, sizeof(Values)) == 0; // sizeof(Values) ==> sizeof(char*) [implicit cast to char*]
+ }
+
+Suspicious 'sizeof' by 'sizeof' expression
+------------------------------------------
+
+Multiplying ``sizeof`` expressions typically makes no sense and is probably a
+logic error. In the following example, the programmer used ``*`` instead of
+``/``.
+
+.. code-block:: c++
+
+ const char kMessage[] = "Hello World!";
+ void getMessage(char* buf) {
+ memcpy(buf, kMessage, sizeof(kMessage) * sizeof(char)); // sizeof(kMessage) / sizeof(char)
+ }
+
+This check may trigger on code using the arraysize macro. The following code is
+working correctly but should be simplified by using only the ``sizeof``
+operator.
+
+.. code-block:: c++
+
+ extern Object objects[100];
+ void InitializeObjects() {
+ memset(objects, 0, arraysize(objects) * sizeof(Object)); // sizeof(objects)
+ }
+
+Suspicious usage of 'sizeof(sizeof(...))'
+-----------------------------------------
+
+Getting the ``sizeof`` of a ``sizeof`` makes no sense and is typically an error
+hidden through macros.
+
+.. code-block:: c++
+
+ #define INT_SZ sizeof(int)
+ int buf[] = { 42 };
+ void getInt(int* dst) {
+ memcpy(dst, buf, sizeof(INT_SZ)); // sizeof(sizeof(int)) is suspicious.
+ }
+
+Options
+-------
+
+.. option:: WarnOnSizeOfConstant
+
+ When non-zero, the check will warn on an expression like
+ ``sizeof(CONSTANT)``. Default is `1`.
+
+.. option:: WarnOnSizeOfIntegerExpression
+
+ When non-zero, the check will warn on an expression like ``sizeof(expr)``
+ where the expression results in an integer. Default is `0`.
+
+.. option:: WarnOnSizeOfThis
+
+ When non-zero, the check will warn on an expression like ``sizeof(this)``.
+ Default is `1`.
+
+.. option:: WarnOnSizeOfCompareToConstant
+
+ When non-zero, the check will warn on an expression like
+ ``sizeof(epxr) <= k`` for a suspicious constant `k` while `k` is `0` or
+ greater than `0x8000`. Default is `1`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-string-constructor.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-string-constructor.rst
new file mode 100644
index 0000000..5deedf1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-string-constructor.rst
@@ -0,0 +1,44 @@
+.. title:: clang-tidy - bugprone-string-constructor
+
+bugprone-string-constructor
+===========================
+
+Finds string constructors that are suspicious and probably errors.
+
+A common mistake is to swap parameters to the 'fill' string-constructor.
+
+Examples:
+
+.. code-block:: c++
+
+ std::string str('x', 50); // should be str(50, 'x')
+
+Calling the string-literal constructor with a length bigger than the literal is
+suspicious and adds extra random characters to the string.
+
+Examples:
+
+.. code-block:: c++
+
+ std::string("test", 200); // Will include random characters after "test".
+
+Creating an empty string from constructors with parameters is considered
+suspicious. The programmer should use the empty constructor instead.
+
+Examples:
+
+.. code-block:: c++
+
+ std::string("test", 0); // Creation of an empty string.
+
+Options
+-------
+
+.. option:: WarnOnLargeLength
+
+ When non-zero, the check will warn on a string with a length greater than
+ `LargeLengthThreshold`. Default is `1`.
+
+.. option:: LargeLengthThreshold
+
+ An integer specifying the large length threshold. Default is `0x800000`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-string-integer-assignment.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-string-integer-assignment.rst
new file mode 100644
index 0000000..6401f00
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-string-integer-assignment.rst
@@ -0,0 +1,37 @@
+.. title:: clang-tidy - bugprone-string-integer-assignment
+
+bugprone-string-integer-assignment
+==================================
+
+The check finds assignments of an integer to ``std::basic_string<CharT>``
+(``std::string``, ``std::wstring``, etc.). The source of the problem is the
+following assignment operator of ``std::basic_string<CharT>``:
+
+.. code-block:: c++
+
+ basic_string& operator=( CharT ch );
+
+Numeric types can be implicitly casted to character types.
+
+.. code-block:: c++
+
+ std::string s;
+ int x = 5965;
+ s = 6;
+ s = x;
+
+Use the appropriate conversion functions or character literals.
+
+.. code-block:: c++
+
+ std::string s;
+ int x = 5965;
+ s = '6';
+ s = std::to_string(x);
+
+In order to suppress false positives, use an explicit cast.
+
+.. code-block:: c++
+
+ std::string s;
+ s = static_cast<char>(6);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-string-literal-with-embedded-nul.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-string-literal-with-embedded-nul.rst
new file mode 100644
index 0000000..c1c4d32
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-string-literal-with-embedded-nul.rst
@@ -0,0 +1,36 @@
+.. title:: clang-tidy - bugprone-string-literal-with-embedded-nul
+
+bugprone-string-literal-with-embedded-nul
+=========================================
+
+Finds occurrences of string literal with embedded NUL character and validates
+their usage.
+
+Invalid escaping
+----------------
+
+Special characters can be escaped within a string literal by using their
+hexadecimal encoding like ``\x42``. A common mistake is to escape them
+like this ``\0x42`` where the ``\0`` stands for the NUL character.
+
+.. code-block:: c++
+
+ const char* Example[] = "Invalid character: \0x12 should be \x12";
+ const char* Bytes[] = "\x03\0x02\0x01\0x00\0xFF\0xFF\0xFF";
+
+Truncated literal
+-----------------
+
+String-like classes can manipulate strings with embedded NUL as they are keeping
+track of the bytes and the length. This is not the case for a ``char*``
+(NUL-terminated) string.
+
+A common mistake is to pass a string-literal with embedded NUL to a string
+constructor expecting a NUL-terminated string. The bytes after the first NUL
+character are truncated.
+
+.. code-block:: c++
+
+ std::string str("abc\0def"); // "def" is truncated
+ str += "\0"; // This statement is doing nothing
+ if (str == "\0abc") return; // This expression is always true
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-enum-usage.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-enum-usage.rst
new file mode 100644
index 0000000..5e765be
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-enum-usage.rst
@@ -0,0 +1,78 @@
+.. title:: clang-tidy - bugprone-suspicious-enum-usage
+
+bugprone-suspicious-enum-usage
+==============================
+
+The checker detects various cases when an enum is probably misused (as a bitmask
+).
+
+1. When "ADD" or "bitwise OR" is used between two enum which come from different
+ types and these types value ranges are not disjoint.
+
+The following cases will be investigated only using :option:`StrictMode`. We
+regard the enum as a (suspicious)
+bitmask if the three conditions below are true at the same time:
+
+* at most half of the elements of the enum are non pow-of-2 numbers (because of
+ short enumerations)
+* there is another non pow-of-2 number than the enum constant representing all
+ choices (the result "bitwise OR" operation of all enum elements)
+* enum type variable/enumconstant is used as an argument of a `+` or "bitwise OR
+ " operator
+
+So whenever the non pow-of-2 element is used as a bitmask element we diagnose a
+misuse and give a warning.
+
+2. Investigating the right hand side of `+=` and `|=` operator.
+3. Check only the enum value side of a `|` and `+` operator if one of them is not
+ enum val.
+4. Check both side of `|` or `+` operator where the enum values are from the
+ same enum type.
+
+Examples:
+
+.. code-block:: c++
+
+ enum { A, B, C };
+ enum { D, E, F = 5 };
+ enum { G = 10, H = 11, I = 12 };
+
+ unsigned flag;
+ flag =
+ A |
+ H; // OK, disjoint value intervalls in the enum types ->probably good use.
+ flag = B | F; // Warning, have common values so they are probably misused.
+
+ // Case 2:
+ enum Bitmask {
+ A = 0,
+ B = 1,
+ C = 2,
+ D = 4,
+ E = 8,
+ F = 16,
+ G = 31 // OK, real bitmask.
+ };
+
+ enum Almostbitmask {
+ AA = 0,
+ BB = 1,
+ CC = 2,
+ DD = 4,
+ EE = 8,
+ FF = 16,
+ GG // Problem, forgot to initialize.
+ };
+
+ unsigned flag = 0;
+ flag |= E; // OK.
+ flag |=
+ EE; // Warning at the decl, and note that it was used here as a bitmask.
+
+Options
+-------
+.. option:: StrictMode
+
+ Default value: 0.
+ When non-null the suspicious bitmask usage will be investigated additionally
+ to the different enum usage check.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-memset-usage.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-memset-usage.rst
new file mode 100644
index 0000000..82609d1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-memset-usage.rst
@@ -0,0 +1,54 @@
+.. title:: clang-tidy - bugprone-suspicious-memset-usage
+
+bugprone-suspicious-memset-usage
+================================
+
+This check finds ``memset()`` calls with potential mistakes in their arguments.
+Considering the function as ``void* memset(void* destination, int fill_value,
+size_t byte_count)``, the following cases are covered:
+
+**Case 1: Fill value is a character ``'0'``**
+
+Filling up a memory area with ASCII code 48 characters is not customary,
+possibly integer zeroes were intended instead.
+The check offers a replacement of ``'0'`` with ``0``. Memsetting character
+pointers with ``'0'`` is allowed.
+
+**Case 2: Fill value is truncated**
+
+Memset converts ``fill_value`` to ``unsigned char`` before using it. If
+``fill_value`` is out of unsigned character range, it gets truncated
+and memory will not contain the desired pattern.
+
+**Case 3: Byte count is zero**
+
+Calling memset with a literal zero in its ``byte_count`` argument is likely
+to be unintended and swapped with ``fill_value``. The check offers to swap
+these two arguments.
+
+Corresponding cpplint.py check name: ``runtime/memset``.
+
+
+Examples:
+
+.. code-block:: c++
+
+ void foo() {
+ int i[5] = {1, 2, 3, 4, 5};
+ int *ip = i;
+ char c = '1';
+ char *cp = &c;
+ int v = 0;
+
+ // Case 1
+ memset(ip, '0', 1); // suspicious
+ memset(cp, '0', 1); // OK
+
+ // Case 2
+ memset(ip, 0xabcd, 1); // fill value gets truncated
+ memset(ip, 0x00, 1); // OK
+
+ // Case 3
+ memset(ip, sizeof(int), v); // zero length, potentially swapped
+ memset(ip, 0, 1); // OK
+ }
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-missing-comma.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-missing-comma.rst
new file mode 100644
index 0000000..9fe9153
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-missing-comma.rst
@@ -0,0 +1,59 @@
+.. title:: clang-tidy - bugprone-suspicious-missing-comma
+
+bugprone-suspicious-missing-comma
+=================================
+
+String literals placed side-by-side are concatenated at translation phase 6
+(after the preprocessor). This feature is used to represent long string
+literal on multiple lines.
+
+For instance, the following declarations are equivalent:
+
+.. code-block:: c++
+
+ const char* A[] = "This is a test";
+ const char* B[] = "This" " is a " "test";
+
+A common mistake done by programmers is to forget a comma between two string
+literals in an array initializer list.
+
+.. code-block:: c++
+
+ const char* Test[] = {
+ "line 1",
+ "line 2" // Missing comma!
+ "line 3",
+ "line 4",
+ "line 5"
+ };
+
+The array contains the string "line 2line3" at offset 1 (i.e. Test[1]). Clang
+won't generate warnings at compile time.
+
+This check may warn incorrectly on cases like:
+
+.. code-block:: c++
+
+ const char* SupportedFormat[] = {
+ "Error %s",
+ "Code " PRIu64, // May warn here.
+ "Warning %s",
+ };
+
+Options
+-------
+
+.. option:: SizeThreshold
+
+ An unsigned integer specifying the minimum size of a string literal to be
+ considered by the check. Default is `5U`.
+
+.. option:: RatioThreshold
+
+ A string specifying the maximum threshold ratio [0, 1.0] of suspicious string
+ literals to be considered. Default is `".2"`.
+
+.. option:: MaxConcatenatedTokens
+
+ An unsigned integer specifying the maximum number of concatenated tokens.
+ Default is `5U`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-semicolon.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-semicolon.rst
new file mode 100644
index 0000000..a3eb098
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-semicolon.rst
@@ -0,0 +1,72 @@
+.. title:: clang-tidy - bugprone-suspicious-semicolon
+
+bugprone-suspicious-semicolon
+=============================
+
+Finds most instances of stray semicolons that unexpectedly alter the meaning of
+the code. More specifically, it looks for ``if``, ``while``, ``for`` and
+``for-range`` statements whose body is a single semicolon, and then analyzes the
+context of the code (e.g. indentation) in an attempt to determine whether that
+is intentional.
+
+ .. code-block:: c++
+
+ if (x < y);
+ {
+ x++;
+ }
+
+Here the body of the ``if`` statement consists of only the semicolon at the end
+of the first line, and `x` will be incremented regardless of the condition.
+
+
+ .. code-block:: c++
+
+ while ((line = readLine(file)) != NULL);
+ processLine(line);
+
+As a result of this code, `processLine()` will only be called once, when the
+``while`` loop with the empty body exits with `line == NULL`. The indentation of
+the code indicates the intention of the programmer.
+
+
+ .. code-block:: c++
+
+ if (x >= y);
+ x -= y;
+
+While the indentation does not imply any nesting, there is simply no valid
+reason to have an `if` statement with an empty body (but it can make sense for
+a loop). So this check issues a warning for the code above.
+
+To solve the issue remove the stray semicolon or in case the empty body is
+intentional, reflect this using code indentation or put the semicolon in a new
+line. For example:
+
+ .. code-block:: c++
+
+ while (readWhitespace());
+ Token t = readNextToken();
+
+Here the second line is indented in a way that suggests that it is meant to be
+the body of the `while` loop - whose body is in fact empty, because of the
+semicolon at the end of the first line.
+
+Either remove the indentation from the second line:
+
+ .. code-block:: c++
+
+ while (readWhitespace());
+ Token t = readNextToken();
+
+... or move the semicolon from the end of the first line to a new line:
+
+ .. code-block:: c++
+
+ while (readWhitespace())
+ ;
+
+ Token t = readNextToken();
+
+In this case the check will assume that you know what you are doing, and will
+not raise a warning.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-string-compare.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-string-compare.rst
new file mode 100644
index 0000000..be3d2b6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-suspicious-string-compare.rst
@@ -0,0 +1,64 @@
+.. title:: clang-tidy - bugprone-suspicious-string-compare
+
+bugprone-suspicious-string-compare
+==================================
+
+Find suspicious usage of runtime string comparison functions.
+This check is valid in C and C++.
+
+Checks for calls with implicit comparator and proposed to explicitly add it.
+
+.. code-block:: c++
+
+ if (strcmp(...)) // Implicitly compare to zero
+ if (!strcmp(...)) // Won't warn
+ if (strcmp(...) != 0) // Won't warn
+
+Checks that compare function results (i,e, ``strcmp``) are compared to valid
+constant. The resulting value is
+
+.. code::
+
+ < 0 when lower than,
+ > 0 when greater than,
+ == 0 when equals.
+
+A common mistake is to compare the result to `1` or `-1`.
+
+.. code-block:: c++
+
+ if (strcmp(...) == -1) // Incorrect usage of the returned value.
+
+Additionally, the check warns if the results value is implicitly cast to a
+*suspicious* non-integer type. It's happening when the returned value is used in
+a wrong context.
+
+.. code-block:: c++
+
+ if (strcmp(...) < 0.) // Incorrect usage of the returned value.
+
+Options
+-------
+
+.. option:: WarnOnImplicitComparison
+
+ When non-zero, the check will warn on implicit comparison. `1` by default.
+
+.. option:: WarnOnLogicalNotComparison
+
+ When non-zero, the check will warn on logical not comparison. `0` by default.
+
+.. option:: StringCompareLikeFunctions
+
+ A string specifying the comma-separated names of the extra string comparison
+ functions. Default is an empty string.
+ The check will detect the following string comparison functions:
+ `__builtin_memcmp`, `__builtin_strcasecmp`, `__builtin_strcmp`,
+ `__builtin_strncasecmp`, `__builtin_strncmp`, `_mbscmp`, `_mbscmp_l`,
+ `_mbsicmp`, `_mbsicmp_l`, `_mbsnbcmp`, `_mbsnbcmp_l`, `_mbsnbicmp`,
+ `_mbsnbicmp_l`, `_mbsncmp`, `_mbsncmp_l`, `_mbsnicmp`, `_mbsnicmp_l`,
+ `_memicmp`, `_memicmp_l`, `_stricmp`, `_stricmp_l`, `_strnicmp`,
+ `_strnicmp_l`, `_wcsicmp`, `_wcsicmp_l`, `_wcsnicmp`, `_wcsnicmp_l`,
+ `lstrcmp`, `lstrcmpi`, `memcmp`, `memicmp`, `strcasecmp`, `strcmp`,
+ `strcmpi`, `stricmp`, `strncasecmp`, `strncmp`, `strnicmp`, `wcscasecmp`,
+ `wcscmp`, `wcsicmp`, `wcsncmp`, `wcsnicmp`, `wmemcmp`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-swapped-arguments.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-swapped-arguments.rst
new file mode 100644
index 0000000..30ae925
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-swapped-arguments.rst
@@ -0,0 +1,6 @@
+.. title:: clang-tidy - bugprone-swapped-arguments
+
+bugprone-swapped-arguments
+==========================
+
+Finds potentially swapped arguments by looking at implicit conversions.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-terminating-continue.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-terminating-continue.rst
new file mode 100644
index 0000000..1a6ae81
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-terminating-continue.rst
@@ -0,0 +1,17 @@
+.. title:: clang-tidy - bugprone-terminating-continue
+
+bugprone-terminating-continue
+=============================
+
+Detects `do while` loops with a condition always evaluating to false that
+have a `continue` statement, as this `continue` terminates the loop
+effectively.
+
+.. code-block:: c++
+
+ void f() {
+ do {
+ // some code
+ continue; // terminating continue
+ // some other code
+ } while(false);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-throw-keyword-missing.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-throw-keyword-missing.rst
new file mode 100644
index 0000000..240a62e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-throw-keyword-missing.rst
@@ -0,0 +1,21 @@
+.. title:: clang-tidy - bugprone-throw-keyword-missing
+
+bugprone-throw-keyword-missing
+==============================
+
+Warns about a potentially missing ``throw`` keyword. If a temporary object is created, but the
+object's type derives from (or is the same as) a class that has 'EXCEPTION', 'Exception' or
+'exception' in its name, we can assume that the programmer's intention was to throw that object.
+
+Example:
+
+.. code-block:: c++
+
+ void f(int i) {
+ if (i < 0) {
+ // Exception is created but is not thrown.
+ std::runtime_error("Unexpected argument");
+ }
+ }
+
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-undefined-memory-manipulation.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-undefined-memory-manipulation.rst
new file mode 100644
index 0000000..2735184
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-undefined-memory-manipulation.rst
@@ -0,0 +1,7 @@
+.. title:: clang-tidy - bugprone-undefined-memory-manipulation
+
+bugprone-undefined-memory-manipulation
+======================================
+
+Finds calls of memory manipulation functions ``memset()``, ``memcpy()`` and
+``memmove()`` on not TriviallyCopyable objects resulting in undefined behavior.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-undelegated-constructor.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-undelegated-constructor.rst
new file mode 100644
index 0000000..b32ed38
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-undelegated-constructor.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - bugprone-undelegated-constructor
+
+bugprone-undelegated-constructor
+================================
+
+Finds creation of temporary objects in constructors that look like a
+function call to another constructor of the same class.
+
+The user most likely meant to use a delegating constructor or base class
+initializer.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-unused-raii.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-unused-raii.rst
new file mode 100644
index 0000000..f1987c5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-unused-raii.rst
@@ -0,0 +1,30 @@
+.. title:: clang-tidy - bugprone-unused-raii
+
+bugprone-unused-raii
+====================
+
+Finds temporaries that look like RAII objects.
+
+The canonical example for this is a scoped lock.
+
+.. code-block:: c++
+
+ {
+ scoped_lock(&global_mutex);
+ critical_section();
+ }
+
+The destructor of the scoped_lock is called before the ``critical_section`` is
+entered, leaving it unprotected.
+
+We apply a number of heuristics to reduce the false positive count of this
+check:
+
+- Ignore code expanded from macros. Testing frameworks make heavy use of this.
+
+- Ignore types with trivial destructors. They are very unlikely to be RAII
+ objects and there's no difference when they are deleted.
+
+- Ignore objects at the end of a compound statement (doesn't change behavior).
+
+- Ignore objects returned from a call.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-unused-return-value.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-unused-return-value.rst
new file mode 100644
index 0000000..68d8e73
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-unused-return-value.rst
@@ -0,0 +1,31 @@
+.. title:: clang-tidy - bugprone-unused-return-value
+
+bugprone-unused-return-value
+============================
+
+Warns on unused function return values. The checked funtions can be configured.
+
+Options
+-------
+
+.. option:: CheckedFunctions
+
+ Semicolon-separated list of functions to check. Defaults to
+ ``::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty``.
+ This means that the calls to following functions are checked by default:
+
+ - ``std::async()``. Not using the return value makes the call synchronous.
+ - ``std::launder()``. Not using the return value usually means that the
+ function interface was misunderstood by the programmer. Only the returned
+ pointer is "laundered", not the argument.
+ - ``std::remove()``, ``std::remove_if()`` and ``std::unique()``. The returned
+ iterator indicates the boundary between elements to keep and elements to be
+ removed. Not using the return value means that the information about which
+ elements to remove is lost.
+ - ``std::unique_ptr::release()``. Not using the return value can lead to
+ resource leaks if the same pointer isn't stored anywhere else. Often,
+ ignoring the ``release()`` return value indicates that the programmer
+ confused the function with ``reset()``.
+ - ``std::basic_string::empty()`` and ``std::vector::empty()``. Not using the
+ return value often indicates that the programmer confused the function with
+ ``clear()``.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-use-after-move.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-use-after-move.rst
new file mode 100644
index 0000000..05b0e09
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-use-after-move.rst
@@ -0,0 +1,203 @@
+.. title:: clang-tidy - bugprone-use-after-move
+
+bugprone-use-after-move
+=======================
+
+Warns if an object is used after it has been moved, for example:
+
+ .. code-block:: c++
+
+ std::string str = "Hello, world!\n";
+ std::vector<std::string> messages;
+ messages.emplace_back(std::move(str));
+ std::cout << str;
+
+The last line will trigger a warning that ``str`` is used after it has been
+moved.
+
+The check does not trigger a warning if the object is reinitialized after the
+move and before the use. For example, no warning will be output for this code:
+
+ .. code-block:: c++
+
+ messages.emplace_back(std::move(str));
+ str = "Greetings, stranger!\n";
+ std::cout << str;
+
+The check takes control flow into account. A warning is only emitted if the use
+can be reached from the move. This means that the following code does not
+produce a warning:
+
+ .. code-block:: c++
+
+ if (condition) {
+ messages.emplace_back(std::move(str));
+ } else {
+ std::cout << str;
+ }
+
+On the other hand, the following code does produce a warning:
+
+ .. code-block:: c++
+
+ for (int i = 0; i < 10; ++i) {
+ std::cout << str;
+ messages.emplace_back(std::move(str));
+ }
+
+(The use-after-move happens on the second iteration of the loop.)
+
+In some cases, the check may not be able to detect that two branches are
+mutually exclusive. For example (assuming that ``i`` is an int):
+
+ .. code-block:: c++
+
+ if (i == 1) {
+ messages.emplace_back(std::move(str));
+ }
+ if (i == 2) {
+ std::cout << str;
+ }
+
+In this case, the check will erroneously produce a warning, even though it is
+not possible for both the move and the use to be executed.
+
+An erroneous warning can be silenced by reinitializing the object after the
+move:
+
+ .. code-block:: c++
+
+ if (i == 1) {
+ messages.emplace_back(std::move(str));
+ str = "";
+ }
+ if (i == 2) {
+ std::cout << str;
+ }
+
+Subsections below explain more precisely what exactly the check considers to be
+a move, use, and reinitialization.
+
+Unsequenced moves, uses, and reinitializations
+----------------------------------------------
+
+In many cases, C++ does not make any guarantees about the order in which
+sub-expressions of a statement are evaluated. This means that in code like the
+following, it is not guaranteed whether the use will happen before or after the
+move:
+
+ .. code-block:: c++
+
+ void f(int i, std::vector<int> v);
+ std::vector<int> v = { 1, 2, 3 };
+ f(v[1], std::move(v));
+
+In this kind of situation, the check will note that the use and move are
+unsequenced.
+
+The check will also take sequencing rules into account when reinitializations
+occur in the same statement as moves or uses. A reinitialization is only
+considered to reinitialize a variable if it is guaranteed to be evaluated after
+the move and before the use.
+
+Move
+----
+
+The check currently only considers calls of ``std::move`` on local variables or
+function parameters. It does not check moves of member variables or global
+variables.
+
+Any call of ``std::move`` on a variable is considered to cause a move of that
+variable, even if the result of ``std::move`` is not passed to an rvalue
+reference parameter.
+
+This means that the check will flag a use-after-move even on a type that does
+not define a move constructor or move assignment operator. This is intentional.
+Developers may use ``std::move`` on such a type in the expectation that the type
+will add move semantics in the future. If such a ``std::move`` has the potential
+to cause a use-after-move, we want to warn about it even if the type does not
+implement move semantics yet.
+
+Furthermore, if the result of ``std::move`` *is* passed to an rvalue reference
+parameter, this will always be considered to cause a move, even if the function
+that consumes this parameter does not move from it, or if it does so only
+conditionally. For example, in the following situation, the check will assume
+that a move always takes place:
+
+ .. code-block:: c++
+
+ std::vector<std::string> messages;
+ void f(std::string &&str) {
+ // Only remember the message if it isn't empty.
+ if (!str.empty()) {
+ messages.emplace_back(std::move(str));
+ }
+ }
+ std::string str = "";
+ f(std::move(str));
+
+The check will assume that the last line causes a move, even though, in this
+particular case, it does not. Again, this is intentional.
+
+When analyzing the order in which moves, uses and reinitializations happen (see
+section `Unsequenced moves, uses, and reinitializations`_), the move is assumed
+to occur in whichever function the result of the ``std::move`` is passed to.
+
+Use
+---
+
+Any occurrence of the moved variable that is not a reinitialization (see below)
+is considered to be a use.
+
+An exception to this are objects of type ``std::unique_ptr``,
+``std::shared_ptr`` and ``std::weak_ptr``, which have defined move behavior
+(objects of these classes are guaranteed to be empty after they have been moved
+from). Therefore, an object of these classes will only be considered to be used
+if it is dereferenced, i.e. if ``operator*``, ``operator->`` or ``operator[]``
+(in the case of ``std::unique_ptr<T []>``) is called on it.
+
+If multiple uses occur after a move, only the first of these is flagged.
+
+Reinitialization
+----------------
+
+The check considers a variable to be reinitialized in the following cases:
+
+ - The variable occurs on the left-hand side of an assignment.
+
+ - The variable is passed to a function as a non-const pointer or non-const
+ lvalue reference. (It is assumed that the variable may be an out-parameter
+ for the function.)
+
+ - ``clear()`` or ``assign()`` is called on the variable and the variable is of
+ one of the standard container types ``basic_string``, ``vector``, ``deque``,
+ ``forward_list``, ``list``, ``set``, ``map``, ``multiset``, ``multimap``,
+ ``unordered_set``, ``unordered_map``, ``unordered_multiset``,
+ ``unordered_multimap``.
+
+ - ``reset()`` is called on the variable and the variable is of type
+ ``std::unique_ptr``, ``std::shared_ptr`` or ``std::weak_ptr``.
+
+If the variable in question is a struct and an individual member variable of
+that struct is written to, the check does not consider this to be a
+reinitialization -- even if, eventually, all member variables of the struct are
+written to. For example:
+
+ .. code-block:: c++
+
+ struct S {
+ std::string str;
+ int i;
+ };
+ S s = { "Hello, world!\n", 42 };
+ S s_other = std::move(s);
+ s.str = "Lorem ipsum";
+ s.i = 99;
+
+The check will not consider ``s`` to be reinitialized after the last line;
+instead, the line that assigns to ``s.str`` will be flagged as a use-after-move.
+This is intentional as this pattern of reinitializing a struct is error-prone.
+For example, if an additional member variable is added to ``S``, it is easy to
+forget to add the reinitialization for this additional member. Instead, it is
+safer to assign to the entire struct in one go, and this will also avoid the
+use-after-move warning.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-virtual-near-miss.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-virtual-near-miss.rst
new file mode 100644
index 0000000..ac27479
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/bugprone-virtual-near-miss.rst
@@ -0,0 +1,20 @@
+.. title:: clang-tidy - bugprone-virtual-near-miss
+
+bugprone-virtual-near-miss
+==========================
+
+Warn if a function is a near miss (ie. the name is very similar and the function
+signiture is the same) to a virtual function from a base class.
+
+Example:
+
+.. code-block:: c++
+
+ struct Base {
+ virtual void func();
+ };
+
+ struct Derived : Base {
+ virtual funk();
+ // warning: 'Derived::funk' has a similar name and the same signature as virtual method 'Base::func'; did you mean to override it?
+ };
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl03-c.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl03-c.rst
new file mode 100644
index 0000000..2e4780b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl03-c.rst
@@ -0,0 +1,9 @@
+.. title:: clang-tidy - cert-dcl03-c
+.. meta::
+ :http-equiv=refresh: 5;URL=misc-static-assert.html
+
+cert-dcl03-c
+============
+
+The cert-dcl03-c check is an alias, please see
+`misc-static-assert <misc-static-assert.html>`_ for more information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl21-cpp.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl21-cpp.rst
new file mode 100644
index 0000000..d5c2948
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl21-cpp.rst
@@ -0,0 +1,12 @@
+.. title:: clang-tidy - cert-dcl21-cpp
+
+cert-dcl21-cpp
+==============
+
+This check flags postfix ``operator++`` and ``operator--`` declarations
+if the return type is not a const object. This also warns if the return type
+is a reference type.
+
+This check corresponds to the CERT C++ Coding Standard recommendation
+`DCL21-CPP. Overloaded postfix increment and decrement operators should return a const object
+<https://www.securecoding.cert.org/confluence/display/cplusplus/DCL21-CPP.+Overloaded+postfix+increment+and+decrement+operators+should+return+a+const+object>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl50-cpp.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl50-cpp.rst
new file mode 100644
index 0000000..5fc1fbf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl50-cpp.rst
@@ -0,0 +1,11 @@
+.. title:: clang-tidy - cert-dcl50-cpp
+
+cert-dcl50-cpp
+==============
+
+This check flags all function definitions (but not declarations) of C-style
+variadic functions.
+
+This check corresponds to the CERT C++ Coding Standard rule
+`DCL50-CPP. Do not define a C-style variadic function
+<https://www.securecoding.cert.org/confluence/display/cplusplus/DCL50-CPP.+Do+not+define+a+C-style+variadic+function>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl54-cpp.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl54-cpp.rst
new file mode 100644
index 0000000..e0b575c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl54-cpp.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - cert-dcl54-cpp
+.. meta::
+ :http-equiv=refresh: 5;URL=misc-new-delete-overloads.html
+
+cert-dcl54-cpp
+==============
+
+The cert-dcl54-cpp check is an alias, please see
+`misc-new-delete-overloads <misc-new-delete-overloads.html>`_ for more
+information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl58-cpp.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl58-cpp.rst
new file mode 100644
index 0000000..a86d1b9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl58-cpp.rst
@@ -0,0 +1,21 @@
+.. title:: clang-tidy - cert-dcl58-cpp
+
+cert-dcl58-cpp
+==============
+
+Modification of the ``std`` or ``posix`` namespace can result in undefined
+behavior.
+This check warns for such modifications.
+
+Examples:
+
+.. code-block:: c++
+
+ namespace std {
+ int x; // May cause undefined behavior.
+ }
+
+
+This check corresponds to the CERT C++ Coding Standard rule
+`DCL58-CPP. Do not modify the standard namespaces
+<https://www.securecoding.cert.org/confluence/display/cplusplus/DCL58-CPP.+Do+not+modify+the+standard+namespaces>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl59-cpp.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl59-cpp.rst
new file mode 100644
index 0000000..9528c04
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-dcl59-cpp.rst
@@ -0,0 +1,9 @@
+.. title:: clang-tidy - cert-dcl59-cpp
+.. meta::
+ :http-equiv=refresh: 5;URL=google-build-namespaces.html
+
+cert-dcl59-cpp
+==============
+
+The cert-dcl59-cpp check is an alias, please see
+`google-build-namespaces <google-build-namespaces.html>`_ for more information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-env33-c.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-env33-c.rst
new file mode 100644
index 0000000..c5321b0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-env33-c.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - cert-env33-c
+
+cert-env33-c
+============
+
+This check flags calls to ``system()``, ``popen()``, and ``_popen()``, which
+execute a command processor. It does not flag calls to ``system()`` with a null
+pointer argument, as such a call checks for the presence of a command processor
+but does not actually attempt to execute a command.
+
+This check corresponds to the CERT C Coding Standard rule
+`ENV33-C. Do not call system()
+<https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=2130132>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err09-cpp.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err09-cpp.rst
new file mode 100644
index 0000000..1494bcc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err09-cpp.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - cert-err09-cpp
+.. meta::
+ :http-equiv=refresh: 5;URL=misc-throw-by-value-catch-by-reference.html
+
+cert-err09-cpp
+==============
+
+The cert-err09-cpp check is an alias, please see
+`misc-throw-by-value-catch-by-reference <misc-throw-by-value-catch-by-reference.html>`_
+for more information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err34-c.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err34-c.rst
new file mode 100644
index 0000000..362aef2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err34-c.rst
@@ -0,0 +1,28 @@
+.. title:: clang-tidy - cert-err34-c
+
+cert-err34-c
+============
+
+This check flags calls to string-to-number conversion functions that do not
+verify the validity of the conversion, such as ``atoi()`` or ``scanf()``. It
+does not flag calls to ``strtol()``, or other, related conversion functions that
+do perform better error checking.
+
+.. code-block:: c
+
+ #include <stdlib.h>
+
+ void func(const char *buff) {
+ int si;
+
+ if (buff) {
+ si = atoi(buff); /* 'atoi' used to convert a string to an integer, but function will
+ not report conversion errors; consider using 'strtol' instead. */
+ } else {
+ /* Handle error */
+ }
+ }
+
+This check corresponds to the CERT C Coding Standard rule
+`ERR34-C. Detect errors when converting a string to a number
+<https://www.securecoding.cert.org/confluence/display/c/ERR34-C.+Detect+errors+when+converting+a+string+to+a+number>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err52-cpp.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err52-cpp.rst
new file mode 100644
index 0000000..a29dc7b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err52-cpp.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - cert-err52-cpp
+
+cert-err52-cpp
+==============
+
+This check flags all call expressions involving ``setjmp()`` and ``longjmp()``.
+
+This check corresponds to the CERT C++ Coding Standard rule
+`ERR52-CPP. Do not use setjmp() or longjmp()
+<https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=1834>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err58-cpp.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err58-cpp.rst
new file mode 100644
index 0000000..6a7f615
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err58-cpp.rst
@@ -0,0 +1,11 @@
+.. title:: clang-tidy - cert-err58-cpp
+
+cert-err58-cpp
+==============
+
+This check flags all ``static`` or ``thread_local`` variable declarations where
+the initializer for the object may throw an exception.
+
+This check corresponds to the CERT C++ Coding Standard rule
+`ERR58-CPP. Handle all exceptions thrown before main() begins executing
+<https://www.securecoding.cert.org/confluence/display/cplusplus/ERR58-CPP.+Handle+all+exceptions+thrown+before+main%28%29+begins+executing>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err60-cpp.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err60-cpp.rst
new file mode 100644
index 0000000..9fcb840
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err60-cpp.rst
@@ -0,0 +1,11 @@
+.. title:: clang-tidy - cert-err60-cpp
+
+cert-err60-cpp
+==============
+
+This check flags all throw expressions where the exception object is not nothrow
+copy constructible.
+
+This check corresponds to the CERT C++ Coding Standard rule
+`ERR60-CPP. Exception objects must be nothrow copy constructible
+<https://www.securecoding.cert.org/confluence/display/cplusplus/ERR60-CPP.+Exception+objects+must+be+nothrow+copy+constructible>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err61-cpp.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err61-cpp.rst
new file mode 100644
index 0000000..f0cd0fe
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-err61-cpp.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - cert-err61-cpp
+.. meta::
+ :http-equiv=refresh: 5;URL=misc-throw-by-value-catch-by-reference.html
+
+cert-err61-cpp
+==============
+
+The cert-err61-cpp check is an alias, please see
+`misc-throw-by-value-catch-by-reference <misc-throw-by-value-catch-by-reference.html>`_
+for more information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-fio38-c.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-fio38-c.rst
new file mode 100644
index 0000000..5ce37f4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-fio38-c.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - cert-fio38-c
+.. meta::
+ :http-equiv=refresh: 5;URL=misc-non-copyable-objects.html
+
+cert-fio38-c
+============
+
+The cert-fio38-c check is an alias, please see
+`misc-non-copyable-objects <misc-non-copyable-objects.html>`_ for more
+information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-flp30-c.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-flp30-c.rst
new file mode 100644
index 0000000..c37b639
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-flp30-c.rst
@@ -0,0 +1,11 @@
+.. title:: clang-tidy - cert-flp30-c
+
+cert-flp30-c
+============
+
+This check flags ``for`` loops where the induction expression has a
+floating-point type.
+
+This check corresponds to the CERT C Coding Standard rule
+`FLP30-C. Do not use floating-point variables as loop counters
+<https://www.securecoding.cert.org/confluence/display/c/FLP30-C.+Do+not+use+floating-point+variables+as+loop+counters>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-msc30-c.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-msc30-c.rst
new file mode 100644
index 0000000..afd9b1a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-msc30-c.rst
@@ -0,0 +1,9 @@
+.. title:: clang-tidy - cert-msc30-c
+.. meta::
+ :http-equiv=refresh: 5;URL=cert-msc50-cpp.html
+
+cert-msc30-c
+============
+
+The cert-msc30-c check is an alias, please see
+`cert-msc50-cpp <cert-msc50-cpp.html>`_ for more information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-msc32-c.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-msc32-c.rst
new file mode 100644
index 0000000..df527ec
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-msc32-c.rst
@@ -0,0 +1,9 @@
+.. title:: clang-tidy - cert-msc32-c
+.. meta::
+ :http-equiv=refresh: 5;URL=cert-msc51-cpp.html
+
+cert-msc32-c
+============
+
+The cert-msc32-c check is an alias, please see
+`cert-msc51-cpp <cert-msc51-cpp.html>`_ for more information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-msc50-cpp.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-msc50-cpp.rst
new file mode 100644
index 0000000..debf01c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-msc50-cpp.rst
@@ -0,0 +1,11 @@
+.. title:: clang-tidy - cert-msc50-cpp
+
+cert-msc50-cpp
+==============
+
+Pseudorandom number generators use mathematical algorithms to produce a sequence
+of numbers with good statistical properties, but the numbers produced are not
+genuinely random. The ``std::rand()`` function takes a seed (number), runs a
+mathematical operation on it and returns the result. By manipulating the seed
+the result can be predictable. This check warns for the usage of
+``std::rand()``.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-msc51-cpp.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-msc51-cpp.rst
new file mode 100644
index 0000000..5365369
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-msc51-cpp.rst
@@ -0,0 +1,40 @@
+.. title:: clang-tidy - cert-msc51-cpp
+
+cert-msc51-cpp
+==============
+
+This check flags all pseudo-random number engines, engine adaptor
+instantiations and ``srand()`` when initialized or seeded with default argument,
+constant expression or any user-configurable type. Pseudo-random number
+engines seeded with a predictable value may cause vulnerabilities e.g. in
+security protocols.
+This is a CERT security rule, see
+`MSC51-CPP. Ensure your random number generator is properly seeded
+<https://wiki.sei.cmu.edu/confluence/display/cplusplus/MSC51-CPP.+Ensure+your+random+number+generator+is+properly+seeded>`_ and
+`MSC32-C. Properly seed pseudorandom number generators
+<https://wiki.sei.cmu.edu/confluence/display/c/MSC32-C.+Properly+seed+pseudorandom+number+generators>`_.
+
+Examples:
+
+.. code-block:: c++
+
+ void foo() {
+ std::mt19937 engine1; // Diagnose, always generate the same sequence
+ std::mt19937 engine2(1); // Diagnose
+ engine1.seed(); // Diagnose
+ engine2.seed(1); // Diagnose
+
+ std::time_t t;
+ engine1.seed(std::time(&t)); // Diagnose, system time might be controlled by user
+
+ int x = atoi(argv[1]);
+ std::mt19937 engine3(x); // Will not warn
+ }
+
+Options
+-------
+
+.. option:: DisallowedSeedTypes
+
+ A comma-separated list of the type names which are disallowed.
+ Default values are ``time_t``, ``std::time_t``.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-oop11-cpp.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-oop11-cpp.rst
new file mode 100644
index 0000000..dcd0fee
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cert-oop11-cpp.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - cert-oop11-cpp
+.. meta::
+ :http-equiv=refresh: 5;URL=performance-move-constructor-init.html
+
+cert-oop11-cpp
+==============
+
+The cert-oop11-cpp check is an alias, please see
+`performance-move-constructor-init <performance-move-constructor-init.html>`_
+for more information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-avoid-goto.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-avoid-goto.rst
new file mode 100644
index 0000000..fcb7dd3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-avoid-goto.rst
@@ -0,0 +1,50 @@
+.. title:: clang-tidy - cppcoreguidelines-avoid-goto
+
+cppcoreguidelines-avoid-goto
+============================
+
+The usage of ``goto`` for control flow is error prone and should be replaced
+with looping constructs. Only forward jumps in nested loops are accepted.
+
+This check implements `ES.76 <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es76-avoid-goto>`_
+from the CppCoreGuidelines and
+`6.3.1 from High Integrity C++ <http://www.codingstandard.com/rule/6-3-1-ensure-that-the-labels-for-a-jump-statement-or-a-switch-condition-appear-later-in-the-same-or-an-enclosing-block/>`_.
+
+For more information on why to avoid programming
+with ``goto`` you can read the famous paper `A Case against the GO TO Statement. <https://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF>`_.
+
+The check diagnoses ``goto`` for backward jumps in every language mode. These
+should be replaced with `C/C++` looping constructs.
+
+.. code-block:: c++
+
+ // Bad, handwritten for loop.
+ int i = 0;
+ // Jump label for the loop
+ loop_start:
+ do_some_operation();
+
+ if (i < 100) {
+ ++i;
+ goto loop_start;
+ }
+
+ // Better
+ for(int i = 0; i < 100; ++i)
+ do_some_operation();
+
+Modern C++ needs ``goto`` only to jump out of nested loops.
+
+.. code-block:: c++
+
+ for(int i = 0; i < 100; ++i) {
+ for(int j = 0; j < 100; ++j) {
+ if (i * j > 500)
+ goto early_exit;
+ }
+ }
+
+ early_exit:
+ some_operation();
+
+All other uses of ``goto`` are diagnosed in `C++`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-c-copy-assignment-signature.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-c-copy-assignment-signature.rst
new file mode 100644
index 0000000..9096ef4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-c-copy-assignment-signature.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - cppcoreguidelines-c-copy-assignment-signature
+.. meta::
+ :http-equiv=refresh: 5;URL=misc-unconventional-assign-operator.html
+
+cppcoreguidelines-c-copy-assignment-signature
+=============================================
+
+The cppcoreguidelines-c-copy-assignment-signature check is an alias, please see
+`misc-unconventional-assign-operator <misc-unconventional-assign-operator.html>`_
+for more information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-interfaces-global-init.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-interfaces-global-init.rst
new file mode 100644
index 0000000..4907858
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-interfaces-global-init.rst
@@ -0,0 +1,14 @@
+.. title:: clang-tidy - cppcoreguidelines-interfaces-global-init
+
+cppcoreguidelines-interfaces-global-init
+========================================
+
+This check flags initializers of globals that access extern objects,
+and therefore can lead to order-of-initialization problems.
+
+This rule is part of the "Interfaces" profile of the C++ Core Guidelines, see
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Ri-global-init
+
+Note that currently this does not flag calls to non-constexpr functions, and
+therefore globals could still be accessed from functions themselves.
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.rst
new file mode 100644
index 0000000..b1e82ca
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.rst
@@ -0,0 +1,22 @@
+.. title:: clang-tidy - cppcoreguidelines-narrowing-conversions
+
+cppcoreguidelines-narrowing-conversions
+=======================================
+
+Checks for silent narrowing conversions, e.g: ``int i = 0; i += 0.1;``. While
+the issue is obvious in this former example, it might not be so in the
+following: ``void MyClass::f(double d) { int_member_ += d; }``.
+
+This rule is part of the "Expressions and statements" profile of the C++ Core
+Guidelines, corresponding to rule ES.46. See
+
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Res-narrowing.
+
+We enforce only part of the guideline, more specifically, we flag:
+ - All floating-point to integer conversions that are not marked by an explicit
+ cast (c-style or ``static_cast``). For example: ``int i = 0; i += 0.1;``,
+ ``void f(int); f(0.1);``,
+ - All applications of binary operators where the left-hand-side is an integer
+ and the right-hand-size is a floating-point. For example:
+ ``int i; i+= 0.1;``.
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-no-malloc.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-no-malloc.rst
new file mode 100644
index 0000000..d481a67
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-no-malloc.rst
@@ -0,0 +1,46 @@
+.. title:: clang-tidy - cppcoreguidelines-no-malloc
+
+cppcoreguidelines-no-malloc
+===========================
+
+This check handles C-Style memory management using ``malloc()``, ``realloc()``,
+``calloc()`` and ``free()``. It warns about its use and tries to suggest the use
+of an appropriate RAII object.
+Furthermore, it can be configured to check against a user-specified list of functions
+that are used for memory management (e.g. ``posix_memalign()``).
+See `C++ Core Guidelines <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-mallocfree>`_.
+
+There is no attempt made to provide fix-it hints, since manual resource
+management isn't easily transformed automatically into RAII.
+
+.. code-block:: c++
+
+ // Warns each of the following lines.
+ // Containers like std::vector or std::string should be used.
+ char* some_string = (char*) malloc(sizeof(char) * 20);
+ char* some_string = (char*) realloc(sizeof(char) * 30);
+ free(some_string);
+
+ int* int_array = (int*) calloc(30, sizeof(int));
+
+ // Rather use a smartpointer or stack variable.
+ struct some_struct* s = (struct some_struct*) malloc(sizeof(struct some_struct));
+
+Options
+-------
+
+.. option:: Allocations
+
+ Semicolon-separated list of fully qualified names of memory allocation functions.
+ Defaults to ``::malloc;::calloc``.
+
+.. option:: Deallocations
+
+ Semicolon-separated list of fully qualified names of memory allocation functions.
+ Defaults to ``::free``.
+
+.. option:: Reallocations
+
+ Semicolon-separated list of fully qualified names of memory allocation functions.
+ Defaults to ``::realloc``.
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-owning-memory.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-owning-memory.rst
new file mode 100644
index 0000000..3f6f8c4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-owning-memory.rst
@@ -0,0 +1,176 @@
+.. title:: clang-tidy - cppcoreguidelines-owning-memory
+
+cppcoreguidelines-owning-memory
+===============================
+
+This check implements the type-based semantics of ``gsl::owner<T*>``, which allows
+static analysis on code, that uses raw pointers to handle resources like
+dynamic memory, but won't introduce RAII concepts.
+
+The relevant sections in the `C++ Core Guidelines <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md>`_ are I.11, C.33, R.3 and GSL.Views
+The definition of a ``gsl::owner<T*>`` is straight forward
+
+.. code-block:: c++
+
+ namespace gsl { template <typename T> owner = T; }
+
+It is therefore simple to introduce the owner even without using an implementation of
+the `Guideline Support Library <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#gsl-guideline-support-library>`_.
+
+All checks are purely type based and not (yet) flow sensitive.
+
+The following examples will demonstrate the correct and incorrect initializations
+of owners, assignment is handled the same way. Note that both ``new`` and
+``malloc()``-like resource functions are considered to produce resources.
+
+.. code-block:: c++
+
+ // Creating an owner with factory functions is checked.
+ gsl::owner<int*> function_that_returns_owner() { return gsl::owner<int*>(new int(42)); }
+
+ // Dynamic memory must be assigned to an owner
+ int* Something = new int(42); // BAD, will be caught
+ gsl::owner<int*> Owner = new int(42); // Good
+ gsl::owner<int*> Owner = new int[42]; // Good as well
+
+ // Returned owner must be assigned to an owner
+ int* Something = function_that_returns_owner(); // Bad, factory function
+ gsl::owner<int*> Owner = function_that_returns_owner(); // Good, result lands in owner
+
+ // Something not a resource or owner should not be assigned to owners
+ int Stack = 42;
+ gsl::owner<int*> Owned = &Stack; // Bad, not a resource assigned
+
+In the case of dynamic memory as resource, only ``gsl::owner<T*>`` variables are allowed
+to be deleted.
+
+.. code-block:: c++
+
+ // Example Bad, non-owner as resource handle, will be caught.
+ int* NonOwner = new int(42); // First warning here, since new must land in an owner
+ delete NonOwner; // Second warning here, since only owners are allowed to be deleted
+
+ // Example Good, Ownership correclty stated
+ gsl::owner<int*> Owner = new int(42); // Good
+ delete Owner; // Good as well, statically enforced, that only owners get deleted
+
+The check will furthermore ensure, that functions, that expect a ``gsl::owner<T*>`` as
+argument get called with either a ``gsl::owner<T*>`` or a newly created resource.
+
+.. code-block:: c++
+
+ void expects_owner(gsl::owner<int*> o) { delete o; }
+
+ // Bad Code
+ int NonOwner = 42;
+ expects_owner(&NonOwner); // Bad, will get caught
+
+ // Good Code
+ gsl::owner<int*> Owner = new int(42);
+ expects_owner(Owner); // Good
+ expects_owner(new int(42)); // Good as well, recognized created resource
+
+ // Port legacy code for better resource-safety
+ gsl::owner<FILE*> File = fopen("my_file.txt", "rw+");
+ FILE* BadFile = fopen("another_file.txt", "w"); // Bad, warned
+
+ // ... use the file
+
+ fclose(File); // Ok, File is annotated as 'owner<>'
+ fclose(BadFile); // BadFile is not an 'owner<>', will be warned
+
+
+Options
+-------
+
+.. option:: LegacyResourceProducers
+
+ Semicolon-separated list of fully qualified names of legacy functions that create
+ resources but cannot introduce ``gsl::owner<>``.
+ Defaults to ``::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile``.
+
+
+.. option:: LegacyResourceConsumers
+
+ Semicolon-separated list of fully qualified names of legacy functions expecting
+ resource owners as pointer arguments but cannot introduce ``gsl::owner<>``.
+ Defaults to ``::free;::realloc;::freopen;::fclose``.
+
+
+Limitations
+-----------
+
+Using ``gsl::owner<T*>`` in a typedef or alias is not handled correctly.
+
+.. code-block:: c++
+
+ using heap_int = gsl::owner<int*>;
+ heap_int allocated = new int(42); // False positive!
+
+The ``gsl::owner<T*>`` is declared as a templated type alias.
+In template functions and classes, like in the example below, the information
+of the type aliases gets lost. Therefore using ``gsl::owner<T*>`` in a heavy templated
+code base might lead to false positives.
+
+Known code constructs that do not get diagnosed correctly are:
+
+- ``std::exchange``
+- ``std::vector<gsl::owner<T*>>``
+
+.. code-block:: c++
+
+ // This template function works as expected. Type information doesn't get lost.
+ template <typename T>
+ void delete_owner(gsl::owner<T*> owned_object) {
+ delete owned_object; // Everything alright
+ }
+
+ gsl::owner<int*> function_that_returns_owner() { return gsl::owner<int*>(new int(42)); }
+
+ // Type deduction does not work for auto variables.
+ // This is caught by the check and will be noted accordingly.
+ auto OwnedObject = function_that_returns_owner(); // Type of OwnedObject will be int*
+
+ // Problematic function template that looses the typeinformation on owner
+ template <typename T>
+ void bad_template_function(T some_object) {
+ // This line will trigger the warning, that a non-owner is assigned to an owner
+ gsl::owner<T*> new_owner = some_object;
+ }
+
+ // Calling the function with an owner still yields a false positive.
+ bad_template_function(gsl::owner<int*>(new int(42)));
+
+
+ // The same issue occurs with templated classes like the following.
+ template <typename T>
+ class OwnedValue {
+ public:
+ const T getValue() const { return _val; }
+ private:
+ T _val;
+ };
+
+ // Code, that yields a false positive.
+ OwnedValue<gsl::owner<int*>> Owner(new int(42)); // Type deduction yield T -> int *
+ // False positive, getValue returns int* and not gsl::owner<int*>
+ gsl::owner<int*> OwnedInt = Owner.getValue();
+
+Another limitation of the current implementation is only the type based checking.
+Suppose you have code like the following:
+
+.. code-block:: c++
+
+ // Two owners with assigned resources
+ gsl::owner<int*> Owner1 = new int(42);
+ gsl::owner<int*> Owner2 = new int(42);
+
+ Owner2 = Owner1; // Conceptual Leak of initial resource of Owner2!
+ Owner1 = nullptr;
+
+The semantic of a ``gsl::owner<T*>`` is mostly like a ``std::unique_ptr<T>``, therefore
+assignment of two ``gsl::owner<T*>`` is considered a move, which requires that the
+resource ``Owner2`` must have been released before the assignment.
+This kind of condition could be catched in later improvements of this check with
+flowsensitive analysis. Currently, the `Clang Static Analyzer` catches this bug
+for dynamic memory, but not for general types of resources.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-array-to-pointer-decay.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-array-to-pointer-decay.rst
new file mode 100644
index 0000000..172df2b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-array-to-pointer-decay.rst
@@ -0,0 +1,12 @@
+.. title:: clang-tidy - cppcoreguidelines-pro-bounds-array-to-pointer-decay
+
+cppcoreguidelines-pro-bounds-array-to-pointer-decay
+===================================================
+
+This check flags all array to pointer decays.
+
+Pointers should not be used as arrays. ``span<T>`` is a bounds-checked, safe
+alternative to using pointers to access arrays.
+
+This rule is part of the "Bounds safety" profile of the C++ Core Guidelines, see
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-bounds-decay.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-constant-array-index.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-constant-array-index.rst
new file mode 100644
index 0000000..4528f2a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-constant-array-index.rst
@@ -0,0 +1,25 @@
+.. title:: clang-tidy - cppcoreguidelines-pro-bounds-constant-array-index
+
+cppcoreguidelines-pro-bounds-constant-array-index
+=================================================
+
+This check flags all array subscript expressions on static arrays and
+``std::arrays`` that either do not have a constant integer expression index or
+are out of bounds (for ``std::array``). For out-of-bounds checking of static
+arrays, see the `-Warray-bounds` Clang diagnostic.
+
+This rule is part of the "Bounds safety" profile of the C++ Core Guidelines, see
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-bounds-arrayindex.
+
+Options
+-------
+
+.. option:: GslHeader
+
+ The check can generate fixes after this option has been set to the name of
+ the include file that contains ``gsl::at()``, e.g. `"gsl/gsl.h"`.
+
+.. option:: IncludeStyle
+
+ A string specifying which include-style is used, `llvm` or `google`. Default
+ is `llvm`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-pointer-arithmetic.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-pointer-arithmetic.rst
new file mode 100644
index 0000000..e0660df
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-pointer-arithmetic.rst
@@ -0,0 +1,14 @@
+.. title:: clang-tidy - cppcoreguidelines-pro-bounds-pointer-arithmetic
+
+cppcoreguidelines-pro-bounds-pointer-arithmetic
+===============================================
+
+This check flags all usage of pointer arithmetic, because it could lead to an
+invalid pointer. Subtraction of two pointers is not flagged by this check.
+
+Pointers should only refer to single objects, and pointer arithmetic is fragile
+and easy to get wrong. ``span<T>`` is a bounds-checked, safe type for accessing
+arrays of data.
+
+This rule is part of the "Bounds safety" profile of the C++ Core Guidelines, see
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-bounds-arithmetic.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-const-cast.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-const-cast.rst
new file mode 100644
index 0000000..f3f0fb4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-const-cast.rst
@@ -0,0 +1,12 @@
+.. title:: clang-tidy - cppcoreguidelines-pro-type-const-cast
+
+cppcoreguidelines-pro-type-const-cast
+=====================================
+
+This check flags all uses of ``const_cast`` in C++ code.
+
+Modifying a variable that was declared const is undefined behavior, even with
+``const_cast``.
+
+This rule is part of the "Type safety" profile of the C++ Core Guidelines, see
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-type-constcast.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-cstyle-cast.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-cstyle-cast.rst
new file mode 100644
index 0000000..1c21dd0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-cstyle-cast.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - cppcoreguidelines-pro-type-cstyle-cast
+
+cppcoreguidelines-pro-type-cstyle-cast
+======================================
+
+This check flags all use of C-style casts that perform a ``static_cast``
+downcast, ``const_cast``, or ``reinterpret_cast``.
+
+Use of these casts can violate type safety and cause the program to access a
+variable that is actually of type X to be accessed as if it were of an unrelated
+type Z. Note that a C-style ``(T)expression`` cast means to perform the first of
+the following that is possible: a ``const_cast``, a ``static_cast``, a
+``static_cast`` followed by a ``const_cast``, a ``reinterpret_cast``, or a
+``reinterpret_cast`` followed by a ``const_cast``. This rule bans
+``(T)expression`` only when used to perform an unsafe cast.
+
+This rule is part of the "Type safety" profile of the C++ Core Guidelines, see
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-type-cstylecast.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst
new file mode 100644
index 0000000..2fdb4e3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst
@@ -0,0 +1,38 @@
+.. title:: clang-tidy - cppcoreguidelines-pro-type-member-init
+
+cppcoreguidelines-pro-type-member-init
+======================================
+
+The check flags user-defined constructor definitions that do not
+initialize all fields that would be left in an undefined state by
+default construction, e.g. builtins, pointers and record types without
+user-provided default constructors containing at least one such
+type. If these fields aren't initialized, the constructor will leave
+some of the memory in an undefined state.
+
+For C++11 it suggests fixes to add in-class field initializers. For
+older versions it inserts the field initializers into the constructor
+initializer list. It will also initialize any direct base classes that
+need to be zeroed in the constructor initializer list.
+
+The check takes assignment of fields in the constructor body into
+account but generates false positives for fields initialized in
+methods invoked in the constructor body.
+
+The check also flags variables with automatic storage duration that have record
+types without a user-provided constructor and are not initialized. The suggested
+fix is to zero initialize the variable via ``{}`` for C++11 and beyond or ``=
+{}`` for older language versions.
+
+Options
+-------
+
+.. option:: IgnoreArrays
+
+ If set to non-zero, the check will not warn about array members that are not
+ zero-initialized during construction. For performance critical code, it may
+ be important to not initialize fixed-size array members. Default is `0`.
+
+This rule is part of the "Type safety" profile of the C++ Core
+Guidelines, corresponding to rule Type.6. See
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-type-memberinit.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-reinterpret-cast.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-reinterpret-cast.rst
new file mode 100644
index 0000000..2ef76f2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-reinterpret-cast.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - cppcoreguidelines-pro-type-reinterpret-cast
+
+cppcoreguidelines-pro-type-reinterpret-cast
+===========================================
+
+This check flags all uses of ``reinterpret_cast`` in C++ code.
+
+Use of these casts can violate type safety and cause the program to access a
+variable that is actually of type ``X`` to be accessed as if it were of an
+unrelated type ``Z``.
+
+This rule is part of the "Type safety" profile of the C++ Core Guidelines, see
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-type-reinterpretcast.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-static-cast-downcast.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-static-cast-downcast.rst
new file mode 100644
index 0000000..880b8b0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-static-cast-downcast.rst
@@ -0,0 +1,15 @@
+.. title:: clang-tidy - cppcoreguidelines-pro-type-static-cast-downcast
+
+cppcoreguidelines-pro-type-static-cast-downcast
+===============================================
+
+This check flags all usages of ``static_cast``, where a base class is casted to
+a derived class. In those cases, a fix-it is provided to convert the cast to a
+``dynamic_cast``.
+
+Use of these casts can violate type safety and cause the program to access a
+variable that is actually of type ``X`` to be accessed as if it were of an
+unrelated type ``Z``.
+
+This rule is part of the "Type safety" profile of the C++ Core Guidelines, see
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-type-downcast.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-union-access.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-union-access.rst
new file mode 100644
index 0000000..cdcf713
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-union-access.rst
@@ -0,0 +1,16 @@
+.. title:: clang-tidy - cppcoreguidelines-pro-type-union-access
+
+cppcoreguidelines-pro-type-union-access
+=======================================
+
+This check flags all access to members of unions. Passing unions as a whole is
+not flagged.
+
+Reading from a union member assumes that member was the last one written, and
+writing to a union member assumes another member with a nontrivial destructor
+had its destructor called. This is fragile because it cannot generally be
+enforced to be safe in the language and so relies on programmer discipline to
+get it right.
+
+This rule is part of the "Type safety" profile of the C++ Core Guidelines, see
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-type-unions.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-vararg.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-vararg.rst
new file mode 100644
index 0000000..26fcd0c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-vararg.rst
@@ -0,0 +1,17 @@
+.. title:: clang-tidy - cppcoreguidelines-pro-type-vararg
+
+cppcoreguidelines-pro-type-vararg
+=================================
+
+This check flags all calls to c-style vararg functions and all use of
+``va_arg``.
+
+To allow for SFINAE use of vararg functions, a call is not flagged if a literal
+0 is passed as the only vararg argument.
+
+Passing to varargs assumes the correct type will be read. This is fragile
+because it cannot generally be enforced to be safe in the language and so relies
+on programmer discipline to get it right.
+
+This rule is part of the "Type safety" profile of the C++ Core Guidelines, see
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-type-varargs.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-slicing.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-slicing.rst
new file mode 100644
index 0000000..44f3dca
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-slicing.rst
@@ -0,0 +1,25 @@
+.. title:: clang-tidy - cppcoreguidelines-slicing
+
+cppcoreguidelines-slicing
+=========================
+
+Flags slicing of member variables or vtable. Slicing happens when copying a
+derived object into a base object: the members of the derived object (both
+member variables and virtual member functions) will be discarded. This can be
+misleading especially for member function slicing, for example:
+
+.. code-block:: c++
+
+ struct B { int a; virtual int f(); };
+ struct D : B { int b; int f() override; };
+
+ void use(B b) { // Missing reference, intended?
+ b.f(); // Calls B::f.
+ }
+
+ D d;
+ use(d); // Slice.
+
+See the relevant C++ Core Guidelines sections for details:
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es63-dont-slice
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c145-access-polymorphic-objects-through-pointers-and-references
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-special-member-functions.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-special-member-functions.rst
new file mode 100644
index 0000000..28a5e8e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-special-member-functions.rst
@@ -0,0 +1,49 @@
+.. title:: clang-tidy - cppcoreguidelines-special-member-functions
+
+cppcoreguidelines-special-member-functions
+==========================================
+
+The check finds classes where some but not all of the special member functions
+are defined.
+
+By default the compiler defines a copy constructor, copy assignment operator,
+move constructor, move assignment operator and destructor. The default can be
+suppressed by explicit user-definitions. The relationship between which
+functions will be suppressed by definitions of other functions is complicated
+and it is advised that all five are defaulted or explicitly defined.
+
+Note that defining a function with ``= delete`` is considered to be a
+definition.
+
+This rule is part of the "Constructors, assignments, and destructors" profile of the C++ Core
+Guidelines, corresponding to rule C.21. See
+
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c21-if-you-define-or-delete-any-default-operation-define-or-delete-them-all.
+
+Options
+-------
+
+.. option:: AllowSoleDefaultDtor
+
+ When set to `1` (default is `0`), this check doesn't flag classes with a sole, explicitly
+ defaulted destructor. An example for such a class is:
+
+ .. code-block:: c++
+
+ struct A {
+ virtual ~A() = default;
+ };
+
+.. option:: AllowMissingMoveFunctions
+
+ When set to `1` (default is `0`), this check doesn't flag classes which define no move
+ operations at all. It still flags classes which define only one of either
+ move constructor or move assignment operator. With this option enabled, the following class won't be flagged:
+
+ .. code-block:: c++
+
+ struct A {
+ A(const A&);
+ A& operator=(const A&);
+ ~A();
+ }
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-default-arguments.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-default-arguments.rst
new file mode 100644
index 0000000..ab011bf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-default-arguments.rst
@@ -0,0 +1,24 @@
+.. title:: clang-tidy - fuchsia-default-arguments
+
+fuchsia-default-arguments
+=========================
+
+Warns if a function or method is declared or called with default arguments.
+
+For example, the declaration:
+
+.. code-block:: c++
+
+ int foo(int value = 5) { return value; }
+
+will cause a warning.
+
+A function call expression that uses a default argument will be diagnosed.
+Calling it without defaults will not cause a warning:
+
+.. code-block:: c++
+
+ foo(); // warning
+ foo(0); // no warning
+
+See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-header-anon-namespaces.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-header-anon-namespaces.rst
new file mode 100644
index 0000000..42b5753
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-header-anon-namespaces.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - fuchsia-header-anon-namespaces
+.. meta::
+ :http-equiv=refresh: 5;URL=google-build-namespaces.html
+
+fuchsia-header-anon-namespaces
+==============================
+
+The fuchsia-header-anon-namespaces check is an alias, please see
+`google-build-namespace <google-build-namespaces.html>`_
+for more information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-multiple-inheritance.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-multiple-inheritance.rst
new file mode 100644
index 0000000..b52ec2b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-multiple-inheritance.rst
@@ -0,0 +1,46 @@
+.. title:: clang-tidy - fuchsia-multiple-inheritance
+
+fuchsia-multiple-inheritance
+============================
+
+Warns if a class inherits from multiple classes that are not pure virtual.
+
+For example, declaring a class that inherits from multiple concrete classes is
+disallowed:
+
+.. code-block:: c++
+
+ class Base_A {
+ public:
+ virtual int foo() { return 0; }
+ };
+
+ class Base_B {
+ public:
+ virtual int bar() { return 0; }
+ };
+
+ // Warning
+ class Bad_Child1 : public Base_A, Base_B {};
+
+A class that inherits from a pure virtual is allowed:
+
+.. code-block:: c++
+
+ class Interface_A {
+ public:
+ virtual int foo() = 0;
+ };
+
+ class Interface_B {
+ public:
+ virtual int bar() = 0;
+ };
+
+ // No warning
+ class Good_Child1 : public Interface_A, Interface_B {
+ virtual int foo() override { return 0; }
+ virtual int bar() override { return 0; }
+ };
+
+See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-overloaded-operator.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-overloaded-operator.rst
new file mode 100644
index 0000000..070780f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-overloaded-operator.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - fuchsia-overloaded-operator
+
+fuchsia-overloaded-operator
+===========================
+
+Warns if an operator is overloaded, except for the assignment (copy and move)
+operators.
+
+For example:
+
+.. code-block:: c++
+
+ int operator+(int); // Warning
+
+ B &operator=(const B &Other); // No warning
+ B &operator=(B &&Other) // No warning
+
+See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-restrict-system-includes.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-restrict-system-includes.rst
new file mode 100644
index 0000000..622e025
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-restrict-system-includes.rst
@@ -0,0 +1,32 @@
+.. title:: clang-tidy - fuchsia-restrict-system-includes
+
+fuchsia-restrict-system-includes
+================================
+
+Checks for allowed system includes and suggests removal of any others.
+
+It is important to note that running this check with fixes may break code, as
+the fix removes headers. Fixes are applied to source and header files, but not
+to system headers.
+
+For example, given the allowed system includes 'a.h,b*':
+
+.. code-block:: c++
+
+ #include <a.h>
+ #include <b.h>
+ #include <bar.h>
+ #include <c.h> // Warning, as c.h is not explicitly allowed
+
+All system includes can be allowed with '*', and all can be disallowed with an
+empty string ('').
+
+Options
+-------
+
+.. option:: Includes
+
+ A string containing a comma separated glob list of allowed include filenames.
+ Similar to the -checks glob list for running clang-tidy itself, the two
+ wildcard characters are '*' and '-', to include and exclude globs,
+ respectively.The default is '*', which allows all includes.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-statically-constructed-objects.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-statically-constructed-objects.rst
new file mode 100644
index 0000000..7c1c0ae
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-statically-constructed-objects.rst
@@ -0,0 +1,43 @@
+.. title:: clang-tidy - fuchsia-statically-constructed-objects
+
+fuchsia-statically-constructed-objects
+======================================
+
+Warns if global, non-trivial objects with static storage are constructed, unless
+the object is statically initialized with a ``constexpr`` constructor or has no
+explicit constructor.
+
+For example:
+
+.. code-block:: c++
+
+ class A {};
+
+ class B {
+ public:
+ B(int Val) : Val(Val) {}
+ private:
+ int Val;
+ };
+
+ class C {
+ public:
+ C(int Val) : Val(Val) {}
+ constexpr C() : Val(0) {}
+
+ private:
+ int Val;
+ };
+
+ static A a; // No warning, as there is no explicit constructor
+ static C c(0); // No warning, as constructor is constexpr
+
+ static B b(0); // Warning, as constructor is not constexpr
+ static C c2(0, 1); // Warning, as constructor is not constexpr
+
+ static int i; // No warning, as it is trivial
+
+ extern int get_i();
+ static C(get_i()) // Warning, as the constructor is dynamically initialized
+
+See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-trailing-return.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-trailing-return.rst
new file mode 100644
index 0000000..e67f477
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-trailing-return.rst
@@ -0,0 +1,35 @@
+.. title:: clang-tidy - fuchsia-trailing-return
+
+fuchsia-trailing-return
+=======================
+
+Functions that have trailing returns are disallowed, except for those using
+``decltype`` specifiers and lambda with otherwise unutterable return types.
+
+For example:
+
+.. code-block:: c++
+
+ // No warning
+ int add_one(const int arg) { return arg; }
+
+ // Warning
+ auto get_add_one() -> int (*)(const int) {
+ return add_one;
+ }
+
+Exceptions are made for lambdas and ``decltype`` specifiers:
+
+.. code-block:: c++
+
+ // No warning
+ auto lambda = [](double x, double y) -> double {return x + y;};
+
+ // No warning
+ template <typename T1, typename T2>
+ auto fn(const T1 &lhs, const T2 &rhs) -> decltype(lhs + rhs) {
+ return lhs + rhs;
+ }
+
+
+See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-virtual-inheritance.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-virtual-inheritance.rst
new file mode 100644
index 0000000..f73a49b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/fuchsia-virtual-inheritance.rst
@@ -0,0 +1,14 @@
+.. title:: clang-tidy - fuchsia-virtual-inheritance
+
+fuchsia-virtual-inheritance
+===========================
+
+Warns if classes are defined with virtual inheritance.
+
+For example, classes should not be defined with virtual inheritance:
+
+.. code-block:: c++
+
+ class B : public virtual A {}; // warning
+
+See the features disallowed in Fuchsia at https://fuchsia.googlesource.com/zircon/+/master/docs/cxx.md
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-build-explicit-make-pair.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-build-explicit-make-pair.rst
new file mode 100644
index 0000000..e3e9eeb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-build-explicit-make-pair.rst
@@ -0,0 +1,11 @@
+.. title:: clang-tidy - google-build-explicit-make-pair
+
+google-build-explicit-make-pair
+===============================
+
+Check that ``make_pair``'s template arguments are deduced.
+
+G++ 4.6 in C++11 mode fails badly if ``make_pair``'s template arguments are
+specified explicitly, and such use isn't intended in any case.
+
+Corresponding cpplint.py check name: `build/explicit_make_pair`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-build-namespaces.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-build-namespaces.rst
new file mode 100644
index 0000000..69c01d3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-build-namespaces.rst
@@ -0,0 +1,24 @@
+.. title:: clang-tidy - google-build-namespaces
+
+google-build-namespaces
+=======================
+
+`cert-dcl59-cpp` redirects here as an alias for this check.
+`fuchsia-header-anon-namespaces` redirects here as an alias for this check.
+
+Finds anonymous namespaces in headers.
+
+https://google.github.io/styleguide/cppguide.html#Namespaces
+
+Corresponding cpplint.py check name: `build/namespaces`.
+
+Options
+-------
+
+.. option:: HeaderFileExtensions
+
+ A comma-separated list of filename extensions of header files (the filename
+ extensions should not include "." prefix). Default is "h,hh,hpp,hxx".
+ For header files without an extension, use an empty string (if there are no
+ other desired extensions) or leave an empty element in the list. e.g.,
+ "h,hh,hpp,hxx," (note the trailing comma).
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-build-using-namespace.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-build-using-namespace.rst
new file mode 100644
index 0000000..f01bfed
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-build-using-namespace.rst
@@ -0,0 +1,19 @@
+.. title:: clang-tidy - google-build-using-namespace
+
+google-build-using-namespace
+============================
+
+Finds ``using namespace`` directives.
+
+The check implements the following rule of the
+`Google C++ Style Guide <https://google.github.io/styleguide/cppguide.html#Namespaces>`_:
+
+ You may not use a using-directive to make all names from a namespace
+ available.
+
+ .. code-block:: c++
+
+ // Forbidden -- This pollutes the namespace.
+ using namespace foo;
+
+Corresponding cpplint.py check name: `build/namespaces`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-default-arguments.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-default-arguments.rst
new file mode 100644
index 0000000..c02099c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-default-arguments.rst
@@ -0,0 +1,8 @@
+.. title:: clang-tidy - google-default-arguments
+
+google-default-arguments
+========================
+
+Checks that default arguments are not given for virtual methods.
+
+See https://google.github.io/styleguide/cppguide.html#Default_Arguments
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-explicit-constructor.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-explicit-constructor.rst
new file mode 100644
index 0000000..acafc1a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-explicit-constructor.rst
@@ -0,0 +1,56 @@
+.. title:: clang-tidy - google-explicit-constructor
+
+google-explicit-constructor
+===========================
+
+
+Checks that constructors callable with a single argument and conversion
+operators are marked explicit to avoid the risk of unintentional implicit
+conversions.
+
+Consider this example:
+
+.. code-block:: c++
+
+ struct S {
+ int x;
+ operator bool() const { return true; }
+ };
+
+ bool f() {
+ S a{1};
+ S b{2};
+ return a == b;
+ }
+
+The function will return ``true``, since the objects are implicitly converted to
+``bool`` before comparison, which is unlikely to be the intent.
+
+The check will suggest inserting ``explicit`` before the constructor or
+conversion operator declaration. However, copy and move constructors should not
+be explicit, as well as constructors taking a single ``initializer_list``
+argument.
+
+This code:
+
+.. code-block:: c++
+
+ struct S {
+ S(int a);
+ explicit S(const S&);
+ operator bool() const;
+ ...
+
+will become
+
+.. code-block:: c++
+
+ struct S {
+ explicit S(int a);
+ S(const S&);
+ explicit operator bool() const;
+ ...
+
+
+
+See https://google.github.io/styleguide/cppguide.html#Explicit_Constructors
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-global-names-in-headers.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-global-names-in-headers.rst
new file mode 100644
index 0000000..88ba906
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-global-names-in-headers.rst
@@ -0,0 +1,21 @@
+.. title:: clang-tidy - google-global-names-in-headers
+
+google-global-names-in-headers
+==============================
+
+Flag global namespace pollution in header files. Right now it only triggers on
+``using`` declarations and directives.
+
+The relevant style guide section is
+https://google.github.io/styleguide/cppguide.html#Namespaces.
+
+Options
+-------
+
+.. option:: HeaderFileExtensions
+
+ A comma-separated list of filename extensions of header files (the filename
+ extensions should not contain "." prefix). Default is "h".
+ For header files without an extension, use an empty string (if there are no
+ other desired extensions) or leave an empty element in the list. e.g.,
+ "h,hh,hpp,hxx," (note the trailing comma).
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-objc-avoid-throwing-exception.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-objc-avoid-throwing-exception.rst
new file mode 100644
index 0000000..39b0217
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-objc-avoid-throwing-exception.rst
@@ -0,0 +1,39 @@
+.. title:: clang-tidy - google-objc-avoid-throwing-exception
+
+google-objc-avoid-throwing-exception
+====================================
+
+Finds uses of throwing exceptions usages in Objective-C files.
+
+For the same reason as the Google C++ style guide, we prefer not throwing
+exceptions from Objective-C code.
+
+The corresponding C++ style guide rule:
+https://google.github.io/styleguide/cppguide.html#Exceptions
+
+Instead, prefer passing in ``NSError **`` and return ``BOOL`` to indicate success or failure.
+
+A counterexample:
+
+.. code-block:: objc
+
+ - (void)readFile {
+ if ([self isError]) {
+ @throw [NSException exceptionWithName:...];
+ }
+ }
+
+Instead, returning an error via ``NSError **`` is preferred:
+
+.. code-block:: objc
+
+ - (BOOL)readFileWithError:(NSError **)error {
+ if ([self isError]) {
+ *error = [NSError errorWithDomain:...];
+ return NO;
+ }
+ return YES;
+ }
+
+The corresponding style guide rule:
+http://google.github.io/styleguide/objcguide.html#avoid-throwing-exceptions
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-objc-global-variable-declaration.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-objc-global-variable-declaration.rst
new file mode 100644
index 0000000..d470370
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-objc-global-variable-declaration.rst
@@ -0,0 +1,47 @@
+.. title:: clang-tidy - google-objc-global-variable-declaration
+
+google-objc-global-variable-declaration
+=======================================
+
+Finds global variable declarations in Objective-C files that do not follow the
+pattern of variable names in Google's Objective-C Style Guide.
+
+The corresponding style guide rule:
+http://google.github.io/styleguide/objcguide.html#variable-names
+
+All the global variables should follow the pattern of `g[A-Z].*` (variables) or
+`k[A-Z].*` (constants). The check will suggest a variable name that follows the
+pattern if it can be inferred from the original name.
+
+For code:
+
+.. code-block:: objc
+
+ static NSString* myString = @"hello";
+
+The fix will be:
+
+.. code-block:: objc
+
+ static NSString* gMyString = @"hello";
+
+Another example of constant:
+
+.. code-block:: objc
+
+ static NSString* const myConstString = @"hello";
+
+The fix will be:
+
+.. code-block:: objc
+
+ static NSString* const kMyConstString = @"hello";
+
+However for code that prefixed with non-alphabetical characters like:
+
+.. code-block:: objc
+
+ static NSString* __anotherString = @"world";
+
+The check will give a warning message but will not be able to suggest a fix. The
+user need to fix it on his own.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-braces-around-statements.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-braces-around-statements.rst
new file mode 100644
index 0000000..e5c8eb6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-braces-around-statements.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - google-readability-braces-around-statements
+.. meta::
+ :http-equiv=refresh: 5;URL=readability-braces-around-statements.html
+
+google-readability-braces-around-statements
+===========================================
+
+The google-readability-braces-around-statements check is an alias, please see
+`readability-braces-around-statements <readability-braces-around-statements.html>`_
+for more information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-casting.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-casting.rst
new file mode 100644
index 0000000..4c9d1bc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-casting.rst
@@ -0,0 +1,14 @@
+.. title:: clang-tidy - google-readability-casting
+
+google-readability-casting
+==========================
+
+Finds usages of C-style casts.
+
+https://google.github.io/styleguide/cppguide.html#Casting
+
+Corresponding cpplint.py check name: `readability/casting`.
+
+This check is similar to `-Wold-style-cast`, but it suggests automated fixes
+in some cases. The reported locations should not be different from the
+ones generated by `-Wold-style-cast`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-function-size.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-function-size.rst
new file mode 100644
index 0000000..b454628
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-function-size.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - google-readability-function-size
+.. meta::
+ :http-equiv=refresh: 5;URL=readability-function-size.html
+
+google-readability-function-size
+================================
+
+The google-readability-function-size check is an alias, please see
+`readability-function-size <readability-function-size.html>`_ for more
+information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-namespace-comments.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-namespace-comments.rst
new file mode 100644
index 0000000..258a305
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-namespace-comments.rst
@@ -0,0 +1,9 @@
+.. title:: clang-tidy - google-readability-namespace-comments
+.. meta::
+ :http-equiv=refresh: 5;URL=llvm-namespace-comment.html
+
+google-readability-namespace-comments
+=====================================
+
+The google-readability-namespace-comments check is an alias, please see
+`llvm-namespace-comment <llvm-namespace-comment.html>`_ for more information.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-todo.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-todo.rst
new file mode 100644
index 0000000..159d2b4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-readability-todo.rst
@@ -0,0 +1,11 @@
+.. title:: clang-tidy - google-readability-todo
+
+google-readability-todo
+=======================
+
+Finds TODO comments without a username or bug number.
+
+The relevant style guide section is
+https://google.github.io/styleguide/cppguide.html#TODO_Comments.
+
+Corresponding cpplint.py check: `readability/todo`
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-runtime-int.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-runtime-int.rst
new file mode 100644
index 0000000..5e878a4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-runtime-int.rst
@@ -0,0 +1,27 @@
+.. title:: clang-tidy - google-runtime-int
+
+google-runtime-int
+==================
+
+Finds uses of ``short``, ``long`` and ``long long`` and suggest replacing them
+with ``u?intXX(_t)?``.
+
+The corresponding style guide rule:
+https://google.github.io/styleguide/cppguide.html#Integer_Types.
+
+Correspondig cpplint.py check: `runtime/int`.
+
+Options
+-------
+
+.. option:: UnsignedTypePrefix
+
+ A string specifying the unsigned type prefix. Default is `uint`.
+
+.. option:: SignedTypePrefix
+
+ A string specifying the signed type prefix. Default is `int`.
+
+.. option:: TypeSuffix
+
+ A string specifying the type suffix. Default is an empty string.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-runtime-operator.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-runtime-operator.rst
new file mode 100644
index 0000000..67f2993
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-runtime-operator.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - google-runtime-operator
+
+google-runtime-operator
+=======================
+
+Finds overloads of unary ``operator &``.
+
+https://google.github.io/styleguide/cppguide.html#Operator_Overloading
+
+Corresponding cpplint.py check name: `runtime/operator`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-runtime-references.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-runtime-references.rst
new file mode 100644
index 0000000..a210ccc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/google-runtime-references.rst
@@ -0,0 +1,17 @@
+.. title:: clang-tidy - google-runtime-references
+
+google-runtime-references
+=========================
+
+Checks the usage of non-constant references in function parameters.
+
+The corresponding style guide rule:
+https://google.github.io/styleguide/cppguide.html#Reference_Arguments
+
+
+Options
+-------
+
+.. option:: WhiteListTypes
+
+ A semicolon-separated list of names of whitelist types. Default is empty.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-avoid-goto.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-avoid-goto.rst
new file mode 100644
index 0000000..f689bec
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-avoid-goto.rst
@@ -0,0 +1,12 @@
+.. title:: clang-tidy - hicpp-avoid-goto
+
+hicpp-avoid-goto
+================
+
+The `hicpp-avoid-goto` check is an alias to
+`cppcoreguidelines-avoid-goto <cppcoreguidelines-avoid-goto.html>`_.
+Rule `6.3.1 High Integrity C++ <http://www.codingstandard.com/rule/6-3-1-ensure-that-the-labels-for-a-jump-statement-or-a-switch-condition-appear-later-in-the-same-or-an-enclosing-block/>`_
+requires that ``goto`` only skips parts of a block and is not used for other
+reasons.
+
+Both coding guidelines implement the same exception to the usage of ``goto``.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-braces-around-statements.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-braces-around-statements.rst
new file mode 100644
index 0000000..2931aa8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-braces-around-statements.rst
@@ -0,0 +1,11 @@
+.. title:: clang-tidy - hicpp-braces-around-statements
+.. meta::
+ :http-equiv=refresh: 5;URL=readability-braces-around-statements.html
+
+hicpp-braces-around-statements
+==============================
+
+The `hicpp-braces-around-statements` check is an alias, please see
+`readability-braces-around-statements <readability-braces-around-statements.html>`_
+for more information.
+It enforces the `rule 6.1.1 <http://www.codingstandard.com/rule/6-1-1-enclose-the-body-of-a-selection-or-an-iteration-statement-in-a-compound-statement/>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-deprecated-headers.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-deprecated-headers.rst
new file mode 100644
index 0000000..960d918
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-deprecated-headers.rst
@@ -0,0 +1,11 @@
+.. title:: clang-tidy - hicpp-deprecated-headers
+.. meta::
+ :http-equiv=refresh: 5;URL=modernize-deprecated-headers.html
+
+hicpp-deprecated-headers
+========================
+
+The `hicpp-deprecated-headers` check is an alias, please see
+`modernize-deprecated-headers <modernize-deprecated-headers.html>`_
+for more information.
+It enforces the `rule 1.3.3 <http://www.codingstandard.com/rule/1-3-3-do-not-use-the-c-standard-library-h-headers/>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-exception-baseclass.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-exception-baseclass.rst
new file mode 100644
index 0000000..42563ae
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-exception-baseclass.rst
@@ -0,0 +1,30 @@
+.. title:: clang-tidy - hicpp-exception-baseclass
+
+hicpp-exception-baseclass
+=========================
+
+Ensure that every value that in a ``throw`` expression is an instance of
+``std::exception``.
+
+This enforces `rule 15.1 <http://www.codingstandard.com/section/15-1-throwing-an-exception/>`_
+of the High Integrity C++ Coding Standard.
+
+.. code-block:: c++
+
+ class custom_exception {};
+
+ void throwing() noexcept(false) {
+ // Problematic throw expressions.
+ throw int(42);
+ throw custom_exception();
+ }
+
+ class mathematical_error : public std::exception {};
+
+ void throwing2() noexcept(false) {
+ // These kind of throws are ok.
+ throw mathematical_error();
+ throw std::runtime_error();
+ throw std::exception();
+ }
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-explicit-conversions.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-explicit-conversions.rst
new file mode 100644
index 0000000..3ee0b78
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-explicit-conversions.rst
@@ -0,0 +1,17 @@
+.. title:: clang-tidy - hicpp-explicit-conversions
+.. meta::
+ :http-equiv=refresh: 5;URL=google-explicit-constructor.html
+
+hicpp-explicit-conversions
+==========================
+
+This check is an alias for `google-explicit-constructor <google-explicit-constructor.html>`_.
+Used to enforce parts of `rule 5.4.1 <http://www.codingstandard.com/rule/5-4-1-only-use-casting-forms-static_cast-excl-void-dynamic_cast-or-explicit-constructor-call/>`_.
+This check will enforce that constructors and conversion operators are marked `explicit`.
+Other forms of casting checks are implemented in other places.
+The following checks can be used to check for more forms of casting:
+
+- `cppcoreguidelines-pro-type-static-cast-downcast <cppcoreguidelines-pro-type-static-cast-downcast.html>`_
+- `cppcoreguidelines-pro-type-reinterpret-cast <cppcoreguidelines-pro-type-reinterpret-cast.html>`_
+- `cppcoreguidelines-pro-type-const-cast <cppcoreguidelines-pro-type-const-cast.html>`_
+- `cppcoreguidelines-pro-type-cstyle-cast <cppcoreguidelines-pro-type-cstyle-cast.html>`_
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-function-size.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-function-size.rst
new file mode 100644
index 0000000..4b1f616
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-function-size.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - hicpp-function-size
+.. meta::
+ :http-equiv=refresh: 5;URL=readability-function-size.html
+
+hicpp-function-size
+===================
+
+This check is an alias for `readability-function-size <readability-function-size.html>`_.
+Useful to enforce multiple sections on function complexity.
+
+- `rule 8.2.2 <http://www.codingstandard.com/rule/8-2-2-do-not-declare-functions-with-an-excessive-number-of-parameters/>`_
+- `rule 8.3.1 <http://www.codingstandard.com/rule/8-3-1-do-not-write-functions-with-an-excessive-mccabe-cyclomatic-complexity/>`_
+- `rule 8.3.2 <http://www.codingstandard.com/rule/8-3-2-do-not-write-functions-with-a-high-static-program-path-count/>`_
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-invalid-access-moved.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-invalid-access-moved.rst
new file mode 100644
index 0000000..4fac3f5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-invalid-access-moved.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - hicpp-invalid-access-moved
+.. meta::
+ :http-equiv=refresh: 5;URL=bugprone-use-after-move.html
+
+hicpp-invalid-access-moved
+==========================
+
+This check is an alias for `bugprone-use-after-move <bugprone-use-after-move.html>`_.
+
+Implements parts of the `rule 8.4.1 <http://www.codingstandard.com/rule/8-4-1-do-not-access-an-invalid-object-or-an-object-with-indeterminate-value/>`_ to check if moved-from objects are accessed.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-member-init.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-member-init.rst
new file mode 100644
index 0000000..7f985e2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-member-init.rst
@@ -0,0 +1,11 @@
+.. title:: clang-tidy - hicpp-member-init
+.. meta::
+ :http-equiv=refresh: 5;URL=cppcoreguidelines-pro-type-member-init.html
+
+hicpp-member-init
+=================
+
+This check is an alias for `cppcoreguidelines-pro-type-member-init <cppcoreguidelines-pro-type-member-init.html>`_.
+Implements the check for
+`rule 12.4.2 <http://www.codingstandard.com/rule/12-4-2-ensure-that-a-constructor-initializes-explicitly-all-base-classes-and-non-static-data-members/>`_
+to initialize class members in the right order.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-move-const-arg.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-move-const-arg.rst
new file mode 100644
index 0000000..c8d34d0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-move-const-arg.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - hicpp-move-const-arg
+.. meta::
+ :http-equiv=refresh: 5;URL=performance-move-const-arg.html
+
+hicpp-move-const-arg
+====================
+
+The `hicpp-move-const-arg` check is an alias, please see
+`performance-move-const-arg <performance-move-const-arg.html>`_ for more information.
+It enforces the `rule 17.3.1 <http://www.codingstandard.com/rule/17-3-1-do-not-use-stdmove-on-objects-declared-with-const-or-const-type/>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst
new file mode 100644
index 0000000..2cace63
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst
@@ -0,0 +1,96 @@
+.. title:: clang-tidy - hicpp-multiway-paths-covered
+
+hicpp-multiway-paths-covered
+============================
+
+This check discovers situations where code paths are not fully-covered.
+It furthermore suggests using ``if`` instead of ``switch`` if the code will be more clear.
+The `rule 6.1.2 <http://www.codingstandard.com/rule/6-1-2-explicitly-cover-all-paths-through-multi-way-selection-statements/>`_
+and `rule 6.1.4 <http://www.codingstandard.com/rule/6-1-4-ensure-that-a-switch-statement-has-at-least-two-case-labels-distinct-from-the-default-label/>`_
+of the High Integrity C++ Coding Standard are enforced.
+
+``if-else if`` chains that miss a final ``else`` branch might lead to unexpected
+program execution and be the result of a logical error.
+If the missing ``else`` branch is intended you can leave it empty with a clarifying
+comment.
+This warning can be noisy on some code bases, so it is disabled by default.
+
+.. code-block:: c++
+
+ void f1() {
+ int i = determineTheNumber();
+
+ if(i > 0) {
+ // Some Calculation
+ } else if (i < 0) {
+ // Precondition violated or something else.
+ }
+ // ...
+ }
+
+Similar arguments hold for ``switch`` statements which do not cover all possible code paths.
+
+.. code-block:: c++
+
+ // The missing default branch might be a logical error. It can be kept empty
+ // if there is nothing to do, making it explicit.
+ void f2(int i) {
+ switch (i) {
+ case 0: // something
+ break;
+ case 1: // something else
+ break;
+ }
+ // All other numbers?
+ }
+
+ // Violates this rule as well, but already emits a compiler warning (-Wswitch).
+ enum Color { Red, Green, Blue, Yellow };
+ void f3(enum Color c) {
+ switch (c) {
+ case Red: // We can't drive for now.
+ break;
+ case Green: // We are allowed to drive.
+ break;
+ }
+ // Other cases missing
+ }
+
+
+The `rule 6.1.4 <http://www.codingstandard.com/rule/6-1-4-ensure-that-a-switch-statement-has-at-least-two-case-labels-distinct-from-the-default-label/>`_
+requires every ``switch`` statement to have at least two ``case`` labels other than a `default` label.
+Otherwise, the ``switch`` could be better expressed with an ``if`` statement.
+Degenerated ``switch`` statements without any labels are caught as well.
+
+.. code-block:: c++
+
+ // Degenerated switch that could be better written as `if`
+ int i = 42;
+ switch(i) {
+ case 1: // do something here
+ default: // do somethe else here
+ }
+
+ // Should rather be the following:
+ if (i == 1) {
+ // do something here
+ }
+ else {
+ // do something here
+ }
+
+
+.. code-block:: c++
+
+ // A completly degenerated switch will be diagnosed.
+ int i = 42;
+ switch(i) {}
+
+
+Options
+-------
+
+.. option:: WarnOnMissingElse
+
+ Boolean flag that activates a warning for missing ``else`` branches.
+ Default is `0`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-named-parameter.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-named-parameter.rst
new file mode 100644
index 0000000..4bb8505
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-named-parameter.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - hicpp-named-parameter
+.. meta::
+ :http-equiv=refresh: 5;URL=readability-named-parameter.html
+
+hicpp-named-parameter
+=====================
+
+This check is an alias for `readability-named-parameter <readability-named-parameter.html>`_.
+
+Implements `rule 8.2.1 <http://www.codingstandard.com/rule/8-2-1-make-parameter-names-absent-or-identical-in-all-declarations/>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-new-delete-operators.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-new-delete-operators.rst
new file mode 100644
index 0000000..88c26ad
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-new-delete-operators.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - hicpp-new-delete-operators
+.. meta::
+ :http-equiv=refresh: 5;URL=misc-new-delete-overloads.html
+
+hicpp-new-delete-operators
+==========================
+
+This check is an alias for `misc-new-delete-overloads <misc-new-delete-overloads.html>`_.
+Implements `rule 12.3.1 <http://www.codingstandard.com/section/12-3-free-store/>`_ to ensure
+the `new` and `delete` operators have the correct signature.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-no-array-decay.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-no-array-decay.rst
new file mode 100644
index 0000000..01f140e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-no-array-decay.rst
@@ -0,0 +1,11 @@
+.. title:: clang-tidy - hicpp-no-array-decay
+.. meta::
+ :http-equiv=refresh: 5;URL=cppcoreguidelines-pro-bounds-array-to-pointer-decay.html
+
+hicpp-no-array-decay
+====================
+
+The `hicpp-no-array-decay` check is an alias, please see
+`cppcoreguidelines-pro-bounds-array-to-pointer-decay <cppcoreguidelines-pro-bounds-array-to-pointer-decay.html>`_
+for more information.
+It enforces the `rule 4.1.1 <http://www.codingstandard.com/section/4-1-array-to-pointer-conversion/>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-no-assembler.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-no-assembler.rst
new file mode 100644
index 0000000..8295895
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-no-assembler.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - hicpp-no-assembler
+
+hicpp-no-assembler
+===================
+
+Check for assembler statements. No fix is offered.
+
+Inline assembler is forbidden by the `High Intergrity C++ Coding Standard
+<http://www.codingstandard.com/section/7-5-the-asm-declaration/>`_
+as it restricts the portability of code.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-no-malloc.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-no-malloc.rst
new file mode 100644
index 0000000..768342f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-no-malloc.rst
@@ -0,0 +1,11 @@
+.. title:: clang-tidy - hicpp-no-malloc
+.. meta::
+ :http-equiv=refresh: 5;URL=cppcoreguidelines-no-malloc.html
+
+hicpp-no-malloc
+===============
+
+The `hicpp-no-malloc` check is an alias, please see
+`cppcoreguidelines-no-malloc <cppcoreguidelines-no-malloc.html>`_
+for more information.
+It enforces the `rule 5.3.2 <http://www.codingstandard.com/rule/5-3-2-allocate-memory-using-new-and-release-it-using-delete/>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-noexcept-move.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-noexcept-move.rst
new file mode 100644
index 0000000..10573ec
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-noexcept-move.rst
@@ -0,0 +1,9 @@
+.. title:: clang-tidy - hicpp-noexcept-move
+.. meta::
+ :http-equiv=refresh: 5;URL=misc-noexcept-moveconstructor.html
+
+hicpp-noexcept-move
+===================
+
+This check is an alias for `misc-noexcept-moveconstructor <misc-noexcept-moveconstructor.html>`_.
+Checks `rule 12.5.4 <http://www.codingstandard.com/rule/12-5-4-declare-noexcept-the-move-constructor-and-move-assignment-operator>`_ to mark move assignment and move construction `noexcept`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-signed-bitwise.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-signed-bitwise.rst
new file mode 100644
index 0000000..59b19b6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-signed-bitwise.rst
@@ -0,0 +1,9 @@
+.. title:: clang-tidy - hicpp-signed-bitwise
+
+hicpp-signed-bitwise
+====================
+
+Finds uses of bitwise operations on signed integer types, which may lead to
+undefined or implementation defined behaviour.
+
+The according rule is defined in the `High Integrity C++ Standard, Section 5.6.1 <http://www.codingstandard.com/section/5-6-shift-operators/>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-special-member-functions.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-special-member-functions.rst
new file mode 100644
index 0000000..4173177
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-special-member-functions.rst
@@ -0,0 +1,9 @@
+.. title:: clang-tidy - hicpp-special-member-functions
+.. meta::
+ :http-equiv=refresh: 5;URL=cppcoreguidelines-special-member-functions.html
+
+hicpp-special-member-functions
+==============================
+
+This check is an alias for `cppcoreguidelines-special-member-functions <cppcoreguidelines-special-member-functions.html>`_.
+Checks that special member functions have the correct signature, according to `rule 12.5.7 <http://www.codingstandard.com/rule/12-5-7-declare-assignment-operators-with-the-ref-qualifier/>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-static-assert.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-static-assert.rst
new file mode 100644
index 0000000..b5d4e41
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-static-assert.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - hicpp-static-assert
+.. meta::
+ :http-equiv=refresh: 5;URL=misc-static-assert.html
+
+hicpp-static-assert
+===================
+
+The `hicpp-static-assert` check is an alias, please see
+`misc-static-assert <misc-static-assert.html>`_ for more information.
+It enforces the `rule 7.1.10 <http://www.codingstandard.com/rule/6-1-1-enclose-the-body-of-a-selection-or-an-iteration-statement-in-a-compound-statement/>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-undelegated-constructor.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-undelegated-constructor.rst
new file mode 100644
index 0000000..db521c5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-undelegated-constructor.rst
@@ -0,0 +1,25 @@
+.. title:: clang-tidy - hicpp-undelegated-construtor
+.. meta::
+ :http-equiv=refresh: 5;URL=bugprone-undelegated-constructor.html
+
+hicpp-undelegated-constructor
+=============================
+
+This check is an alias for `bugprone-undelegated-constructor <bugprone-undelegated-constructor.html>`_.
+Partially implements `rule 12.4.5 <http://www.codingstandard.com/rule/12-4-5-use-delegating-constructors-to-reduce-code-duplication/>`_
+to find misplaced constructor calls inside a constructor.
+
+.. code-block:: c++
+
+ struct Ctor {
+ Ctor();
+ Ctor(int);
+ Ctor(int, int);
+ Ctor(Ctor *i) {
+ // All Ctor() calls result in a temporary object
+ Ctor(); // did you intend to call a delegated constructor?
+ Ctor(0); // did you intend to call a delegated constructor?
+ Ctor(1, 2); // did you intend to call a delegated constructor?
+ foo();
+ }
+ };
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-auto.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-auto.rst
new file mode 100644
index 0000000..23d0067
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-auto.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - hicpp-use-auto
+.. meta::
+ :http-equiv=refresh: 5;URL=modernize-use-auto.html
+
+hicpp-use-auto
+==============
+
+The `hicpp-use-auto` check is an alias, please see
+`modernize-use-auto <modernize-use-auto.html>`_ for more information.
+It enforces the `rule 7.1.8 <http://www.codingstandard.com/rule/7-1-8-use-auto-id-expr-when-declaring-a-variable-to-have-the-same-type-as-its-initializer-function-call/>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-emplace.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-emplace.rst
new file mode 100644
index 0000000..07853c8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-emplace.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - hicpp-use-emplace
+.. meta::
+ :http-equiv=refresh: 5;URL=modernize-use-emplace.html
+
+hicpp-use-emplace
+=================
+
+The `hicpp-use-emplace` check is an alias, please see
+`modernize-use-emplace <modernize-use-emplace.html>`_ for more information.
+It enforces the `rule 17.4.2 <http://www.codingstandard.com/rule/17-4-2-use-api-calls-that-construct-objects-in-place/>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-equals-default.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-equals-default.rst
new file mode 100644
index 0000000..1dcf581
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-equals-default.rst
@@ -0,0 +1,9 @@
+.. title:: clang-tidy - hicpp-use-equals-defaults
+.. meta::
+ :http-equiv=refresh: 5;URL=modernize-use-equals-default.html
+
+hicpp-use-equals-default
+========================
+
+This check is an alias for `modernize-use-equals-default <modernize-use-equals-default.html>`_.
+Implements `rule 12.5.1 <http://www.codingstandard.com/rule/12-5-1-define-explicitly-default-or-delete-implicit-special-member-functions-of-concrete-classes/>`_ to explicitly default special member functions.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-equals-delete.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-equals-delete.rst
new file mode 100644
index 0000000..4d98786
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-equals-delete.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - hicpp-use-equals-delete
+.. meta::
+ :http-equiv=refresh: 5;URL=modernize-use-equals-delete.html
+
+hicpp-use-equals-delete
+=======================
+
+This check is an alias for `modernize-use-equals-delete <modernize-use-equals-delete.html>`_.
+Implements `rule 12.5.1 <http://www.codingstandard.com/rule/12-5-1-define-explicitly-default-or-delete-implicit-special-member-functions-of-concrete-classes/>`_
+to explicitly default or delete special member functions.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-noexcept.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-noexcept.rst
new file mode 100644
index 0000000..1a30ddf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-noexcept.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - hicpp-use-noexcept
+.. meta::
+ :http-equiv=refresh: 5;URL=modernize-use-noexcept.html
+
+hicpp-use-noexcept
+==================
+
+The `hicpp-use-noexcept` check is an alias, please see
+`modernize-use-noexcept <modernize-use-noexcept.html>`_ for more information.
+It enforces the `rule 1.3.5 <http://www.codingstandard.com/rule/1-3-5-do-not-use-throw-exception-specifications/>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-nullptr.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-nullptr.rst
new file mode 100644
index 0000000..9bd9051
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-nullptr.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - hicpp-use-nullptr
+.. meta::
+ :http-equiv=refresh: 5;URL=modernize-use-nullptr.html
+
+hicpp-use-nullptr
+=================
+
+The `hicpp-use-nullptr` check is an alias, please see
+`modernize-use-nullptr <modernize-use-nullptr.html>`_ for more information.
+It enforces the `rule 2.5.3 <http://www.codingstandard.com/rule/2-5-3-use-nullptr-for-the-null-pointer-constant/>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-override.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-override.rst
new file mode 100644
index 0000000..62541fa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-use-override.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - hicpp-use-override
+.. meta::
+ :http-equiv=refresh: 5;URL=modernize-use-override.html
+
+hicpp-use-override
+==================
+
+This check is an alias for `modernize-use-override <modernize-use-override.html>`_.
+Implements `rule 10.2.1 <http://www.codingstandard.com/section/10-2-virtual-functions/>`_ to
+declare a virtual function `override` when overriding.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-vararg.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-vararg.rst
new file mode 100644
index 0000000..92562e4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/hicpp-vararg.rst
@@ -0,0 +1,11 @@
+.. title:: clang-tidy - hicpp-vararg
+.. meta::
+ :http-equiv=refresh: 5;URL=cppcoreguidelines-pro-type-vararg.html
+
+hicpp-vararg
+============
+
+The `hicpp-vararg` check is an alias, please see
+`cppcoreguidelines-pro-type-vararg <cppcoreguidelines-pro-type-vararg.html>`_
+for more information.
+It enforces the `rule 14.1.1 <http://www.codingstandard.com/section/14-1-template-declarations/>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/list.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/list.rst
new file mode 100644
index 0000000..9bb68bc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -0,0 +1,238 @@
+.. title:: clang-tidy - Clang-Tidy Checks
+
+Clang-Tidy Checks
+=================
+
+.. toctree::
+ abseil-string-find-startswith
+ android-cloexec-accept
+ android-cloexec-accept4
+ android-cloexec-creat
+ android-cloexec-dup
+ android-cloexec-epoll-create
+ android-cloexec-epoll-create1
+ android-cloexec-fopen
+ android-cloexec-inotify-init
+ android-cloexec-inotify-init1
+ android-cloexec-memfd-create
+ android-cloexec-open
+ android-cloexec-socket
+ android-comparison-in-temp-failure-retry
+ boost-use-to-string
+ bugprone-argument-comment
+ bugprone-assert-side-effect
+ bugprone-bool-pointer-implicit-conversion
+ bugprone-copy-constructor-init
+ bugprone-dangling-handle
+ bugprone-exception-escape
+ bugprone-fold-init-type
+ bugprone-forward-declaration-namespace
+ bugprone-forwarding-reference-overload
+ bugprone-inaccurate-erase
+ bugprone-incorrect-roundings
+ bugprone-integer-division
+ bugprone-lambda-function-name
+ bugprone-macro-parentheses
+ bugprone-macro-repeated-side-effects
+ bugprone-misplaced-operator-in-strlen-in-alloc
+ bugprone-misplaced-widening-cast
+ bugprone-move-forwarding-reference
+ bugprone-multiple-statement-macro
+ bugprone-parent-virtual-call
+ bugprone-sizeof-container
+ bugprone-sizeof-expression
+ bugprone-string-constructor
+ bugprone-string-integer-assignment
+ bugprone-string-literal-with-embedded-nul
+ bugprone-suspicious-enum-usage
+ bugprone-suspicious-memset-usage
+ bugprone-suspicious-missing-comma
+ bugprone-suspicious-semicolon
+ bugprone-suspicious-string-compare
+ bugprone-swapped-arguments
+ bugprone-terminating-continue
+ bugprone-throw-keyword-missing
+ bugprone-undefined-memory-manipulation
+ bugprone-undelegated-constructor
+ bugprone-unused-raii
+ bugprone-unused-return-value
+ bugprone-use-after-move
+ bugprone-virtual-near-miss
+ cert-dcl03-c (redirects to misc-static-assert) <cert-dcl03-c>
+ cert-dcl21-cpp
+ cert-dcl50-cpp
+ cert-dcl54-cpp (redirects to misc-new-delete-overloads) <cert-dcl54-cpp>
+ cert-dcl58-cpp
+ cert-dcl59-cpp (redirects to google-build-namespaces) <cert-dcl59-cpp>
+ cert-env33-c
+ cert-err09-cpp (redirects to misc-throw-by-value-catch-by-reference) <cert-err09-cpp>
+ cert-err34-c
+ cert-err52-cpp
+ cert-err58-cpp
+ cert-err60-cpp
+ cert-err61-cpp (redirects to misc-throw-by-value-catch-by-reference) <cert-err61-cpp>
+ cert-fio38-c (redirects to misc-non-copyable-objects) <cert-fio38-c>
+ cert-flp30-c
+ cert-msc30-c (redirects to cert-msc50-cpp) <cert-msc30-c>
+ cert-msc32-c (redirects to cert-msc51-cpp) <cert-msc32-c>
+ cert-msc50-cpp
+ cert-msc51-cpp
+ cert-oop11-cpp (redirects to performance-move-constructor-init) <cert-oop11-cpp>
+ cppcoreguidelines-avoid-goto
+ cppcoreguidelines-c-copy-assignment-signature (redirects to misc-unconventional-assign-operator) <cppcoreguidelines-c-copy-assignment-signature>
+ cppcoreguidelines-interfaces-global-init
+ cppcoreguidelines-narrowing-conversions
+ cppcoreguidelines-no-malloc
+ cppcoreguidelines-owning-memory
+ cppcoreguidelines-pro-bounds-array-to-pointer-decay
+ cppcoreguidelines-pro-bounds-constant-array-index
+ cppcoreguidelines-pro-bounds-pointer-arithmetic
+ cppcoreguidelines-pro-type-const-cast
+ cppcoreguidelines-pro-type-cstyle-cast
+ cppcoreguidelines-pro-type-member-init
+ cppcoreguidelines-pro-type-reinterpret-cast
+ cppcoreguidelines-pro-type-static-cast-downcast
+ cppcoreguidelines-pro-type-union-access
+ cppcoreguidelines-pro-type-vararg
+ cppcoreguidelines-slicing
+ cppcoreguidelines-special-member-functions
+ fuchsia-default-arguments
+ fuchsia-header-anon-namespaces (redirects to google-build-namespaces) <fuchsia-header-anon-namespaces>
+ fuchsia-multiple-inheritance
+ fuchsia-overloaded-operator
+ fuchsia-restrict-system-includes
+ fuchsia-statically-constructed-objects
+ fuchsia-trailing-return
+ fuchsia-virtual-inheritance
+ google-build-explicit-make-pair
+ google-build-namespaces
+ google-build-using-namespace
+ google-default-arguments
+ google-explicit-constructor
+ google-global-names-in-headers
+ google-objc-avoid-throwing-exception
+ google-objc-global-variable-declaration
+ google-readability-braces-around-statements (redirects to readability-braces-around-statements) <google-readability-braces-around-statements>
+ google-readability-casting
+ google-readability-function-size (redirects to readability-function-size) <google-readability-function-size>
+ google-readability-namespace-comments (redirects to llvm-namespace-comment) <google-readability-namespace-comments>
+ google-readability-todo
+ google-runtime-int
+ google-runtime-operator
+ google-runtime-references
+ hicpp-avoid-goto
+ hicpp-braces-around-statements (redirects to readability-braces-around-statements) <hicpp-braces-around-statements>
+ hicpp-deprecated-headers (redirects to modernize-deprecated-headers) <hicpp-deprecated-headers>
+ hicpp-exception-baseclass
+ hicpp-explicit-conversions (redirects to google-explicit-constructor) <hicpp-explicit-conversions>
+ hicpp-function-size (redirects to readability-function-size) <hicpp-function-size>
+ hicpp-invalid-access-moved (redirects to bugprone-use-after-move) <hicpp-invalid-access-moved>
+ hicpp-member-init (redirects to cppcoreguidelines-pro-type-member-init) <hicpp-member-init>
+ hicpp-move-const-arg (redirects to performance-move-const-arg) <hicpp-move-const-arg>
+ hicpp-multiway-paths-covered
+ hicpp-named-parameter (redirects to readability-named-parameter) <hicpp-named-parameter>
+ hicpp-new-delete-operators (redirects to misc-new-delete-overloads) <hicpp-new-delete-operators>
+ hicpp-no-array-decay (redirects to cppcoreguidelines-pro-bounds-array-to-pointer-decay) <hicpp-no-array-decay>
+ hicpp-no-assembler
+ hicpp-no-malloc (redirects to cppcoreguidelines-no-malloc) <hicpp-no-malloc>
+ hicpp-noexcept-move (redirects to misc-noexcept-moveconstructor) <hicpp-noexcept-move>
+ hicpp-signed-bitwise
+ hicpp-special-member-functions (redirects to cppcoreguidelines-special-member-functions) <hicpp-special-member-functions>
+ hicpp-static-assert (redirects to misc-static-assert) <hicpp-static-assert>
+ hicpp-undelegated-constructor (redirects to bugprone-undelegated-constructor) <hicpp-undelegated-constructor>
+ hicpp-use-auto (redirects to modernize-use-auto) <hicpp-use-auto>
+ hicpp-use-emplace (redirects to modernize-use-emplace) <hicpp-use-emplace>
+ hicpp-use-equals-default (redirects to modernize-use-equals-default) <hicpp-use-equals-default>
+ hicpp-use-equals-delete (redirects to modernize-use-equals-delete) <hicpp-use-equals-delete>
+ hicpp-use-noexcept (redirects to modernize-use-noexcept) <hicpp-use-noexcept>
+ hicpp-use-nullptr (redirects to modernize-use-nullptr) <hicpp-use-nullptr>
+ hicpp-use-override (redirects to modernize-use-override) <hicpp-use-override>
+ hicpp-vararg (redirects to cppcoreguidelines-pro-type-vararg) <hicpp-vararg>
+ llvm-header-guard
+ llvm-include-order
+ llvm-namespace-comment
+ llvm-twine-local
+ misc-definitions-in-headers
+ misc-misplaced-const
+ misc-new-delete-overloads
+ misc-non-copyable-objects
+ misc-redundant-expression
+ misc-static-assert
+ misc-throw-by-value-catch-by-reference
+ misc-unconventional-assign-operator
+ misc-uniqueptr-reset-release
+ misc-unused-alias-decls
+ misc-unused-parameters
+ misc-unused-using-decls
+ modernize-avoid-bind
+ modernize-deprecated-headers
+ modernize-loop-convert
+ modernize-make-shared
+ modernize-make-unique
+ modernize-pass-by-value
+ modernize-raw-string-literal
+ modernize-redundant-void-arg
+ modernize-replace-auto-ptr
+ modernize-replace-random-shuffle
+ modernize-return-braced-init-list
+ modernize-shrink-to-fit
+ modernize-unary-static-assert
+ modernize-use-auto
+ modernize-use-bool-literals
+ modernize-use-default-member-init
+ modernize-use-emplace
+ modernize-use-equals-default
+ modernize-use-equals-delete
+ modernize-use-noexcept
+ modernize-use-nullptr
+ modernize-use-override
+ modernize-use-transparent-functors
+ modernize-use-uncaught-exceptions
+ modernize-use-using
+ mpi-buffer-deref
+ mpi-type-mismatch
+ objc-avoid-nserror-init
+ objc-avoid-spinlock
+ objc-forbidden-subclassing
+ objc-property-declaration
+ performance-faster-string-find
+ performance-for-range-copy
+ performance-implicit-conversion-in-loop
+ performance-inefficient-algorithm
+ performance-inefficient-string-concatenation
+ performance-inefficient-vector-operation
+ performance-move-const-arg
+ performance-move-constructor-init
+ performance-noexcept-move-constructor
+ performance-type-promotion-in-math-fn
+ performance-unnecessary-copy-initialization
+ performance-unnecessary-value-param
+ portability-simd-intrinsics
+ readability-avoid-const-params-in-decls
+ readability-braces-around-statements
+ readability-container-size-empty
+ readability-delete-null-pointer
+ readability-deleted-default
+ readability-else-after-return
+ readability-function-size
+ readability-identifier-naming
+ readability-implicit-bool-conversion
+ readability-inconsistent-declaration-parameter-name
+ readability-misleading-indentation
+ readability-misplaced-array-index
+ readability-named-parameter
+ readability-non-const-parameter
+ readability-redundant-control-flow
+ readability-redundant-declaration
+ readability-redundant-function-ptr-dereference
+ readability-redundant-member-init
+ readability-redundant-smartptr-get
+ readability-redundant-string-cstr
+ readability-redundant-string-init
+ readability-simplify-boolean-expr
+ readability-simplify-subscript-expr
+ readability-static-accessed-through-instance
+ readability-static-definition-in-anonymous-namespace
+ readability-string-compare
+ readability-uniqueptr-delete-release
+ zircon-temporary-objects
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/llvm-header-guard.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/llvm-header-guard.rst
new file mode 100644
index 0000000..58233ec
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/llvm-header-guard.rst
@@ -0,0 +1,17 @@
+.. title:: clang-tidy - llvm-header-guard
+
+llvm-header-guard
+=================
+
+Finds and fixes header guards that do not adhere to LLVM style.
+
+Options
+-------
+
+.. option:: HeaderFileExtensions
+
+ A comma-separated list of filename extensions of header files (the filename
+ extensions should not include "." prefix). Default is "h,hh,hpp,hxx".
+ For header files without an extension, use an empty string (if there are no
+ other desired extensions) or leave an empty element in the list. e.g.,
+ "h,hh,hpp,hxx," (note the trailing comma).
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/llvm-include-order.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/llvm-include-order.rst
new file mode 100644
index 0000000..dba9837
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/llvm-include-order.rst
@@ -0,0 +1,9 @@
+.. title:: clang-tidy - llvm-include-order
+
+llvm-include-order
+==================
+
+
+Checks the correct order of ``#includes``.
+
+See http://llvm.org/docs/CodingStandards.html#include-style
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/llvm-namespace-comment.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/llvm-namespace-comment.rst
new file mode 100644
index 0000000..f6bc598
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/llvm-namespace-comment.rst
@@ -0,0 +1,41 @@
+.. title:: clang-tidy - llvm-namespace-comment
+
+llvm-namespace-comment
+======================
+
+`google-readability-namespace-comments` redirects here as an alias for this
+check.
+
+Checks that long namespaces have a closing comment.
+
+http://llvm.org/docs/CodingStandards.html#namespace-indentation
+
+https://google.github.io/styleguide/cppguide.html#Namespaces
+
+.. code-block:: c++
+
+ namespace n1 {
+ void f();
+ }
+
+ // becomes
+
+ namespace n1 {
+ void f();
+ } // namespace n1
+
+
+Options
+-------
+
+.. option:: ShortNamespaceLines
+
+ Requires the closing brace of the namespace definition to be followed by a
+ closing comment if the body of the namespace has more than
+ `ShortNamespaceLines` lines of code. The value is an unsigned integer that
+ defaults to `1U`.
+
+.. option:: SpacesBeforeComments
+
+ An unsigned integer specifying the number of spaces before the comment
+ closing a namespace definition. Default is `1U`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/llvm-twine-local.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/llvm-twine-local.rst
new file mode 100644
index 0000000..ec9ef1c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/llvm-twine-local.rst
@@ -0,0 +1,16 @@
+.. title:: clang-tidy - llvm-twine-local
+
+llvm-twine-local
+================
+
+
+Looks for local ``Twine`` variables which are prone to use after frees and
+should be generally avoided.
+
+.. code-block:: c++
+
+ static Twine Moo = Twine("bark") + "bah";
+
+ // becomes
+
+ static std::string Moo = (Twine("bark") + "bah").str();
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-definitions-in-headers.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-definitions-in-headers.rst
new file mode 100644
index 0000000..1b6c2cd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-definitions-in-headers.rst
@@ -0,0 +1,100 @@
+.. title:: clang-tidy - misc-definitions-in-headers
+
+misc-definitions-in-headers
+===========================
+
+Finds non-extern non-inline function and variable definitions in header files,
+which can lead to potential ODR violations in case these headers are included
+from multiple translation units.
+
+.. code-block:: c++
+
+ // Foo.h
+ int a = 1; // Warning: variable definition.
+ extern int d; // OK: extern variable.
+
+ namespace N {
+ int e = 2; // Warning: variable definition.
+ }
+
+ // Warning: variable definition.
+ const char* str = "foo";
+
+ // OK: internal linkage variable definitions are ignored for now.
+ // Although these might also cause ODR violations, we can be less certain and
+ // should try to keep the false-positive rate down.
+ static int b = 1;
+ const int c = 1;
+ const char* const str2 = "foo";
+ constexpr int k = 1;
+
+ // Warning: function definition.
+ int g() {
+ return 1;
+ }
+
+ // OK: inline function definition is allowed to be defined multiple times.
+ inline int e() {
+ return 1;
+ }
+
+ class A {
+ public:
+ int f1() { return 1; } // OK: implicitly inline member function definition is allowed.
+ int f2();
+
+ static int d;
+ };
+
+ // Warning: not an inline member function definition.
+ int A::f2() { return 1; }
+
+ // OK: class static data member declaration is allowed.
+ int A::d = 1;
+
+ // OK: function template is allowed.
+ template<typename T>
+ T f3() {
+ T a = 1;
+ return a;
+ }
+
+ // Warning: full specialization of a function template is not allowed.
+ template <>
+ int f3() {
+ int a = 1;
+ return a;
+ }
+
+ template <typename T>
+ struct B {
+ void f1();
+ };
+
+ // OK: member function definition of a class template is allowed.
+ template <typename T>
+ void B<T>::f1() {}
+
+ class CE {
+ constexpr static int i = 5; // OK: inline variable definition.
+ };
+
+ inline int i = 5; // OK: inline variable definition.
+
+ constexpr int f10() { return 0; } // OK: constexpr function implies inline.
+
+Options
+-------
+
+.. option:: HeaderFileExtensions
+
+ A comma-separated list of filename extensions of header files (the filename
+ extensions should not include "." prefix). Default is "h,hh,hpp,hxx".
+ For header files without an extension, use an empty string (if there are no
+ other desired extensions) or leave an empty element in the list. e.g.,
+ "h,hh,hpp,hxx," (note the trailing comma).
+
+.. option:: UseHeaderFileExtension
+
+ When non-zero, the check will use the file extension to distinguish header
+ files. Default is `1`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-misplaced-const.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-misplaced-const.rst
new file mode 100644
index 0000000..ee1549f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-misplaced-const.rst
@@ -0,0 +1,22 @@
+.. title:: clang-tidy - misc-misplaced-const
+
+misc-misplaced-const
+====================
+
+This check diagnoses when a ``const`` qualifier is applied to a ``typedef`` to a
+pointer type rather than to the pointee, because such constructs are often
+misleading to developers because the ``const`` applies to the pointer rather
+than the pointee.
+
+For instance, in the following code, the resulting type is ``int *`` ``const``
+rather than ``const int *``:
+
+.. code-block:: c++
+
+ typedef int *int_ptr;
+ void f(const int_ptr ptr);
+
+The check does not diagnose when the underlying ``typedef`` type is a pointer to
+a ``const`` type or a function pointer type. This is because the ``const``
+qualifier is less likely to be mistaken because it would be redundant (or
+disallowed) on the underlying pointee type.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-new-delete-overloads.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-new-delete-overloads.rst
new file mode 100644
index 0000000..727436d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-new-delete-overloads.rst
@@ -0,0 +1,19 @@
+.. title:: clang-tidy - misc-new-delete-overloads
+
+misc-new-delete-overloads
+=========================
+
+`cert-dcl54-cpp` redirects here as an alias for this check.
+
+The check flags overloaded operator ``new()`` and operator ``delete()``
+functions that do not have a corresponding free store function defined within
+the same scope.
+For instance, the check will flag a class implementation of a non-placement
+operator ``new()`` when the class does not also define a non-placement operator
+``delete()`` function as well.
+
+The check does not flag implicitly-defined operators, deleted or private
+operators, or placement operators.
+
+This check corresponds to CERT C++ Coding Standard rule `DCL54-CPP. Overload allocation and deallocation functions as a pair in the same scope
+<https://www.securecoding.cert.org/confluence/display/cplusplus/DCL54-CPP.+Overload+allocation+and+deallocation+functions+as+a+pair+in+the+same+scope>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-non-copyable-objects.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-non-copyable-objects.rst
new file mode 100644
index 0000000..d1f7bba
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-non-copyable-objects.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - misc-non-copyable-objects
+
+misc-non-copyable-objects
+=========================
+
+`cert-fio38-c` redirects here as an alias for this check.
+
+The check flags dereferences and non-pointer declarations of objects that are
+not meant to be passed by value, such as C FILE objects or POSIX
+``pthread_mutex_t`` objects.
+
+This check corresponds to CERT C++ Coding Standard rule `FIO38-C. Do not copy a FILE object
+<https://www.securecoding.cert.org/confluence/display/c/FIO38-C.+Do+not+copy+a+FILE+object>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-redundant-expression.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-redundant-expression.rst
new file mode 100644
index 0000000..83c29bd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-redundant-expression.rst
@@ -0,0 +1,25 @@
+.. title:: clang-tidy - misc-redundant-expression
+
+misc-redundant-expression
+=========================
+
+Detect redundant expressions which are typically errors due to copy-paste.
+
+Depending on the operator expressions may be
+
+- redundant,
+
+- always ``true``,
+
+- always ``false``,
+
+- always a constant (zero or one).
+
+Examples:
+
+.. code-block:: c++
+
+ ((x+1) | (x+1)) // (x+1) is redundant
+ (p->x == p->x) // always true
+ (p->x < p->x) // always false
+ (speed - speed + 1 == 12) // speed - speed is always zero
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-static-assert.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-static-assert.rst
new file mode 100644
index 0000000..cf0cc2d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-static-assert.rst
@@ -0,0 +1,12 @@
+.. title:: clang-tidy - misc-static-assert
+
+misc-static-assert
+==================
+
+`cert-dcl03-c` redirects here as an alias for this check.
+
+Replaces ``assert()`` with ``static_assert()`` if the condition is evaluatable
+at compile time.
+
+The condition of ``static_assert()`` is evaluated at compile time which is
+safer and more efficient.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-throw-by-value-catch-by-reference.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-throw-by-value-catch-by-reference.rst
new file mode 100644
index 0000000..1a6d6b3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-throw-by-value-catch-by-reference.rst
@@ -0,0 +1,34 @@
+.. title:: clang-tidy - misc-throw-by-value-catch-by-reference
+
+misc-throw-by-value-catch-by-reference
+======================================
+
+"cert-err09-cpp" redirects here as an alias for this check.
+"cert-err61-cpp" redirects here as an alias for this check.
+
+Finds violations of the rule "Throw by value, catch by reference" presented for
+example in "C++ Coding Standards" by H. Sutter and A. Alexandrescu.
+
+Exceptions:
+ * Throwing string literals will not be flagged despite being a pointer. They
+ are not susceptible to slicing and the usage of string literals is idomatic.
+ * Catching character pointers (``char``, ``wchar_t``, unicode character types)
+ will not be flagged to allow catching sting literals.
+ * Moved named values will not be flagged as not throwing an anonymous
+ temporary. In this case we can be sure that the user knows that the object
+ can't be accessed outside catch blocks handling the error.
+ * Throwing function parameters will not be flagged as not throwing an
+ anonymous temporary. This allows helper functions for throwing.
+ * Re-throwing caught exception variables will not be flragged as not throwing
+ an anonymous temporary. Although this can usually be done by just writing
+ ``throw;`` it happens often enough in real code.
+
+Options
+-------
+
+.. option:: CheckThrowTemporaries
+
+ Triggers detection of violations of the rule `Throw anonymous temporaries
+ <https://www.securecoding.cert.org/confluence/display/cplusplus/ERR09-CPP.+Throw+anonymous+temporaries>`_.
+ Default is `1`.
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-unconventional-assign-operator.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-unconventional-assign-operator.rst
new file mode 100644
index 0000000..8b85332
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-unconventional-assign-operator.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - misc-unconventional-assign-operator
+
+misc-unconventional-assign-operator
+===================================
+
+
+Finds declarations of assign operators with the wrong return and/or argument
+types and definitions with good return type but wrong ``return`` statements.
+
+ * The return type must be ``Class&``.
+ * Works with move-assign and assign by value.
+ * Private and deleted operators are ignored.
+ * The operator must always return ``*this``.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-uniqueptr-reset-release.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-uniqueptr-reset-release.rst
new file mode 100644
index 0000000..858fbe7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-uniqueptr-reset-release.rst
@@ -0,0 +1,16 @@
+.. title:: clang-tidy - misc-uniqueptr-reset-release
+
+misc-uniqueptr-reset-release
+============================
+
+Find and replace ``unique_ptr::reset(release())`` with ``std::move()``.
+
+Example:
+
+.. code-block:: c++
+
+ std::unique_ptr<Foo> x, y;
+ x.reset(y.release()); -> x = std::move(y);
+
+If ``y`` is already rvalue, ``std::move()`` is not added. ``x`` and ``y`` can
+also be ``std::unique_ptr<Foo>*``.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-unused-alias-decls.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-unused-alias-decls.rst
new file mode 100644
index 0000000..d0e8c71
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-unused-alias-decls.rst
@@ -0,0 +1,7 @@
+.. title:: clang-tidy - misc-unused-alias-decls
+
+misc-unused-alias-decls
+=======================
+
+
+Finds unused namespace alias declarations.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-unused-parameters.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-unused-parameters.rst
new file mode 100644
index 0000000..3dfeb29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-unused-parameters.rst
@@ -0,0 +1,42 @@
+.. title:: clang-tidy - misc-unused-parameters
+
+misc-unused-parameters
+======================
+
+Finds unused function parameters. Unused parameters may signify a bug in the
+code (e.g. when a different parameter is used instead). The suggested fixes
+either comment parameter name out or remove the parameter completely, if all
+callers of the function are in the same translation unit and can be updated.
+
+The check is similar to the `-Wunused-parameter` compiler diagnostic and can be
+used to prepare a codebase to enabling of that diagnostic. By default the check
+is more permissive (see :option:`StrictMode`).
+
+.. code-block:: c++
+
+ void a(int i) { /*some code that doesn't use `i`*/ }
+
+ // becomes
+
+ void a(int /*i*/) { /*some code that doesn't use `i`*/ }
+
+.. code-block:: c++
+
+ static void staticFunctionA(int i);
+ static void staticFunctionA(int i) { /*some code that doesn't use `i`*/ }
+
+ // becomes
+
+ static void staticFunctionA()
+ static void staticFunctionA() { /*some code that doesn't use `i`*/ }
+
+Options
+-------
+
+.. option:: StrictMode
+
+ When zero (default value), the check will ignore trivially unused parameters,
+ i.e. when the corresponding function has an empty body (and in case of
+ constructors - no constructor initializers). When the function body is empty,
+ an unused parameter is unlikely to be unnoticed by a human reader, and
+ there's basically no place for a bug to hide.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-unused-using-decls.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-unused-using-decls.rst
new file mode 100644
index 0000000..9de1cb2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/misc-unused-using-decls.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - misc-unused-using-decls
+
+misc-unused-using-decls
+=======================
+
+Finds unused ``using`` declarations.
+
+Example:
+
+.. code-block:: c++
+
+ namespace n { class C; }
+ using n::C; // Never actually used.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-avoid-bind.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-avoid-bind.rst
new file mode 100644
index 0000000..7ea9bec
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-avoid-bind.rst
@@ -0,0 +1,37 @@
+.. title:: clang-tidy - modernize-avoid-bind
+
+modernize-avoid-bind
+====================
+
+The check finds uses of ``std::bind`` and replaces simple uses with lambdas.
+Lambdas will use value-capture where required.
+
+Right now it only handles free functions, not member functions.
+
+Given:
+
+.. code-block:: c++
+
+ int add(int x, int y) { return x + y; }
+
+Then:
+
+.. code-block:: c++
+
+ void f() {
+ int x = 2;
+ auto clj = std::bind(add, x, _1);
+ }
+
+is replaced by:
+
+.. code-block:: c++
+
+ void f() {
+ int x = 2;
+ auto clj = [=](auto && arg1) { return add(x, arg1); };
+ }
+
+``std::bind`` can be hard to read and can result in larger object files and
+binaries due to type information that will not be produced by equivalent
+lambdas.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-deprecated-headers.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-deprecated-headers.rst
new file mode 100644
index 0000000..4c4750a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-deprecated-headers.rst
@@ -0,0 +1,49 @@
+.. title:: clang-tidy - modernize-deprecated-headers
+
+modernize-deprecated-headers
+============================
+
+Some headers from C library were deprecated in C++ and are no longer welcome in
+C++ codebases. Some have no effect in C++. For more details refer to the C++ 14
+Standard [depr.c.headers] section.
+
+This check replaces C standard library headers with their C++ alternatives and
+removes redundant ones.
+
+Improtant note: the Standard doesn't guarantee that the C++ headers declare all
+the same functions in the global namespace. The check in its current form can
+break the code that uses library symbols from the global namespace.
+
+* `<assert.h>`
+* `<complex.h>`
+* `<ctype.h>`
+* `<errno.h>`
+* `<fenv.h>` // deprecated since C++11
+* `<float.h>`
+* `<inttypes.h>`
+* `<limits.h>`
+* `<locale.h>`
+* `<math.h>`
+* `<setjmp.h>`
+* `<signal.h>`
+* `<stdarg.h>`
+* `<stddef.h>`
+* `<stdint.h>`
+* `<stdio.h>`
+* `<stdlib.h>`
+* `<string.h>`
+* `<tgmath.h>` // deprecated since C++11
+* `<time.h>`
+* `<uchar.h>` // deprecated since C++11
+* `<wchar.h>`
+* `<wctype.h>`
+
+If the specified standard is older than C++11 the check will only replace
+headers deprecated before C++11, otherwise -- every header that appeared in
+the previous list.
+
+These headers don't have effect in C++:
+
+* `<iso646.h>`
+* `<stdalign.h>`
+* `<stdbool.h>`
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-loop-convert.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-loop-convert.rst
new file mode 100644
index 0000000..bad574f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-loop-convert.rst
@@ -0,0 +1,255 @@
+.. title:: clang-tidy - modernize-loop-convert
+
+modernize-loop-convert
+======================
+
+This check converts ``for(...; ...; ...)`` loops to use the new range-based
+loops in C++11.
+
+Three kinds of loops can be converted:
+
+- Loops over statically allocated arrays.
+- Loops over containers, using iterators.
+- Loops over array-like containers, using ``operator[]`` and ``at()``.
+
+MinConfidence option
+--------------------
+
+risky
+^^^^^
+
+In loops where the container expression is more complex than just a
+reference to a declared expression (a variable, function, enum, etc.),
+and some part of it appears elsewhere in the loop, we lower our confidence
+in the transformation due to the increased risk of changing semantics.
+Transformations for these loops are marked as `risky`, and thus will only
+be converted if the minimum required confidence level is set to `risky`.
+
+.. code-block:: c++
+
+ int arr[10][20];
+ int l = 5;
+
+ for (int j = 0; j < 20; ++j)
+ int k = arr[l][j] + l; // using l outside arr[l] is considered risky
+
+ for (int i = 0; i < obj.getVector().size(); ++i)
+ obj.foo(10); // using 'obj' is considered risky
+
+See
+:ref:`Range-based loops evaluate end() only once<IncorrectRiskyTransformation>`
+for an example of an incorrect transformation when the minimum required confidence
+level is set to `risky`.
+
+reasonable (Default)
+^^^^^^^^^^^^^^^^^^^^
+
+If a loop calls ``.end()`` or ``.size()`` after each iteration, the
+transformation for that loop is marked as `reasonable`, and thus will
+be converted if the required confidence level is set to `reasonable`
+(default) or lower.
+
+.. code-block:: c++
+
+ // using size() is considered reasonable
+ for (int i = 0; i < container.size(); ++i)
+ cout << container[i];
+
+safe
+^^^^
+
+Any other loops that do not match the above criteria to be marked as
+`risky` or `reasonable` are marked `safe`, and thus will be converted
+if the required confidence level is set to `safe` or lower.
+
+.. code-block:: c++
+
+ int arr[] = {1,2,3};
+
+ for (int i = 0; i < 3; ++i)
+ cout << arr[i];
+
+Example
+-------
+
+Original:
+
+.. code-block:: c++
+
+ const int N = 5;
+ int arr[] = {1,2,3,4,5};
+ vector<int> v;
+ v.push_back(1);
+ v.push_back(2);
+ v.push_back(3);
+
+ // safe conversion
+ for (int i = 0; i < N; ++i)
+ cout << arr[i];
+
+ // reasonable conversion
+ for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
+ cout << *it;
+
+ // reasonable conversion
+ for (int i = 0; i < v.size(); ++i)
+ cout << v[i];
+
+After applying the check with minimum confidence level set to `reasonable` (default):
+
+.. code-block:: c++
+
+ const int N = 5;
+ int arr[] = {1,2,3,4,5};
+ vector<int> v;
+ v.push_back(1);
+ v.push_back(2);
+ v.push_back(3);
+
+ // safe conversion
+ for (auto & elem : arr)
+ cout << elem;
+
+ // reasonable conversion
+ for (auto & elem : v)
+ cout << elem;
+
+ // reasonable conversion
+ for (auto & elem : v)
+ cout << elem;
+
+Limitations
+-----------
+
+There are certain situations where the tool may erroneously perform
+transformations that remove information and change semantics. Users of the tool
+should be aware of the behaviour and limitations of the check outlined by
+the cases below.
+
+Comments inside loop headers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Comments inside the original loop header are ignored and deleted when
+transformed.
+
+.. code-block:: c++
+
+ for (int i = 0; i < N; /* This will be deleted */ ++i) { }
+
+Range-based loops evaluate end() only once
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The C++11 range-based for loop calls ``.end()`` only once during the
+initialization of the loop. If in the original loop ``.end()`` is called after
+each iteration the semantics of the transformed loop may differ.
+
+.. code-block:: c++
+
+ // The following is semantically equivalent to the C++11 range-based for loop,
+ // therefore the semantics of the header will not change.
+ for (iterator it = container.begin(), e = container.end(); it != e; ++it) { }
+
+ // Instead of calling .end() after each iteration, this loop will be
+ // transformed to call .end() only once during the initialization of the loop,
+ // which may affect semantics.
+ for (iterator it = container.begin(); it != container.end(); ++it) { }
+
+.. _IncorrectRiskyTransformation:
+
+As explained above, calling member functions of the container in the body
+of the loop is considered `risky`. If the called member function modifies the
+container the semantics of the converted loop will differ due to ``.end()``
+being called only once.
+
+.. code-block:: c++
+
+ bool flag = false;
+ for (vector<T>::iterator it = vec.begin(); it != vec.end(); ++it) {
+ // Add a copy of the first element to the end of the vector.
+ if (!flag) {
+ // This line makes this transformation 'risky'.
+ vec.push_back(*it);
+ flag = true;
+ }
+ cout << *it;
+ }
+
+The original code above prints out the contents of the container including the
+newly added element while the converted loop, shown below, will only print the
+original contents and not the newly added element.
+
+.. code-block:: c++
+
+ bool flag = false;
+ for (auto & elem : vec) {
+ // Add a copy of the first element to the end of the vector.
+ if (!flag) {
+ // This line makes this transformation 'risky'
+ vec.push_back(elem);
+ flag = true;
+ }
+ cout << elem;
+ }
+
+Semantics will also be affected if ``.end()`` has side effects. For example, in
+the case where calls to ``.end()`` are logged the semantics will change in the
+transformed loop if ``.end()`` was originally called after each iteration.
+
+.. code-block:: c++
+
+ iterator end() {
+ num_of_end_calls++;
+ return container.end();
+ }
+
+Overloaded operator->() with side effects
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Similarly, if ``operator->()`` was overloaded to have side effects, such as
+logging, the semantics will change. If the iterator's ``operator->()`` was used
+in the original loop it will be replaced with ``<container element>.<member>``
+instead due to the implicit dereference as part of the range-based for loop.
+Therefore any side effect of the overloaded ``operator->()`` will no longer be
+performed.
+
+.. code-block:: c++
+
+ for (iterator it = c.begin(); it != c.end(); ++it) {
+ it->func(); // Using operator->()
+ }
+ // Will be transformed to:
+ for (auto & elem : c) {
+ elem.func(); // No longer using operator->()
+ }
+
+Pointers and references to containers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+While most of the check's risk analysis is dedicated to determining whether
+the iterator or container was modified within the loop, it is possible to
+circumvent the analysis by accessing and modifying the container through a
+pointer or reference.
+
+If the container were directly used instead of using the pointer or reference
+the following transformation would have only been applied at the `risky`
+level since calling a member function of the container is considered `risky`.
+The check cannot identify expressions associated with the container that are
+different than the one used in the loop header, therefore the transformation
+below ends up being performed at the `safe` level.
+
+.. code-block:: c++
+
+ vector<int> vec;
+
+ vector<int> *ptr = &vec;
+ vector<int> &ref = vec;
+
+ for (vector<int>::iterator it = vec.begin(), e = vec.end(); it != e; ++it) {
+ if (!flag) {
+ // Accessing and modifying the container is considered risky, but the risk
+ // level is not raised here.
+ ptr->push_back(*it);
+ ref.push_back(*it);
+ flag = true;
+ }
+ }
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-make-shared.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-make-shared.rst
new file mode 100644
index 0000000..e73b320
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-make-shared.rst
@@ -0,0 +1,50 @@
+.. title:: clang-tidy - modernize-make-shared
+
+modernize-make-shared
+=====================
+
+This check finds the creation of ``std::shared_ptr`` objects by explicitly
+calling the constructor and a ``new`` expression, and replaces it with a call
+to ``std::make_shared``.
+
+.. code-block:: c++
+
+ auto my_ptr = std::shared_ptr<MyPair>(new MyPair(1, 2));
+
+ // becomes
+
+ auto my_ptr = std::make_shared<MyPair>(1, 2);
+
+This check also finds calls to ``std::shared_ptr::reset()`` with a ``new``
+expression, and replaces it with a call to ``std::make_shared``.
+
+.. code-block:: c++
+
+ my_ptr.reset(new MyPair(1, 2));
+
+ // becomes
+
+ my_ptr = std::make_shared<MyPair>(1, 2);
+
+Options
+-------
+
+.. option:: MakeSmartPtrFunction
+
+ A string specifying the name of make-shared-ptr function. Default is
+ `std::make_shared`.
+
+.. option:: MakeSmartPtrFunctionHeader
+
+ A string specifying the corresponding header of make-shared-ptr function.
+ Default is `memory`.
+
+.. option:: IncludeStyle
+
+ A string specifying which include-style is used, `llvm` or `google`. Default
+ is `llvm`.
+
+.. option:: IgnoreMacros
+
+ If set to non-zero, the check will not give warnings inside macros. Default
+ is `1`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-make-unique.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-make-unique.rst
new file mode 100644
index 0000000..1961f05
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-make-unique.rst
@@ -0,0 +1,50 @@
+.. title:: clang-tidy - modernize-make-unique
+
+modernize-make-unique
+=====================
+
+This check finds the creation of ``std::unique_ptr`` objects by explicitly
+calling the constructor and a ``new`` expression, and replaces it with a call
+to ``std::make_unique``, introduced in C++14.
+
+.. code-block:: c++
+
+ auto my_ptr = std::unique_ptr<MyPair>(new MyPair(1, 2));
+
+ // becomes
+
+ auto my_ptr = std::make_unique<MyPair>(1, 2);
+
+This check also finds calls to ``std::unique_ptr::reset()`` with a ``new``
+expression, and replaces it with a call to ``std::make_unique``.
+
+.. code-block:: c++
+
+ my_ptr.reset(new MyPair(1, 2));
+
+ // becomes
+
+ my_ptr = std::make_unique<MyPair>(1, 2);
+
+Options
+-------
+
+.. option:: MakeSmartPtrFunction
+
+ A string specifying the name of make-unique-ptr function. Default is
+ `std::make_unique`.
+
+.. option:: MakeSmartPtrFunctionHeader
+
+ A string specifying the corresponding header of make-unique-ptr function.
+ Default is `memory`.
+
+.. option:: IncludeStyle
+
+ A string specifying which include-style is used, `llvm` or `google`. Default
+ is `llvm`.
+
+.. option:: IgnoreMacros
+
+ If set to non-zero, the check will not give warnings inside macros. Default
+ is `1`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-pass-by-value.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-pass-by-value.rst
new file mode 100644
index 0000000..1dfbf95
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-pass-by-value.rst
@@ -0,0 +1,166 @@
+.. title:: clang-tidy - modernize-pass-by-value
+
+modernize-pass-by-value
+=======================
+
+With move semantics added to the language and the standard library updated with
+move constructors added for many types it is now interesting to take an
+argument directly by value, instead of by const-reference, and then copy. This
+check allows the compiler to take care of choosing the best way to construct
+the copy.
+
+The transformation is usually beneficial when the calling code passes an
+*rvalue* and assumes the move construction is a cheap operation. This short
+example illustrates how the construction of the value happens:
+
+ .. code-block:: c++
+
+ void foo(std::string s);
+ std::string get_str();
+
+ void f(const std::string &str) {
+ foo(str); // lvalue -> copy construction
+ foo(get_str()); // prvalue -> move construction
+ }
+
+.. note::
+
+ Currently, only constructors are transformed to make use of pass-by-value.
+ Contributions that handle other situations are welcome!
+
+
+Pass-by-value in constructors
+-----------------------------
+
+Replaces the uses of const-references constructor parameters that are copied
+into class fields. The parameter is then moved with `std::move()`.
+
+Since ``std::move()`` is a library function declared in `<utility>` it may be
+necessary to add this include. The check will add the include directive when
+necessary.
+
+ .. code-block:: c++
+
+ #include <string>
+
+ class Foo {
+ public:
+ - Foo(const std::string &Copied, const std::string &ReadOnly)
+ - : Copied(Copied), ReadOnly(ReadOnly)
+ + Foo(std::string Copied, const std::string &ReadOnly)
+ + : Copied(std::move(Copied)), ReadOnly(ReadOnly)
+ {}
+
+ private:
+ std::string Copied;
+ const std::string &ReadOnly;
+ };
+
+ std::string get_cwd();
+
+ void f(const std::string &Path) {
+ // The parameter corresponding to 'get_cwd()' is move-constructed. By
+ // using pass-by-value in the Foo constructor we managed to avoid a
+ // copy-construction.
+ Foo foo(get_cwd(), Path);
+ }
+
+
+If the parameter is used more than once no transformation is performed since
+moved objects have an undefined state. It means the following code will be left
+untouched:
+
+.. code-block:: c++
+
+ #include <string>
+
+ void pass(const std::string &S);
+
+ struct Foo {
+ Foo(const std::string &S) : Str(S) {
+ pass(S);
+ }
+
+ std::string Str;
+ };
+
+
+Known limitations
+^^^^^^^^^^^^^^^^^
+
+A situation where the generated code can be wrong is when the object referenced
+is modified before the assignment in the init-list through a "hidden" reference.
+
+Example:
+
+.. code-block:: c++
+
+ std::string s("foo");
+
+ struct Base {
+ Base() {
+ s = "bar";
+ }
+ };
+
+ struct Derived : Base {
+ - Derived(const std::string &S) : Field(S)
+ + Derived(std::string S) : Field(std::move(S))
+ { }
+
+ std::string Field;
+ };
+
+ void f() {
+ - Derived d(s); // d.Field holds "bar"
+ + Derived d(s); // d.Field holds "foo"
+ }
+
+
+Note about delayed template parsing
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When delayed template parsing is enabled, constructors part of templated
+contexts; templated constructors, constructors in class templates, constructors
+of inner classes of template classes, etc., are not transformed. Delayed
+template parsing is enabled by default on Windows as a Microsoft extension:
+`Clang Compiler User’s Manual - Microsoft extensions`_.
+
+Delayed template parsing can be enabled using the `-fdelayed-template-parsing`
+flag and disabled using `-fno-delayed-template-parsing`.
+
+Example:
+
+.. code-block:: c++
+
+ template <typename T> class C {
+ std::string S;
+
+ public:
+ = // using -fdelayed-template-parsing (default on Windows)
+ = C(const std::string &S) : S(S) {}
+
+ + // using -fno-delayed-template-parsing (default on non-Windows systems)
+ + C(std::string S) : S(std::move(S)) {}
+ };
+
+.. _Clang Compiler User’s Manual - Microsoft extensions: http://clang.llvm.org/docs/UsersManual.html#microsoft-extensions
+
+.. seealso::
+
+ For more information about the pass-by-value idiom, read: `Want Speed? Pass by Value`_.
+
+ .. _Want Speed? Pass by Value: https://web.archive.org/web/20140205194657/http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
+
+Options
+-------
+
+.. option:: IncludeStyle
+
+ A string specifying which include-style is used, `llvm` or `google`. Default
+ is `llvm`.
+
+.. option:: ValuesOnly
+
+ When non-zero, the check only warns about copied parameters that are already
+ passed by value. Default is `0`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-raw-string-literal.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-raw-string-literal.rst
new file mode 100644
index 0000000..3525d57
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-raw-string-literal.rst
@@ -0,0 +1,46 @@
+.. title:: clang-tidy - modernize-raw-string-literal
+
+modernize-raw-string-literal
+============================
+
+This check selectively replaces string literals containing escaped characters
+with raw string literals.
+
+Example:
+
+.. code-blocK:: c++
+
+ const char *const Quotes{"embedded \"quotes\""};
+ const char *const Paragraph{"Line one.\nLine two.\nLine three.\n"};
+ const char *const SingleLine{"Single line.\n"};
+ const char *const TrailingSpace{"Look here -> \n"};
+ const char *const Tab{"One\tTwo\n"};
+ const char *const Bell{"Hello!\a And welcome!"};
+ const char *const Path{"C:\\Program Files\\Vendor\\Application.exe"};
+ const char *const RegEx{"\\w\\([a-z]\\)"};
+
+becomes
+
+.. code-block:: c++
+
+ const char *const Quotes{R"(embedded "quotes")"};
+ const char *const Paragraph{"Line one.\nLine two.\nLine three.\n"};
+ const char *const SingleLine{"Single line.\n"};
+ const char *const TrailingSpace{"Look here -> \n"};
+ const char *const Tab{"One\tTwo\n"};
+ const char *const Bell{"Hello!\a And welcome!"};
+ const char *const Path{R"(C:\Program Files\Vendor\Application.exe)"};
+ const char *const RegEx{R"(\w\([a-z]\))"};
+
+The presence of any of the following escapes can cause the string to be
+converted to a raw string literal: ``\\``, ``\'``, ``\"``, ``\?``,
+and octal or hexadecimal escapes for printable ASCII characters.
+
+A string literal containing only escaped newlines is a common way of
+writing lines of text output. Introducing physical newlines with raw
+string literals in this case is likely to impede readability. These
+string literals are left unchanged.
+
+An escaped horizontal tab, form feed, or vertical tab prevents the string
+literal from being converted. The presence of a horizontal tab, form feed or
+vertical tab in source code is not visually obvious.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-redundant-void-arg.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-redundant-void-arg.rst
new file mode 100644
index 0000000..d1a03e3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-redundant-void-arg.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - modernize-redundant-void-arg
+
+modernize-redundant-void-arg
+============================
+
+Find and remove redundant ``void`` argument lists.
+
+Examples:
+ =================================== ===========================
+ Initial code Code with applied fixes
+ =================================== ===========================
+ ``int f(void);`` ``int f();``
+ ``int (*f(void))(void);`` ``int (*f())();``
+ ``typedef int (*f_t(void))(void);`` ``typedef int (*f_t())();``
+ ``void (C::*p)(void);`` ``void (C::*p)();``
+ ``C::C(void) {}`` ``C::C() {}``
+ ``C::~C(void) {}`` ``C::~C() {}``
+ =================================== ===========================
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-replace-auto-ptr.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-replace-auto-ptr.rst
new file mode 100644
index 0000000..1cbd68c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-replace-auto-ptr.rst
@@ -0,0 +1,79 @@
+.. title:: clang-tidy - modernize-replace-auto-ptr
+
+modernize-replace-auto-ptr
+==========================
+
+This check replaces the uses of the deprecated class ``std::auto_ptr`` by
+``std::unique_ptr`` (introduced in C++11). The transfer of ownership, done
+by the copy-constructor and the assignment operator, is changed to match
+``std::unique_ptr`` usage by using explicit calls to ``std::move()``.
+
+Migration example:
+
+.. code-block:: c++
+
+ -void take_ownership_fn(std::auto_ptr<int> int_ptr);
+ +void take_ownership_fn(std::unique_ptr<int> int_ptr);
+
+ void f(int x) {
+ - std::auto_ptr<int> a(new int(x));
+ - std::auto_ptr<int> b;
+ + std::unique_ptr<int> a(new int(x));
+ + std::unique_ptr<int> b;
+
+ - b = a;
+ - take_ownership_fn(b);
+ + b = std::move(a);
+ + take_ownership_fn(std::move(b));
+ }
+
+Since ``std::move()`` is a library function declared in ``<utility>`` it may be
+necessary to add this include. The check will add the include directive when
+necessary.
+
+Known Limitations
+-----------------
+* If headers modification is not activated or if a header is not allowed to be
+ changed this check will produce broken code (compilation error), where the
+ headers' code will stay unchanged while the code using them will be changed.
+
+* Client code that declares a reference to an ``std::auto_ptr`` coming from
+ code that can't be migrated (such as a header coming from a 3\ :sup:`rd`
+ party library) will produce a compilation error after migration. This is
+ because the type of the reference will be changed to ``std::unique_ptr`` but
+ the type returned by the library won't change, binding a reference to
+ ``std::unique_ptr`` from an ``std::auto_ptr``. This pattern doesn't make much
+ sense and usually ``std::auto_ptr`` are stored by value (otherwise what is
+ the point in using them instead of a reference or a pointer?).
+
+ .. code-block:: c++
+
+ // <3rd-party header...>
+ std::auto_ptr<int> get_value();
+ const std::auto_ptr<int> & get_ref();
+
+ // <calling code (with migration)...>
+ -std::auto_ptr<int> a(get_value());
+ +std::unique_ptr<int> a(get_value()); // ok, unique_ptr constructed from auto_ptr
+
+ -const std::auto_ptr<int> & p = get_ptr();
+ +const std::unique_ptr<int> & p = get_ptr(); // won't compile
+
+* Non-instantiated templates aren't modified.
+
+ .. code-block:: c++
+
+ template <typename X>
+ void f() {
+ std::auto_ptr<X> p;
+ }
+
+ // only 'f<int>()' (or similar) will trigger the replacement.
+
+Options
+-------
+
+.. option:: IncludeStyle
+
+ A string specifying which include-style is used, `llvm` or `google`. Default
+ is `llvm`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-replace-random-shuffle.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-replace-random-shuffle.rst
new file mode 100644
index 0000000..50674d4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-replace-random-shuffle.rst
@@ -0,0 +1,41 @@
+.. title:: clang-tidy - modernize-replace-random-shuffle
+
+modernize-replace-random-shuffle
+================================
+
+This check will find occurrences of ``std::random_shuffle`` and replace it with ``std::shuffle``. In C++17 ``std::random_shuffle`` will no longer be available and thus we need to replace it.
+
+Below are two examples of what kind of occurrences will be found and two examples of what it will be replaced with.
+
+.. code-block:: c++
+
+ std::vector<int> v;
+
+ // First example
+ std::random_shuffle(vec.begin(), vec.end());
+
+ // Second example
+ std::random_shuffle(vec.begin(), vec.end(), randomFunc);
+
+Both of these examples will be replaced with:
+
+.. code-block:: c++
+
+ std::shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
+
+The second example will also receive a warning that ``randomFunc`` is no longer supported in the same way as before so if the user wants the same functionality, the user will need to change the implementation of the ``randomFunc``.
+
+One thing to be aware of here is that ``std::random_device`` is quite expensive to initialize. So if you are using the code in a performance critical place, you probably want to initialize it elsewhere.
+Another thing is that the seeding quality of the suggested fix is quite poor: ``std::mt19937`` has an internal state of 624 32-bit integers, but is only seeded with a single integer. So if you require
+higher quality randomness, you should consider seeding better, for example:
+
+.. code-block:: c++
+
+ std::shuffle(v.begin(), v.end(), []() {
+ std::mt19937::result_type seeds[std::mt19937::state_size];
+ std::random_device device;
+ std::uniform_int_distribution<typename std::mt19937::result_type> dist;
+ std::generate(std::begin(seeds), std::end(seeds), [&] { return dist(device); });
+ std::seed_seq seq(std::begin(seeds), std::end(seeds));
+ return std::mt19937(seq);
+ }());
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-return-braced-init-list.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-return-braced-init-list.rst
new file mode 100644
index 0000000..2631d90
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-return-braced-init-list.rst
@@ -0,0 +1,22 @@
+.. title:: clang-tidy - modernize-return-braced-init-list
+
+modernize-return-braced-init-list
+=================================
+
+Replaces explicit calls to the constructor in a return with a braced
+initializer list. This way the return type is not needlessly duplicated in the
+function definition and the return statement.
+
+.. code:: c++
+
+ Foo bar() {
+ Baz baz;
+ return Foo(baz);
+ }
+
+ // transforms to:
+
+ Foo bar() {
+ Baz baz;
+ return {baz};
+ }
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-shrink-to-fit.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-shrink-to-fit.rst
new file mode 100644
index 0000000..4d7ffaf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-shrink-to-fit.rst
@@ -0,0 +1,12 @@
+.. title:: clang-tidy - modernize-shrink-to-fit
+
+modernize-shrink-to-fit
+=======================
+
+
+Replace copy and swap tricks on shrinkable containers with the
+``shrink_to_fit()`` method call.
+
+The ``shrink_to_fit()`` method is more readable and more effective than
+the copy and swap trick to reduce the capacity of a shrinkable container.
+Note that, the ``shrink_to_fit()`` method is only available in C++11 and up.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-unary-static-assert.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-unary-static-assert.rst
new file mode 100644
index 0000000..31ece10
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-unary-static-assert.rst
@@ -0,0 +1,25 @@
+.. title:: clang-tidy - modernize-unary-static-assert
+
+modernize-unary-static-assert
+=============================
+
+The check diagnoses any ``static_assert`` declaration with an empty string literal
+and provides a fix-it to replace the declaration with a single-argument ``static_assert`` declaration.
+
+The check is only applicable for C++17 and later code.
+
+The following code:
+
+.. code-block:: c++
+
+ void f_textless(int a) {
+ static_assert(sizeof(a) <= 10, "");
+ }
+
+is replaced by:
+
+.. code-block:: c++
+
+ void f_textless(int a) {
+ static_assert(sizeof(a) <= 10);
+ }
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-auto.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-auto.rst
new file mode 100644
index 0000000..a73e86e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-auto.rst
@@ -0,0 +1,233 @@
+.. title:: clang-tidy - modernize-use-auto
+
+modernize-use-auto
+==================
+
+This check is responsible for using the ``auto`` type specifier for variable
+declarations to *improve code readability and maintainability*. For example:
+
+.. code-block:: c++
+
+ std::vector<int>::iterator I = my_container.begin();
+
+ // transforms to:
+
+ auto I = my_container.begin();
+
+The ``auto`` type specifier will only be introduced in situations where the
+variable type matches the type of the initializer expression. In other words
+``auto`` should deduce the same type that was originally spelled in the source.
+However, not every situation should be transformed:
+
+.. code-block:: c++
+
+ int val = 42;
+ InfoStruct &I = SomeObject.getInfo();
+
+ // Should not become:
+
+ auto val = 42;
+ auto &I = SomeObject.getInfo();
+
+In this example using ``auto`` for builtins doesn't improve readability. In
+other situations it makes the code less self-documenting impairing readability
+and maintainability. As a result, ``auto`` is used only introduced in specific
+situations described below.
+
+Iterators
+---------
+
+Iterator type specifiers tend to be long and used frequently, especially in
+loop constructs. Since the functions generating iterators have a common format,
+the type specifier can be replaced without obscuring the meaning of code while
+improving readability and maintainability.
+
+.. code-block:: c++
+
+ for (std::vector<int>::iterator I = my_container.begin(),
+ E = my_container.end();
+ I != E; ++I) {
+ }
+
+ // becomes
+
+ for (auto I = my_container.begin(), E = my_container.end(); I != E; ++I) {
+ }
+
+The check will only replace iterator type-specifiers when all of the following
+conditions are satisfied:
+
+* The iterator is for one of the standard container in ``std`` namespace:
+
+ * ``array``
+ * ``deque``
+ * ``forward_list``
+ * ``list``
+ * ``vector``
+ * ``map``
+ * ``multimap``
+ * ``set``
+ * ``multiset``
+ * ``unordered_map``
+ * ``unordered_multimap``
+ * ``unordered_set``
+ * ``unordered_multiset``
+ * ``queue``
+ * ``priority_queue``
+ * ``stack``
+
+* The iterator is one of the possible iterator types for standard containers:
+
+ * ``iterator``
+ * ``reverse_iterator``
+ * ``const_iterator``
+ * ``const_reverse_iterator``
+
+* In addition to using iterator types directly, typedefs or other ways of
+ referring to those types are also allowed. However, implementation-specific
+ types for which a type like ``std::vector<int>::iterator`` is itself a
+ typedef will not be transformed. Consider the following examples:
+
+.. code-block:: c++
+
+ // The following direct uses of iterator types will be transformed.
+ std::vector<int>::iterator I = MyVec.begin();
+ {
+ using namespace std;
+ list<int>::iterator I = MyList.begin();
+ }
+
+ // The type specifier for J would transform to auto since it's a typedef
+ // to a standard iterator type.
+ typedef std::map<int, std::string>::const_iterator map_iterator;
+ map_iterator J = MyMap.begin();
+
+ // The following implementation-specific iterator type for which
+ // std::vector<int>::iterator could be a typedef would not be transformed.
+ __gnu_cxx::__normal_iterator<int*, std::vector> K = MyVec.begin();
+
+* The initializer for the variable being declared is not a braced initializer
+ list. Otherwise, use of ``auto`` would cause the type of the variable to be
+ deduced as ``std::initializer_list``.
+
+New expressions
+---------------
+
+Frequently, when a pointer is declared and initialized with ``new``, the
+pointee type is written twice: in the declaration type and in the
+``new`` expression. In this cases, the declaration type can be replaced with
+``auto`` improving readability and maintainability.
+
+.. code-block:: c++
+
+ TypeName *my_pointer = new TypeName(my_param);
+
+ // becomes
+
+ auto *my_pointer = new TypeName(my_param);
+
+The check will also replace the declaration type in multiple declarations, if
+the following conditions are satisfied:
+
+* All declared variables have the same type (i.e. all of them are pointers to
+ the same type).
+* All declared variables are initialized with a ``new`` expression.
+* The types of all the new expressions are the same than the pointee of the
+ declaration type.
+
+.. code-block:: c++
+
+ TypeName *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;
+
+ // becomes
+
+ auto *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;
+
+Cast expressions
+----------------
+
+Frequently, when a variable is declared and initialized with a cast, the
+variable type is written twice: in the declaration type and in the
+cast expression. In this cases, the declaration type can be replaced with
+``auto`` improving readability and maintainability.
+
+.. code-block:: c++
+
+ TypeName *my_pointer = static_cast<TypeName>(my_param);
+
+ // becomes
+
+ auto *my_pointer = static_cast<TypeName>(my_param);
+
+The check handles ``static_cast``, ``dynamic_cast``, ``const_cast``,
+``reinterpret_cast``, functional casts, C-style casts and function templates
+that behave as casts, such as ``llvm::dyn_cast``, ``boost::lexical_cast`` and
+``gsl::narrow_cast``. Calls to function templates are considered to behave as
+casts if the first template argument is explicit and is a type, and the function
+returns that type, or a pointer or reference to it.
+
+Known Limitations
+-----------------
+
+* If the initializer is an explicit conversion constructor, the check will not
+ replace the type specifier even though it would be safe to do so.
+
+* User-defined iterators are not handled at this time.
+
+Options
+-------
+
+.. option:: MinTypeNameLength
+
+ If the option is set to non-zero (default `5`), the check will ignore type
+ names having a length less than the option value. The option affects
+ expressions only, not iterators.
+ Spaces between multi-lexeme type names (``long int``) are considered as one.
+ If ``RemoveStars`` option (see below) is set to non-zero, then ``*s`` in
+ the type are also counted as a part of the type name.
+
+.. code-block:: c++
+
+ // MinTypeNameLength = 0, RemoveStars=0
+
+ int a = static_cast<int>(foo()); // ---> auto a = ...
+ // length(bool *) = 4
+ bool *b = new bool; // ---> auto *b = ...
+ unsigned c = static_cast<unsigned>(foo()); // ---> auto c = ...
+
+ // MinTypeNameLength = 5, RemoveStars=0
+
+ int a = static_cast<int>(foo()); // ---> int a = ...
+ bool b = static_cast<bool>(foo()); // ---> bool b = ...
+ bool *pb = static_cast<bool*>(foo()); // ---> bool *pb = ...
+ unsigned c = static_cast<unsigned>(foo()); // ---> auto c = ...
+ // length(long <on-or-more-spaces> int) = 8
+ long int d = static_cast<long int>(foo()); // ---> auto d = ...
+
+ // MinTypeNameLength = 5, RemoveStars=1
+
+ int a = static_cast<int>(foo()); // ---> int a = ...
+ // length(int * * ) = 5
+ int **pa = static_cast<int**>(foo()); // ---> auto pa = ...
+ bool b = static_cast<bool>(foo()); // ---> bool b = ...
+ bool *pb = static_cast<bool*>(foo()); // ---> auto pb = ...
+ unsigned c = static_cast<unsigned>(foo()); // ---> auto c = ...
+ long int d = static_cast<long int>(foo()); // ---> auto d = ...
+
+.. option:: RemoveStars
+
+ If the option is set to non-zero (default is `0`), the check will remove
+ stars from the non-typedef pointer types when replacing type names with
+ ``auto``. Otherwise, the check will leave stars. For example:
+
+.. code-block:: c++
+
+ TypeName *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;
+
+ // RemoveStars = 0
+
+ auto *my_first_pointer = new TypeName, *my_second_pointer = new TypeName;
+
+ // RemoveStars = 1
+
+ auto my_first_pointer = new TypeName, my_second_pointer = new TypeName;
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-bool-literals.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-bool-literals.rst
new file mode 100644
index 0000000..792d3a4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-bool-literals.rst
@@ -0,0 +1,28 @@
+.. title:: clang-tidy - modernize-use-bool-literals
+
+modernize-use-bool-literals
+===========================
+
+Finds integer literals which are cast to ``bool``.
+
+.. code-block:: c++
+
+ bool p = 1;
+ bool f = static_cast<bool>(1);
+ std::ios_base::sync_with_stdio(0);
+ bool x = p ? 1 : 0;
+
+ // transforms to
+
+ bool p = true;
+ bool f = true;
+ std::ios_base::sync_with_stdio(false);
+ bool x = p ? true : false;
+
+Options
+-------
+
+.. option:: IgnoreMacros
+
+ If set to non-zero, the check will not give warnings inside macros. Default
+ is `1`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-default-member-init.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-default-member-init.rst
new file mode 100644
index 0000000..6a199ec
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-default-member-init.rst
@@ -0,0 +1,54 @@
+.. title:: clang-tidy - modernize-use-default-member-init
+
+modernize-use-default-member-init
+=================================
+
+This check converts a default constructor's member initializers into the new
+default member initializers in C++11. Other member initializers that match the
+default member initializer are removed. This can reduce repeated code or allow
+use of '= default'.
+
+.. code-block:: c++
+
+ struct A {
+ A() : i(5), j(10.0) {}
+ A(int i) : i(i), j(10.0) {}
+ int i;
+ double j;
+ };
+
+ // becomes
+
+ struct A {
+ A() {}
+ A(int i) : i(i) {}
+ int i{5};
+ double j{10.0};
+ };
+
+.. note::
+ Only converts member initializers for built-in types, enums, and pointers.
+ The `readability-redundant-member-init` check will remove redundant member
+ initializers for classes.
+
+Options
+-------
+
+.. option:: UseAssignment
+
+ If this option is set to non-zero (default is `0`), the check will initialise
+ members with an assignment. For example:
+
+.. code-block:: c++
+
+ struct A {
+ A() {}
+ A(int i) : i(i) {}
+ int i = 5;
+ double j = 10.0;
+ };
+
+.. option:: IgnoreMacros
+
+ If this option is set to non-zero (default is `1`), the check will not warn
+ about members declared inside macros.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-default.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-default.rst
new file mode 100644
index 0000000..ce58706
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-default.rst
@@ -0,0 +1,11 @@
+:orphan:
+
+.. title:: clang-tidy - modernize-use-default
+.. meta::
+ :http-equiv=refresh: 5;URL=modernize-use-equals-default.html
+
+modernize-use-default
+=====================
+
+This check has been renamed to
+`modernize-use-equals-default <modernize-use-equals-default.html>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-emplace.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-emplace.rst
new file mode 100644
index 0000000..533125e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-emplace.rst
@@ -0,0 +1,147 @@
+.. title:: clang-tidy - modernize-use-emplace
+
+modernize-use-emplace
+=====================
+
+The check flags insertions to an STL-style container done by calling the
+``push_back`` method with an explicitly-constructed temporary of the container
+element type. In this case, the corresponding ``emplace_back`` method
+results in less verbose and potentially more efficient code.
+Right now the check doesn't support ``push_front`` and ``insert``.
+It also doesn't support ``insert`` functions for associative containers
+because replacing ``insert`` with ``emplace`` may result in
+`speed regression <http://htmlpreview.github.io/?https://github.com/HowardHinnant/papers/blob/master/insert_vs_emplace.html>`_, but it might get support with some addition flag in the future.
+
+By default only ``std::vector``, ``std::deque``, ``std::list`` are considered.
+This list can be modified using the :option:`ContainersWithPushBack` option.
+
+Before:
+
+.. code-block:: c++
+
+ std::vector<MyClass> v;
+ v.push_back(MyClass(21, 37));
+
+ std::vector<std::pair<int, int>> w;
+
+ w.push_back(std::pair<int, int>(21, 37));
+ w.push_back(std::make_pair(21L, 37L));
+
+After:
+
+.. code-block:: c++
+
+ std::vector<MyClass> v;
+ v.emplace_back(21, 37);
+
+ std::vector<std::pair<int, int>> w;
+ w.emplace_back(21, 37);
+ w.emplace_back(21L, 37L);
+
+By default, the check is able to remove unnecessary ``std::make_pair`` and
+``std::make_tuple`` calls from ``push_back`` calls on containers of
+``std::pair`` and ``std::tuple``. Custom tuple-like types can be modified by
+the :option:`TupleTypes` option; custom make functions can be modified by the
+:option:`TupleMakeFunctions` option.
+
+The other situation is when we pass arguments that will be converted to a type
+inside a container.
+
+Before:
+
+.. code-block:: c++
+
+ std::vector<boost::optional<std::string> > v;
+ v.push_back("abc");
+
+After:
+
+.. code-block:: c++
+
+ std::vector<boost::optional<std::string> > v;
+ v.emplace_back("abc");
+
+
+In some cases the transformation would be valid, but the code wouldn't be
+exception safe. In this case the calls of ``push_back`` won't be replaced.
+
+.. code-block:: c++
+
+ std::vector<std::unique_ptr<int>> v;
+ v.push_back(std::unique_ptr<int>(new int(0)));
+ auto *ptr = new int(1);
+ v.push_back(std::unique_ptr<int>(ptr));
+
+This is because replacing it with ``emplace_back`` could cause a leak of this
+pointer if ``emplace_back`` would throw exception before emplacement (e.g. not
+enough memory to add a new element).
+
+For more info read item 42 - "Consider emplacement instead of insertion." of
+Scott Meyers "Effective Modern C++".
+
+The default smart pointers that are considered are ``std::unique_ptr``,
+``std::shared_ptr``, ``std::auto_ptr``. To specify other smart pointers or
+other classes use the :option:`SmartPointers` option.
+
+
+Check also doesn't fire if any argument of the constructor call would be:
+
+ - a bit-field (bit-fields can't bind to rvalue/universal reference)
+
+ - a ``new`` expression (to avoid leak)
+
+ - if the argument would be converted via derived-to-base cast.
+
+This check requires C++11 or higher to run.
+
+Options
+-------
+
+.. option:: ContainersWithPushBack
+
+ Semicolon-separated list of class names of custom containers that support
+ ``push_back``.
+
+.. option:: IgnoreImplicitConstructors
+
+ When non-zero, the check will ignore implicitly constructed arguments of
+ ``push_back``, e.g.
+
+ .. code-block:: c++
+
+ std::vector<std::string> v;
+ v.push_back("a"); // Ignored when IgnoreImplicitConstructors is ``1``.
+
+ Default is ``0``.
+
+.. option:: SmartPointers
+
+ Semicolon-separated list of class names of custom smart pointers.
+
+.. option:: TupleTypes
+
+ Semicolon-separated list of ``std::tuple``-like class names.
+
+.. option:: TupleMakeFunctions
+
+ Semicolon-separated list of ``std::make_tuple``-like function names. Those
+ function calls will be removed from ``push_back`` calls and turned into
+ ``emplace_back``.
+
+Example
+^^^^^^^
+
+.. code-block:: c++
+
+ std::vector<MyTuple<int, bool, char>> x;
+ x.push_back(MakeMyTuple(1, false, 'x'));
+
+transforms to:
+
+.. code-block:: c++
+
+ std::vector<MyTuple<int, bool, char>> x;
+ x.emplace_back(1, false, 'x');
+
+when :option:`TupleTypes` is set to ``MyTuple`` and :option:`TupleMakeFunctions`
+is set to ``MakeMyTuple``.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-equals-default.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-equals-default.rst
new file mode 100644
index 0000000..4b2368c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-equals-default.rst
@@ -0,0 +1,36 @@
+.. title:: clang-tidy - modernize-use-equals-default
+
+modernize-use-equals-default
+============================
+
+This check replaces default bodies of special member functions with ``=
+default;``. The explicitly defaulted function declarations enable more
+opportunities in optimization, because the compiler might treat explicitly
+defaulted functions as trivial.
+
+.. code-block:: c++
+
+ struct A {
+ A() {}
+ ~A();
+ };
+ A::~A() {}
+
+ // becomes
+
+ struct A {
+ A() = default;
+ ~A();
+ };
+ A::~A() = default;
+
+.. note::
+ Move-constructor and move-assignment operator are not supported yet.
+
+Options
+-------
+
+.. option:: IgnoreMacros
+
+ If set to non-zero, the check will not give warnings inside macros. Default
+ is `1`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-equals-delete.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-equals-delete.rst
new file mode 100644
index 0000000..bfa54e4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-equals-delete.rst
@@ -0,0 +1,25 @@
+.. title:: clang-tidy - modernize-use-equals-delete
+
+modernize-use-equals-delete
+===========================
+
+This check marks unimplemented private special member functions with ``= delete``.
+To avoid false-positives, this check only applies in a translation unit that has
+all other member functions implemented.
+
+.. code-block:: c++
+
+ struct A {
+ private:
+ A(const A&);
+ A& operator=(const A&);
+ };
+
+ // becomes
+
+ struct A {
+ private:
+ A(const A&) = delete;
+ A& operator=(const A&) = delete;
+ };
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-noexcept.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-noexcept.rst
new file mode 100644
index 0000000..084dad7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-noexcept.rst
@@ -0,0 +1,90 @@
+.. title:: clang-tidy - modernize-use-noexcept
+
+modernize-use-noexcept
+======================
+
+This check replaces deprecated dynamic exception specifications with
+the appropriate noexcept specification (introduced in C++11). By
+default this check will replace ``throw()`` with ``noexcept``,
+and ``throw(<exception>[,...])`` or ``throw(...)`` with
+``noexcept(false)``.
+
+Example
+-------
+
+.. code-block:: c++
+
+ void foo() throw();
+ void bar() throw(int) {}
+
+transforms to:
+
+.. code-block:: c++
+
+ void foo() noexcept;
+ void bar() noexcept(false) {}
+
+Options
+-------
+
+.. option:: ReplacementString
+
+Users can use :option:`ReplacementString` to specify a macro to use
+instead of ``noexcept``. This is useful when maintaining source code
+that uses custom exception specification marking other than
+``noexcept``. Fix-it hints will only be generated for non-throwing
+specifications.
+
+Example
+^^^^^^^
+
+.. code-block:: c++
+
+ void bar() throw(int);
+ void foo() throw();
+
+transforms to:
+
+.. code-block:: c++
+
+ void bar() throw(int); // No fix-it generated.
+ void foo() NOEXCEPT;
+
+if the :option:`ReplacementString` option is set to `NOEXCEPT`.
+
+.. option:: UseNoexceptFalse
+
+Enabled by default, disabling will generate fix-it hints that remove
+throwing dynamic exception specs, e.g., ``throw(<something>)``,
+completely without providing a replacement text, except for
+destructors and delete operators that are ``noexcept(true)`` by
+default.
+
+Example
+^^^^^^^
+
+.. code-block:: c++
+
+ void foo() throw(int) {}
+
+ struct bar {
+ void foobar() throw(int);
+ void operator delete(void *ptr) throw(int);
+ void operator delete[](void *ptr) throw(int);
+ ~bar() throw(int);
+ }
+
+transforms to:
+
+.. code-block:: c++
+
+ void foo() {}
+
+ struct bar {
+ void foobar();
+ void operator delete(void *ptr) noexcept(false);
+ void operator delete[](void *ptr) noexcept(false);
+ ~bar() noexcept(false);
+ }
+
+if the :option:`UseNoexceptFalse` option is set to `0`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-nullptr.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-nullptr.rst
new file mode 100644
index 0000000..e65b65b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-nullptr.rst
@@ -0,0 +1,67 @@
+.. title:: clang-tidy - modernize-use-nullptr
+
+modernize-use-nullptr
+=====================
+
+The check converts the usage of null pointer constants (eg. ``NULL``, ``0``)
+to use the new C++11 ``nullptr`` keyword.
+
+Example
+-------
+
+.. code-block:: c++
+
+ void assignment() {
+ char *a = NULL;
+ char *b = 0;
+ char c = 0;
+ }
+
+ int *ret_ptr() {
+ return 0;
+ }
+
+
+transforms to:
+
+.. code-block:: c++
+
+ void assignment() {
+ char *a = nullptr;
+ char *b = nullptr;
+ char c = 0;
+ }
+
+ int *ret_ptr() {
+ return nullptr;
+ }
+
+Options
+-------
+
+.. option:: NullMacros
+
+ Comma-separated list of macro names that will be transformed along with
+ ``NULL``. By default this check will only replace the ``NULL`` macro and will
+ skip any similar user-defined macros.
+
+Example
+^^^^^^^
+
+.. code-block:: c++
+
+ #define MY_NULL (void*)0
+ void assignment() {
+ void *p = MY_NULL;
+ }
+
+transforms to:
+
+.. code-block:: c++
+
+ #define MY_NULL NULL
+ void assignment() {
+ int *p = nullptr;
+ }
+
+if the :option:`NullMacros` option is set to ``MY_NULL``.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-override.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-override.rst
new file mode 100644
index 0000000..f2c778a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-override.rst
@@ -0,0 +1,7 @@
+.. title:: clang-tidy - modernize-use-override
+
+modernize-use-override
+======================
+
+
+Use C++11's ``override`` and remove ``virtual`` where applicable.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-transparent-functors.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-transparent-functors.rst
new file mode 100644
index 0000000..8887275
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-transparent-functors.rst
@@ -0,0 +1,39 @@
+.. title:: clang-tidy - modernize-use-transparent-functors
+
+modernize-use-transparent-functors
+==================================
+
+Prefer transparent functors to non-transparent ones. When using transparent
+functors, the type does not need to be repeated. The code is easier to read,
+maintain and less prone to errors. It is not possible to introduce unwanted
+conversions.
+
+ .. code-block:: c++
+
+ // Non-transparent functor
+ std::map<int, std::string, std::greater<int>> s;
+
+ // Transparent functor.
+ std::map<int, std::string, std::greater<>> s;
+
+ // Non-transparent functor
+ using MyFunctor = std::less<MyType>;
+
+It is not always a safe transformation though. The following case will be
+untouched to preserve the semantics.
+
+ .. code-block:: c++
+
+ // Non-transparent functor
+ std::map<const char *, std::string, std::greater<std::string>> s;
+
+Options
+-------
+
+.. option:: SafeMode
+
+ If the option is set to non-zero, the check will not diagnose cases where
+ using a transparent functor cannot be guaranteed to produce identical results
+ as the original code. The default value for this option is `0`.
+
+This check requires using C++14 or higher to run.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-uncaught-exceptions.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-uncaught-exceptions.rst
new file mode 100644
index 0000000..615f2e3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-uncaught-exceptions.rst
@@ -0,0 +1,64 @@
+.. title:: clang-tidy - modernize-use-uncaught-exceptions
+
+modernize-use-uncaught-exceptions
+====================================
+
+This check will warn on calls to ``std::uncaught_exception`` and replace them
+with calls to ``std::uncaught_exceptions``, since ``std::uncaught_exception``
+was deprecated in C++17.
+
+Below are a few examples of what kind of occurrences will be found and what
+they will be replaced with.
+
+.. code-block:: c++
+
+ #define MACRO1 std::uncaught_exception
+ #define MACRO2 std::uncaught_exception
+
+ int uncaught_exception() {
+ return 0;
+ }
+
+ int main() {
+ int res;
+
+ res = uncaught_exception();
+ // No warning, since it is not the deprecated function from namespace std
+
+ res = MACRO2();
+ // Warning, but will not be replaced
+
+ res = std::uncaught_exception();
+ // Warning and replaced
+
+ using std::uncaught_exception;
+ // Warning and replaced
+
+ res = uncaught_exception();
+ // Warning and replaced
+ }
+
+After applying the fixes the code will look like the following:
+
+.. code-block:: c++
+
+ #define MACRO1 std::uncaught_exception
+ #define MACRO2 std::uncaught_exception
+
+ int uncaught_exception() {
+ return 0;
+ }
+
+ int main() {
+ int res;
+
+ res = uncaught_exception();
+
+ res = MACRO2();
+
+ res = std::uncaught_exceptions();
+
+ using std::uncaught_exceptions;
+
+ res = uncaught_exceptions();
+ }
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-using.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-using.rst
new file mode 100644
index 0000000..1456a91
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/modernize-use-using.rst
@@ -0,0 +1,34 @@
+.. title:: clang-tidy - modernize-use-using
+
+modernize-use-using
+===================
+
+The check converts the usage of ``typedef`` with ``using`` keyword.
+
+Before:
+
+.. code-block:: c++
+
+ typedef int variable;
+
+ class Class{};
+ typedef void (Class::* MyPtrType)() const;
+
+After:
+
+.. code-block:: c++
+
+ using variable = int;
+
+ class Class{};
+ using MyPtrType = void (Class::*)() const;
+
+This check requires using C++11 or higher to run.
+
+Options
+-------
+
+.. option:: IgnoreMacros
+
+ If set to non-zero, the check will not give warnings inside macros. Default
+ is `1`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/mpi-buffer-deref.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/mpi-buffer-deref.rst
new file mode 100644
index 0000000..ef9f391
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/mpi-buffer-deref.rst
@@ -0,0 +1,26 @@
+.. title:: clang-tidy - mpi-buffer-deref
+
+mpi-buffer-deref
+================
+
+This check verifies if a buffer passed to an MPI (Message Passing Interface)
+function is sufficiently dereferenced. Buffers should be passed as a single
+pointer or array. As MPI function signatures specify ``void *`` for their buffer
+types, insufficiently dereferenced buffers can be passed, like for example as
+double pointers or multidimensional arrays, without a compiler warning emitted.
+
+Examples:
+
+.. code-block:: c++
+
+ // A double pointer is passed to the MPI function.
+ char *buf;
+ MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+
+ // A multidimensional array is passed to the MPI function.
+ short buf[1][1];
+ MPI_Send(buf, 1, MPI_SHORT, 0, 0, MPI_COMM_WORLD);
+
+ // A pointer to an array is passed to the MPI function.
+ short *buf[1];
+ MPI_Send(buf, 1, MPI_SHORT, 0, 0, MPI_COMM_WORLD);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/mpi-type-mismatch.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/mpi-type-mismatch.rst
new file mode 100644
index 0000000..10752ef
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/mpi-type-mismatch.rst
@@ -0,0 +1,21 @@
+.. title:: clang-tidy - mpi-type-mismatch
+
+mpi-type-mismatch
+=================
+
+This check verifies if buffer type and MPI (Message Passing Interface) datatype
+pairs match for used MPI functions. All MPI datatypes defined by the MPI
+standard (3.1) are verified by this check. User defined typedefs, custom MPI
+datatypes and null pointer constants are skipped, in the course of verification.
+
+Example:
+
+.. code-block:: c++
+
+ // In this case, the buffer type matches MPI datatype.
+ char buf;
+ MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+
+ // In the following case, the buffer type does not match MPI datatype.
+ int buf;
+ MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/objc-avoid-nserror-init.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/objc-avoid-nserror-init.rst
new file mode 100644
index 0000000..265794c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/objc-avoid-nserror-init.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - objc-avoid-nserror-init
+
+objc-avoid-nserror-init
+=======================
+
+Finds improper initialization of ``NSError`` objects.
+
+According to Apple developer document, we should always use factory method
+``errorWithDomain:code:userInfo:`` to create new NSError objects instead
+of ``[NSError alloc] init]``. Otherwise it will lead to a warning message
+during runtime.
+
+The corresponding information about ``NSError`` creation: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/CreateCustomizeNSError/CreateCustomizeNSError.html
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/objc-avoid-spinlock.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/objc-avoid-spinlock.rst
new file mode 100644
index 0000000..d1b11fc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/objc-avoid-spinlock.rst
@@ -0,0 +1,15 @@
+.. title:: clang-tidy - objc-avoid-spinlock
+
+objc-avoid-spinlock
+===================
+
+Finds usages of ``OSSpinlock``, which is deprecated due to potential livelock
+problems.
+
+This check will detect following function invocations:
+
+- ``OSSpinlockLock``
+- ``OSSpinlockTry``
+- ``OSSpinlockUnlock``
+
+The corresponding information about the problem of ``OSSpinlock``: https://blog.postmates.com/why-spinlocks-are-bad-on-ios-b69fc5221058
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/objc-forbidden-subclassing.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/objc-forbidden-subclassing.rst
new file mode 100644
index 0000000..4bb023c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/objc-forbidden-subclassing.rst
@@ -0,0 +1,28 @@
+.. title:: clang-tidy - objc-forbidden-subclassing
+
+objc-forbidden-subclassing
+==========================
+
+Finds Objective-C classes which are subclasses of classes which are not designed
+to be subclassed.
+
+By default, includes a list of Objective-C classes which are publicly documented
+as not supporting subclassing.
+
+.. note::
+
+ Instead of using this check, for code under your control, you should add
+ ``__attribute__((objc_subclassing_restricted))`` before your ``@interface``
+ declarations to ensure the compiler prevents others from subclassing your
+ Objective-C classes.
+ See https://clang.llvm.org/docs/AttributeReference.html#objc-subclassing-restricted
+
+Options
+-------
+
+.. option:: ForbiddenSuperClassNames
+
+ Semicolon-separated list of names of Objective-C classes which
+ do not support subclassing.
+
+ Defaults to `ABNewPersonViewController;ABPeoplePickerNavigationController;ABPersonViewController;ABUnknownPersonViewController;NSHashTable;NSMapTable;NSPointerArray;NSPointerFunctions;NSTimer;UIActionSheet;UIAlertView;UIImagePickerController;UITextInputMode;UIWebView`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/objc-property-declaration.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/objc-property-declaration.rst
new file mode 100644
index 0000000..f851056
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/objc-property-declaration.rst
@@ -0,0 +1,69 @@
+.. title:: clang-tidy - objc-property-declaration
+
+objc-property-declaration
+=========================
+
+Finds property declarations in Objective-C files that do not follow the pattern
+of property names in Apple's programming guide. The property name should be
+in the format of Lower Camel Case.
+
+For code:
+
+.. code-block:: objc
+
+ @property(nonatomic, assign) int LowerCamelCase;
+
+The fix will be:
+
+.. code-block:: objc
+
+ @property(nonatomic, assign) int lowerCamelCase;
+
+The check will only fix 'CamelCase' to 'camelCase'. In some other cases we will
+only provide warning messages since the property name could be complicated.
+Users will need to come up with a proper name by their own.
+
+This check also accepts special acronyms as prefixes or suffixes. Such prefixes or suffixes
+will suppress the Lower Camel Case check according to the guide:
+https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingBasics.html#//apple_ref/doc/uid/20001281-1002931-BBCFHEAB
+
+For a full list of well-known acronyms:
+https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/APIAbbreviations.html#//apple_ref/doc/uid/20001285-BCIHCGAE
+
+The corresponding style rule: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingIvarsAndTypes.html#//apple_ref/doc/uid/20001284-1001757
+
+The check will also accept property declared in category with a prefix of
+lowercase letters followed by a '_' to avoid naming conflict. For example:
+
+.. code-block:: objc
+
+ @property(nonatomic, assign) int abc_lowerCamelCase;
+
+The corresponding style rule: https://developer.apple.com/library/content/qa/qa1908/_index.html
+
+
+Options
+-------
+
+.. option:: Acronyms
+
+ Semicolon-separated list of custom acronyms that can be used as a prefix
+ or a suffix of property names.
+
+ By default, appends to the list of default acronyms (
+ ``IncludeDefaultAcronyms`` set to ``1``).
+ If ``IncludeDefaultAcronyms`` is set to ``0``, instead replaces the
+ default list of acronyms.
+
+.. option:: IncludeDefaultAcronyms
+
+ Integer value (defaults to ``1``) to control whether the default
+ acronyms are included in the list of acronyms.
+
+ If set to ``1``, the value in ``Acronyms`` is appended to the
+ default list of acronyms:
+
+ ``ACL;API;ARGB;ASCII;BGRA;CMYK;DNS;FPS;FTP;GIF;GPS;HD;HDR;HTML;HTTP;HTTPS;HUD;ID;JPG;JS;LAN;LZW;MDNS;MIDI;OS;PDF;PIN;PNG;POI;PSTN;PTR;QA;QOS;RGB;RGBA;RGBX;ROM;RPC;RTF;RTL;SDK;SSO;TCP;TIFF;TTS;UI;URI;URL;VC;VOIP;VPN;VR;WAN;XML``.
+
+ If set to ``0``, the value in ``Acronyms`` replaces the default list
+ of acronyms.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-faster-string-find.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-faster-string-find.rst
new file mode 100644
index 0000000..8d7265e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-faster-string-find.rst
@@ -0,0 +1,28 @@
+.. title:: clang-tidy - performance-faster-string-find
+
+performance-faster-string-find
+==============================
+
+Optimize calls to ``std::string::find()`` and friends when the needle passed is
+a single character string literal. The character literal overload is more
+efficient.
+
+Examples:
+
+.. code-block:: c++
+
+ str.find("A");
+
+ // becomes
+
+ str.find('A');
+
+Options
+-------
+
+.. option:: StringLikeClasses
+
+ Semicolon-separated list of names of string-like classes. By default only
+ ``std::basic_string`` is considered. The list of methods to consired is
+ fixed.
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-for-range-copy.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-for-range-copy.rst
new file mode 100644
index 0000000..2e7db98
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-for-range-copy.rst
@@ -0,0 +1,27 @@
+.. title:: clang-tidy - performance-for-range-copy
+
+performance-for-range-copy
+==========================
+
+Finds C++11 for ranges where the loop variable is copied in each iteration but
+it would suffice to obtain it by const reference.
+
+The check is only applied to loop variables of types that are expensive to copy
+which means they are not trivially copyable or have a non-trivial copy
+constructor or destructor.
+
+To ensure that it is safe to replace the copy with a const reference the
+following heuristic is employed:
+
+1. The loop variable is const qualified.
+2. The loop variable is not const, but only const methods or operators are
+ invoked on it, or it is used as const reference or value argument in
+ constructors or function calls.
+
+Options
+-------
+
+.. option:: WarnOnAllAutoCopies
+
+ When non-zero, warns on any use of `auto` as the type of the range-based for
+ loop variable. Default is `0`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-implicit-cast-in-loop.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-implicit-cast-in-loop.rst
new file mode 100644
index 0000000..280e7c0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-implicit-cast-in-loop.rst
@@ -0,0 +1,12 @@
+:orphan:
+
+.. title:: clang-tidy - performance-implicit-cast-in-loop
+.. meta::
+ :http-equiv=refresh: 5;URL=performance-implicit-conversion-in-loop.html
+
+performance-implicit-cast-in-loop
+=================================
+
+This check has been renamed to `performance-implicit-conversion-in-loop
+<performance-implicit-conversion-in-loop.html>`_.
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-implicit-conversion-in-loop.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-implicit-conversion-in-loop.rst
new file mode 100644
index 0000000..14e4d31
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-implicit-conversion-in-loop.rst
@@ -0,0 +1,21 @@
+.. title:: clang-tidy - performance-implicit-conversion-in-loop
+
+performance-implicit-conversion-in-loop
+=======================================
+
+This warning appears in a range-based loop with a loop variable of const ref
+type where the type of the variable does not match the one returned by the
+iterator. This means that an implicit conversion happens, which can for example
+result in expensive deep copies.
+
+Example:
+
+.. code-block:: c++
+
+ map<int, vector<string>> my_map;
+ for (const pair<int, vector<string>>& p : my_map) {}
+ // The iterator type is in fact pair<const int, vector<string>>, which means
+ // that the compiler added a conversion, resulting in a copy of the vectors.
+
+The easiest solution is usually to use ``const auto&`` instead of writing the
+type manually.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-inefficient-algorithm.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-inefficient-algorithm.rst
new file mode 100644
index 0000000..7002744
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-inefficient-algorithm.rst
@@ -0,0 +1,29 @@
+.. title:: clang-tidy - performance-inefficient-algorithm
+
+performance-inefficient-algorithm
+=================================
+
+
+Warns on inefficient use of STL algorithms on associative containers.
+
+Associative containers implements some of the algorithms as methods which
+should be preferred to the algorithms in the algorithm header. The methods
+can take advanatage of the order of the elements.
+
+.. code-block:: c++
+
+ std::set<int> s;
+ auto it = std::find(s.begin(), s.end(), 43);
+
+ // becomes
+
+ auto it = s.find(43);
+
+.. code-block:: c++
+
+ std::set<int> s;
+ auto c = std::count(s.begin(), s.end(), 43);
+
+ // becomes
+
+ auto c = s.count(43);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-inefficient-string-concatenation.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-inefficient-string-concatenation.rst
new file mode 100644
index 0000000..60910c6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-inefficient-string-concatenation.rst
@@ -0,0 +1,59 @@
+.. title:: clang-tidy - performance-inefficient-string-concatenation
+
+performance-inefficient-string-concatenation
+============================================
+
+This check warns about the performance overhead arising from concatenating
+strings using the ``operator+``, for instance:
+
+.. code-block:: c++
+
+ std::string a("Foo"), b("Bar");
+ a = a + b;
+
+Instead of this structure you should use ``operator+=`` or ``std::string``'s
+(``std::basic_string``) class member function ``append()``. For instance:
+
+.. code-block:: c++
+
+ std::string a("Foo"), b("Baz");
+ for (int i = 0; i < 20000; ++i) {
+ a = a + "Bar" + b;
+ }
+
+Could be rewritten in a greatly more efficient way like:
+
+.. code-block:: c++
+
+ std::string a("Foo"), b("Baz");
+ for (int i = 0; i < 20000; ++i) {
+ a.append("Bar").append(b);
+ }
+
+And this can be rewritten too:
+
+.. code-block:: c++
+
+ void f(const std::string&) {}
+ std::string a("Foo"), b("Baz");
+ void g() {
+ f(a + "Bar" + b);
+ }
+
+In a slightly more efficient way like:
+
+.. code-block:: c++
+
+ void f(const std::string&) {}
+ std::string a("Foo"), b("Baz");
+ void g() {
+ f(std::string(a).append("Bar").append(b));
+ }
+
+Options
+-------
+
+.. option:: StrictMode
+
+ When zero, the check will only check the string usage in ``while``, ``for``
+ and ``for-range`` statements. Default is `0`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-inefficient-vector-operation.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-inefficient-vector-operation.rst
new file mode 100644
index 0000000..8cf9318
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-inefficient-vector-operation.rst
@@ -0,0 +1,49 @@
+.. title:: clang-tidy - performance-inefficient-vector-operation
+
+performance-inefficient-vector-operation
+========================================
+
+Finds possible inefficient ``std::vector`` operations (e.g. ``push_back``,
+``emplace_back``) that may cause unnecessary memory reallocations.
+
+Currently, the check only detects following kinds of loops with a single
+statement body:
+
+* Counter-based for loops start with 0:
+
+.. code-block:: c++
+
+ std::vector<int> v;
+ for (int i = 0; i < n; ++i) {
+ v.push_back(n);
+ // This will trigger the warning since the push_back may cause multiple
+ // memory reallocations in v. This can be avoid by inserting a 'reserve(n)'
+ // statement before the for statement.
+ }
+
+
+* For-range loops like ``for (range-declaration : range_expression)``, the type
+ of ``range_expression`` can be ``std::vector``, ``std::array``,
+ ``std::deque``, ``std::set``, ``std::unordered_set``, ``std::map``,
+ ``std::unordered_set``:
+
+.. code-block:: c++
+
+ std::vector<int> data;
+ std::vector<int> v;
+
+ for (auto element : data) {
+ v.push_back(element);
+ // This will trigger the warning since the 'push_back' may cause multiple
+ // memory reallocations in v. This can be avoid by inserting a
+ // 'reserve(data.size())' statement before the for statement.
+ }
+
+
+Options
+-------
+
+.. option:: VectorLikeClasses
+
+ Semicolon-separated list of names of vector-like classes. By default only
+ ``::std::vector`` is considered.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-move-const-arg.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-move-const-arg.rst
new file mode 100644
index 0000000..39e1ca4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-move-const-arg.rst
@@ -0,0 +1,37 @@
+.. title:: clang-tidy - performance-move-const-arg
+
+performance-move-const-arg
+==========================
+
+The check warns
+
+- if ``std::move()`` is called with a constant argument,
+
+- if ``std::move()`` is called with an argument of a trivially-copyable type,
+
+- if the result of ``std::move()`` is passed as a const reference argument.
+
+In all three cases, the check will suggest a fix that removes the
+``std::move()``.
+
+Here are examples of each of the three cases:
+
+.. code-block:: c++
+
+ const string s;
+ return std::move(s); // Warning: std::move of the const variable has no effect
+
+ int x;
+ return std::move(x); // Warning: std::move of the variable of a trivially-copyable type has no effect
+
+ void f(const string &s);
+ string s;
+ f(std::move(s)); // Warning: passing result of std::move as a const reference argument; no move will actually happen
+
+Options
+-------
+
+.. option:: CheckTriviallyCopyableMove
+
+ If non-zero, enables detection of trivially copyable types that do not
+ have a move constructor. Default is non-zero.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-move-constructor-init.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-move-constructor-init.rst
new file mode 100644
index 0000000..a193b9e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-move-constructor-init.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - performance-move-constructor-init
+
+performance-move-constructor-init
+=================================
+
+"cert-oop11-cpp" redirects here as an alias for this check.
+
+The check flags user-defined move constructors that have a ctor-initializer
+initializing a member or base class through a copy constructor instead of a
+move constructor.
+
+Options
+-------
+
+.. option:: IncludeStyle
+
+ A string specifying which include-style is used, `llvm` or `google`. Default
+ is `llvm`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-noexcept-move-constructor.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-noexcept-move-constructor.rst
new file mode 100644
index 0000000..05f1d85
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-noexcept-move-constructor.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - performance-noexcept-move-constructor
+
+performance-noexcept-move-constructor
+=====================================
+
+
+The check flags user-defined move constructors and assignment operators not
+marked with ``noexcept`` or marked with ``noexcept(expr)`` where ``expr``
+evaluates to ``false`` (but is not a ``false`` literal itself).
+
+Move constructors of all the types used with STL containers, for example,
+need to be declared ``noexcept``. Otherwise STL will choose copy constructors
+instead. The same is valid for move assignment operations.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-type-promotion-in-math-fn.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-type-promotion-in-math-fn.rst
new file mode 100644
index 0000000..a27a482
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-type-promotion-in-math-fn.rst
@@ -0,0 +1,21 @@
+.. title:: clang-tidy - performance-type-promotion-in-math-fn
+
+performance-type-promotion-in-math-fn
+=====================================
+
+Finds calls to C math library functions (from ``math.h`` or, in C++, ``cmath``)
+with implicit ``float`` to ``double`` promotions.
+
+For example, warns on ``::sin(0.f)``, because this funciton's parameter is a
+double. You probably meant to call ``std::sin(0.f)`` (in C++), or ``sinf(0.f)``
+(in C).
+
+.. code-block:: c++
+
+ float a;
+ asin(a);
+
+ // becomes
+
+ float a;
+ std::asin(a);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
new file mode 100644
index 0000000..2bd7755
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-copy-initialization.rst
@@ -0,0 +1,37 @@
+.. title:: clang-tidy - performance-unnecessary-copy-initialization
+
+performance-unnecessary-copy-initialization
+===========================================
+
+Finds local variable declarations that are initialized using the copy
+constructor of a non-trivially-copyable type but it would suffice to obtain a
+const reference.
+
+The check is only applied if it is safe to replace the copy by a const
+reference. This is the case when the variable is const qualified or when it is
+only used as a const, i.e. only const methods or operators are invoked on it, or
+it is used as const reference or value argument in constructors or function
+calls.
+
+Example:
+
+.. code-block:: c++
+
+ const string& constReference();
+ void Function() {
+ // The warning will suggest making this a const reference.
+ const string UnnecessaryCopy = constReference();
+ }
+
+ struct Foo {
+ const string& name() const;
+ };
+ void Function(const Foo& foo) {
+ // The warning will suggest making this a const reference.
+ string UnnecessaryCopy1 = foo.name();
+ UnnecessaryCopy1.find("bar");
+
+ // The warning will suggest making this a const reference.
+ string UnnecessaryCopy2 = UnnecessaryCopy1;
+ UnnecessaryCopy2.find("bar");
+ }
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-value-param.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-value-param.rst
new file mode 100644
index 0000000..e69610e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/performance-unnecessary-value-param.rst
@@ -0,0 +1,63 @@
+.. title:: clang-tidy - performance-unnecessary-value-param
+
+performance-unnecessary-value-param
+===================================
+
+Flags value parameter declarations of expensive to copy types that are copied
+for each invocation but it would suffice to pass them by const reference.
+
+The check is only applied to parameters of types that are expensive to copy
+which means they are not trivially copyable or have a non-trivial copy
+constructor or destructor.
+
+To ensure that it is safe to replace the value parameter with a const reference
+the following heuristic is employed:
+
+1. the parameter is const qualified;
+2. the parameter is not const, but only const methods or operators are invoked
+ on it, or it is used as const reference or value argument in constructors or
+ function calls.
+
+Example:
+
+.. code-block:: c++
+
+ void f(const string Value) {
+ // The warning will suggest making Value a reference.
+ }
+
+ void g(ExpensiveToCopy Value) {
+ // The warning will suggest making Value a const reference.
+ Value.ConstMethd();
+ ExpensiveToCopy Copy(Value);
+ }
+
+If the parameter is not const, only copied or assigned once and has a
+non-trivial move-constructor or move-assignment operator respectively the check
+will suggest to move it.
+
+Example:
+
+.. code-block:: c++
+
+ void setValue(string Value) {
+ Field = Value;
+ }
+
+Will become:
+
+.. code-block:: c++
+
+ #include <utility>
+
+ void setValue(string Value) {
+ Field = std::move(Value);
+ }
+
+Options
+-------
+
+.. option:: IncludeStyle
+
+ A string specifying which include-style is used, `llvm` or `google`. Default
+ is `llvm`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/portability-simd-intrinsics.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/portability-simd-intrinsics.rst
new file mode 100644
index 0000000..2cd9d9f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/portability-simd-intrinsics.rst
@@ -0,0 +1,49 @@
+.. title:: clang-tidy - portability-simd-intrinsics
+
+portability-simd-intrinsics
+===========================
+
+Finds SIMD intrinsics calls and suggests ``std::experimental::simd`` (`P0214`_)
+alternatives.
+
+If the option ``Suggest`` is set to non-zero, for
+
+.. code-block:: c++
+
+ _mm_add_epi32(a, b); // x86
+ vec_add(a, b); // Power
+
+the check suggests an alternative: ``operator+`` on ``std::experimental::simd``
+objects.
+
+Otherwise, it just complains the intrinsics are non-portable (and there are
+`P0214`_ alternatives).
+
+Many architectures provide SIMD operations (e.g. x86 SSE/AVX, Power AltiVec/VSX,
+ARM NEON). It is common that SIMD code implementing the same algorithm, is
+written in multiple target-dispatching pieces to optimize for different
+architectures or micro-architectures.
+
+The C++ standard proposal `P0214`_ and its extensions cover many common SIMD
+operations. By migrating from target-dependent intrinsics to `P0214`_
+operations, the SIMD code can be simplified and pieces for different targets can
+be unified.
+
+Refer to `P0214`_ for introduction and motivation for the data-parallel standard
+library.
+
+Options
+-------
+
+.. option:: Suggest
+
+ If this option is set to non-zero (default is `0`), the check will suggest
+ `P0214`_ alternatives, otherwise it only points out the intrinsic function is
+ non-portable.
+
+.. option:: Std
+
+ The namespace used to suggest `P0214`_ alternatives. If not specified, `std::`
+ for `-std=c++2a` and `std::experimental::` for `-std=c++11`.
+
+.. _P0214: http://wg21.link/p0214
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-avoid-const-params-in-decls.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-avoid-const-params-in-decls.rst
new file mode 100644
index 0000000..3aea5d0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-avoid-const-params-in-decls.rst
@@ -0,0 +1,17 @@
+.. title:: clang-tidy - readability-avoid-const-params-in-decls
+
+readability-avoid-const-params-in-decls
+=======================================
+
+Checks whether a function declaration has parameters that are top level
+``const``.
+
+``const`` values in declarations do not affect the signature of a function, so
+they should not be put there.
+
+Examples:
+
+.. code-block:: c++
+
+ void f(const string); // Bad: const is top level.
+ void f(const string&); // Good: const is not top level.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-braces-around-statements.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-braces-around-statements.rst
new file mode 100644
index 0000000..2c08165
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-braces-around-statements.rst
@@ -0,0 +1,38 @@
+.. title:: clang-tidy - readability-braces-around-statements
+
+readability-braces-around-statements
+====================================
+
+`google-readability-braces-around-statements` redirects here as an alias for
+this check.
+
+Checks that bodies of ``if`` statements and loops (``for``, ``do while``, and
+``while``) are inside braces.
+
+Before:
+
+.. code-block:: c++
+
+ if (condition)
+ statement;
+
+After:
+
+.. code-block:: c++
+
+ if (condition) {
+ statement;
+ }
+
+Options
+-------
+
+.. option:: ShortStatementLines
+
+ Defines the minimal number of lines that the statement should have in order
+ to trigger this check.
+
+ The number of lines is counted from the end of condition or initial keyword
+ (``do``/``else``) until the last line of the inner statement. Default value
+ `0` means that braces will be added to all statements (not having them
+ already).
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-container-size-empty.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-container-size-empty.rst
new file mode 100644
index 0000000..541320c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-container-size-empty.rst
@@ -0,0 +1,26 @@
+.. title:: clang-tidy - readability-container-size-empty
+
+readability-container-size-empty
+================================
+
+
+Checks whether a call to the ``size()`` method can be replaced with a call to
+``empty()``.
+
+The emptiness of a container should be checked using the ``empty()`` method
+instead of the ``size()`` method. It is not guaranteed that ``size()`` is a
+constant-time function, and it is generally more efficient and also shows
+clearer intent to use ``empty()``. Furthermore some containers may implement
+the ``empty()`` method but not implement the ``size()`` method. Using
+``empty()`` whenever possible makes it easier to switch to another container in
+the future.
+
+The check issues warning if a container has ``size()`` and ``empty()`` methods
+matching following signatures:
+
+.. code-block:: c++
+
+ size_type size() const;
+ bool empty() const;
+
+`size_type` can be any kind of integer type.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-delete-null-pointer.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-delete-null-pointer.rst
new file mode 100644
index 0000000..21c91b4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-delete-null-pointer.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - readability-delete-null-pointer
+
+readability-delete-null-pointer
+===============================
+
+Checks the ``if`` statements where a pointer's existence is checked and then deletes the pointer.
+The check is unnecessary as deleting a null pointer has no effect.
+
+.. code:: c++
+
+ int *p;
+ if (p)
+ delete p;
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-deleted-default.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-deleted-default.rst
new file mode 100644
index 0000000..00134eb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-deleted-default.rst
@@ -0,0 +1,22 @@
+.. title:: clang-tidy - readability-deleted-default
+
+readability-deleted-default
+===========================
+
+Checks that constructors and assignment operators marked as ``= default`` are
+not actually deleted by the compiler.
+
+.. code-block:: c++
+
+ class Example {
+ public:
+ // This constructor is deleted because I is missing a default value.
+ Example() = default;
+ // This is fine.
+ Example(const Example& Other) = default;
+ // This operator is deleted because I cannot be assigned (it is const).
+ Example& operator=(const Example& Other) = default;
+
+ private:
+ const int I;
+ };
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-else-after-return.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-else-after-return.rst
new file mode 100644
index 0000000..949b5bb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-else-after-return.rst
@@ -0,0 +1,64 @@
+.. title:: clang-tidy - readability-else-after-return
+
+readability-else-after-return
+=============================
+
+`LLVM Coding Standards <http://llvm.org/docs/CodingStandards.html>`_ advises to
+reduce indentation where possible and where it makes understanding code easier.
+Early exit is one of the suggested enforcements of that. Please do not use
+``else`` or ``else if`` after something that interrupts control flow - like
+``return``, ``break``, ``continue``, ``throw``.
+
+The following piece of code illustrates how the check works. This piece of code:
+
+.. code-block:: c++
+
+ void foo(int Value) {
+ int Local = 0;
+ for (int i = 0; i < 42; i++) {
+ if (Value == 1) {
+ return;
+ } else {
+ Local++;
+ }
+
+ if (Value == 2)
+ continue;
+ else
+ Local++;
+
+ if (Value == 3) {
+ throw 42;
+ } else {
+ Local++;
+ }
+ }
+ }
+
+
+Would be transformed into:
+
+.. code-block:: c++
+
+ void foo(int Value) {
+ int Local = 0;
+ for (int i = 0; i < 42; i++) {
+ if (Value == 1) {
+ return;
+ }
+ Local++;
+
+ if (Value == 2)
+ continue;
+ Local++;
+
+ if (Value == 3) {
+ throw 42;
+ }
+ Local++;
+ }
+ }
+
+
+This check helps to enforce this `LLVM Coding Standards recommendation
+<http://llvm.org/docs/CodingStandards.html#don-t-use-else-after-a-return>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-function-size.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-function-size.rst
new file mode 100644
index 0000000..3360fbd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-function-size.rst
@@ -0,0 +1,45 @@
+.. title:: clang-tidy - readability-function-size
+
+readability-function-size
+=========================
+
+`google-readability-function-size` redirects here as an alias for this check.
+
+Checks for large functions based on various metrics.
+
+Options
+-------
+
+.. option:: LineThreshold
+
+ Flag functions exceeding this number of lines. The default is `-1` (ignore
+ the number of lines).
+
+.. option:: StatementThreshold
+
+ Flag functions exceeding this number of statements. This may differ
+ significantly from the number of lines for macro-heavy code. The default is
+ `800`.
+
+.. option:: BranchThreshold
+
+ Flag functions exceeding this number of control statements. The default is
+ `-1` (ignore the number of branches).
+
+.. option:: ParameterThreshold
+
+ Flag functions that exceed a specified number of parameters. The default
+ is `-1` (ignore the number of parameters).
+
+.. option:: NestingThreshold
+
+ Flag compound statements which create next nesting level after
+ `NestingThreshold`. This may differ significantly from the expected value
+ for macro-heavy code. The default is `-1` (ignore the nesting level).
+
+.. option:: VariableThreshold
+
+ Flag functions exceeding this number of variables declared in the body.
+ The default is `-1` (ignore the number of variables).
+ Please note that function parameters and variables declared in lambdas,
+ GNU Statement Expressions, and nested class inline functions are not counted.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-identifier-naming.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-identifier-naming.rst
new file mode 100644
index 0000000..30408c1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-identifier-naming.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - readability-identifier-naming
+
+readability-identifier-naming
+=============================
+
+Checks for identifiers naming style mismatch.
+
+This check will try to enforce coding guidelines on the identifiers naming.
+It supports `lower_case`, `UPPER_CASE`, `camelBack` and `CamelCase` casing and
+tries to convert from one to another if a mismatch is detected.
+
+It also supports a fixed prefix and suffix that will be prepended or
+appended to the identifiers, regardless of the casing.
+
+Many configuration options are available, in order to be able to create
+different rules for different kind of identifier. In general, the
+rules are falling back to a more generic rule if the specific case is not
+configured.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-implicit-bool-cast.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-implicit-bool-cast.rst
new file mode 100644
index 0000000..a6a3492
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-implicit-bool-cast.rst
@@ -0,0 +1,11 @@
+:orphan:
+
+.. title:: clang-tidy - readability-implicit-bool-cast
+.. meta::
+ :http-equiv=refresh: 5;URL=readability-implicit-bool-conversion.html
+
+readability-implicit-bool-cast
+==============================
+
+This check has been renamed to `readability-implicit-bool-conversion
+<readability-implicit-bool-conversion.html>`_.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-implicit-bool-conversion.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-implicit-bool-conversion.rst
new file mode 100644
index 0000000..64f3f73
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-implicit-bool-conversion.rst
@@ -0,0 +1,132 @@
+.. title:: clang-tidy - readability-implicit-bool-conversion
+
+readability-implicit-bool-conversion
+====================================
+
+This check can be used to find implicit conversions between built-in types and
+booleans. Depending on use case, it may simply help with readability of the code,
+or in some cases, point to potential bugs which remain unnoticed due to implicit
+conversions.
+
+The following is a real-world example of bug which was hiding behind implicit
+``bool`` conversion:
+
+.. code-block:: c++
+
+ class Foo {
+ int m_foo;
+
+ public:
+ void setFoo(bool foo) { m_foo = foo; } // warning: implicit conversion bool -> int
+ int getFoo() { return m_foo; }
+ };
+
+ void use(Foo& foo) {
+ bool value = foo.getFoo(); // warning: implicit conversion int -> bool
+ }
+
+This code is the result of unsuccessful refactoring, where type of ``m_foo``
+changed from ``bool`` to ``int``. The programmer forgot to change all
+occurrences of ``bool``, and the remaining code is no longer correct, yet it
+still compiles without any visible warnings.
+
+In addition to issuing warnings, fix-it hints are provided to help solve the
+reported issues. This can be used for improving readability of code, for
+example:
+
+.. code-block:: c++
+
+ void conversionsToBool() {
+ float floating;
+ bool boolean = floating;
+ // ^ propose replacement: bool boolean = floating != 0.0f;
+
+ int integer;
+ if (integer) {}
+ // ^ propose replacement: if (integer != 0) {}
+
+ int* pointer;
+ if (!pointer) {}
+ // ^ propose replacement: if (pointer == nullptr) {}
+
+ while (1) {}
+ // ^ propose replacement: while (true) {}
+ }
+
+ void functionTakingInt(int param);
+
+ void conversionsFromBool() {
+ bool boolean;
+ functionTakingInt(boolean);
+ // ^ propose replacement: functionTakingInt(static_cast<int>(boolean));
+
+ functionTakingInt(true);
+ // ^ propose replacement: functionTakingInt(1);
+ }
+
+In general, the following conversion types are checked:
+
+- integer expression/literal to boolean,
+
+- floating expression/literal to boolean,
+
+- pointer/pointer to member/``nullptr``/``NULL`` to boolean,
+
+- boolean expression/literal to integer,
+
+- boolean expression/literal to floating.
+
+The rules for generating fix-it hints are:
+
+- in case of conversions from other built-in type to bool, an explicit
+ comparison is proposed to make it clear what exaclty is being compared:
+
+ - ``bool boolean = floating;`` is changed to
+ ``bool boolean = floating == 0.0f;``,
+
+ - for other types, appropriate literals are used (``0``, ``0u``, ``0.0f``,
+ ``0.0``, ``nullptr``),
+
+- in case of negated expressions conversion to bool, the proposed replacement
+ with comparison is simplified:
+
+ - ``if (!pointer)`` is changed to ``if (pointer == nullptr)``,
+
+- in case of conversions from bool to other built-in types, an explicit
+ ``static_cast`` is proposed to make it clear that a conversion is taking
+ place:
+
+ - ``int integer = boolean;`` is changed to
+ ``int integer = static_cast<int>(boolean);``,
+
+- if the conversion is performed on type literals, an equivalent literal is
+ proposed, according to what type is actually expected, for example:
+
+ - ``functionTakingBool(0);`` is changed to ``functionTakingBool(false);``,
+
+ - ``functionTakingInt(true);`` is changed to ``functionTakingInt(1);``,
+
+ - for other types, appropriate literals are used (``false``, ``true``, ``0``,
+ ``1``, ``0u``, ``1u``, ``0.0f``, ``1.0f``, ``0.0``, ``1.0f``).
+
+Some additional accommodations are made for pre-C++11 dialects:
+
+- ``false`` literal conversion to pointer is detected,
+
+- instead of ``nullptr`` literal, ``0`` is proposed as replacement.
+
+Occurrences of implicit conversions inside macros and template instantiations
+are deliberately ignored, as it is not clear how to deal with such cases.
+
+Options
+-------
+
+.. option:: AllowIntegerConditions
+
+ When non-zero, the check will allow conditional integer conversions. Default
+ is `0`.
+
+.. option:: AllowPointerConditions
+
+ When non-zero, the check will allow conditional pointer conversions. Default
+ is `0`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-inconsistent-declaration-parameter-name.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-inconsistent-declaration-parameter-name.rst
new file mode 100644
index 0000000..a47bb41
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-inconsistent-declaration-parameter-name.rst
@@ -0,0 +1,63 @@
+.. title:: clang-tidy - readability-inconsistent-declaration-parameter-name
+
+readability-inconsistent-declaration-parameter-name
+===================================================
+
+Find function declarations which differ in parameter names.
+
+Example:
+
+.. code-block:: c++
+
+ // in foo.hpp:
+ void foo(int a, int b, int c);
+
+ // in foo.cpp:
+ void foo(int d, int e, int f); // warning
+
+This check should help to enforce consistency in large projects, where it often
+happens that a definition of function is refactored, changing the parameter
+names, but its declaration in header file is not updated. With this check, we
+can easily find and correct such inconsistencies, keeping declaration and
+definition always in sync.
+
+Unnamed parameters are allowed and are not taken into account when comparing
+function declarations, for example:
+
+.. code-block:: c++
+
+ void foo(int a);
+ void foo(int); // no warning
+
+One name is also allowed to be a case-insensitive prefix/suffix of the other:
+
+.. code-block:: c++
+
+ void foo(int count);
+ void foo(int count_input) { // no warning
+ int count = adjustCount(count_input);
+ }
+
+To help with refactoring, in some cases fix-it hints are generated to align
+parameter names to a single naming convention. This works with the assumption
+that the function definition is the most up-to-date version, as it directly
+references parameter names in its body. Example:
+
+.. code-block:: c++
+
+ void foo(int a); // warning and fix-it hint (replace "a" to "b")
+ int foo(int b) { return b + 2; } // definition with use of "b"
+
+In the case of multiple redeclarations or function template specializations,
+a warning is issued for every redeclaration or specialization inconsistent with
+the definition or the first declaration seen in a translation unit.
+
+.. option:: IgnoreMacros
+
+ If this option is set to non-zero (default is `1`), the check will not warn
+ about names declared inside macros.
+
+.. option:: Strict
+
+ If this option is set to non-zero (default is `0`), then names must match
+ exactly (or be absent).
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-misleading-indentation.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-misleading-indentation.rst
new file mode 100644
index 0000000..5d52c77
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-misleading-indentation.rst
@@ -0,0 +1,38 @@
+.. title:: clang-tidy - readability-misleading-indentation
+
+readability-misleading-indentation
+==================================
+
+Correct indentation helps to understand code. Mismatch of the syntactical
+structure and the indentation of the code may hide serious problems.
+Missing braces can also make it significantly harder to read the code,
+therefore it is important to use braces.
+
+The way to avoid dangling else is to always check that an ``else`` belongs
+to the ``if`` that begins in the same column.
+
+You can omit braces when your inner part of e.g. an ``if`` statement has only
+one statement in it. Although in that case you should begin the next statement
+in the same column with the ``if``.
+
+Examples:
+
+.. code-block:: c++
+
+ // Dangling else:
+ if (cond1)
+ if (cond2)
+ foo1();
+ else
+ foo2(); // Wrong indentation: else belongs to if(cond2) statement.
+
+ // Missing braces:
+ if (cond1)
+ foo1();
+ foo2(); // Not guarded by if(cond1).
+
+Limitations
+-----------
+
+Note that this check only works as expected when the tabs or spaces are used
+consistently and not mixed.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-misplaced-array-index.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-misplaced-array-index.rst
new file mode 100644
index 0000000..26a5af7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-misplaced-array-index.rst
@@ -0,0 +1,27 @@
+.. title:: clang-tidy - readability-misplaced-array-index
+
+readability-misplaced-array-index
+=================================
+
+This check warns for unusual array index syntax.
+
+The following code has unusual array index syntax:
+
+.. code-block:: c++
+
+ void f(int *X, int Y) {
+ Y[X] = 0;
+ }
+
+becomes
+
+.. code-block:: c++
+
+ void f(int *X, int Y) {
+ X[Y] = 0;
+ }
+
+The check warns about such unusual syntax for readability reasons:
+ * There are programmers that are not familiar with this unusual syntax.
+ * It is possible that variables are mixed up.
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-named-parameter.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-named-parameter.rst
new file mode 100644
index 0000000..8d28c0a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-named-parameter.rst
@@ -0,0 +1,16 @@
+.. title:: clang-tidy - readability-named-parameter
+
+readability-named-parameter
+===========================
+
+Find functions with unnamed arguments.
+
+The check implements the following rule originating in the Google C++ Style
+Guide:
+
+https://google.github.io/styleguide/cppguide.html#Function_Declarations_and_Definitions
+
+All parameters should be named, with identical names in the declaration and
+implementation.
+
+Corresponding cpplint.py check name: `readability/function`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-non-const-parameter.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-non-const-parameter.rst
new file mode 100644
index 0000000..0729470
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-non-const-parameter.rst
@@ -0,0 +1,46 @@
+.. title:: clang-tidy - readability-non-const-parameter
+
+readability-non-const-parameter
+===============================
+
+The check finds function parameters of a pointer type that could be changed to
+point to a constant type instead.
+
+When ``const`` is used properly, many mistakes can be avoided. Advantages when
+using ``const`` properly:
+
+- prevent unintentional modification of data;
+
+- get additional warnings such as using uninitialized data;
+
+- make it easier for developers to see possible side effects.
+
+This check is not strict about constness, it only warns when the constness will
+make the function interface safer.
+
+.. code-block:: c++
+
+ // warning here; the declaration "const char *p" would make the function
+ // interface safer.
+ char f1(char *p) {
+ return *p;
+ }
+
+ // no warning; the declaration could be more const "const int * const p" but
+ // that does not make the function interface safer.
+ int f2(const int *p) {
+ return *p;
+ }
+
+ // no warning; making x const does not make the function interface safer
+ int f3(int x) {
+ return x;
+ }
+
+ // no warning; Technically, *p can be const ("const struct S *p"). But making
+ // *p const could be misleading. People might think that it's safe to pass
+ // const data to this function.
+ struct S { int *a; int *b; };
+ int f3(struct S *p) {
+ *(p->a) = 0;
+ }
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-control-flow.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-control-flow.rst
new file mode 100644
index 0000000..aeaf345
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-control-flow.rst
@@ -0,0 +1,50 @@
+.. title:: clang-tidy - readability-redundant-control-flow
+
+readability-redundant-control-flow
+==================================
+
+This check looks for procedures (functions returning no value) with ``return``
+statements at the end of the function. Such ``return`` statements are redundant.
+
+Loop statements (``for``, ``while``, ``do while``) are checked for redundant
+``continue`` statements at the end of the loop body.
+
+Examples:
+
+The following function `f` contains a redundant ``return`` statement:
+
+.. code-block:: c++
+
+ extern void g();
+ void f() {
+ g();
+ return;
+ }
+
+becomes
+
+.. code-block:: c++
+
+ extern void g();
+ void f() {
+ g();
+ }
+
+The following function `k` contains a redundant ``continue`` statement:
+
+.. code-block:: c++
+
+ void k() {
+ for (int i = 0; i < 10; ++i) {
+ continue;
+ }
+ }
+
+becomes
+
+.. code-block:: c++
+
+ void k() {
+ for (int i = 0; i < 10; ++i) {
+ }
+ }
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-declaration.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-declaration.rst
new file mode 100644
index 0000000..8ce7aac
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-declaration.rst
@@ -0,0 +1,37 @@
+.. title:: clang-tidy - readability-redundant-declaration
+
+readability-redundant-declaration
+=================================
+
+Finds redundant variable and function declarations.
+
+.. code-block:: c++
+
+ extern int X;
+ extern int X;
+
+becomes
+
+.. code-block:: c++
+
+ extern int X;
+
+Such redundant declarations can be removed without changing program behaviour.
+They can for instance be unintentional left overs from previous refactorings
+when code has been moved around. Having redundant declarations could in worst
+case mean that there are typos in the code that cause bugs.
+
+Normally the code can be automatically fixed, :program:`clang-tidy` can remove
+the second declaration. However there are 2 cases when you need to fix the code
+manually:
+
+* When the declarations are in different header files;
+* When multiple variables are declared together.
+
+Options
+-------
+
+.. option:: IgnoreMacros
+
+ If set to non-zero, the check will not give warnings inside macros. Default
+ is `1`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-function-ptr-dereference.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-function-ptr-dereference.rst
new file mode 100644
index 0000000..d8c7ec7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-function-ptr-dereference.rst
@@ -0,0 +1,24 @@
+.. title:: clang-tidy - readability-redundant-function-ptr-dereference
+
+readability-redundant-function-ptr-dereference
+==============================================
+
+Finds redundant dereferences of a function pointer.
+
+Before:
+
+.. code-block:: c++
+
+ int f(int,int);
+ int (*p)(int, int) = &f;
+
+ int i = (**p)(10, 50);
+
+After:
+
+.. code-block:: c++
+
+ int f(int,int);
+ int (*p)(int, int) = &f;
+
+ int i = (*p)(10, 50);
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
new file mode 100644
index 0000000..a640e16
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-member-init.rst
@@ -0,0 +1,20 @@
+.. title:: clang-tidy - readability-redundant-member-init
+
+readability-redundant-member-init
+=================================
+
+Finds member initializations that are unnecessary because the same default
+constructor would be called if they were not present.
+
+Example:
+
+.. code-block:: c++
+
+ // Explicitly initializing the member s is unnecessary.
+ class Foo {
+ public:
+ Foo() : s() {}
+
+ private:
+ std::string s;
+ };
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-smartptr-get.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-smartptr-get.rst
new file mode 100644
index 0000000..3fc77c5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-smartptr-get.rst
@@ -0,0 +1,16 @@
+.. title:: clang-tidy - readability-redundant-smartptr-get
+
+readability-redundant-smartptr-get
+==================================
+
+Find and remove redundant calls to smart pointer's ``.get()`` method.
+
+Examples:
+
+.. code-block:: c++
+
+ ptr.get()->Foo() ==> ptr->Foo()
+ *ptr.get() ==> *ptr
+ *ptr->get() ==> **ptr
+ if (ptr.get() == nullptr) ... => if (ptr == nullptr) ...
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-cstr.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-cstr.rst
new file mode 100644
index 0000000..e6760a4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-cstr.rst
@@ -0,0 +1,7 @@
+.. title:: clang-tidy - readability-redundant-string-cstr
+
+readability-redundant-string-cstr
+=================================
+
+
+Finds unnecessary calls to ``std::string::c_str()`` and ``std::string::data()``.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
new file mode 100644
index 0000000..e4136ea
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-redundant-string-init.rst
@@ -0,0 +1,19 @@
+.. title:: clang-tidy - readability-redundant-string-init
+
+readability-redundant-string-init
+=================================
+
+Finds unnecessary string initializations.
+
+Examples:
+
+.. code-block:: c++
+
+ // Initializing string with empty string literal is unnecessary.
+ std::string a = "";
+ std::string b("");
+
+ // becomes
+
+ std::string a;
+ std::string b;
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-simplify-boolean-expr.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-simplify-boolean-expr.rst
new file mode 100644
index 0000000..b333e18
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-simplify-boolean-expr.rst
@@ -0,0 +1,86 @@
+.. title:: clang-tidy - readability-simplify-boolean-expr
+
+readability-simplify-boolean-expr
+=================================
+
+Looks for boolean expressions involving boolean constants and simplifies
+them to use the appropriate boolean expression directly.
+
+Examples:
+
+=========================================== ================
+Initial expression Result
+------------------------------------------- ----------------
+``if (b == true)`` ``if (b)``
+``if (b == false)`` ``if (!b)``
+``if (b && true)`` ``if (b)``
+``if (b && false)`` ``if (false)``
+``if (b || true)`` ``if (true)``
+``if (b || false)`` ``if (b)``
+``e ? true : false`` ``e``
+``e ? false : true`` ``!e``
+``if (true) t(); else f();`` ``t();``
+``if (false) t(); else f();`` ``f();``
+``if (e) return true; else return false;`` ``return e;``
+``if (e) return false; else return true;`` ``return !e;``
+``if (e) b = true; else b = false;`` ``b = e;``
+``if (e) b = false; else b = true;`` ``b = !e;``
+``if (e) return true; return false;`` ``return e;``
+``if (e) return false; return true;`` ``return !e;``
+=========================================== ================
+
+The resulting expression ``e`` is modified as follows:
+ 1. Unnecessary parentheses around the expression are removed.
+ 2. Negated applications of ``!`` are eliminated.
+ 3. Negated applications of comparison operators are changed to use the
+ opposite condition.
+ 4. Implicit conversions of pointers, including pointers to members, to
+ ``bool`` are replaced with explicit comparisons to ``nullptr`` in C++11
+ or ``NULL`` in C++98/03.
+ 5. Implicit casts to ``bool`` are replaced with explicit casts to ``bool``.
+ 6. Object expressions with ``explicit operator bool`` conversion operators
+ are replaced with explicit casts to ``bool``.
+ 7. Implicit conversions of integral types to ``bool`` are replaced with
+ explicit comparisons to ``0``.
+
+Examples:
+ 1. The ternary assignment ``bool b = (i < 0) ? true : false;`` has redundant
+ parentheses and becomes ``bool b = i < 0;``.
+
+ 2. The conditional return ``if (!b) return false; return true;`` has an
+ implied double negation and becomes ``return b;``.
+
+ 3. The conditional return ``if (i < 0) return false; return true;`` becomes
+ ``return i >= 0;``.
+
+ The conditional return ``if (i != 0) return false; return true;`` becomes
+ ``return i == 0;``.
+
+ 4. The conditional return ``if (p) return true; return false;`` has an
+ implicit conversion of a pointer to ``bool`` and becomes
+ ``return p != nullptr;``.
+
+ The ternary assignment ``bool b = (i & 1) ? true : false;`` has an
+ implicit conversion of ``i & 1`` to ``bool`` and becomes
+ ``bool b = (i & 1) != 0;``.
+
+ 5. The conditional return ``if (i & 1) return true; else return false;`` has
+ an implicit conversion of an integer quantity ``i & 1`` to ``bool`` and
+ becomes ``return (i & 1) != 0;``
+
+ 6. Given ``struct X { explicit operator bool(); };``, and an instance ``x`` of
+ ``struct X``, the conditional return ``if (x) return true; return false;``
+ becomes ``return static_cast<bool>(x);``
+
+Options
+-------
+
+.. option:: ChainedConditionalReturn
+
+ If non-zero, conditional boolean return statements at the end of an
+ ``if/else if`` chain will be transformed. Default is `0`.
+
+.. option:: ChainedConditionalAssignment
+
+ If non-zero, conditional boolean assignments at the end of an ``if/else
+ if`` chain will be transformed. Default is `0`.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-simplify-subscript-expr.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-simplify-subscript-expr.rst
new file mode 100644
index 0000000..f3f44be
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-simplify-subscript-expr.rst
@@ -0,0 +1,23 @@
+.. title:: clang-tidy - readability-simplify-subscript-expr
+
+readability-simplify-subscript-expr
+===================================
+
+This check simplifies subscript expressions. Currently this covers calling
+``.data()`` and immediately doing an array subscript operation to obtain a
+single element, in which case simply calling ``operator[]`` suffice.
+
+Examples:
+
+.. code-block:: c++
+
+ std::string s = ...;
+ char c = s.data()[i]; // char c = s[i];
+
+Options
+-------
+
+.. option:: Types
+
+ The list of type(s) that triggers this check. Default is
+ `::std::basic_string;::std::basic_string_view;::std::vector;::std::array`
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-static-accessed-through-instance.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-static-accessed-through-instance.rst
new file mode 100644
index 0000000..879b87c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-static-accessed-through-instance.rst
@@ -0,0 +1,31 @@
+.. title:: clang-tidy - readability-static-accessed-through-instance
+
+readability-static-accessed-through-instance
+============================================
+
+Checks for member expressions that access static members through instances, and
+replaces them with uses of the appropriate qualified-id.
+
+Example:
+
+The following code:
+
+.. code-block:: c++
+
+ struct C {
+ static void foo();
+ static int x;
+ };
+
+ C *c1 = new C();
+ c1->foo();
+ c1->x;
+
+is changed to:
+
+.. code-block:: c++
+
+ C *c1 = new C();
+ C::foo();
+ C::x;
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-static-definition-in-anonymous-namespace.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-static-definition-in-anonymous-namespace.rst
new file mode 100644
index 0000000..c1803d4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-static-definition-in-anonymous-namespace.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - readability-static-definition-in-anonymous-namespace
+
+readability-static-definition-in-anonymous-namespace
+====================================================
+
+Finds static function and variable definitions in anonymous namespace.
+
+In this case, ``static`` is redundant, because anonymous namespace limits the
+visibility of definitions to a single translation unit.
+
+.. code-block:: c++
+
+ namespace {
+ static int a = 1; // Warning.
+ static const b = 1; // Warning.
+ }
+
+The check will apply a fix by removing the redundant ``static`` qualifier.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-string-compare.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-string-compare.rst
new file mode 100644
index 0000000..58d01d5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-string-compare.rst
@@ -0,0 +1,54 @@
+.. title:: clang-tidy - readability-string-compare
+
+readability-string-compare
+==========================
+
+Finds string comparisons using the compare method.
+
+A common mistake is to use the string's ``compare`` method instead of using the
+equality or inequality operators. The compare method is intended for sorting
+functions and thus returns a negative number, a positive number or
+zero depending on the lexicographical relationship between the strings compared.
+If an equality or inequality check can suffice, that is recommended. This is
+recommended to avoid the risk of incorrect interpretation of the return value
+and to simplify the code. The string equality and inequality operators can
+also be faster than the ``compare`` method due to early termination.
+
+Examples:
+
+.. code-block:: c++
+
+ std::string str1{"a"};
+ std::string str2{"b"};
+
+ // use str1 != str2 instead.
+ if (str1.compare(str2)) {
+ }
+
+ // use str1 == str2 instead.
+ if (!str1.compare(str2)) {
+ }
+
+ // use str1 == str2 instead.
+ if (str1.compare(str2) == 0) {
+ }
+
+ // use str1 != str2 instead.
+ if (str1.compare(str2) != 0) {
+ }
+
+ // use str1 == str2 instead.
+ if (0 == str1.compare(str2)) {
+ }
+
+ // use str1 != str2 instead.
+ if (0 != str1.compare(str2)) {
+ }
+
+ // Use str1 == "foo" instead.
+ if (str1.compare("foo") == 0) {
+ }
+
+The above code examples shows the list of if-statements that this check will
+give a warning for. All of them uses ``compare`` to check if equality or
+inequality of two strings instead of using the correct operators.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-uniqueptr-delete-release.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-uniqueptr-delete-release.rst
new file mode 100644
index 0000000..beec1d5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/readability-uniqueptr-delete-release.rst
@@ -0,0 +1,17 @@
+.. title:: clang-tidy - readability-uniqueptr-delete-release
+
+readability-uniqueptr-delete-release
+====================================
+
+Replace ``delete <unique_ptr>.release()`` with ``<unique_ptr> = nullptr``.
+The latter is shorter, simpler and does not require use of raw pointer APIs.
+
+.. code-block:: c++
+
+ std::unique_ptr<int> P;
+ delete P.release();
+
+ // becomes
+
+ std::unique_ptr<int> P;
+ P = nullptr;
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/zircon-temporary-objects.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/zircon-temporary-objects.rst
new file mode 100644
index 0000000..7491f77
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/checks/zircon-temporary-objects.rst
@@ -0,0 +1,53 @@
+.. title:: clang-tidy - zircon-temporary-objects
+
+zircon-temporary-objects
+========================
+
+Warns on construction of specific temporary objects in the Zircon kernel.
+If the object should be flagged, If the object should be flagged, the fully
+qualified type name must be explicitly passed to the check.
+
+For example, given the list of classes "Foo" and "NS::Bar", all of the
+following will trigger the warning:
+
+.. code-block:: c++
+
+ Foo();
+ Foo F = Foo();
+ func(Foo());
+
+ namespace NS {
+
+ Bar();
+
+ }
+
+With the same list, the following will not trigger the warning:
+
+.. code-block:: c++
+
+ Foo F; // Non-temporary construction okay
+ Foo F(param); // Non-temporary construction okay
+ Foo *F = new Foo(); // New construction okay
+
+ Bar(); // Not NS::Bar, so okay
+ NS::Bar B; // Non-temporary construction okay
+
+Note that objects must be explicitly specified in order to be flagged,
+and so objects that inherit a specified object will not be flagged.
+
+This check matches temporary objects without regard for inheritance and so a
+prohibited base class type does not similarly prohibit derived class types.
+
+.. code-block:: c++
+
+ class Derived : Foo {} // Derived is not explicitly disallowed
+ Derived(); // and so temporary construction is okay
+
+Options
+-------
+
+.. option:: Names
+
+ A semi-colon-separated list of fully-qualified names of C++ classes that
+ should not be constructed as temporaries. Default is empty.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/index.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/index.rst
new file mode 100644
index 0000000..ec6c24f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clang-tidy/index.rst
@@ -0,0 +1,810 @@
+==========
+Clang-Tidy
+==========
+
+.. contents::
+
+See also:
+
+.. toctree::
+ :maxdepth: 1
+
+ The list of clang-tidy checks <checks/list>
+
+:program:`clang-tidy` is a clang-based C++ "linter" tool. Its purpose is to
+provide an extensible framework for diagnosing and fixing typical programming
+errors, like style violations, interface misuse, or bugs that can be deduced via
+static analysis. :program:`clang-tidy` is modular and provides a convenient
+interface for writing new checks.
+
+
+Using clang-tidy
+================
+
+:program:`clang-tidy` is a `LibTooling`_-based tool, and it's easier to work
+with if you set up a compile command database for your project (for an example
+of how to do this see `How To Setup Tooling For LLVM`_). You can also specify
+compilation options on the command line after ``--``:
+
+.. code-block:: console
+
+ $ clang-tidy test.cpp -- -Imy_project/include -DMY_DEFINES ...
+
+:program:`clang-tidy` has its own checks and can also run Clang static analyzer
+checks. Each check has a name and the checks to run can be chosen using the
+``-checks=`` option, which specifies a comma-separated list of positive and
+negative (prefixed with ``-``) globs. Positive globs add subsets of checks,
+negative globs remove them. For example,
+
+.. code-block:: console
+
+ $ clang-tidy test.cpp -checks=-*,clang-analyzer-*,-clang-analyzer-cplusplus*
+
+will disable all default checks (``-*``) and enable all ``clang-analyzer-*``
+checks except for ``clang-analyzer-cplusplus*`` ones.
+
+The ``-list-checks`` option lists all the enabled checks. When used without
+``-checks=``, it shows checks enabled by default. Use ``-checks=*`` to see all
+available checks or with any other value of ``-checks=`` to see which checks are
+enabled by this value.
+
+.. _checks-groups-table:
+
+There are currently the following groups of checks:
+
+====================== =========================================================
+Name prefix Description
+====================== =========================================================
+``android-`` Checks related to Android.
+``boost-`` Checks related to Boost library.
+``bugprone-`` Checks that target bugprone code constructs.
+``cert-`` Checks related to CERT Secure Coding Guidelines.
+``cppcoreguidelines-`` Checks related to C++ Core Guidelines.
+``clang-analyzer-`` Clang Static Analyzer checks.
+``fuchsia-`` Checks related to Fuchsia coding conventions.
+``google-`` Checks related to Google coding conventions.
+``hicpp-`` Checks related to High Integrity C++ Coding Standard.
+``llvm-`` Checks related to the LLVM coding conventions.
+``misc-`` Checks that we didn't have a better category for.
+``modernize-`` Checks that advocate usage of modern (currently "modern"
+ means "C++11") language constructs.
+``mpi-`` Checks related to MPI (Message Passing Interface).
+``objc-`` Checks related to Objective-C coding conventions.
+``performance-`` Checks that target performance-related issues.
+``portability-`` Checks that target portability-related issues that don't
+ relate to any particular coding style.
+``readability-`` Checks that target readability-related issues that don't
+ relate to any particular coding style.
+``zircon-`` Checks related to Zircon kernel coding conventions.
+====================== =========================================================
+
+Clang diagnostics are treated in a similar way as check diagnostics. Clang
+diagnostics are displayed by :program:`clang-tidy` and can be filtered out using
+``-checks=`` option. However, the ``-checks=`` option does not affect
+compilation arguments, so it can not turn on Clang warnings which are not
+already turned on in build configuration. The ``-warnings-as-errors=`` option
+upgrades any warnings emitted under the ``-checks=`` flag to errors (but it
+does not enable any checks itself).
+
+Clang diagnostics have check names starting with ``clang-diagnostic-``.
+Diagnostics which have a corresponding warning option, are named
+``clang-diagnostic-<warning-option>``, e.g. Clang warning controlled by
+``-Wliteral-conversion`` will be reported with check name
+``clang-diagnostic-literal-conversion``.
+
+The ``-fix`` flag instructs :program:`clang-tidy` to fix found errors if
+supported by corresponding checks.
+
+An overview of all the command-line options:
+
+.. code-block:: console
+
+ $ clang-tidy --help
+ USAGE: clang-tidy [options] <source0> [... <sourceN>]
+
+ OPTIONS:
+
+ Generic Options:
+
+ -help - Display available options (-help-hidden for more)
+ -help-list - Display list of available options (-help-list-hidden for more)
+ -version - Display the version of this program
+
+ clang-tidy options:
+
+ -checks=<string> -
+ Comma-separated list of globs with optional '-'
+ prefix. Globs are processed in order of
+ appearance in the list. Globs without '-'
+ prefix add checks with matching names to the
+ set, globs with the '-' prefix remove checks
+ with matching names from the set of enabled
+ checks. This option's value is appended to the
+ value of the 'Checks' option in .clang-tidy
+ file, if any.
+ -config=<string> -
+ Specifies a configuration in YAML/JSON format:
+ -config="{Checks: '*',
+ CheckOptions: [{key: x,
+ value: y}]}"
+ When the value is empty, clang-tidy will
+ attempt to find a file named .clang-tidy for
+ each source file in its parent directories.
+ -dump-config -
+ Dumps configuration in the YAML format to
+ stdout. This option can be used along with a
+ file name (and '--' if the file is outside of a
+ project with configured compilation database).
+ The configuration used for this file will be
+ printed.
+ Use along with -checks=* to include
+ configuration of all checks.
+ -enable-check-profile -
+ Enable per-check timing profiles, and print a
+ report to stderr.
+ -explain-config -
+ For each enabled check explains, where it is
+ enabled, i.e. in clang-tidy binary, command
+ line or a specific configuration file.
+ -export-fixes=<filename> -
+ YAML file to store suggested fixes in. The
+ stored fixes can be applied to the input source
+ code with clang-apply-replacements.
+ -extra-arg=<string> - Additional argument to append to the compiler command line
+ -extra-arg-before=<string> - Additional argument to prepend to the compiler command line
+ -fix -
+ Apply suggested fixes. Without -fix-errors
+ clang-tidy will bail out if any compilation
+ errors were found.
+ -fix-errors -
+ Apply suggested fixes even if compilation
+ errors were found. If compiler errors have
+ attached fix-its, clang-tidy will apply them as
+ well.
+ -format-style=<string> -
+ Style for formatting code around applied fixes:
+ - 'none' (default) turns off formatting
+ - 'file' (literally 'file', not a placeholder)
+ uses .clang-format file in the closest parent
+ directory
+ - '{ <json> }' specifies options inline, e.g.
+ -format-style='{BasedOnStyle: llvm, IndentWidth: 8}'
+ - 'llvm', 'google', 'webkit', 'mozilla'
+ See clang-format documentation for the up-to-date
+ information about formatting styles and options.
+ This option overrides the 'FormatStyle` option in
+ .clang-tidy file, if any.
+ -header-filter=<string> -
+ Regular expression matching the names of the
+ headers to output diagnostics from. Diagnostics
+ from the main file of each translation unit are
+ always displayed.
+ Can be used together with -line-filter.
+ This option overrides the 'HeaderFilter' option
+ in .clang-tidy file, if any.
+ -line-filter=<string> -
+ List of files with line ranges to filter the
+ warnings. Can be used together with
+ -header-filter. The format of the list is a
+ JSON array of objects:
+ [
+ {"name":"file1.cpp","lines":[[1,3],[5,7]]},
+ {"name":"file2.h"}
+ ]
+ -list-checks -
+ List all enabled checks and exit. Use with
+ -checks=* to list all available checks.
+ -p=<string> - Build path
+ -quiet -
+ Run clang-tidy in quiet mode. This suppresses
+ printing statistics about ignored warnings and
+ warnings treated as errors if the respective
+ options are specified.
+ -store-check-profile=<prefix> -
+ By default reports are printed in tabulated
+ format to stderr. When this option is passed,
+ these per-TU profiles are instead stored as JSON.
+ -system-headers - Display the errors from system headers.
+ -vfsoverlay=<filename> -
+ Overlay the virtual filesystem described by file
+ over the real file system.
+ -warnings-as-errors=<string> -
+ Upgrades warnings to errors. Same format as
+ '-checks'.
+ This option's value is appended to the value of
+ the 'WarningsAsErrors' option in .clang-tidy
+ file, if any.
+
+ -p <build-path> is used to read a compile command database.
+
+ For example, it can be a CMake build directory in which a file named
+ compile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
+ CMake option to get this output). When no build path is specified,
+ a search for compile_commands.json will be attempted through all
+ parent paths of the first input file . See:
+ http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an
+ example of setting up Clang Tooling on a source tree.
+
+ <source0> ... specify the paths of source files. These paths are
+ looked up in the compile command database. If the path of a file is
+ absolute, it needs to point into CMake's source tree. If the path is
+ relative, the current working directory needs to be in the CMake
+ source tree and the file must be in a subdirectory of the current
+ working directory. "./" prefixes in the relative files will be
+ automatically removed, but the rest of a relative path must be a
+ suffix of a path in the compile command database.
+
+
+ Configuration files:
+ clang-tidy attempts to read configuration for each source file from a
+ .clang-tidy file located in the closest parent directory of the source
+ file. If any configuration options have a corresponding command-line
+ option, command-line option takes precedence. The effective
+ configuration can be inspected using -dump-config:
+
+ $ clang-tidy -dump-config
+ ---
+ Checks: '-*,some-check'
+ WarningsAsErrors: ''
+ HeaderFilterRegex: ''
+ FormatStyle: none
+ User: user
+ CheckOptions:
+ - key: some-check.SomeOption
+ value: 'some value'
+ ...
+
+:program:`clang-tidy` diagnostics are intended to call out code that does
+not adhere to a coding standard, or is otherwise problematic in some way.
+However, if it is known that the code is correct, the check-specific ways
+to silence the diagnostics could be used, if they are available (e.g.
+bugprone-use-after-move can be silenced by re-initializing the variable after
+it has been moved out, misc-string-integer-assignment can be suppressed by
+explicitly casting the integer to char, readability-implicit-bool-conversion
+can also be suppressed by using explicit casts, etc.). If they are not
+available or if changing the semantics of the code is not desired,
+the ``NOLINT`` or ``NOLINTNEXTLINE`` comments can be used instead. For example:
+
+.. code-block:: c++
+
+ class Foo
+ {
+ // Silent all the diagnostics for the line
+ Foo(int param); // NOLINT
+
+ // Silent only the specified checks for the line
+ Foo(double param); // NOLINT(google-explicit-constructor, google-runtime-int)
+
+ // Silent only the specified diagnostics for the next line
+ // NOLINTNEXTLINE(google-explicit-constructor, google-runtime-int)
+ Foo(bool param);
+ };
+
+The formal syntax of ``NOLINT``/``NOLINTNEXTLINE`` is the following:
+
+.. parsed-literal::
+
+ lint-comment:
+ lint-command
+ lint-command lint-args
+
+ lint-args:
+ **(** check-name-list **)**
+
+ check-name-list:
+ *check-name*
+ check-name-list **,** *check-name*
+
+ lint-command:
+ **NOLINT**
+ **NOLINTNEXTLINE**
+
+Note that whitespaces between ``NOLINT``/``NOLINTNEXTLINE`` and the opening
+parenthesis are not allowed (in this case the comment will be treated just as
+``NOLINT``/``NOLINTNEXTLINE``), whereas in check names list (inside
+the parenthesis) whitespaces can be used and will be ignored.
+
+.. _LibTooling: http://clang.llvm.org/docs/LibTooling.html
+.. _How To Setup Tooling For LLVM: http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+
+
+Getting Involved
+================
+
+:program:`clang-tidy` has several own checks and can run Clang static analyzer
+checks, but its power is in the ability to easily write custom checks.
+
+Checks are organized in modules, which can be linked into :program:`clang-tidy`
+with minimal or no code changes in :program:`clang-tidy`.
+
+Checks can plug into the analysis on the preprocessor level using `PPCallbacks`_
+or on the AST level using `AST Matchers`_. When an error is found, checks can
+report them in a way similar to how Clang diagnostics work. A fix-it hint can be
+attached to a diagnostic message.
+
+The interface provided by :program:`clang-tidy` makes it easy to write useful
+and precise checks in just a few lines of code. If you have an idea for a good
+check, the rest of this document explains how to do this.
+
+There are a few tools particularly useful when developing clang-tidy checks:
+ * ``add_new_check.py`` is a script to automate the process of adding a new
+ check, it will create the check, update the CMake file and create a test;
+ * ``rename_check.py`` does what the script name suggests, renames an existing
+ check;
+ * :program:`clang-query` is invaluable for interactive prototyping of AST
+ matchers and exploration of the Clang AST;
+ * `clang-check`_ with the ``-ast-dump`` (and optionally ``-ast-dump-filter``)
+ provides a convenient way to dump AST of a C++ program.
+
+
+.. _AST Matchers: http://clang.llvm.org/docs/LibASTMatchers.html
+.. _PPCallbacks: http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html
+.. _clang-check: http://clang.llvm.org/docs/ClangCheck.html
+
+
+Choosing the Right Place for your Check
+---------------------------------------
+
+If you have an idea of a check, you should decide whether it should be
+implemented as a:
+
++ *Clang diagnostic*: if the check is generic enough, targets code patterns that
+ most probably are bugs (rather than style or readability issues), can be
+ implemented effectively and with extremely low false positive rate, it may
+ make a good Clang diagnostic.
+
++ *Clang static analyzer check*: if the check requires some sort of control flow
+ analysis, it should probably be implemented as a static analyzer check.
+
++ *clang-tidy check* is a good choice for linter-style checks, checks that are
+ related to a certain coding style, checks that address code readability, etc.
+
+
+Preparing your Workspace
+------------------------
+
+If you are new to LLVM development, you should read the `Getting Started with
+the LLVM System`_, `Using Clang Tools`_ and `How To Setup Tooling For LLVM`_
+documents to check out and build LLVM, Clang and Clang Extra Tools with CMake.
+
+Once you are done, change to the ``llvm/tools/clang/tools/extra`` directory, and
+let's start!
+
+.. _Getting Started with the LLVM System: http://llvm.org/docs/GettingStarted.html
+.. _Using Clang Tools: http://clang.llvm.org/docs/ClangTools.html
+
+
+The Directory Structure
+-----------------------
+
+:program:`clang-tidy` source code resides in the
+``llvm/tools/clang/tools/extra`` directory and is structured as follows:
+
+::
+
+ clang-tidy/ # Clang-tidy core.
+ |-- ClangTidy.h # Interfaces for users and checks.
+ |-- ClangTidyModule.h # Interface for clang-tidy modules.
+ |-- ClangTidyModuleRegistry.h # Interface for registering of modules.
+ ...
+ |-- google/ # Google clang-tidy module.
+ |-+
+ |-- GoogleTidyModule.cpp
+ |-- GoogleTidyModule.h
+ ...
+ |-- llvm/ # LLVM clang-tidy module.
+ |-+
+ |-- LLVMTidyModule.cpp
+ |-- LLVMTidyModule.h
+ ...
+ |-- objc/ # Objective-C clang-tidy module.
+ |-+
+ |-- ObjCTidyModule.cpp
+ |-- ObjCTidyModule.h
+ ...
+ |-- tool/ # Sources of the clang-tidy binary.
+ ...
+ test/clang-tidy/ # Integration tests.
+ ...
+ unittests/clang-tidy/ # Unit tests.
+ |-- ClangTidyTest.h
+ |-- GoogleModuleTest.cpp
+ |-- LLVMModuleTest.cpp
+ |-- ObjCModuleTest.cpp
+ ...
+
+
+Writing a clang-tidy Check
+--------------------------
+
+So you have an idea of a useful check for :program:`clang-tidy`.
+
+First, if you're not familiar with LLVM development, read through the `Getting
+Started with LLVM`_ document for instructions on setting up your workflow and
+the `LLVM Coding Standards`_ document to familiarize yourself with the coding
+style used in the project. For code reviews we mostly use `LLVM Phabricator`_.
+
+.. _Getting Started with LLVM: http://llvm.org/docs/GettingStarted.html
+.. _LLVM Coding Standards: http://llvm.org/docs/CodingStandards.html
+.. _LLVM Phabricator: http://llvm.org/docs/Phabricator.html
+
+Next, you need to decide which module the check belongs to. Modules
+are located in subdirectories of `clang-tidy/
+<http://reviews.llvm.org/diffusion/L/browse/clang-tools-extra/trunk/clang-tidy/>`_
+and contain checks targeting a certain aspect of code quality (performance,
+readability, etc.), certain coding style or standard (Google, LLVM, CERT, etc.)
+or a widely used API (e.g. MPI). Their names are same as user-facing check
+groups names described :ref:`above <checks-groups-table>`.
+
+After choosing the module and the name for the check, run the
+``clang-tidy/add_new_check.py`` script to create the skeleton of the check and
+plug it to :program:`clang-tidy`. It's the recommended way of adding new checks.
+
+If we want to create a `readability-awesome-function-names`, we would run:
+
+.. code-block:: console
+
+ $ clang-tidy/add_new_check.py readability awesome-function-names
+
+
+The ``add_new_check.py`` script will:
+ * create the class for your check inside the specified module's directory and
+ register it in the module and in the build system;
+ * create a lit test file in the ``test/clang-tidy/`` directory;
+ * create a documentation file and include it into the
+ ``docs/clang-tidy/checks/list.rst``.
+
+Let's see in more detail at the check class definition:
+
+.. code-block:: c++
+
+ ...
+
+ #include "../ClangTidy.h"
+
+ namespace clang {
+ namespace tidy {
+ namespace readability {
+
+ ...
+ class AwesomeFunctionNamesCheck : public ClangTidyCheck {
+ public:
+ AwesomeFunctionNamesCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ };
+
+ } // namespace readability
+ } // namespace tidy
+ } // namespace clang
+
+ ...
+
+Constructor of the check receives the ``Name`` and ``Context`` parameters, and
+must forward them to the ``ClangTidyCheck`` constructor.
+
+In our case the check needs to operate on the AST level and it overrides the
+``registerMatchers`` and ``check`` methods. If we wanted to analyze code on the
+preprocessor level, we'd need instead to override the ``registerPPCallbacks``
+method.
+
+In the ``registerMatchers`` method we create an AST Matcher (see `AST Matchers`_
+for more information) that will find the pattern in the AST that we want to
+inspect. The results of the matching are passed to the ``check`` method, which
+can further inspect them and report diagnostics.
+
+.. code-block:: c++
+
+ using namespace ast_matchers;
+
+ void AwesomeFunctionNamesCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(functionDecl().bind("x"), this);
+ }
+
+ void AwesomeFunctionNamesCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>("x");
+ if (MatchedDecl->getName().startswith("awesome_"))
+ return;
+ diag(MatchedDecl->getLocation(), "function %0 is insufficiently awesome")
+ << MatchedDecl
+ << FixItHint::CreateInsertion(MatchedDecl->getLocation(), "awesome_");
+ }
+
+(If you want to see an example of a useful check, look at
+`clang-tidy/google/ExplicitConstructorCheck.h
+<http://reviews.llvm.org/diffusion/L/browse/clang-tools-extra/trunk/clang-tidy/google/ExplicitConstructorCheck.h>`_
+and `clang-tidy/google/ExplicitConstructorCheck.cpp
+<http://reviews.llvm.org/diffusion/L/browse/clang-tools-extra/trunk/clang-tidy/google/ExplicitConstructorCheck.cpp>`_).
+
+
+Registering your Check
+----------------------
+
+(The ``add_new_check.py`` takes care of registering the check in an existing
+module. If you want to create a new module or know the details, read on.)
+
+The check should be registered in the corresponding module with a distinct name:
+
+.. code-block:: c++
+
+ class MyModule : public ClangTidyModule {
+ public:
+ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+ CheckFactories.registerCheck<ExplicitConstructorCheck>(
+ "my-explicit-constructor");
+ }
+ };
+
+Now we need to register the module in the ``ClangTidyModuleRegistry`` using a
+statically initialized variable:
+
+.. code-block:: c++
+
+ static ClangTidyModuleRegistry::Add<MyModule> X("my-module",
+ "Adds my lint checks.");
+
+
+When using LLVM build system, we need to use the following hack to ensure the
+module is linked into the :program:`clang-tidy` binary:
+
+Add this near the ``ClangTidyModuleRegistry::Add<MyModule>`` variable:
+
+.. code-block:: c++
+
+ // This anchor is used to force the linker to link in the generated object file
+ // and thus register the MyModule.
+ volatile int MyModuleAnchorSource = 0;
+
+And this to the main translation unit of the :program:`clang-tidy` binary (or
+the binary you link the ``clang-tidy`` library in)
+``clang-tidy/tool/ClangTidyMain.cpp``:
+
+.. code-block:: c++
+
+ // This anchor is used to force the linker to link the MyModule.
+ extern volatile int MyModuleAnchorSource;
+ static int MyModuleAnchorDestination = MyModuleAnchorSource;
+
+
+Configuring Checks
+------------------
+
+If a check needs configuration options, it can access check-specific options
+using the ``Options.get<Type>("SomeOption", DefaultValue)`` call in the check
+constructor. In this case the check should also override the
+``ClangTidyCheck::storeOptions`` method to make the options provided by the
+check discoverable. This method lets :program:`clang-tidy` know which options
+the check implements and what the current values are (e.g. for the
+``-dump-config`` command line option).
+
+.. code-block:: c++
+
+ class MyCheck : public ClangTidyCheck {
+ const unsigned SomeOption1;
+ const std::string SomeOption2;
+
+ public:
+ MyCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ SomeOption(Options.get("SomeOption1", -1U)),
+ SomeOption(Options.get("SomeOption2", "some default")) {}
+
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override {
+ Options.store(Opts, "SomeOption1", SomeOption1);
+ Options.store(Opts, "SomeOption2", SomeOption2);
+ }
+ ...
+
+Assuming the check is registered with the name "my-check", the option can then
+be set in a ``.clang-tidy`` file in the following way:
+
+.. code-block:: yaml
+
+ CheckOptions:
+ - key: my-check.SomeOption1
+ value: 123
+ - key: my-check.SomeOption2
+ value: 'some other value'
+
+If you need to specify check options on a command line, you can use the inline
+YAML format:
+
+.. code-block:: console
+
+ $ clang-tidy -config="{CheckOptions: [{key: a, value: b}, {key: x, value: y}]}" ...
+
+
+Testing Checks
+--------------
+
+To run tests for :program:`clang-tidy` use the command:
+
+.. code-block:: console
+
+ $ ninja check-clang-tools
+
+:program:`clang-tidy` checks can be tested using either unit tests or
+`lit`_ tests. Unit tests may be more convenient to test complex replacements
+with strict checks. `Lit`_ tests allow using partial text matching and regular
+expressions which makes them more suitable for writing compact tests for
+diagnostic messages.
+
+The ``check_clang_tidy.py`` script provides an easy way to test both
+diagnostic messages and fix-its. It filters out ``CHECK`` lines from the test
+file, runs :program:`clang-tidy` and verifies messages and fixes with two
+separate `FileCheck`_ invocations: once with FileCheck's directive
+prefix set to ``CHECK-MESSAGES``, validating the diagnostic messages,
+and once with the directive prefix set to ``CHECK-FIXES``, running
+against the fixed code (i.e., the code after generated fix-its are
+applied). In particular, ``CHECK-FIXES:`` can be used to check
+that code was not modified by fix-its, by checking that it is present
+unchanged in the fixed code. The full set of `FileCheck`_ directives
+is available (e.g., ``CHECK-MESSAGES-SAME:``, ``CHECK-MESSAGES-NOT:``), though
+typically the basic ``CHECK`` forms (``CHECK-MESSAGES`` and ``CHECK-FIXES``)
+are sufficient for clang-tidy tests. Note that the `FileCheck`_
+documentation mostly assumes the default prefix (``CHECK``), and hence
+describes the directive as ``CHECK:``, ``CHECK-SAME:``, ``CHECK-NOT:``, etc.
+Replace ``CHECK`` by either ``CHECK-FIXES`` or ``CHECK-MESSAGES`` for
+clang-tidy tests.
+
+An additional check enabled by ``check_clang_tidy.py`` ensures that
+if `CHECK-MESSAGES:` is used in a file then every warning or error
+must have an associated CHECK in that file.
+
+To use the ``check_clang_tidy.py`` script, put a .cpp file with the
+appropriate ``RUN`` line in the ``test/clang-tidy`` directory. Use
+``CHECK-MESSAGES:`` and ``CHECK-FIXES:`` lines to write checks against
+diagnostic messages and fixed code.
+
+It's advised to make the checks as specific as possible to avoid checks matching
+to incorrect parts of the input. Use ``[[@LINE+X]]``/``[[@LINE-X]]``
+substitutions and distinct function and variable names in the test code.
+
+Here's an example of a test using the ``check_clang_tidy.py`` script (the full
+source code is at `test/clang-tidy/google-readability-casting.cpp`_):
+
+.. code-block:: c++
+
+ // RUN: %check_clang_tidy %s google-readability-casting %t
+
+ void f(int a) {
+ int b = (int)a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant cast to the same type [google-readability-casting]
+ // CHECK-FIXES: int b = a;
+ }
+
+To check more than one scenario in the same test file use
+``-check-suffix=SUFFIX-NAME`` on ``check_clang_tidy.py`` command line.
+With ``-check-suffix=SUFFIX-NAME`` you need to replace your ``CHECK-*``
+directives with ``CHECK-MESSAGES-SUFFIX-NAME`` and ``CHECK-FIXES-SUFFIX-NAME``.
+
+Here's an example:
+
+.. code-block:: c++
+
+ // RUN: %check_clang_tidy -check-suffix=USING-A %s misc-unused-using-decls %t -- -- -DUSING_A
+ // RUN: %check_clang_tidy -check-suffix=USING-B %s misc-unused-using-decls %t -- -- -DUSING_B
+ // RUN: %check_clang_tidy %s misc-unused-using-decls %t
+ ...
+ // CHECK-MESSAGES-USING-A: :[[@LINE-8]]:10: warning: using decl 'A' {{.*}}
+ // CHECK-MESSAGES-USING-B: :[[@LINE-7]]:10: warning: using decl 'B' {{.*}}
+ // CHECK-MESSAGES: :[[@LINE-6]]:10: warning: using decl 'C' {{.*}}
+ // CHECK-FIXES-USING-A-NOT: using a::A;$
+ // CHECK-FIXES-USING-B-NOT: using a::B;$
+ // CHECK-FIXES-NOT: using a::C;$
+
+
+There are many dark corners in the C++ language, and it may be difficult to make
+your check work perfectly in all cases, especially if it issues fix-it hints. The
+most frequent pitfalls are macros and templates:
+
+1. code written in a macro body/template definition may have a different meaning
+ depending on the macro expansion/template instantiation;
+2. multiple macro expansions/template instantiations may result in the same code
+ being inspected by the check multiple times (possibly, with different
+ meanings, see 1), and the same warning (or a slightly different one) may be
+ issued by the check multiple times; :program:`clang-tidy` will deduplicate
+ _identical_ warnings, but if the warnings are slightly different, all of them
+ will be shown to the user (and used for applying fixes, if any);
+3. making replacements to a macro body/template definition may be fine for some
+ macro expansions/template instantiations, but easily break some other
+ expansions/instantiations.
+
+.. _lit: http://llvm.org/docs/CommandGuide/lit.html
+.. _FileCheck: http://llvm.org/docs/CommandGuide/FileCheck.html
+.. _test/clang-tidy/google-readability-casting.cpp: http://reviews.llvm.org/diffusion/L/browse/clang-tools-extra/trunk/test/clang-tidy/google-readability-casting.cpp
+
+
+Running clang-tidy on LLVM
+--------------------------
+
+To test a check it's best to try it out on a larger code base. LLVM and Clang
+are the natural targets as you already have the source code around. The most
+convenient way to run :program:`clang-tidy` is with a compile command database;
+CMake can automatically generate one, for a description of how to enable it see
+`How To Setup Tooling For LLVM`_. Once ``compile_commands.json`` is in place and
+a working version of :program:`clang-tidy` is in ``PATH`` the entire code base
+can be analyzed with ``clang-tidy/tool/run-clang-tidy.py``. The script executes
+:program:`clang-tidy` with the default set of checks on every translation unit
+in the compile command database and displays the resulting warnings and errors.
+The script provides multiple configuration flags.
+
+* The default set of checks can be overridden using the ``-checks`` argument,
+ taking the identical format as :program:`clang-tidy` does. For example
+ ``-checks=-*,modernize-use-override`` will run the ``modernize-use-override``
+ check only.
+
+* To restrict the files examined you can provide one or more regex arguments
+ that the file names are matched against.
+ ``run-clang-tidy.py clang-tidy/.*Check\.cpp`` will only analyze clang-tidy
+ checks. It may also be necessary to restrict the header files warnings are
+ displayed from using the ``-header-filter`` flag. It has the same behavior
+ as the corresponding :program:`clang-tidy` flag.
+
+* To apply suggested fixes ``-fix`` can be passed as an argument. This gathers
+ all changes in a temporary directory and applies them. Passing ``-format``
+ will run clang-format over changed lines.
+
+
+On checks profiling
+-------------------
+
+:program:`clang-tidy` can collect per-check profiling info, and output it
+for each processed source file (translation unit).
+
+To enable profiling info collection, use the ``-enable-check-profile`` argument.
+The timings will be output to ``stderr`` as a table. Example output:
+
+.. code-block:: console
+
+ $ clang-tidy -enable-check-profile -checks=-*,readability-function-size source.cpp
+ ===-------------------------------------------------------------------------===
+ clang-tidy checks profiling
+ ===-------------------------------------------------------------------------===
+ Total Execution Time: 1.0282 seconds (1.0258 wall clock)
+
+ ---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name ---
+ 0.9136 (100.0%) 0.1146 (100.0%) 1.0282 (100.0%) 1.0258 (100.0%) readability-function-size
+ 0.9136 (100.0%) 0.1146 (100.0%) 1.0282 (100.0%) 1.0258 (100.0%) Total
+
+It can also store that data as JSON files for further processing. Example output:
+
+.. code-block:: console
+
+ $ clang-tidy -enable-check-profile -store-check-profile=. -checks=-*,readability-function-size source.cpp
+ $ # Note that there won't be timings table printed to the console.
+ $ ls /tmp/out/
+ 20180516161318717446360-source.cpp.json
+ $ cat 20180516161318717446360-source.cpp.json
+ {
+ "file": "/path/to/source.cpp",
+ "timestamp": "2018-05-16 16:13:18.717446360",
+ "profile": {
+ "time.clang-tidy.readability-function-size.wall": 1.0421266555786133e+00,
+ "time.clang-tidy.readability-function-size.user": 9.2088400000005421e-01,
+ "time.clang-tidy.readability-function-size.sys": 1.2418899999999974e-01
+ }
+ }
+
+There is only one argument that controls profile storage:
+
+* ``-store-check-profile=<prefix>``
+
+ By default reports are printed in tabulated format to stderr. When this option
+ is passed, these per-TU profiles are instead stored as JSON.
+ If the prefix is not an absolute path, it is considered to be relative to the
+ directory from where you have run :program:`clang-tidy`. All ``.`` and ``..``
+ patterns in the path are collapsed, and symlinks are resolved.
+
+ Example:
+ Let's suppose you have a source file named ``example.cpp``, located in the
+ ``/source`` directory. Only the input filename is used, not the full path
+ to the source file. Additionally, it is prefixed with the current timestamp.
+
+ * If you specify ``-store-check-profile=/tmp``, then the profile will be saved
+ to ``/tmp/<ISO8601-like timestamp>-example.cpp.json``
+
+ * If you run :program:`clang-tidy` from within ``/foo`` directory, and specify
+ ``-store-check-profile=.``, then the profile will still be saved to
+ ``/foo/<ISO8601-like timestamp>-example.cpp.json``
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/clangd.rst b/src/third_party/llvm-project/clang-tools-extra/docs/clangd.rst
new file mode 100644
index 0000000..97736ef
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/clangd.rst
@@ -0,0 +1,123 @@
+============
+Clangd
+============
+
+.. contents::
+
+.. toctree::
+ :maxdepth: 1
+
+:program:`Clangd` is an implementation of the `Language Server Protocol
+<https://github.com/Microsoft/language-server-protocol>`_ leveraging Clang.
+Clangd's goal is to provide language "smartness" features like code completion,
+find references, etc. for clients such as C/C++ Editors.
+
+Using Clangd
+==================
+
+:program:`Clangd` is not meant to be used by C/C++ developers directly but
+rather from a client implementing the protocol. A client would be typically
+implemented in an IDE or an editor.
+
+At the moment, `Visual Studio Code <https://code.visualstudio.com/>`_ is mainly
+used in order to test :program:`Clangd` but more clients are likely to make
+use of :program:`Clangd` in the future as it matures and becomes a production
+quality tool. If you are interested in trying :program:`Clangd` in combination
+with Visual Studio Code, you can start by `installing Clangd`_ or
+`building Clangd`_, then open Visual Studio Code in the clangd-vscode folder and
+launch the extension.
+
+Installing Clangd
+==================
+
+Packages are available for debian-based distributions, see the `LLVM packages
+page <http://apt.llvm.org/>`_. :program:`Clangd` is included in the
+`clang-tools` package.
+However, it is a good idea to check your distribution's packaging system first
+as it might already be available.
+
+Otherwise, you can install :program:`Clangd` by `building Clangd`_ first.
+
+Building Clangd
+==================
+
+You can follow the instructions for `building Clang
+<https://clang.llvm.org/get_started.html>`_ but "extra Clang tools" is **not**
+optional.
+
+Current Status
+==================
+
+Many features could be implemented in :program:`Clangd`.
+Here is a list of features that could be useful with the status of whether or
+not they are already implemented in :program:`Clangd` and specified in the
+Language Server Protocol. Note that for some of the features, it is not clear
+whether or not they should be part of the Language Server Protocol, so those
+features might be eventually developed outside :program:`Clangd` or as an
+extension to the protocol.
+
++-------------------------------------+------------+----------+
+| C/C++ Editor feature | LSP | Clangd |
++=====================================+============+==========+
+| Formatting | Yes | Yes |
++-------------------------------------+------------+----------+
+| Completion | Yes | Yes |
++-------------------------------------+------------+----------+
+| Diagnostics | Yes | Yes |
++-------------------------------------+------------+----------+
+| Fix-its | Yes | Yes |
++-------------------------------------+------------+----------+
+| Go to Definition | Yes | Yes |
++-------------------------------------+------------+----------+
+| Signature Help | Yes | Yes |
++-------------------------------------+------------+----------+
+| Document Highlights | Yes | Yes |
++-------------------------------------+------------+----------+
+| Rename | Yes | Yes |
++-------------------------------------+------------+----------+
+| Source hover | Yes | Yes |
++-------------------------------------+------------+----------+
+| Find References | Yes | No |
++-------------------------------------+------------+----------+
+| Code Lens | Yes | No |
++-------------------------------------+------------+----------+
+| Document Symbols | Yes | Yes |
++-------------------------------------+------------+----------+
+| Workspace Symbols | Yes | No |
++-------------------------------------+------------+----------+
+| Syntax and Semantic Coloring | No | No |
++-------------------------------------+------------+----------+
+| Code folding | No | No |
++-------------------------------------+------------+----------+
+| Call hierarchy | No | No |
++-------------------------------------+------------+----------+
+| Type hierarchy | No | No |
++-------------------------------------+------------+----------+
+| Organize Includes | No | No |
++-------------------------------------+------------+----------+
+| Quick Assist | No | No |
++-------------------------------------+------------+----------+
+| Extract Local Variable | No | No |
++-------------------------------------+------------+----------+
+| Extract Function/Method | No | No |
++-------------------------------------+------------+----------+
+| Hide Method | No | No |
++-------------------------------------+------------+----------+
+| Implement Method | No | No |
++-------------------------------------+------------+----------+
+| Gen. Getters/Setters | No | No |
++-------------------------------------+------------+----------+
+
+Getting Involved
+==================
+
+A good place for interested contributors is the `Clang developer mailing list
+<http://lists.llvm.org/mailman/listinfo/cfe-dev>`_.
+If you're also interested in contributing patches to :program:`Clangd`, take a
+look at the `LLVM Developer Policy
+<http://llvm.org/docs/DeveloperPolicy.html>`_ and `Code Reviews
+<http://llvm.org/docs/Phabricator.html>`_ page. Contributions of new features
+to the `Language Server Protocol
+<https://github.com/Microsoft/language-server-protocol>`_ itself would also be
+very useful, so that :program:`Clangd` can eventually implement them in a
+conforming way.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/conf.py b/src/third_party/llvm-project/clang-tools-extra/docs/conf.py
new file mode 100644
index 0000000..5ac1821
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/conf.py
@@ -0,0 +1,243 @@
+# -*- coding: utf-8 -*-
+#
+# Extra Clang Tools documentation build configuration file, created by
+# sphinx-quickstart on Wed Feb 13 10:00:18 2013.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+from datetime import date
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.todo', 'sphinx.ext.mathjax']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Extra Clang Tools'
+copyright = u'2007-%d, The Clang Team' % date.today().year
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short version.
+version = '7'
+# The full version, including alpha/beta/rc tags.
+release = '7'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'friendly'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'haiku'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'ExtraClangToolsdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'ExtraClangTools.tex', u'Extra Clang Tools Documentation',
+ u'The Clang Team', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'extraclangtools', u'Extra Clang Tools Documentation',
+ [u'The Clang Team'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'ExtraClangTools', u'Extra Clang Tools Documentation',
+ u'The Clang Team', 'ExtraClangTools', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/cpp11-migrate.rst b/src/third_party/llvm-project/clang-tools-extra/docs/cpp11-migrate.rst
new file mode 100644
index 0000000..0a42961
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/cpp11-migrate.rst
@@ -0,0 +1,4 @@
+:orphan:
+
+All :program:`clang-modernize` transforms have moved to :doc:`clang-tidy/index`
+(see the ``modernize`` module).
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/doxygen-mainpage.dox b/src/third_party/llvm-project/clang-tools-extra/docs/doxygen-mainpage.dox
new file mode 100644
index 0000000..a4527b8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/doxygen-mainpage.dox
@@ -0,0 +1,9 @@
+/// \mainpage clang-tools
+///
+/// \section main_intro Introduction
+/// Welcome to clang tools.
+///
+/// This documentation describes the **internal** software that makes
+/// up clang tools, not the **external** use of clang tools. For
+/// usage instructions, please see the programmer's guide or reference
+/// manual.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/doxygen.cfg.in b/src/third_party/llvm-project/clang-tools-extra/docs/doxygen.cfg.in
new file mode 100644
index 0000000..8809588
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/doxygen.cfg.in
@@ -0,0 +1,2305 @@
+# Doxyfile 1.8.6
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = clang-tools
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = @PACKAGE_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = @abs_builddir@/doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH = ../..
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 2
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 2
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = NO
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = \
+ @abs_srcdir@/../change-namespace \
+ @abs_srcdir@/../clang-apply-replacements \
+ @abs_srcdir@/../clang-doc \
+ @abs_srcdir@/../clang-move \
+ @abs_srcdir@/../clang-query \
+ @abs_srcdir@/../clang-reorder-fields \
+ @abs_srcdir@/../clang-tidy \
+ @abs_srcdir@/../clangd \
+ @abs_srcdir@/../include-fixer \
+ @abs_srcdir@/../modularize \
+ @abs_srcdir@/../pp-trace \
+ @abs_srcdir@/../tool-template \
+ @abs_srcdir@/doxygen-mainpage.dox
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = YES
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 4
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX = clang::
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = @clang_tools_doxygen_generate_qhp@
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE = @clang_tools_doxygen_qch_filename@
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = @clang_tools_doxygen_qhp_namespace@
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME = @clang_tools_doxygen_qhp_cust_filter_name@
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS = @clang_tools_doxygen_qhp_cust_filter_attrs@
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION = @clang_tools_doxygen_qhelpgenerator_path@
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = @enable_searchengine@
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavours of web server based searching depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools. See
+# the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = @enable_server_based_search@
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = @enable_external_search@
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL = @searchengine_url@
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID = clang-tools
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS = @extra_search_mappings@
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH = @abs_srcdir@/../../../include \
+ @abs_srcdir@/../../../../../include
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = LLVM_ALIGNAS(x)=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have an
+# all uppercase name, and do not end with a semicolon. Such function macros are
+# typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have an unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = YES
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = YES
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = @DOT_IMAGE_FORMAT@
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH = @DOT@
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/include-fixer.rst b/src/third_party/llvm-project/clang-tools-extra/docs/include-fixer.rst
new file mode 100644
index 0000000..fcd2998
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/include-fixer.rst
@@ -0,0 +1,155 @@
+===================
+Clang-Include-Fixer
+===================
+
+.. contents::
+
+One of the major nuisances of C++ compared to other languages is the manual
+management of ``#include`` directives in any file.
+:program:`clang-include-fixer` addresses one aspect of this problem by providing
+an automated way of adding ``#include`` directives for missing symbols in one
+translation unit.
+
+While inserting missing ``#include``, :program:`clang-include-fixer` adds
+missing namespace qualifiers to all instances of an unidentified symbol if
+the symbol is missing some prefix namespace qualifiers.
+
+Setup
+=====
+
+To use :program:`clang-include-fixer` two databases are required. Both can be
+generated with existing tools.
+
+- Compilation database. Contains the compiler commands for any given file in a
+ project and can be generated by CMake, see `How To Setup Tooling For LLVM`_.
+- Symbol index. Contains all symbol information in a project to match a given
+ identifier to a header file.
+
+Ideally both databases (``compile_commands.json`` and
+``find_all_symbols_db.yaml``) are linked into the root of the source tree they
+correspond to. Then the :program:`clang-include-fixer` can automatically pick
+them up if called with a source file from that tree. Note that by default
+``compile_commands.json`` as generated by CMake does not include header files,
+so only implementation files can be handled by tools.
+
+.. _How To Setup Tooling For LLVM: http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+
+Creating a Symbol Index From a Compilation Database
+---------------------------------------------------
+
+The include fixer contains :program:`find-all-symbols`, a tool to create a
+symbol database in YAML format from a compilation database by parsing all
+source files listed in it. The following list of commands shows how to set up a
+database for LLVM, any project built by CMake should follow similar steps.
+
+.. code-block:: console
+
+ $ cd path/to/llvm-build
+ $ ninja find-all-symbols // build find-all-symbols tool.
+ $ ninja clang-include-fixer // build clang-include-fixer tool.
+ $ ls compile_commands.json # Make sure compile_commands.json exists.
+ compile_commands.json
+ $ path/to/llvm/source/tools/clang/tools/extra/include-fixer/find-all-symbols/tool/run-find-all-symbols.py
+ ... wait as clang indexes the code base ...
+ $ ln -s $PWD/find_all_symbols_db.yaml path/to/llvm/source/ # Link database into the source tree.
+ $ ln -s $PWD/compile_commands.json path/to/llvm/source/ # Also link compilation database if it's not there already.
+ $ cd path/to/llvm/source
+ $ /path/to/clang-include-fixer -db=yaml path/to/file/with/missing/include.cpp
+ Added #include "foo.h"
+
+Integrate with Vim
+------------------
+To run `clang-include-fixer` on a potentially unsaved buffer in Vim. Add the
+following key binding to your ``.vimrc``:
+
+.. code-block:: console
+
+ noremap <leader>cf :pyf path/to/llvm/source/tools/clang/tools/extra/include-fixer/tool/clang-include-fixer.py<cr>
+
+This enables `clang-include-fixer` for NORMAL and VISUAL mode. Change
+`<leader>cf` to another binding if you need clang-include-fixer on a different
+key. The `<leader> key
+<http://vim.wikia.com/wiki/Mapping_keys_in_Vim_-_Tutorial_(Part_3)#Map_leader>`_
+is a reference to a specific key defined by the mapleader variable and is bound
+to backslash by default.
+
+Make sure vim can find :program:`clang-include-fixer`:
+
+- Add the path to :program:`clang-include-fixer` to the PATH environment variable.
+- Or set ``g:clang_include_fixer_path`` in vimrc: ``let g:clang_include_fixer_path=path/to/clang-include-fixer``
+
+You can customize the number of headers being shown by setting
+``let g:clang_include_fixer_maximum_suggested_headers=5``
+
+Customized settings in `.vimrc`:
+
+- ``let g:clang_include_fixer_path = "clang-include-fixer"``
+
+ Set clang-include-fixer binary file path.
+
+- ``let g:clang_include_fixer_maximum_suggested_headers = 3``
+
+ Set the maximum number of ``#includes`` to show. Default is 3.
+
+- ``let g:clang_include_fixer_increment_num = 5``
+
+ Set the increment number of #includes to show every time when pressing ``m``.
+ Default is 5.
+
+- ``let g:clang_include_fixer_jump_to_include = 0``
+
+ Set to 1 if you want to jump to the new inserted ``#include`` line. Default is
+ 0.
+
+- ``let g:clang_include_fixer_query_mode = 0``
+
+ Set to 1 if you want to insert ``#include`` for the symbol under the cursor.
+ Default is 0. Compared to normal mode, this mode won't parse the source file
+ and only search the sysmbol from database, which is faster than normal mode.
+
+See ``clang-include-fixer.py`` for more details.
+
+Integrate with Emacs
+--------------------
+To run `clang-include-fixer` on a potentially unsaved buffer in Emacs.
+Ensure that Emacs finds ``clang-include-fixer.el`` by adding the directory
+containing the file to the ``load-path`` and requiring the `clang-include-fixer`
+in your ``.emacs``:
+
+.. code-block:: console
+
+ (add-to-list 'load-path "path/to/llvm/source/tools/clang/tools/extra/include-fixer/tool/"
+ (require 'clang-include-fixer)
+
+Within Emacs the tool can be invoked with the command
+``M-x clang-include-fixer``. This will insert the header that defines the
+first undefined symbol; if there is more than one header that would define the
+symbol, the user is prompted to select one.
+
+To include the header that defines the symbol at point, run
+``M-x clang-include-fixer-at-point``.
+
+Make sure Emacs can find :program:`clang-include-fixer`:
+
+- Either add the parent directory of :program:`clang-include-fixer` to the PATH
+ environment variable, or customize the Emacs user option
+ ``clang-include-fixer-executable`` to point to the file name of the program.
+
+How it Works
+============
+
+To get the most information out of Clang at parse time,
+:program:`clang-include-fixer` runs in tandem with the parse and receives
+callbacks from Clang's semantic analysis. In particular it reuses the existing
+support for typo corrections. Whenever Clang tries to correct a potential typo
+it emits a callback to the include fixer which then looks for a corresponding
+file. At this point rich lookup information is still available, which is not
+available in the AST at a later stage.
+
+The identifier that should be typo corrected is then sent to the database, if a
+header file is returned it is added as an include directive at the top of the
+file.
+
+Currently :program:`clang-include-fixer` only inserts a single include at a
+time to avoid getting caught in follow-up errors. If multiple `#include`
+additions are desired the program can be rerun until a fix-point is reached.
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/index.rst b/src/third_party/llvm-project/clang-tools-extra/docs/index.rst
new file mode 100644
index 0000000..55fd1a6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/index.rst
@@ -0,0 +1,36 @@
+.. Extra Clang Tools documentation master file, created by
+ sphinx-quickstart on Wed Feb 13 10:00:18 2013.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+.. title:: Welcome to Extra Clang Tools's documentation!
+
+Introduction
+============
+Welcome to the clang-tools-extra project which contains extra tools built using
+Clang's tooling API's.
+
+.. toctree::
+ :maxdepth: 1
+
+ ReleaseNotes
+
+Contents
+========
+.. toctree::
+ :maxdepth: 2
+
+ clang-tidy/index
+ include-fixer
+ modularize
+ pp-trace
+ clang-rename
+ clangd
+ clang-doc
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/make.bat b/src/third_party/llvm-project/clang-tools-extra/docs/make.bat
new file mode 100644
index 0000000..09b798c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/make.bat
@@ -0,0 +1,190 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\ExtraClangTools.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\ExtraClangTools.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/modularize.rst b/src/third_party/llvm-project/clang-tools-extra/docs/modularize.rst
new file mode 100644
index 0000000..6fe49b4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/modularize.rst
@@ -0,0 +1,265 @@
+.. index:: modularize
+
+==================================
+Modularize User's Manual
+==================================
+
+.. toctree::
+ :hidden:
+
+ ModularizeUsage
+
+:program:`modularize` is a standalone tool that checks whether a set of headers
+provides the consistent definitions required to use modules. For example, it
+detects whether the same entity (say, a NULL macro or size_t typedef) is
+defined in multiple headers or whether a header produces different definitions
+under different circumstances. These conditions cause modules built from the
+headers to behave poorly, and should be fixed before introducing a module
+map.
+
+:program:`modularize` also has an assistant mode option for generating
+a module map file based on the provided header list. The generated file
+is a functional module map that can be used as a starting point for a
+module.map file.
+
+Getting Started
+===============
+
+To build from source:
+
+1. Read `Getting Started with the LLVM System`_ and `Clang Tools
+ Documentation`_ for information on getting sources for LLVM, Clang, and
+ Clang Extra Tools.
+
+2. `Getting Started with the LLVM System`_ and `Building LLVM with CMake`_ give
+ directions for how to build. With sources all checked out into the
+ right place the LLVM build will build Clang Extra Tools and their
+ dependencies automatically.
+
+ * If using CMake, you can also use the ``modularize`` target to build
+ just the modularize tool and its dependencies.
+
+Before continuing, take a look at :doc:`ModularizeUsage` to see how to invoke
+modularize.
+
+.. _Getting Started with the LLVM System: http://llvm.org/docs/GettingStarted.html
+.. _Building LLVM with CMake: http://llvm.org/docs/CMake.html
+.. _Clang Tools Documentation: http://clang.llvm.org/docs/ClangTools.html
+
+What Modularize Checks
+======================
+
+Modularize will check for the following:
+
+* Duplicate global type and variable definitions
+* Duplicate macro definitions
+* Macro instances, 'defined(macro)', or #if, #elif, #ifdef, #ifndef conditions
+ that evaluate differently in a header
+* #include directives inside 'extern "C/C++" {}' or 'namespace (name) {}' blocks
+* Module map header coverage completeness (in the case of a module map input
+ only)
+
+Modularize will do normal C/C++ parsing, reporting normal errors and warnings,
+but will also report special error messages like the following::
+
+ error: '(symbol)' defined at multiple locations:
+ (file):(row):(column)
+ (file):(row):(column)
+
+ error: header '(file)' has different contents depending on how it was included
+
+The latter might be followed by messages like the following::
+
+ note: '(symbol)' in (file) at (row):(column) not always provided
+
+Checks will also be performed for macro expansions, defined(macro)
+expressions, and preprocessor conditional directives that evaluate
+inconsistently, and can produce error messages like the following::
+
+ (...)/SubHeader.h:11:5:
+ #if SYMBOL == 1
+ ^
+ error: Macro instance 'SYMBOL' has different values in this header,
+ depending on how it was included.
+ 'SYMBOL' expanded to: '1' with respect to these inclusion paths:
+ (...)/Header1.h
+ (...)/SubHeader.h
+ (...)/SubHeader.h:3:9:
+ #define SYMBOL 1
+ ^
+ Macro defined here.
+ 'SYMBOL' expanded to: '2' with respect to these inclusion paths:
+ (...)/Header2.h
+ (...)/SubHeader.h
+ (...)/SubHeader.h:7:9:
+ #define SYMBOL 2
+ ^
+ Macro defined here.
+
+Checks will also be performed for '#include' directives that are
+nested inside 'extern "C/C++" {}' or 'namespace (name) {}' blocks,
+and can produce error message like the following::
+
+ IncludeInExtern.h:2:3:
+ #include "Empty.h"
+ ^
+ error: Include directive within extern "C" {}.
+ IncludeInExtern.h:1:1:
+ extern "C" {
+ ^
+ The "extern "C" {}" block is here.
+
+.. _module-map-coverage:
+
+Module Map Coverage Check
+=========================
+
+The coverage check uses the Clang library to read and parse the
+module map file. Starting at the module map file directory, or just the
+include paths, if specified, it will collect the names of all the files it
+considers headers (no extension, .h, or .inc--if you need more, modify the
+isHeader function). It then compares the headers against those referenced
+in the module map, either explicitly named, or implicitly named via an
+umbrella directory or umbrella file, as parsed by the ModuleMap object.
+If headers are found which are not referenced or covered by an umbrella
+directory or file, warning messages will be produced, and this program
+will return an error code of 1. If no problems are found, an error code of
+0 is returned.
+
+Note that in the case of umbrella headers, this tool invokes the compiler
+to preprocess the file, and uses a callback to collect the header files
+included by the umbrella header or any of its nested includes. If any
+front end options are needed for these compiler invocations, these
+can be included on the command line after the module map file argument.
+
+Warning message have the form:
+
+ warning: module.modulemap does not account for file: Level3A.h
+
+Note that for the case of the module map referencing a file that does
+not exist, the module map parser in Clang will (at the time of this
+writing) display an error message.
+
+To limit the checks :program:`modularize` does to just the module
+map coverage check, use the ``-coverage-check-only option``.
+
+For example::
+
+ modularize -coverage-check-only module.modulemap
+
+.. _module-map-generation:
+
+Module Map Generation
+=====================
+
+If you specify the ``-module-map-path=<module map file>``,
+:program:`modularize` will output a module map based on the input header list.
+A module will be created for each header. Also, if the header in the header
+list is a partial path, a nested module hierarchy will be created in which a
+module will be created for each subdirectory component in the header path,
+with the header itself represented by the innermost module. If other headers
+use the same subdirectories, they will be enclosed in these same modules also.
+
+For example, for the header list::
+
+ SomeTypes.h
+ SomeDecls.h
+ SubModule1/Header1.h
+ SubModule1/Header2.h
+ SubModule2/Header3.h
+ SubModule2/Header4.h
+ SubModule2.h
+
+The following module map will be generated::
+
+ // Output/NoProblemsAssistant.txt
+ // Generated by: modularize -module-map-path=Output/NoProblemsAssistant.txt \
+ -root-module=Root NoProblemsAssistant.modularize
+
+ module SomeTypes {
+ header "SomeTypes.h"
+ export *
+ }
+ module SomeDecls {
+ header "SomeDecls.h"
+ export *
+ }
+ module SubModule1 {
+ module Header1 {
+ header "SubModule1/Header1.h"
+ export *
+ }
+ module Header2 {
+ header "SubModule1/Header2.h"
+ export *
+ }
+ }
+ module SubModule2 {
+ module Header3 {
+ header "SubModule2/Header3.h"
+ export *
+ }
+ module Header4 {
+ header "SubModule2/Header4.h"
+ export *
+ }
+ header "SubModule2.h"
+ export *
+ }
+
+An optional ``-root-module=<root-name>`` option can be used to cause a root module
+to be created which encloses all the modules.
+
+An optional ``-problem-files-list=<problem-file-name>`` can be used to input
+a list of files to be excluded, perhaps as a temporary stop-gap measure until
+problem headers can be fixed.
+
+For example, with the same header list from above::
+
+ // Output/NoProblemsAssistant.txt
+ // Generated by: modularize -module-map-path=Output/NoProblemsAssistant.txt \
+ -root-module=Root NoProblemsAssistant.modularize
+
+ module Root {
+ module SomeTypes {
+ header "SomeTypes.h"
+ export *
+ }
+ module SomeDecls {
+ header "SomeDecls.h"
+ export *
+ }
+ module SubModule1 {
+ module Header1 {
+ header "SubModule1/Header1.h"
+ export *
+ }
+ module Header2 {
+ header "SubModule1/Header2.h"
+ export *
+ }
+ }
+ module SubModule2 {
+ module Header3 {
+ header "SubModule2/Header3.h"
+ export *
+ }
+ module Header4 {
+ header "SubModule2/Header4.h"
+ export *
+ }
+ header "SubModule2.h"
+ export *
+ }
+ }
+
+Note that headers with dependents will be ignored with a warning, as the
+Clang module mechanism doesn't support headers the rely on other headers
+to be included first.
+
+The module map format defines some keywords which can't be used in module
+names. If a header has one of these names, an underscore ('_') will be
+prepended to the name. For example, if the header name is ``header.h``,
+because ``header`` is a keyword, the module name will be ``_header``.
+For a list of the module map keywords, please see:
+`Lexical structure <http://clang.llvm.org/docs/Modules.html#lexical-structure>`_
diff --git a/src/third_party/llvm-project/clang-tools-extra/docs/pp-trace.rst b/src/third_party/llvm-project/clang-tools-extra/docs/pp-trace.rst
new file mode 100644
index 0000000..b8768ed
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/docs/pp-trace.rst
@@ -0,0 +1,825 @@
+.. index:: pp-trace
+
+==================================
+pp-trace User's Manual
+==================================
+
+.. toctree::
+ :hidden:
+
+:program:`pp-trace` is a standalone tool that traces preprocessor
+activity. It's also used as a test of Clang's PPCallbacks interface.
+It runs a given source file through the Clang preprocessor, displaying
+selected information from callback functions overridden in a
+`PPCallbacks <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html>`_
+derivation. The output is in a high-level YAML format, described in
+:ref:`OutputFormat`.
+
+.. _Usage:
+
+pp-trace Usage
+==============
+
+Command Line Format
+-------------------
+
+``pp-trace [<pp-trace-options>] <source-file> [<front-end-options>]``
+
+``<pp-trace-options>`` is a place-holder for options
+specific to pp-trace, which are described below in
+:ref:`CommandLineOptions`.
+
+``<source-file>`` specifies the source file to run through the preprocessor.
+
+``<front-end-options>`` is a place-holder for regular
+`Clang Compiler Options <http://clang.llvm.org/docs/UsersManual.html#command-line-options>`_,
+which must follow the <source-file>.
+
+.. _CommandLineOptions:
+
+Command Line Options
+--------------------
+
+.. option:: -ignore <callback-name-list>
+
+ This option specifies a comma-separated list of names of callbacks
+ that shouldn't be traced. It can be used to eliminate unwanted
+ trace output. The callback names are the name of the actual
+ callback function names in the PPCallbacks class:
+
+ * FileChanged
+ * FileSkipped
+ * FileNotFound
+ * InclusionDirective
+ * moduleImport
+ * EndOfMainFile
+ * Ident
+ * PragmaDirective
+ * PragmaComment
+ * PragmaDetectMismatch
+ * PragmaDebug
+ * PragmaMessage
+ * PragmaDiagnosticPush
+ * PragmaDiagnosticPop
+ * PragmaDiagnostic
+ * PragmaOpenCLExtension
+ * PragmaWarning
+ * PragmaWarningPush
+ * PragmaWarningPop
+ * MacroExpands
+ * MacroDefined
+ * MacroUndefined
+ * Defined
+ * SourceRangeSkipped
+ * If
+ * Elif
+ * Ifdef
+ * Ifndef
+ * Else
+ * Endif
+
+.. option:: -output <output-file>
+
+ By default, pp-trace outputs the trace information to stdout. Use this
+ option to output the trace information to a file.
+
+.. _OutputFormat:
+
+pp-trace Output Format
+======================
+
+The pp-trace output is formatted as YAML. See http://yaml.org/ for general
+YAML information. It's arranged as a sequence of information about the
+callback call, including the callback name and argument information, for
+example:::
+
+ ---
+ - Callback: Name
+ Argument1: Value1
+ Argument2: Value2
+ (etc.)
+ ...
+
+With real data:::
+
+ ---
+ - Callback: FileChanged
+ Loc: "c:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-include.cpp:1:1"
+ Reason: EnterFile
+ FileType: C_User
+ PrevFID: (invalid)
+ (etc.)
+ - Callback: FileChanged
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-include.cpp:5:1"
+ Reason: ExitFile
+ FileType: C_User
+ PrevFID: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/Input/Level1B.h"
+ - Callback: EndOfMainFile
+ ...
+
+In all but one case (MacroDirective) the "Argument" scalars have the same
+name as the argument in the corresponding PPCallbacks callback function.
+
+Callback Details
+----------------
+
+The following sections describe the pupose and output format for each callback.
+
+Click on the callback name in the section heading to see the Doxygen
+documentation for the callback.
+
+The argument descriptions table describes the callback argument information
+displayed.
+
+The Argument Name field in most (but not all) cases is the same name as the
+callback function parameter.
+
+The Argument Value Syntax field describes the values that will be displayed
+for the argument value. It uses an ad hoc representation that mixes literal
+and symbolic representations. Enumeration member symbols are shown as the
+actual enum member in a (member1|member2|...) form. A name in parentheses
+can either represent a place holder for the described value, or confusingly,
+it might be a literal, such as (null), for a null pointer.
+Locations are shown as quoted only to avoid confusing the documentation generator.
+
+The Clang C++ Type field is the type from the callback function declaration.
+
+The description describes the argument or what is displayed for it.
+
+Note that in some cases, such as when a structure pointer is an argument
+value, only some key member or members are shown to represent the value,
+instead of trying to display all members of the structure.
+
+`FileChanged <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a7cc8cfaf34114fc65e92af621cd6464e>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+FileChanged is called when the preprocessor enters or exits a file, both the
+top level file being compiled, as well as any #include directives. It will
+also be called as a result of a system header pragma or in internal renaming
+of a file.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+Reason (EnterFile|ExitFile|SystemHeaderPragma|RenameFile) PPCallbacks::FileChangeReason Reason for change.
+FileType (C_User|C_System|C_ExternCSystem) SrcMgr::CharacteristicKind Include type.
+PrevFID ((file)|(invalid)) FileID Previous file, if any.
+============== ================================================== ============================== ==============================
+
+Example:::
+
+ - Callback: FileChanged
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-include.cpp:1:1"
+ Reason: EnterFile
+ FileType: C_User
+ PrevFID: (invalid)
+
+`FileSkipped <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#ab5b338a0670188eb05fa7685bbfb5128>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+FileSkipped is called when a source file is skipped as the result of header
+guard optimization.
+
+Argument descriptions:
+
+============== ================================================== ============================== ========================================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ========================================================
+ParentFile ("(file)" or (null)) const FileEntry The file that #included the skipped file.
+FilenameTok (token) const Token The token in ParentFile that indicates the skipped file.
+FileType (C_User|C_System|C_ExternCSystem) SrcMgr::CharacteristicKind The file type.
+============== ================================================== ============================== ========================================================
+
+Example:::
+
+ - Callback: FileSkipped
+ ParentFile: "/path/filename.h"
+ FilenameTok: "filename.h"
+ FileType: C_User
+
+`FileNotFound <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a3045151545f987256bfa8d978916ef00>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+FileNotFound is called when an inclusion directive results in a file-not-found error.
+
+Argument descriptions:
+
+============== ================================================== ============================== =====================================================================================================================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== =====================================================================================================================================
+FileName "(file)" StringRef The name of the file being included, as written in the source code.
+RecoveryPath (path) SmallVectorImpl<char> If this client indicates that it can recover from this missing file, the client should set this as an additional header search patch.
+============== ================================================== ============================== =====================================================================================================================================
+
+Example:::
+
+ - Callback: FileNotFound
+ FileName: "/path/filename.h"
+ RecoveryPath:
+
+`InclusionDirective <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a557d9738c329793513a6f57d6b60de52>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+InclusionDirective is called when an inclusion directive of any kind (#include</code>, #import</code>, etc.) has been processed, regardless of whether the inclusion will actually result in an inclusion.
+
+Argument descriptions:
+
+============== ================================================== ============================== ============================================================================================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ============================================================================================================
+HashLoc "(file):(line):(col)" SourceLocation The location of the '#' that starts the inclusion directive.
+IncludeTok (token) const Token The token that indicates the kind of inclusion directive, e.g., 'include' or 'import'.
+FileName "(file)" StringRef The name of the file being included, as written in the source code.
+IsAngled (true|false) bool Whether the file name was enclosed in angle brackets; otherwise, it was enclosed in quotes.
+FilenameRange "(file)" CharSourceRange The character range of the quotes or angle brackets for the written file name.
+File "(file)" const FileEntry The actual file that may be included by this inclusion directive.
+SearchPath "(path)" StringRef Contains the search path which was used to find the file in the file system.
+RelativePath "(path)" StringRef The path relative to SearchPath, at which the include file was found.
+Imported ((module name)|(null)) const Module The module, whenever an inclusion directive was automatically turned into a module import or null otherwise.
+============== ================================================== ============================== ============================================================================================================
+
+Example:::
+
+ - Callback: InclusionDirective
+ IncludeTok: include
+ FileName: "Input/Level1B.h"
+ IsAngled: false
+ FilenameRange: "Input/Level1B.h"
+ File: "D:/Clang/llvmnewmod/tools/clang/tools/extra/test/pp-trace/Input/Level1B.h"
+ SearchPath: "D:/Clang/llvmnewmod/tools/clang/tools/extra/test/pp-trace"
+ RelativePath: "Input/Level1B.h"
+ Imported: (null)
+
+`moduleImport <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#af32dcf1b8b7c179c7fcd3e24e89830fe>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+moduleImport is called when there was an explicit module-import syntax.
+
+Argument descriptions:
+
+============== ================================================== ============================== ===========================================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ===========================================================
+ImportLoc "(file):(line):(col)" SourceLocation The location of import directive token.
+Path "(path)" ModuleIdPath The identifiers (and their locations) of the module "path".
+Imported ((module name)|(null)) const Module The imported module; can be null if importing failed.
+============== ================================================== ============================== ===========================================================
+
+Example:::
+
+ - Callback: moduleImport
+ ImportLoc: "d:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-modules.cpp:4:2"
+ Path: [{Name: Level1B, Loc: "d:/Clang/llvmnewmod/tools/clang/tools/extra/test/pp-trace/pp-trace-modules.cpp:4:9"}, {Name: Level2B, Loc: "d:/Clang/llvmnewmod/tools/clang/tools/extra/test/pp-trace/pp-trace-modules.cpp:4:17"}]
+ Imported: Level2B
+
+`EndOfMainFile <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a63e170d069e99bc1c9c7ea0f3bed8bcc>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+EndOfMainFile is called when the end of the main file is reached.
+
+Argument descriptions:
+
+============== ================================================== ============================== ======================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ======================
+(no arguments)
+============== ================================================== ============================== ======================
+
+Example:::
+
+ - Callback: EndOfMainFile
+
+`Ident <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a3683f1d1fa513e9b6193d446a5cc2b66>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Ident is called when a #ident or #sccs directive is read.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+str (name) const std::string The text of the directive.
+============== ================================================== ============================== ==============================
+
+Example:::
+
+ - Callback: Ident
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-ident.cpp:3:1"
+ str: "$Id$"
+
+`PragmaDirective <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a0a2d7a72c62184b3cbde31fb62c6f2f7>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+PragmaDirective is called when start reading any pragma directive.
+
+Argument descriptions:
+
+============== ================================================== ============================== =================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== =================================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+Introducer (PIK_HashPragma|PIK__Pragma|PIK___pragma) PragmaIntroducerKind The type of the pragma directive.
+============== ================================================== ============================== =================================
+
+Example:::
+
+ - Callback: PragmaDirective
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-pragma.cpp:3:1"
+ Introducer: PIK_HashPragma
+
+`PragmaComment <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#ace0d940fc2c12ab76441466aab58dc37>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+PragmaComment is called when a #pragma comment directive is read.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+Kind ((name)|(null)) const IdentifierInfo The comment kind symbol.
+Str (message directive) const std::string The comment message directive.
+============== ================================================== ============================== ==============================
+
+Example:::
+
+ - Callback: PragmaComment
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-pragma.cpp:3:1"
+ Kind: library
+ Str: kernel32.lib
+
+`PragmaDetectMismatch <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#ab11158c9149fb8ad8af1903f4a6cd65d>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+PragmaDetectMismatch is called when a #pragma detect_mismatch directive is read.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+Name "(name)" const std::string The name.
+Value (string) const std::string The value.
+============== ================================================== ============================== ==============================
+
+Example:::
+
+ - Callback: PragmaDetectMismatch
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-pragma.cpp:3:1"
+ Name: name
+ Value: value
+
+`PragmaDebug <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a57cdccb6dcc07e926513ac3d5b121466>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+PragmaDebug is called when a #pragma clang __debug directive is read.
+
+Argument descriptions:
+
+============== ================================================== ============================== ================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ================================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+DebugType (string) StringRef Indicates type of debug message.
+============== ================================================== ============================== ================================
+
+Example:::
+
+ - Callback: PragmaDebug
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-pragma.cpp:3:1"
+ DebugType: warning
+
+`PragmaMessage <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#abb42935d9a9fd8e2c4f51cfdc4ea2ae1>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+PragmaMessage is called when a #pragma message directive is read.
+
+Argument descriptions:
+
+============== ================================================== ============================== =======================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== =======================================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+Namespace (name) StringRef The namespace of the message directive.
+Kind (PMK_Message|PMK_Warning|PMK_Error) PPCallbacks::PragmaMessageKind The type of the message directive.
+Str (string) StringRef The text of the message directive.
+============== ================================================== ============================== =======================================
+
+Example:::
+
+ - Callback: PragmaMessage
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-pragma.cpp:3:1"
+ Namespace: "GCC"
+ Kind: PMK_Message
+ Str: The message text.
+
+`PragmaDiagnosticPush <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a0f3ff19762baa38fe6c5c58022d32979>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+PragmaDiagnosticPush is called when a #pragma gcc dianostic push directive is read.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+Namespace (name) StringRef Namespace name.
+============== ================================================== ============================== ==============================
+
+Example:::
+
+ - Callback: PragmaDiagnosticPush
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-pragma.cpp:3:1"
+ Namespace: "GCC"
+
+`PragmaDiagnosticPop <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#ac94d789873122221fba8d76f6c5ea45e>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+PragmaDiagnosticPop is called when a #pragma gcc dianostic pop directive is read.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+Namespace (name) StringRef Namespace name.
+============== ================================================== ============================== ==============================
+
+Example:::
+
+ - Callback: PragmaDiagnosticPop
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-pragma.cpp:3:1"
+ Namespace: "GCC"
+
+`PragmaDiagnostic <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#afe7938f38a83cb7b4b25a13edfdd7bdd>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+PragmaDiagnostic is called when a #pragma gcc dianostic directive is read.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+Namespace (name) StringRef Namespace name.
+mapping (0|MAP_IGNORE|MAP_WARNING|MAP_ERROR|MAP_FATAL) diag::Severity Mapping type.
+Str (string) StringRef Warning/error name.
+============== ================================================== ============================== ==============================
+
+Example:::
+
+ - Callback: PragmaDiagnostic
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-pragma.cpp:3:1"
+ Namespace: "GCC"
+ mapping: MAP_WARNING
+ Str: WarningName
+
+`PragmaOpenCLExtension <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a92a20a21fadbab4e2c788f4e27fe07e7>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+PragmaOpenCLExtension is called when OpenCL extension is either disabled or enabled with a pragma.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==========================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==========================
+NameLoc "(file):(line):(col)" SourceLocation The location of the name.
+Name (name) const IdentifierInfo Name symbol.
+StateLoc "(file):(line):(col)" SourceLocation The location of the state.
+State (1|0) unsigned Enabled/disabled state.
+============== ================================================== ============================== ==========================
+
+Example:::
+
+ - Callback: PragmaOpenCLExtension
+ NameLoc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-pragma.cpp:3:10"
+ Name: Name
+ StateLoc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-pragma.cpp:3:18"
+ State: 1
+
+`PragmaWarning <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#aa17169d25fa1cf0a6992fc944d1d8730>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+PragmaWarning is called when a #pragma warning directive is read.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+WarningSpec (string) StringRef The warning specifier.
+Ids [(number)[, ...]] ArrayRef<int> The warning numbers.
+============== ================================================== ============================== ==============================
+
+Example:::
+
+ - Callback: PragmaWarning
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-pragma.cpp:3:1"
+ WarningSpec: disable
+ Ids: 1,2,3
+
+`PragmaWarningPush <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#ae5626ef70502687a859f323a809ed0b6>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+PragmaWarningPush is called when a #pragma warning(push) directive is read.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+Level (number) int Warning level.
+============== ================================================== ============================== ==============================
+
+Example:::
+
+ - Callback: PragmaWarningPush
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-pragma.cpp:3:1"
+ Level: 1
+
+`PragmaWarningPop <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#ac98d502af8811b8a6e7342d7cd2b3b95>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+PragmaWarningPop is called when a #pragma warning(pop) directive is read.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+============== ================================================== ============================== ==============================
+
+Example:::
+
+ - Callback: PragmaWarningPop
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-pragma.cpp:3:1"
+
+`MacroExpands <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a9bc725209d3a071ea649144ab996d515>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+MacroExpands is called when ::HandleMacroExpandedIdentifier when a macro invocation is found.
+
+Argument descriptions:
+
+============== ================================================== ============================== ======================================================================================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ======================================================================================================
+MacroNameTok (token) const Token The macro name token.
+MacroDirective (MD_Define|MD_Undefine|MD_Visibility) const MacroDirective The kind of macro directive from the MacroDirective structure.
+Range ["(file):(line):(col)", "(file):(line):(col)"] SourceRange The source range for the expansion.
+Args [(name)|(number)|<(token name)>[, ...]] const MacroArgs The argument tokens. Names and numbers are literal, everything else is of the form '<' tokenName '>'.
+============== ================================================== ============================== ======================================================================================================
+
+Example:::
+
+ - Callback: MacroExpands
+ MacroNameTok: X_IMPL
+ MacroDirective: MD_Define
+ Range: [(nonfile), (nonfile)]
+ Args: [a <plus> y, b]
+
+`MacroDefined <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a8448fc9f96f22ad1b93ff393cffc5a76>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+MacroDefined is called when a macro definition is seen.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================================================
+MacroNameTok (token) const Token The macro name token.
+MacroDirective (MD_Define|MD_Undefine|MD_Visibility) const MacroDirective The kind of macro directive from the MacroDirective structure.
+============== ================================================== ============================== ==============================================================
+
+Example:::
+
+ - Callback: MacroDefined
+ MacroNameTok: X_IMPL
+ MacroDirective: MD_Define
+
+`MacroUndefined <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#acb80fc6171a839db8e290945bf2c9d7a>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+MacroUndefined is called when a macro #undef is seen.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================================================
+MacroNameTok (token) const Token The macro name token.
+MacroDirective (MD_Define|MD_Undefine|MD_Visibility) const MacroDirective The kind of macro directive from the MacroDirective structure.
+============== ================================================== ============================== ==============================================================
+
+Example:::
+
+ - Callback: MacroUndefined
+ MacroNameTok: X_IMPL
+ MacroDirective: MD_Define
+
+`Defined <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a3cc2a644533d0e4088a13d2baf90db94>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Defined is called when the 'defined' operator is seen.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================================================
+MacroNameTok (token) const Token The macro name token.
+MacroDirective (MD_Define|MD_Undefine|MD_Visibility) const MacroDirective The kind of macro directive from the MacroDirective structure.
+Range ["(file):(line):(col)", "(file):(line):(col)"] SourceRange The source range for the directive.
+============== ================================================== ============================== ==============================================================
+
+Example:::
+
+ - Callback: Defined
+ MacroNameTok: MACRO
+ MacroDirective: (null)
+ Range: ["D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:8:5", "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:8:19"]
+
+`SourceRangeSkipped <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#abdb4ebe11610f079ac33515965794b46>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+SourceRangeSkipped is called when a source range is skipped.
+
+Argument descriptions:
+
+============== ================================================== ============================== =========================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== =========================
+Range ["(file):(line):(col)", "(file):(line):(col)"] SourceRange The source range skipped.
+============== ================================================== ============================== =========================
+
+Example:::
+
+ - Callback: SourceRangeSkipped
+ Range: [":/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:8:2", ":/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:9:2"]
+
+`If <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a645edcb0d6becbc6f256f02fd1287778>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If is called when an #if is seen.
+
+Argument descriptions:
+
+============== ================================================== ============================== ===================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ===================================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+ConditionRange ["(file):(line):(col)", "(file):(line):(col)"] SourceRange The source range for the condition.
+ConditionValue (true|false) bool The condition value.
+============== ================================================== ============================== ===================================
+
+Example:::
+
+ - Callback: If
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:8:2"
+ ConditionRange: ["D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:8:4", "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:9:1"]
+ ConditionValue: false
+
+`Elif <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a180c9e106a28d60a6112e16b1bb8302a>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Elif is called when an #elif is seen.
+
+Argument descriptions:
+
+============== ================================================== ============================== ===================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ===================================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+ConditionRange ["(file):(line):(col)", "(file):(line):(col)"] SourceRange The source range for the condition.
+ConditionValue (true|false) bool The condition value.
+IfLoc "(file):(line):(col)" SourceLocation The location of the directive.
+============== ================================================== ============================== ===================================
+
+Example:::
+
+ - Callback: Elif
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:10:2"
+ ConditionRange: ["D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:10:4", "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:11:1"]
+ ConditionValue: false
+ IfLoc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:8:2"
+
+`Ifdef <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a0ce79575dda307784fd51a6dd4eec33d>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Ifdef is called when an #ifdef is seen.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================================================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+MacroNameTok (token) const Token The macro name token.
+MacroDirective (MD_Define|MD_Undefine|MD_Visibility) const MacroDirective The kind of macro directive from the MacroDirective structure.
+============== ================================================== ============================== ==============================================================
+
+Example:::
+
+ - Callback: Ifdef
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-conditional.cpp:3:1"
+ MacroNameTok: MACRO
+ MacroDirective: MD_Define
+
+`Ifndef <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#a767af69f1cdcc4cd880fa2ebf77ad3ad>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Ifndef is called when an #ifndef is seen.
+
+Argument descriptions:
+
+============== ================================================== ============================== ==============================================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ==============================================================
+Loc "(file):(line):(col)" SourceLocation The location of the directive.
+MacroNameTok (token) const Token The macro name token.
+MacroDirective (MD_Define|MD_Undefine|MD_Visibility) const MacroDirective The kind of macro directive from the MacroDirective structure.
+============== ================================================== ============================== ==============================================================
+
+Example:::
+
+ - Callback: Ifndef
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-conditional.cpp:3:1"
+ MacroNameTok: MACRO
+ MacroDirective: MD_Define
+
+`Else <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#ad57f91b6d9c3cbcca326a2bfb49e0314>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Else is called when an #else is seen.
+
+Argument descriptions:
+
+============== ================================================== ============================== ===================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ===================================
+Loc "(file):(line):(col)" SourceLocation The location of the else directive.
+IfLoc "(file):(line):(col)" SourceLocation The location of the if directive.
+============== ================================================== ============================== ===================================
+
+Example:::
+
+ - Callback: Else
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:10:2"
+ IfLoc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:8:2"
+
+`Endif <http://clang.llvm.org/doxygen/classclang_1_1PPCallbacks.html#afc62ca1401125f516d58b1629a2093ce>`_ Callback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Endif is called when an #endif is seen.
+
+Argument descriptions:
+
+============== ================================================== ============================== ====================================
+Argument Name Argument Value Syntax Clang C++ Type Description
+============== ================================================== ============================== ====================================
+Loc "(file):(line):(col)" SourceLocation The location of the endif directive.
+IfLoc "(file):(line):(col)" SourceLocation The location of the if directive.
+============== ================================================== ============================== ====================================
+
+Example:::
+
+ - Callback: Endif
+ Loc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:10:2"
+ IfLoc: "D:/Clang/llvm/tools/clang/tools/extra/test/pp-trace/pp-trace-macro.cpp:8:2"
+
+Building pp-trace
+=================
+
+To build from source:
+
+1. Read `Getting Started with the LLVM System`_ and `Clang Tools
+ Documentation`_ for information on getting sources for LLVM, Clang, and
+ Clang Extra Tools.
+
+2. `Getting Started with the LLVM System`_ and `Building LLVM with CMake`_ give
+ directions for how to build. With sources all checked out into the
+ right place the LLVM build will build Clang Extra Tools and their
+ dependencies automatically.
+
+ * If using CMake, you can also use the ``pp-trace`` target to build
+ just the pp-trace tool and its dependencies.
+
+.. _Getting Started with the LLVM System: http://llvm.org/docs/GettingStarted.html
+.. _Building LLVM with CMake: http://llvm.org/docs/CMake.html
+.. _Clang Tools Documentation: http://clang.llvm.org/docs/ClangTools.html
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/include-fixer/CMakeLists.txt
new file mode 100644
index 0000000..3981fcd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/CMakeLists.txt
@@ -0,0 +1,28 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+add_clang_library(clangIncludeFixer
+ IncludeFixer.cpp
+ IncludeFixerContext.cpp
+ InMemorySymbolIndex.cpp
+ FuzzySymbolIndex.cpp
+ SymbolIndexManager.cpp
+ YamlSymbolIndex.cpp
+
+ LINK_LIBS
+ clangAST
+ clangBasic
+ clangFormat
+ clangFrontend
+ clangLex
+ clangParse
+ clangSema
+ clangTooling
+ clangToolingCore
+ findAllSymbols
+ )
+
+add_subdirectory(plugin)
+add_subdirectory(tool)
+add_subdirectory(find-all-symbols)
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/FuzzySymbolIndex.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/FuzzySymbolIndex.cpp
new file mode 100644
index 0000000..d91f455
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/FuzzySymbolIndex.cpp
@@ -0,0 +1,143 @@
+//===--- FuzzySymbolIndex.cpp - Lookup symbols for autocomplete -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "FuzzySymbolIndex.h"
+#include "llvm/Support/Regex.h"
+
+using clang::find_all_symbols::SymbolAndSignals;
+using llvm::StringRef;
+
+namespace clang {
+namespace include_fixer {
+namespace {
+
+class MemSymbolIndex : public FuzzySymbolIndex {
+public:
+ MemSymbolIndex(std::vector<SymbolAndSignals> Symbols) {
+ for (auto &Symbol : Symbols) {
+ auto Tokens = tokenize(Symbol.Symbol.getName());
+ this->Symbols.emplace_back(
+ StringRef(llvm::join(Tokens.begin(), Tokens.end(), " ")),
+ std::move(Symbol));
+ }
+ }
+
+ std::vector<SymbolAndSignals> search(StringRef Query) override {
+ auto Tokens = tokenize(Query);
+ llvm::Regex Pattern("^" + queryRegexp(Tokens));
+ std::vector<SymbolAndSignals> Results;
+ for (const Entry &E : Symbols)
+ if (Pattern.match(E.first))
+ Results.push_back(E.second);
+ return Results;
+ }
+
+private:
+ using Entry = std::pair<llvm::SmallString<32>, SymbolAndSignals>;
+ std::vector<Entry> Symbols;
+};
+
+// Helpers for tokenize state machine.
+enum TokenizeState {
+ EMPTY, // No pending characters.
+ ONE_BIG, // Read one uppercase letter, could be WORD or Word.
+ BIG_WORD, // Reading an uppercase WORD.
+ SMALL_WORD, // Reading a lowercase word.
+ NUMBER // Reading a number.
+};
+
+enum CharType { UPPER, LOWER, DIGIT, MISC };
+CharType classify(char c) {
+ if (isupper(c))
+ return UPPER;
+ if (islower(c))
+ return LOWER;
+ if (isdigit(c))
+ return DIGIT;
+ return MISC;
+}
+
+} // namespace
+
+std::vector<std::string> FuzzySymbolIndex::tokenize(StringRef Text) {
+ std::vector<std::string> Result;
+ // State describes the treatment of text from Start to I.
+ // Once text is Flush()ed into Result, we're done with it and advance Start.
+ TokenizeState State = EMPTY;
+ size_t Start = 0;
+ auto Flush = [&](size_t End) {
+ if (State != EMPTY) {
+ Result.push_back(Text.substr(Start, End - Start).lower());
+ State = EMPTY;
+ }
+ Start = End;
+ };
+ for (size_t I = 0; I < Text.size(); ++I) {
+ CharType Type = classify(Text[I]);
+ if (Type == MISC)
+ Flush(I);
+ else if (Type == LOWER)
+ switch (State) {
+ case BIG_WORD:
+ Flush(I - 1); // FOOBar: first token is FOO, not FOOB.
+ LLVM_FALLTHROUGH;
+ case ONE_BIG:
+ State = SMALL_WORD;
+ LLVM_FALLTHROUGH;
+ case SMALL_WORD:
+ break;
+ default:
+ Flush(I);
+ State = SMALL_WORD;
+ }
+ else if (Type == UPPER)
+ switch (State) {
+ case ONE_BIG:
+ State = BIG_WORD;
+ LLVM_FALLTHROUGH;
+ case BIG_WORD:
+ break;
+ default:
+ Flush(I);
+ State = ONE_BIG;
+ }
+ else if (Type == DIGIT && State != NUMBER) {
+ Flush(I);
+ State = NUMBER;
+ }
+ }
+ Flush(Text.size());
+ return Result;
+}
+
+std::string
+FuzzySymbolIndex::queryRegexp(const std::vector<std::string> &Tokens) {
+ std::string Result;
+ for (size_t I = 0; I < Tokens.size(); ++I) {
+ if (I)
+ Result.append("[[:alnum:]]* ");
+ for (size_t J = 0; J < Tokens[I].size(); ++J) {
+ if (J)
+ Result.append("([[:alnum:]]* )?");
+ Result.push_back(Tokens[I][J]);
+ }
+ }
+ return Result;
+}
+
+llvm::Expected<std::unique_ptr<FuzzySymbolIndex>>
+FuzzySymbolIndex::createFromYAML(StringRef FilePath) {
+ auto Buffer = llvm::MemoryBuffer::getFile(FilePath);
+ if (!Buffer)
+ return llvm::errorCodeToError(Buffer.getError());
+ return llvm::make_unique<MemSymbolIndex>(
+ find_all_symbols::ReadSymbolInfosFromYAML(Buffer.get()->getBuffer()));
+}
+
+} // namespace include_fixer
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/FuzzySymbolIndex.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/FuzzySymbolIndex.h
new file mode 100644
index 0000000..245191e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/FuzzySymbolIndex.h
@@ -0,0 +1,55 @@
+//===--- FuzzySymbolIndex.h - Lookup symbols for autocomplete ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FUZZY_SYMBOL_INDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FUZZY_SYMBOL_INDEX_H
+
+#include "SymbolIndex.h"
+#include "find-all-symbols/SymbolInfo.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace include_fixer {
+
+// A FuzzySymbolIndex retrieves top-level symbols matching a query string.
+//
+// It refines the contract of SymbolIndex::search to do fuzzy matching:
+// - symbol names are tokenized: "unique ptr", "string ref".
+// - query must match prefixes of symbol tokens: [upt]
+// - if the query has multiple tokens, splits must match: [StR], not [STr].
+// Helpers for tokenization and regex matching are provided.
+//
+// Implementations may choose to truncate results, refuse short queries, etc.
+class FuzzySymbolIndex : public SymbolIndex {
+public:
+ // Loads the specified include-fixer database and returns an index serving it.
+ static llvm::Expected<std::unique_ptr<FuzzySymbolIndex>>
+ createFromYAML(llvm::StringRef File);
+
+ // Helpers for implementing indexes:
+
+ // Transforms a symbol name or query into a sequence of tokens.
+ // - URLHandlerCallback --> [url, handler, callback]
+ // - snake_case11 --> [snake, case, 11]
+ // - _WTF$ --> [wtf]
+ static std::vector<std::string> tokenize(llvm::StringRef Text);
+
+ // Transforms query tokens into an unanchored regexp to match symbol tokens.
+ // - [fe f] --> /f(\w* )?e\w* f/, matches [fee fie foe].
+ static std::string queryRegexp(const std::vector<std::string> &Tokens);
+};
+
+} // namespace include_fixer
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FUZZY_SYMBOL_INDEX_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/InMemorySymbolIndex.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/InMemorySymbolIndex.cpp
new file mode 100644
index 0000000..14753bd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/InMemorySymbolIndex.cpp
@@ -0,0 +1,32 @@
+//===-- InMemorySymbolIndex.cpp--------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InMemorySymbolIndex.h"
+
+using clang::find_all_symbols::SymbolAndSignals;
+
+namespace clang {
+namespace include_fixer {
+
+InMemorySymbolIndex::InMemorySymbolIndex(
+ const std::vector<SymbolAndSignals> &Symbols) {
+ for (const auto &Symbol : Symbols)
+ LookupTable[Symbol.Symbol.getName()].push_back(Symbol);
+}
+
+std::vector<SymbolAndSignals>
+InMemorySymbolIndex::search(llvm::StringRef Identifier) {
+ auto I = LookupTable.find(Identifier);
+ if (I != LookupTable.end())
+ return I->second;
+ return {};
+}
+
+} // namespace include_fixer
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/InMemorySymbolIndex.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/InMemorySymbolIndex.h
new file mode 100644
index 0000000..0e1310e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/InMemorySymbolIndex.h
@@ -0,0 +1,38 @@
+//===-- InMemorySymbolIndex.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INMEMORYSYMBOLINDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INMEMORYSYMBOLINDEX_H
+
+#include "SymbolIndex.h"
+#include <map>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace include_fixer {
+
+/// Xref database with fixed content.
+class InMemorySymbolIndex : public SymbolIndex {
+public:
+ InMemorySymbolIndex(
+ const std::vector<find_all_symbols::SymbolAndSignals> &Symbols);
+
+ std::vector<find_all_symbols::SymbolAndSignals>
+ search(llvm::StringRef Identifier) override;
+
+private:
+ std::map<std::string, std::vector<find_all_symbols::SymbolAndSignals>>
+ LookupTable;
+};
+
+} // namespace include_fixer
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INMEMORYSYMBOLINDEX_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/IncludeFixer.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/IncludeFixer.cpp
new file mode 100644
index 0000000..c6dfd7f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/IncludeFixer.cpp
@@ -0,0 +1,445 @@
+//===-- IncludeFixer.cpp - Include inserter based on sema callbacks -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IncludeFixer.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define DEBUG_TYPE "include-fixer"
+
+using namespace clang;
+
+namespace clang {
+namespace include_fixer {
+namespace {
+/// Manages the parse, gathers include suggestions.
+class Action : public clang::ASTFrontendAction {
+public:
+ explicit Action(SymbolIndexManager &SymbolIndexMgr, bool MinimizeIncludePaths)
+ : SemaSource(SymbolIndexMgr, MinimizeIncludePaths,
+ /*GenerateDiagnostics=*/false) {}
+
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &Compiler,
+ StringRef InFile) override {
+ SemaSource.setFilePath(InFile);
+ return llvm::make_unique<clang::ASTConsumer>();
+ }
+
+ void ExecuteAction() override {
+ clang::CompilerInstance *Compiler = &getCompilerInstance();
+ assert(!Compiler->hasSema() && "CI already has Sema");
+
+ // Set up our hooks into sema and parse the AST.
+ if (hasCodeCompletionSupport() &&
+ !Compiler->getFrontendOpts().CodeCompletionAt.FileName.empty())
+ Compiler->createCodeCompletionConsumer();
+
+ clang::CodeCompleteConsumer *CompletionConsumer = nullptr;
+ if (Compiler->hasCodeCompletionConsumer())
+ CompletionConsumer = &Compiler->getCodeCompletionConsumer();
+
+ Compiler->createSema(getTranslationUnitKind(), CompletionConsumer);
+ SemaSource.setCompilerInstance(Compiler);
+ Compiler->getSema().addExternalSource(&SemaSource);
+
+ clang::ParseAST(Compiler->getSema(), Compiler->getFrontendOpts().ShowStats,
+ Compiler->getFrontendOpts().SkipFunctionBodies);
+ }
+
+ IncludeFixerContext
+ getIncludeFixerContext(const clang::SourceManager &SourceManager,
+ clang::HeaderSearch &HeaderSearch) const {
+ return SemaSource.getIncludeFixerContext(SourceManager, HeaderSearch,
+ SemaSource.getMatchedSymbols());
+ }
+
+private:
+ IncludeFixerSemaSource SemaSource;
+};
+
+} // namespace
+
+IncludeFixerActionFactory::IncludeFixerActionFactory(
+ SymbolIndexManager &SymbolIndexMgr,
+ std::vector<IncludeFixerContext> &Contexts, StringRef StyleName,
+ bool MinimizeIncludePaths)
+ : SymbolIndexMgr(SymbolIndexMgr), Contexts(Contexts),
+ MinimizeIncludePaths(MinimizeIncludePaths) {}
+
+IncludeFixerActionFactory::~IncludeFixerActionFactory() = default;
+
+bool IncludeFixerActionFactory::runInvocation(
+ std::shared_ptr<clang::CompilerInvocation> Invocation,
+ clang::FileManager *Files,
+ std::shared_ptr<clang::PCHContainerOperations> PCHContainerOps,
+ clang::DiagnosticConsumer *Diagnostics) {
+ assert(Invocation->getFrontendOpts().Inputs.size() == 1);
+
+ // Set up Clang.
+ clang::CompilerInstance Compiler(PCHContainerOps);
+ Compiler.setInvocation(std::move(Invocation));
+ Compiler.setFileManager(Files);
+
+ // Create the compiler's actual diagnostics engine. We want to drop all
+ // diagnostics here.
+ Compiler.createDiagnostics(new clang::IgnoringDiagConsumer,
+ /*ShouldOwnClient=*/true);
+ Compiler.createSourceManager(*Files);
+
+ // We abort on fatal errors so don't let a large number of errors become
+ // fatal. A missing #include can cause thousands of errors.
+ Compiler.getDiagnostics().setErrorLimit(0);
+
+ // Run the parser, gather missing includes.
+ auto ScopedToolAction =
+ llvm::make_unique<Action>(SymbolIndexMgr, MinimizeIncludePaths);
+ Compiler.ExecuteAction(*ScopedToolAction);
+
+ Contexts.push_back(ScopedToolAction->getIncludeFixerContext(
+ Compiler.getSourceManager(),
+ Compiler.getPreprocessor().getHeaderSearchInfo()));
+
+ // Technically this should only return true if we're sure that we have a
+ // parseable file. We don't know that though. Only inform users of fatal
+ // errors.
+ return !Compiler.getDiagnostics().hasFatalErrorOccurred();
+}
+
+static bool addDiagnosticsForContext(TypoCorrection &Correction,
+ const IncludeFixerContext &Context,
+ StringRef Code, SourceLocation StartOfFile,
+ ASTContext &Ctx) {
+ auto Reps = createIncludeFixerReplacements(
+ Code, Context, format::getLLVMStyle(), /*AddQualifiers=*/false);
+ if (!Reps || Reps->size() != 1)
+ return false;
+
+ unsigned DiagID = Ctx.getDiagnostics().getCustomDiagID(
+ DiagnosticsEngine::Note, "Add '#include %0' to provide the missing "
+ "declaration [clang-include-fixer]");
+
+ // FIXME: Currently we only generate a diagnostic for the first header. Give
+ // the user choices.
+ const tooling::Replacement &Placed = *Reps->begin();
+
+ auto Begin = StartOfFile.getLocWithOffset(Placed.getOffset());
+ auto End = Begin.getLocWithOffset(std::max(0, (int)Placed.getLength() - 1));
+ PartialDiagnostic PD(DiagID, Ctx.getDiagAllocator());
+ PD << Context.getHeaderInfos().front().Header
+ << FixItHint::CreateReplacement(CharSourceRange::getCharRange(Begin, End),
+ Placed.getReplacementText());
+ Correction.addExtraDiagnostic(std::move(PD));
+ return true;
+}
+
+/// Callback for incomplete types. If we encounter a forward declaration we
+/// have the fully qualified name ready. Just query that.
+bool IncludeFixerSemaSource::MaybeDiagnoseMissingCompleteType(
+ clang::SourceLocation Loc, clang::QualType T) {
+ // Ignore spurious callbacks from SFINAE contexts.
+ if (CI->getSema().isSFINAEContext())
+ return false;
+
+ clang::ASTContext &context = CI->getASTContext();
+ std::string QueryString = QualType(T->getUnqualifiedDesugaredType(), 0)
+ .getAsString(context.getPrintingPolicy());
+ LLVM_DEBUG(llvm::dbgs() << "Query missing complete type '" << QueryString
+ << "'");
+ // Pass an empty range here since we don't add qualifier in this case.
+ std::vector<find_all_symbols::SymbolInfo> MatchedSymbols =
+ query(QueryString, "", tooling::Range());
+
+ if (!MatchedSymbols.empty() && GenerateDiagnostics) {
+ TypoCorrection Correction;
+ FileID FID = CI->getSourceManager().getFileID(Loc);
+ StringRef Code = CI->getSourceManager().getBufferData(FID);
+ SourceLocation StartOfFile =
+ CI->getSourceManager().getLocForStartOfFile(FID);
+ addDiagnosticsForContext(
+ Correction,
+ getIncludeFixerContext(CI->getSourceManager(),
+ CI->getPreprocessor().getHeaderSearchInfo(),
+ MatchedSymbols),
+ Code, StartOfFile, CI->getASTContext());
+ for (const PartialDiagnostic &PD : Correction.getExtraDiagnostics())
+ CI->getSema().Diag(Loc, PD);
+ }
+ return true;
+}
+
+/// Callback for unknown identifiers. Try to piece together as much
+/// qualification as we can get and do a query.
+clang::TypoCorrection IncludeFixerSemaSource::CorrectTypo(
+ const DeclarationNameInfo &Typo, int LookupKind, Scope *S, CXXScopeSpec *SS,
+ CorrectionCandidateCallback &CCC, DeclContext *MemberContext,
+ bool EnteringContext, const ObjCObjectPointerType *OPT) {
+ // Ignore spurious callbacks from SFINAE contexts.
+ if (CI->getSema().isSFINAEContext())
+ return clang::TypoCorrection();
+
+ // We currently ignore the unidentified symbol which is not from the
+ // main file.
+ //
+ // However, this is not always true due to templates in a non-self contained
+ // header, consider the case:
+ //
+ // // header.h
+ // template <typename T>
+ // class Foo {
+ // T t;
+ // };
+ //
+ // // test.cc
+ // // We need to add <bar.h> in test.cc instead of header.h.
+ // class Bar;
+ // Foo<Bar> foo;
+ //
+ // FIXME: Add the missing header to the header file where the symbol comes
+ // from.
+ if (!CI->getSourceManager().isWrittenInMainFile(Typo.getLoc()))
+ return clang::TypoCorrection();
+
+ std::string TypoScopeString;
+ if (S) {
+ // FIXME: Currently we only use namespace contexts. Use other context
+ // types for query.
+ for (const auto *Context = S->getEntity(); Context;
+ Context = Context->getParent()) {
+ if (const auto *ND = dyn_cast<NamespaceDecl>(Context)) {
+ if (!ND->getName().empty())
+ TypoScopeString = ND->getNameAsString() + "::" + TypoScopeString;
+ }
+ }
+ }
+
+ auto ExtendNestedNameSpecifier = [this](CharSourceRange Range) {
+ StringRef Source =
+ Lexer::getSourceText(Range, CI->getSourceManager(), CI->getLangOpts());
+
+ // Skip forward until we find a character that's neither identifier nor
+ // colon. This is a bit of a hack around the fact that we will only get a
+ // single callback for a long nested name if a part of the beginning is
+ // unknown. For example:
+ //
+ // llvm::sys::path::parent_path(...)
+ // ^~~~ ^~~
+ // known
+ // ^~~~
+ // unknown, last callback
+ // ^~~~~~~~~~~
+ // no callback
+ //
+ // With the extension we get the full nested name specifier including
+ // parent_path.
+ // FIXME: Don't rely on source text.
+ const char *End = Source.end();
+ while (isIdentifierBody(*End) || *End == ':')
+ ++End;
+
+ return std::string(Source.begin(), End);
+ };
+
+ /// If we have a scope specification, use that to get more precise results.
+ std::string QueryString;
+ tooling::Range SymbolRange;
+ const auto &SM = CI->getSourceManager();
+ auto CreateToolingRange = [&QueryString, &SM](SourceLocation BeginLoc) {
+ return tooling::Range(SM.getDecomposedLoc(BeginLoc).second,
+ QueryString.size());
+ };
+ if (SS && SS->getRange().isValid()) {
+ auto Range = CharSourceRange::getTokenRange(SS->getRange().getBegin(),
+ Typo.getLoc());
+
+ QueryString = ExtendNestedNameSpecifier(Range);
+ SymbolRange = CreateToolingRange(Range.getBegin());
+ } else if (Typo.getName().isIdentifier() && !Typo.getLoc().isMacroID()) {
+ auto Range =
+ CharSourceRange::getTokenRange(Typo.getBeginLoc(), Typo.getEndLoc());
+
+ QueryString = ExtendNestedNameSpecifier(Range);
+ SymbolRange = CreateToolingRange(Range.getBegin());
+ } else {
+ QueryString = Typo.getAsString();
+ SymbolRange = CreateToolingRange(Typo.getLoc());
+ }
+
+ LLVM_DEBUG(llvm::dbgs() << "TypoScopeQualifiers: " << TypoScopeString
+ << "\n");
+ std::vector<find_all_symbols::SymbolInfo> MatchedSymbols =
+ query(QueryString, TypoScopeString, SymbolRange);
+
+ if (!MatchedSymbols.empty() && GenerateDiagnostics) {
+ TypoCorrection Correction(Typo.getName());
+ Correction.setCorrectionRange(SS, Typo);
+ FileID FID = SM.getFileID(Typo.getLoc());
+ StringRef Code = SM.getBufferData(FID);
+ SourceLocation StartOfFile = SM.getLocForStartOfFile(FID);
+ if (addDiagnosticsForContext(
+ Correction, getIncludeFixerContext(
+ SM, CI->getPreprocessor().getHeaderSearchInfo(),
+ MatchedSymbols),
+ Code, StartOfFile, CI->getASTContext()))
+ return Correction;
+ }
+ return TypoCorrection();
+}
+
+/// Get the minimal include for a given path.
+std::string IncludeFixerSemaSource::minimizeInclude(
+ StringRef Include, const clang::SourceManager &SourceManager,
+ clang::HeaderSearch &HeaderSearch) const {
+ if (!MinimizeIncludePaths)
+ return Include;
+
+ // Get the FileEntry for the include.
+ StringRef StrippedInclude = Include.trim("\"<>");
+ const FileEntry *Entry =
+ SourceManager.getFileManager().getFile(StrippedInclude);
+
+ // If the file doesn't exist return the path from the database.
+ // FIXME: This should never happen.
+ if (!Entry)
+ return Include;
+
+ bool IsSystem;
+ std::string Suggestion =
+ HeaderSearch.suggestPathToFileForDiagnostics(Entry, &IsSystem);
+
+ return IsSystem ? '<' + Suggestion + '>' : '"' + Suggestion + '"';
+}
+
+/// Get the include fixer context for the queried symbol.
+IncludeFixerContext IncludeFixerSemaSource::getIncludeFixerContext(
+ const clang::SourceManager &SourceManager,
+ clang::HeaderSearch &HeaderSearch,
+ ArrayRef<find_all_symbols::SymbolInfo> MatchedSymbols) const {
+ std::vector<find_all_symbols::SymbolInfo> SymbolCandidates;
+ for (const auto &Symbol : MatchedSymbols) {
+ std::string FilePath = Symbol.getFilePath().str();
+ std::string MinimizedFilePath = minimizeInclude(
+ ((FilePath[0] == '"' || FilePath[0] == '<') ? FilePath
+ : "\"" + FilePath + "\""),
+ SourceManager, HeaderSearch);
+ SymbolCandidates.emplace_back(Symbol.getName(), Symbol.getSymbolKind(),
+ MinimizedFilePath, Symbol.getContexts());
+ }
+ return IncludeFixerContext(FilePath, QuerySymbolInfos, SymbolCandidates);
+}
+
+std::vector<find_all_symbols::SymbolInfo>
+IncludeFixerSemaSource::query(StringRef Query, StringRef ScopedQualifiers,
+ tooling::Range Range) {
+ assert(!Query.empty() && "Empty query!");
+
+ // Save all instances of an unidentified symbol.
+ //
+ // We use conservative behavior for detecting the same unidentified symbol
+ // here. The symbols which have the same ScopedQualifier and RawIdentifier
+ // are considered equal. So that include-fixer avoids false positives, and
+ // always adds missing qualifiers to correct symbols.
+ if (!GenerateDiagnostics && !QuerySymbolInfos.empty()) {
+ if (ScopedQualifiers == QuerySymbolInfos.front().ScopedQualifiers &&
+ Query == QuerySymbolInfos.front().RawIdentifier) {
+ QuerySymbolInfos.push_back({Query.str(), ScopedQualifiers, Range});
+ }
+ return {};
+ }
+
+ LLVM_DEBUG(llvm::dbgs() << "Looking up '" << Query << "' at ");
+ LLVM_DEBUG(CI->getSourceManager()
+ .getLocForStartOfFile(CI->getSourceManager().getMainFileID())
+ .getLocWithOffset(Range.getOffset())
+ .print(llvm::dbgs(), CI->getSourceManager()));
+ LLVM_DEBUG(llvm::dbgs() << " ...");
+ llvm::StringRef FileName = CI->getSourceManager().getFilename(
+ CI->getSourceManager().getLocForStartOfFile(
+ CI->getSourceManager().getMainFileID()));
+
+ QuerySymbolInfos.push_back({Query.str(), ScopedQualifiers, Range});
+
+ // Query the symbol based on C++ name Lookup rules.
+ // Firstly, lookup the identifier with scoped namespace contexts;
+ // If that fails, falls back to look up the identifier directly.
+ //
+ // For example:
+ //
+ // namespace a {
+ // b::foo f;
+ // }
+ //
+ // 1. lookup a::b::foo.
+ // 2. lookup b::foo.
+ std::string QueryString = ScopedQualifiers.str() + Query.str();
+ // It's unsafe to do nested search for the identifier with scoped namespace
+ // context, it might treat the identifier as a nested class of the scoped
+ // namespace.
+ std::vector<find_all_symbols::SymbolInfo> MatchedSymbols =
+ SymbolIndexMgr.search(QueryString, /*IsNestedSearch=*/false, FileName);
+ if (MatchedSymbols.empty())
+ MatchedSymbols =
+ SymbolIndexMgr.search(Query, /*IsNestedSearch=*/true, FileName);
+ LLVM_DEBUG(llvm::dbgs() << "Having found " << MatchedSymbols.size()
+ << " symbols\n");
+ // We store a copy of MatchedSymbols in a place where it's globally reachable.
+ // This is used by the standalone version of the tool.
+ this->MatchedSymbols = MatchedSymbols;
+ return MatchedSymbols;
+}
+
+llvm::Expected<tooling::Replacements> createIncludeFixerReplacements(
+ StringRef Code, const IncludeFixerContext &Context,
+ const clang::format::FormatStyle &Style, bool AddQualifiers) {
+ if (Context.getHeaderInfos().empty())
+ return tooling::Replacements();
+ StringRef FilePath = Context.getFilePath();
+ std::string IncludeName =
+ "#include " + Context.getHeaderInfos().front().Header + "\n";
+ // Create replacements for the new header.
+ clang::tooling::Replacements Insertions;
+ auto Err =
+ Insertions.add(tooling::Replacement(FilePath, UINT_MAX, 0, IncludeName));
+ if (Err)
+ return std::move(Err);
+
+ auto CleanReplaces = cleanupAroundReplacements(Code, Insertions, Style);
+ if (!CleanReplaces)
+ return CleanReplaces;
+
+ auto Replaces = std::move(*CleanReplaces);
+ if (AddQualifiers) {
+ for (const auto &Info : Context.getQuerySymbolInfos()) {
+ // Ignore the empty range.
+ if (Info.Range.getLength() > 0) {
+ auto R = tooling::Replacement(
+ {FilePath, Info.Range.getOffset(), Info.Range.getLength(),
+ Context.getHeaderInfos().front().QualifiedName});
+ auto Err = Replaces.add(R);
+ if (Err) {
+ llvm::consumeError(std::move(Err));
+ R = tooling::Replacement(
+ R.getFilePath(), Replaces.getShiftedCodePosition(R.getOffset()),
+ R.getLength(), R.getReplacementText());
+ Replaces = Replaces.merge(tooling::Replacements(R));
+ }
+ }
+ }
+ }
+ return formatReplacements(Code, Replaces, Style);
+}
+
+} // namespace include_fixer
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/IncludeFixer.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/IncludeFixer.h
new file mode 100644
index 0000000..13092a3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/IncludeFixer.h
@@ -0,0 +1,158 @@
+//===-- IncludeFixer.h - Include inserter -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXER_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXER_H
+
+#include "IncludeFixerContext.h"
+#include "SymbolIndexManager.h"
+#include "clang/Format/Format.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "clang/Tooling/Tooling.h"
+#include <memory>
+#include <vector>
+
+namespace clang {
+
+class CompilerInvocation;
+class DiagnosticConsumer;
+class FileManager;
+class PCHContainerOperations;
+
+namespace include_fixer {
+
+class IncludeFixerActionFactory : public clang::tooling::ToolAction {
+public:
+ /// \param SymbolIndexMgr A source for matching symbols to header files.
+ /// \param Contexts The contexts for the symbols being queried.
+ /// \param StyleName Fallback style for reformatting.
+ /// \param MinimizeIncludePaths whether inserted include paths are optimized.
+ IncludeFixerActionFactory(SymbolIndexManager &SymbolIndexMgr,
+ std::vector<IncludeFixerContext> &Contexts,
+ StringRef StyleName,
+ bool MinimizeIncludePaths = true);
+
+ ~IncludeFixerActionFactory() override;
+
+ bool
+ runInvocation(std::shared_ptr<clang::CompilerInvocation> Invocation,
+ clang::FileManager *Files,
+ std::shared_ptr<clang::PCHContainerOperations> PCHContainerOps,
+ clang::DiagnosticConsumer *Diagnostics) override;
+
+private:
+ /// The client to use to find cross-references.
+ SymbolIndexManager &SymbolIndexMgr;
+
+ /// Multiple contexts for files being processed.
+ std::vector<IncludeFixerContext> &Contexts;
+
+ /// Whether inserted include paths should be optimized.
+ bool MinimizeIncludePaths;
+
+ /// The fallback format style for formatting after insertion if no
+ /// clang-format config file was found.
+ std::string FallbackStyle;
+};
+
+/// Create replacements, which are generated by clang-format, for the
+/// missing header and mising qualifiers insertions. The function uses the
+/// first header for insertion.
+///
+/// \param Code The source code.
+/// \param Context The context which contains all information for creating
+/// include-fixer replacements.
+/// \param Style clang-format style being used.
+/// \param AddQualifiers Whether we should add qualifiers to all instances of
+/// an unidentified symbol.
+///
+/// \return Formatted replacements for inserting, sorting headers and adding
+/// qualifiers on success; otherwise, an llvm::Error carrying llvm::StringError
+/// is returned.
+llvm::Expected<tooling::Replacements> createIncludeFixerReplacements(
+ StringRef Code, const IncludeFixerContext &Context,
+ const format::FormatStyle &Style = format::getLLVMStyle(),
+ bool AddQualifiers = true);
+
+/// Handles callbacks from sema, does the include lookup and turns it into an
+/// IncludeFixerContext.
+class IncludeFixerSemaSource : public clang::ExternalSemaSource {
+public:
+ explicit IncludeFixerSemaSource(SymbolIndexManager &SymbolIndexMgr,
+ bool MinimizeIncludePaths,
+ bool GenerateDiagnostics)
+ : SymbolIndexMgr(SymbolIndexMgr),
+ MinimizeIncludePaths(MinimizeIncludePaths),
+ GenerateDiagnostics(GenerateDiagnostics) {}
+
+ void setCompilerInstance(CompilerInstance *CI) { this->CI = CI; }
+ void setFilePath(StringRef FilePath) { this->FilePath = FilePath; }
+
+ /// Callback for incomplete types. If we encounter a forward declaration we
+ /// have the fully qualified name ready. Just query that.
+ bool MaybeDiagnoseMissingCompleteType(clang::SourceLocation Loc,
+ clang::QualType T) override;
+
+ /// Callback for unknown identifiers. Try to piece together as much
+ /// qualification as we can get and do a query.
+ clang::TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo,
+ int LookupKind, Scope *S, CXXScopeSpec *SS,
+ CorrectionCandidateCallback &CCC,
+ DeclContext *MemberContext,
+ bool EnteringContext,
+ const ObjCObjectPointerType *OPT) override;
+
+ /// Get the minimal include for a given path.
+ std::string minimizeInclude(StringRef Include,
+ const clang::SourceManager &SourceManager,
+ clang::HeaderSearch &HeaderSearch) const;
+
+ /// Get the include fixer context for the queried symbol.
+ IncludeFixerContext getIncludeFixerContext(
+ const clang::SourceManager &SourceManager,
+ clang::HeaderSearch &HeaderSearch,
+ ArrayRef<find_all_symbols::SymbolInfo> MatchedSymbols) const;
+
+ /// Get the global matched symbols.
+ ArrayRef<find_all_symbols::SymbolInfo> getMatchedSymbols() const {
+ return MatchedSymbols;
+ }
+
+private:
+ /// Query the database for a given identifier.
+ std::vector<find_all_symbols::SymbolInfo>
+ query(StringRef Query, StringRef ScopedQualifiers, tooling::Range Range);
+
+ CompilerInstance *CI;
+
+ /// The client to use to find cross-references.
+ SymbolIndexManager &SymbolIndexMgr;
+
+ /// The information of the symbols being queried.
+ std::vector<IncludeFixerContext::QuerySymbolInfo> QuerySymbolInfos;
+
+ /// All symbol candidates which match QuerySymbol. We only include the first
+ /// discovered identifier to avoid getting caught in results from error
+ /// recovery.
+ std::vector<find_all_symbols::SymbolInfo> MatchedSymbols;
+
+ /// The file path to the file being processed.
+ std::string FilePath;
+
+ /// Whether we should use the smallest possible include path.
+ bool MinimizeIncludePaths = true;
+
+ /// Whether we should generate diagnostics with fixits for missing symbols.
+ bool GenerateDiagnostics = false;
+};
+} // namespace include_fixer
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/IncludeFixerContext.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/IncludeFixerContext.cpp
new file mode 100644
index 0000000..8106e20
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/IncludeFixerContext.cpp
@@ -0,0 +1,116 @@
+//===-- IncludeFixerContext.cpp - Include fixer context ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IncludeFixerContext.h"
+#include <algorithm>
+
+namespace clang {
+namespace include_fixer {
+
+namespace {
+
+// Splits a multiply qualified names (e.g. a::b::c).
+llvm::SmallVector<llvm::StringRef, 8>
+SplitQualifiers(llvm::StringRef StringQualifiers) {
+ llvm::SmallVector<llvm::StringRef, 8> Qualifiers;
+ StringQualifiers.split(Qualifiers, "::");
+ return Qualifiers;
+}
+
+std::string createQualifiedNameForReplacement(
+ llvm::StringRef RawSymbolName,
+ llvm::StringRef SymbolScopedQualifiersName,
+ const find_all_symbols::SymbolInfo &MatchedSymbol) {
+ // No need to add missing qualifiers if SymbolIndentifer has a global scope
+ // operator "::".
+ if (RawSymbolName.startswith("::"))
+ return RawSymbolName;
+
+ std::string QualifiedName = MatchedSymbol.getQualifiedName();
+
+ // For nested classes, the qualified name constructed from database misses
+ // some stripped qualifiers, because when we search a symbol in database,
+ // we strip qualifiers from the end until we find a result. So append the
+ // missing stripped qualifiers here.
+ //
+ // Get stripped qualifiers.
+ auto SymbolQualifiers = SplitQualifiers(RawSymbolName);
+ std::string StrippedQualifiers;
+ while (!SymbolQualifiers.empty() &&
+ !llvm::StringRef(QualifiedName).endswith(SymbolQualifiers.back())) {
+ StrippedQualifiers =
+ "::" + SymbolQualifiers.back().str() + StrippedQualifiers;
+ SymbolQualifiers.pop_back();
+ }
+ // Append the missing stripped qualifiers.
+ std::string FullyQualifiedName = QualifiedName + StrippedQualifiers;
+
+ // Try to find and skip the common prefix qualifiers.
+ auto FullySymbolQualifiers = SplitQualifiers(FullyQualifiedName);
+ auto ScopedQualifiers = SplitQualifiers(SymbolScopedQualifiersName);
+ auto FullySymbolQualifiersIter = FullySymbolQualifiers.begin();
+ auto SymbolScopedQualifiersIter = ScopedQualifiers.begin();
+ while (FullySymbolQualifiersIter != FullySymbolQualifiers.end() &&
+ SymbolScopedQualifiersIter != ScopedQualifiers.end()) {
+ if (*FullySymbolQualifiersIter != *SymbolScopedQualifiersIter)
+ break;
+ ++FullySymbolQualifiersIter;
+ ++SymbolScopedQualifiersIter;
+ }
+ std::string Result;
+ for (; FullySymbolQualifiersIter != FullySymbolQualifiers.end();
+ ++FullySymbolQualifiersIter) {
+ if (!Result.empty())
+ Result += "::";
+ Result += *FullySymbolQualifiersIter;
+ }
+ return Result;
+}
+
+} // anonymous namespace
+
+IncludeFixerContext::IncludeFixerContext(
+ StringRef FilePath, std::vector<QuerySymbolInfo> QuerySymbols,
+ std::vector<find_all_symbols::SymbolInfo> Symbols)
+ : FilePath(FilePath), QuerySymbolInfos(std::move(QuerySymbols)),
+ MatchedSymbols(std::move(Symbols)) {
+ // Remove replicated QuerySymbolInfos with the same range.
+ //
+ // QuerySymbolInfos may contain replicated elements. Because CorrectTypo
+ // callback doesn't always work as we expected. In somecases, it will be
+ // triggered at the same position or unidentified symbol multiple times.
+ std::sort(QuerySymbolInfos.begin(), QuerySymbolInfos.end(),
+ [&](const QuerySymbolInfo &A, const QuerySymbolInfo &B) {
+ return std::make_pair(A.Range.getOffset(), A.Range.getLength()) <
+ std::make_pair(B.Range.getOffset(), B.Range.getLength());
+ });
+ QuerySymbolInfos.erase(
+ std::unique(QuerySymbolInfos.begin(), QuerySymbolInfos.end(),
+ [](const QuerySymbolInfo &A, const QuerySymbolInfo &B) {
+ return A.Range == B.Range;
+ }),
+ QuerySymbolInfos.end());
+ for (const auto &Symbol : MatchedSymbols) {
+ HeaderInfos.push_back(
+ {Symbol.getFilePath().str(),
+ createQualifiedNameForReplacement(
+ QuerySymbolInfos.front().RawIdentifier,
+ QuerySymbolInfos.front().ScopedQualifiers, Symbol)});
+ }
+ // Deduplicate header infos.
+ HeaderInfos.erase(std::unique(HeaderInfos.begin(), HeaderInfos.end(),
+ [](const HeaderInfo &A, const HeaderInfo &B) {
+ return A.Header == B.Header &&
+ A.QualifiedName == B.QualifiedName;
+ }),
+ HeaderInfos.end());
+}
+
+} // include_fixer
+} // clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/IncludeFixerContext.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/IncludeFixerContext.h
new file mode 100644
index 0000000..3c44574
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/IncludeFixerContext.h
@@ -0,0 +1,95 @@
+//===-- IncludeFixerContext.h - Include fixer context -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXERCONTEXT_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXERCONTEXT_H
+
+#include "find-all-symbols/SymbolInfo.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace include_fixer {
+
+/// \brief A context for a file being processed. It includes all query
+/// information, e.g. symbols being queried in database, all header candidates.
+class IncludeFixerContext {
+public:
+ struct HeaderInfo {
+ /// \brief The header where QualifiedName comes from.
+ std::string Header;
+ /// \brief A symbol name with completed namespace qualifiers which will
+ /// replace the original symbol.
+ std::string QualifiedName;
+ };
+
+ struct QuerySymbolInfo {
+ /// \brief The raw symbol name being queried in database. This name might
+ /// miss some namespace qualifiers, and will be replaced by a fully
+ /// qualified one.
+ std::string RawIdentifier;
+
+ /// \brief The qualifiers of the scope in which SymbolIdentifier lookup
+ /// occurs. It is represented as a sequence of names and scope resolution
+ /// operatiors ::, ending with a scope resolution operator (e.g. a::b::).
+ /// Empty if SymbolIdentifier is not in a specific scope.
+ std::string ScopedQualifiers;
+
+ /// \brief The replacement range of RawIdentifier.
+ tooling::Range Range;
+ };
+
+ IncludeFixerContext() = default;
+ IncludeFixerContext(StringRef FilePath,
+ std::vector<QuerySymbolInfo> QuerySymbols,
+ std::vector<find_all_symbols::SymbolInfo> Symbols);
+
+ /// \brief Get symbol name.
+ llvm::StringRef getSymbolIdentifier() const {
+ return QuerySymbolInfos.front().RawIdentifier;
+ }
+
+ /// \brief Get replacement range of the symbol.
+ tooling::Range getSymbolRange() const {
+ return QuerySymbolInfos.front().Range;
+ }
+
+ /// \brief Get the file path to the file being processed.
+ StringRef getFilePath() const { return FilePath; }
+
+ /// \brief Get header information.
+ const std::vector<HeaderInfo> &getHeaderInfos() const { return HeaderInfos; }
+
+ /// \brief Get information of symbols being querid.
+ const std::vector<QuerySymbolInfo> &getQuerySymbolInfos() const {
+ return QuerySymbolInfos;
+ }
+
+private:
+ friend struct llvm::yaml::MappingTraits<IncludeFixerContext>;
+
+ /// \brief The file path to the file being processed.
+ std::string FilePath;
+
+ /// \brief All instances of an unidentified symbol being queried.
+ std::vector<QuerySymbolInfo> QuerySymbolInfos;
+
+ /// \brief The symbol candidates which match SymbolIdentifier. The symbols are
+ /// sorted in a descending order based on the popularity info in SymbolInfo.
+ std::vector<find_all_symbols::SymbolInfo> MatchedSymbols;
+
+ /// \brief The header information.
+ std::vector<HeaderInfo> HeaderInfos;
+};
+
+} // namespace include_fixer
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_INCLUDEFIXERCONTEXT_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/SymbolIndex.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/SymbolIndex.h
new file mode 100644
index 0000000..f3e6ecd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/SymbolIndex.h
@@ -0,0 +1,38 @@
+//===-- SymbolIndex.h - Interface for symbol-header matching ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_SYMBOLINDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_SYMBOLINDEX_H
+
+#include "find-all-symbols/SymbolInfo.h"
+#include "llvm/ADT/StringRef.h"
+#include <vector>
+
+namespace clang {
+namespace include_fixer {
+
+/// This class provides an interface for finding all `SymbolInfo`s corresponding
+/// to a symbol name from a symbol database.
+class SymbolIndex {
+public:
+ virtual ~SymbolIndex() = default;
+
+ /// Search for all `SymbolInfo`s corresponding to an identifier.
+ /// \param Identifier The unqualified identifier being searched for.
+ /// \returns A list of `SymbolInfo` candidates.
+ // FIXME: Expose the type name so we can also insert using declarations (or
+ // fix the usage)
+ virtual std::vector<find_all_symbols::SymbolAndSignals>
+ search(llvm::StringRef Identifier) = 0;
+};
+
+} // namespace include_fixer
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_SYMBOLINDEX_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/SymbolIndexManager.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/SymbolIndexManager.cpp
new file mode 100644
index 0000000..e4312bf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/SymbolIndexManager.cpp
@@ -0,0 +1,159 @@
+//===-- SymbolIndexManager.cpp - Managing multiple SymbolIndices-*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolIndexManager.h"
+#include "find-all-symbols/SymbolInfo.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Path.h"
+
+#define DEBUG_TYPE "include-fixer"
+
+namespace clang {
+namespace include_fixer {
+
+using find_all_symbols::SymbolInfo;
+using find_all_symbols::SymbolAndSignals;
+
+// Calculate a score based on whether we think the given header is closely
+// related to the given source file.
+static double similarityScore(llvm::StringRef FileName,
+ llvm::StringRef Header) {
+ // Compute the maximum number of common path segements between Header and
+ // a suffix of FileName.
+ // We do not do a full longest common substring computation, as Header
+ // specifies the path we would directly #include, so we assume it is rooted
+ // relatively to a subproject of the repository.
+ int MaxSegments = 1;
+ for (auto FileI = llvm::sys::path::begin(FileName),
+ FileE = llvm::sys::path::end(FileName);
+ FileI != FileE; ++FileI) {
+ int Segments = 0;
+ for (auto HeaderI = llvm::sys::path::begin(Header),
+ HeaderE = llvm::sys::path::end(Header), I = FileI;
+ HeaderI != HeaderE && *I == *HeaderI && I != FileE; ++I, ++HeaderI) {
+ ++Segments;
+ }
+ MaxSegments = std::max(Segments, MaxSegments);
+ }
+ return MaxSegments;
+}
+
+static void rank(std::vector<SymbolAndSignals> &Symbols,
+ llvm::StringRef FileName) {
+ llvm::DenseMap<llvm::StringRef, double> Score;
+ for (const auto &Symbol : Symbols) {
+ // Calculate a score from the similarity of the header the symbol is in
+ // with the current file and the popularity of the symbol.
+ double NewScore = similarityScore(FileName, Symbol.Symbol.getFilePath()) *
+ (1.0 + std::log2(1 + Symbol.Signals.Seen));
+ double &S = Score[Symbol.Symbol.getFilePath()];
+ S = std::max(S, NewScore);
+ }
+ // Sort by the gathered scores. Use file name as a tie breaker so we can
+ // deduplicate.
+ std::sort(Symbols.begin(), Symbols.end(),
+ [&](const SymbolAndSignals &A, const SymbolAndSignals &B) {
+ auto AS = Score[A.Symbol.getFilePath()];
+ auto BS = Score[B.Symbol.getFilePath()];
+ if (AS != BS)
+ return AS > BS;
+ return A.Symbol.getFilePath() < B.Symbol.getFilePath();
+ });
+}
+
+std::vector<find_all_symbols::SymbolInfo>
+SymbolIndexManager::search(llvm::StringRef Identifier,
+ bool IsNestedSearch,
+ llvm::StringRef FileName) const {
+ // The identifier may be fully qualified, so split it and get all the context
+ // names.
+ llvm::SmallVector<llvm::StringRef, 8> Names;
+ Identifier.split(Names, "::");
+
+ bool IsFullyQualified = false;
+ if (Identifier.startswith("::")) {
+ Names.erase(Names.begin()); // Drop first (empty) element.
+ IsFullyQualified = true;
+ }
+
+ // As long as we don't find a result keep stripping name parts from the end.
+ // This is to support nested classes which aren't recorded in the database.
+ // Eventually we will either hit a class (namespaces aren't in the database
+ // either) and can report that result.
+ bool TookPrefix = false;
+ std::vector<SymbolAndSignals> MatchedSymbols;
+ do {
+ std::vector<SymbolAndSignals> Symbols;
+ for (const auto &DB : SymbolIndices) {
+ auto Res = DB.get()->search(Names.back());
+ Symbols.insert(Symbols.end(), Res.begin(), Res.end());
+ }
+
+ LLVM_DEBUG(llvm::dbgs() << "Searching " << Names.back() << "... got "
+ << Symbols.size() << " results...\n");
+
+ for (auto &SymAndSig : Symbols) {
+ const SymbolInfo &Symbol = SymAndSig.Symbol;
+ // Match the identifier name without qualifier.
+ bool IsMatched = true;
+ auto SymbolContext = Symbol.getContexts().begin();
+ auto IdentiferContext = Names.rbegin() + 1; // Skip identifier name.
+ // Match the remaining context names.
+ while (IdentiferContext != Names.rend() &&
+ SymbolContext != Symbol.getContexts().end()) {
+ if (SymbolContext->second == *IdentiferContext) {
+ ++IdentiferContext;
+ ++SymbolContext;
+ } else if (SymbolContext->first ==
+ find_all_symbols::SymbolInfo::ContextType::EnumDecl) {
+ // Skip non-scoped enum context.
+ ++SymbolContext;
+ } else {
+ IsMatched = false;
+ break;
+ }
+ }
+
+ // If the name was qualified we only want to add results if we evaluated
+ // all contexts.
+ if (IsFullyQualified)
+ IsMatched &= (SymbolContext == Symbol.getContexts().end());
+
+ // FIXME: Support full match. At this point, we only find symbols in
+ // database which end with the same contexts with the identifier.
+ if (IsMatched && IdentiferContext == Names.rend()) {
+ // If we're in a situation where we took a prefix but the thing we
+ // found couldn't possibly have a nested member ignore it.
+ if (TookPrefix &&
+ (Symbol.getSymbolKind() == SymbolInfo::SymbolKind::Function ||
+ Symbol.getSymbolKind() == SymbolInfo::SymbolKind::Variable ||
+ Symbol.getSymbolKind() ==
+ SymbolInfo::SymbolKind::EnumConstantDecl ||
+ Symbol.getSymbolKind() == SymbolInfo::SymbolKind::Macro))
+ continue;
+
+ MatchedSymbols.push_back(std::move(SymAndSig));
+ }
+ }
+ Names.pop_back();
+ TookPrefix = true;
+ } while (MatchedSymbols.empty() && !Names.empty() && IsNestedSearch);
+
+ rank(MatchedSymbols, FileName);
+ // Strip signals, they are no longer needed.
+ std::vector<SymbolInfo> Res;
+ for (auto &SymAndSig : MatchedSymbols)
+ Res.push_back(std::move(SymAndSig.Symbol));
+ return Res;
+}
+
+} // namespace include_fixer
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/SymbolIndexManager.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/SymbolIndexManager.h
new file mode 100644
index 0000000..12963dd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/SymbolIndexManager.h
@@ -0,0 +1,66 @@
+//===-- SymbolIndexManager.h - Managing multiple SymbolIndices --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_SYMBOLINDEXMANAGER_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_SYMBOLINDEXMANAGER_H
+
+#include "SymbolIndex.h"
+#include "find-all-symbols/SymbolInfo.h"
+#include "llvm/ADT/StringRef.h"
+
+#ifdef _MSC_VER
+// Disable warnings from ppltasks.h transitively included by <future>.
+#pragma warning(push)
+#pragma warning(disable:4530)
+#endif
+
+#include <future>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+namespace clang {
+namespace include_fixer {
+
+/// This class provides an interface for finding the header files corresponding
+/// to an identifier in the source code from multiple symbol databases.
+class SymbolIndexManager {
+public:
+ void addSymbolIndex(std::function<std::unique_ptr<SymbolIndex>()> F) {
+#if LLVM_ENABLE_THREADS
+ auto Strategy = std::launch::async;
+#else
+ auto Strategy = std::launch::deferred;
+#endif
+ SymbolIndices.push_back(std::async(Strategy, F));
+ }
+
+ /// Search for header files to be included for an identifier.
+ /// \param Identifier The identifier being searched for. May or may not be
+ /// fully qualified.
+ /// \param IsNestedSearch Whether searching nested classes. If true, the
+ /// method tries to strip identifier name parts from the end until it
+ /// finds the corresponding candidates in database (e.g for identifier
+ /// "b::foo", the method will try to find "b" if it fails to find
+ /// "b::foo").
+ ///
+ /// \returns A list of symbol candidates.
+ std::vector<find_all_symbols::SymbolInfo>
+ search(llvm::StringRef Identifier, bool IsNestedSearch = true,
+ llvm::StringRef FileName = "") const;
+
+private:
+ std::vector<std::shared_future<std::unique_ptr<SymbolIndex>>> SymbolIndices;
+};
+
+} // namespace include_fixer
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/YamlSymbolIndex.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/YamlSymbolIndex.cpp
new file mode 100644
index 0000000..f3f2d5a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/YamlSymbolIndex.cpp
@@ -0,0 +1,61 @@
+//===-- YamlSymbolIndex.cpp -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "YamlSymbolIndex.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include <string>
+#include <vector>
+
+using clang::find_all_symbols::SymbolInfo;
+using clang::find_all_symbols::SymbolAndSignals;
+
+namespace clang {
+namespace include_fixer {
+
+llvm::ErrorOr<std::unique_ptr<YamlSymbolIndex>>
+YamlSymbolIndex::createFromFile(llvm::StringRef FilePath) {
+ auto Buffer = llvm::MemoryBuffer::getFile(FilePath);
+ if (!Buffer)
+ return Buffer.getError();
+
+ return std::unique_ptr<YamlSymbolIndex>(new YamlSymbolIndex(
+ find_all_symbols::ReadSymbolInfosFromYAML(Buffer.get()->getBuffer())));
+}
+
+llvm::ErrorOr<std::unique_ptr<YamlSymbolIndex>>
+YamlSymbolIndex::createFromDirectory(llvm::StringRef Directory,
+ llvm::StringRef Name) {
+ // Walk upwards from Directory, looking for files.
+ for (llvm::SmallString<128> PathStorage = Directory; !Directory.empty();
+ Directory = llvm::sys::path::parent_path(Directory)) {
+ assert(Directory.size() <= PathStorage.size());
+ PathStorage.resize(Directory.size()); // Shrink to parent.
+ llvm::sys::path::append(PathStorage, Name);
+ if (auto DB = createFromFile(PathStorage))
+ return DB;
+ }
+ return llvm::make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
+std::vector<SymbolAndSignals>
+YamlSymbolIndex::search(llvm::StringRef Identifier) {
+ std::vector<SymbolAndSignals> Results;
+ for (const auto &Symbol : Symbols) {
+ if (Symbol.Symbol.getName() == Identifier)
+ Results.push_back(Symbol);
+ }
+ return Results;
+}
+
+} // namespace include_fixer
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/YamlSymbolIndex.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/YamlSymbolIndex.h
new file mode 100644
index 0000000..d5d699a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/YamlSymbolIndex.h
@@ -0,0 +1,46 @@
+//===-- YamlSymbolIndex.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_YAMLSYMBOLINDEX_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_YAMLSYMBOLINDEX_H
+
+#include "SymbolIndex.h"
+#include "find-all-symbols/SymbolInfo.h"
+#include "llvm/Support/ErrorOr.h"
+#include <map>
+#include <vector>
+
+namespace clang {
+namespace include_fixer {
+
+/// Yaml format database.
+class YamlSymbolIndex : public SymbolIndex {
+public:
+ /// Create a new Yaml db from a file.
+ static llvm::ErrorOr<std::unique_ptr<YamlSymbolIndex>>
+ createFromFile(llvm::StringRef FilePath);
+ /// Look for a file called \c Name in \c Directory and all parent directories.
+ static llvm::ErrorOr<std::unique_ptr<YamlSymbolIndex>>
+ createFromDirectory(llvm::StringRef Directory, llvm::StringRef Name);
+
+ std::vector<find_all_symbols::SymbolAndSignals>
+ search(llvm::StringRef Identifier) override;
+
+private:
+ explicit YamlSymbolIndex(
+ std::vector<find_all_symbols::SymbolAndSignals> Symbols)
+ : Symbols(std::move(Symbols)) {}
+
+ std::vector<find_all_symbols::SymbolAndSignals> Symbols;
+};
+
+} // namespace include_fixer
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_YAMLSYMBOLINDEX_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/CMakeLists.txt
new file mode 100644
index 0000000..c5fe19b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/CMakeLists.txt
@@ -0,0 +1,24 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_library(findAllSymbols
+ FindAllSymbols.cpp
+ FindAllSymbolsAction.cpp
+ FindAllMacros.cpp
+ HeaderMapCollector.cpp
+ PathConfig.cpp
+ PragmaCommentHandler.cpp
+ STLPostfixHeaderMap.cpp
+ SymbolInfo.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFrontend
+ clangLex
+ clangTooling
+ )
+
+add_subdirectory(tool)
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllMacros.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllMacros.cpp
new file mode 100644
index 0000000..3dc2b96
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllMacros.cpp
@@ -0,0 +1,70 @@
+//===-- FindAllMacros.cpp - find all macros ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FindAllMacros.h"
+#include "HeaderMapCollector.h"
+#include "PathConfig.h"
+#include "SymbolInfo.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Token.h"
+#include "llvm/Support/Path.h"
+
+namespace clang {
+namespace find_all_symbols {
+
+llvm::Optional<SymbolInfo>
+FindAllMacros::CreateMacroSymbol(const Token &MacroNameTok,
+ const MacroInfo *info) {
+ std::string FilePath =
+ getIncludePath(*SM, info->getDefinitionLoc(), Collector);
+ if (FilePath.empty())
+ return llvm::None;
+ return SymbolInfo(MacroNameTok.getIdentifierInfo()->getName(),
+ SymbolInfo::SymbolKind::Macro, FilePath, {});
+}
+
+void FindAllMacros::MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ if (auto Symbol = CreateMacroSymbol(MacroNameTok, MD->getMacroInfo()))
+ ++FileSymbols[*Symbol].Seen;
+}
+
+void FindAllMacros::MacroUsed(const Token &Name, const MacroDefinition &MD) {
+ if (!MD || !SM->isInMainFile(SM->getExpansionLoc(Name.getLocation())))
+ return;
+ if (auto Symbol = CreateMacroSymbol(Name, MD.getMacroInfo()))
+ ++FileSymbols[*Symbol].Used;
+}
+
+void FindAllMacros::MacroExpands(const Token &MacroNameTok,
+ const MacroDefinition &MD, SourceRange Range,
+ const MacroArgs *Args) {
+ MacroUsed(MacroNameTok, MD);
+}
+
+void FindAllMacros::Ifdef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDefinition &MD) {
+ MacroUsed(MacroNameTok, MD);
+}
+
+void FindAllMacros::Ifndef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDefinition &MD) {
+ MacroUsed(MacroNameTok, MD);
+}
+
+void FindAllMacros::EndOfMainFile() {
+ Reporter->reportSymbols(SM->getFileEntryForID(SM->getMainFileID())->getName(),
+ FileSymbols);
+ FileSymbols.clear();
+}
+
+} // namespace find_all_symbols
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllMacros.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllMacros.h
new file mode 100644
index 0000000..10b4a69
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllMacros.h
@@ -0,0 +1,65 @@
+//===-- FindAllMacros.h - find all macros -----------------------*- C++ -*-===//
+//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_MACROS_H
+#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_MACROS_H
+
+#include "SymbolInfo.h"
+#include "SymbolReporter.h"
+#include "clang/Lex/PPCallbacks.h"
+
+namespace clang {
+class MacroInfo;
+namespace find_all_symbols {
+
+class HeaderMapCollector;
+
+/// \brief A preprocessor that collects all macro symbols.
+/// The contexts of a macro will be ignored since they are not available during
+/// preprocessing period.
+class FindAllMacros : public clang::PPCallbacks {
+public:
+ explicit FindAllMacros(SymbolReporter *Reporter, SourceManager *SM,
+ HeaderMapCollector *Collector = nullptr)
+ : Reporter(Reporter), SM(SM), Collector(Collector) {}
+
+ void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override;
+
+ void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
+ SourceRange Range, const MacroArgs *Args) override;
+
+ void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDefinition &MD) override;
+
+ void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDefinition &MD) override;
+
+ void EndOfMainFile() override;
+
+private:
+ llvm::Optional<SymbolInfo> CreateMacroSymbol(const Token &MacroNameTok,
+ const MacroInfo *MD);
+ // Not a callback, just a common path for all usage types.
+ void MacroUsed(const Token &Name, const MacroDefinition &MD);
+
+ SymbolInfo::SignalMap FileSymbols;
+ // Reporter for SymbolInfo.
+ SymbolReporter *const Reporter;
+ SourceManager *const SM;
+ // A remapping header file collector allowing clients to include a different
+ // header.
+ HeaderMapCollector *const Collector;
+};
+
+} // namespace find_all_symbols
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_MACROS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllSymbols.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllSymbols.cpp
new file mode 100644
index 0000000..bd5032d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllSymbols.cpp
@@ -0,0 +1,269 @@
+//===-- FindAllSymbols.cpp - find all symbols--------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FindAllSymbols.h"
+#include "HeaderMapCollector.h"
+#include "PathConfig.h"
+#include "SymbolInfo.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/FileSystem.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace find_all_symbols {
+namespace {
+
+AST_MATCHER(EnumConstantDecl, isInScopedEnum) {
+ if (const auto *ED = dyn_cast<EnumDecl>(Node.getDeclContext()))
+ return ED->isScoped();
+ return false;
+}
+
+AST_POLYMORPHIC_MATCHER(isFullySpecialized,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, VarDecl,
+ CXXRecordDecl)) {
+ if (Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
+ bool IsPartialSpecialization =
+ llvm::isa<VarTemplatePartialSpecializationDecl>(Node) ||
+ llvm::isa<ClassTemplatePartialSpecializationDecl>(Node);
+ return !IsPartialSpecialization;
+ }
+ return false;
+}
+
+std::vector<SymbolInfo::Context> GetContexts(const NamedDecl *ND) {
+ std::vector<SymbolInfo::Context> Contexts;
+ for (const auto *Context = ND->getDeclContext(); Context;
+ Context = Context->getParent()) {
+ if (llvm::isa<TranslationUnitDecl>(Context) ||
+ llvm::isa<LinkageSpecDecl>(Context))
+ break;
+
+ assert(llvm::isa<NamedDecl>(Context) &&
+ "Expect Context to be a NamedDecl");
+ if (const auto *NSD = dyn_cast<NamespaceDecl>(Context)) {
+ if (!NSD->isInlineNamespace())
+ Contexts.emplace_back(SymbolInfo::ContextType::Namespace,
+ NSD->getName().str());
+ } else if (const auto *ED = dyn_cast<EnumDecl>(Context)) {
+ Contexts.emplace_back(SymbolInfo::ContextType::EnumDecl,
+ ED->getName().str());
+ } else {
+ const auto *RD = cast<RecordDecl>(Context);
+ Contexts.emplace_back(SymbolInfo::ContextType::Record,
+ RD->getName().str());
+ }
+ }
+ return Contexts;
+}
+
+llvm::Optional<SymbolInfo>
+CreateSymbolInfo(const NamedDecl *ND, const SourceManager &SM,
+ const HeaderMapCollector *Collector) {
+ SymbolInfo::SymbolKind Type;
+ if (llvm::isa<VarDecl>(ND)) {
+ Type = SymbolInfo::SymbolKind::Variable;
+ } else if (llvm::isa<FunctionDecl>(ND)) {
+ Type = SymbolInfo::SymbolKind::Function;
+ } else if (llvm::isa<TypedefNameDecl>(ND)) {
+ Type = SymbolInfo::SymbolKind::TypedefName;
+ } else if (llvm::isa<EnumConstantDecl>(ND)) {
+ Type = SymbolInfo::SymbolKind::EnumConstantDecl;
+ } else if (llvm::isa<EnumDecl>(ND)) {
+ Type = SymbolInfo::SymbolKind::EnumDecl;
+ // Ignore anonymous enum declarations.
+ if (ND->getName().empty())
+ return llvm::None;
+ } else {
+ assert(llvm::isa<RecordDecl>(ND) &&
+ "Matched decl must be one of VarDecl, "
+ "FunctionDecl, TypedefNameDecl, EnumConstantDecl, "
+ "EnumDecl and RecordDecl!");
+ // C-style record decl can have empty name, e.g "struct { ... } var;".
+ if (ND->getName().empty())
+ return llvm::None;
+ Type = SymbolInfo::SymbolKind::Class;
+ }
+
+ SourceLocation Loc = SM.getExpansionLoc(ND->getLocation());
+ if (!Loc.isValid()) {
+ llvm::errs() << "Declaration " << ND->getNameAsString() << "("
+ << ND->getDeclKindName()
+ << ") has invalid declaration location.";
+ return llvm::None;
+ }
+
+ std::string FilePath = getIncludePath(SM, Loc, Collector);
+ if (FilePath.empty()) return llvm::None;
+
+ return SymbolInfo(ND->getNameAsString(), Type, FilePath, GetContexts(ND));
+}
+
+} // namespace
+
+void FindAllSymbols::registerMatchers(MatchFinder *MatchFinder) {
+ // FIXME: Handle specialization.
+ auto IsInSpecialization = hasAncestor(
+ decl(anyOf(cxxRecordDecl(isExplicitTemplateSpecialization()),
+ functionDecl(isExplicitTemplateSpecialization()))));
+
+ // Matchers for both C and C++.
+ // We only match symbols from header files, i.e. not from main files (see
+ // function's comment for detailed explanation).
+ auto CommonFilter =
+ allOf(unless(isImplicit()), unless(isExpansionInMainFile()));
+
+ auto HasNSOrTUCtxMatcher =
+ hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()));
+
+ // We need seperate rules for C record types and C++ record types since some
+ // template related matchers are inapplicable on C record declarations.
+ //
+ // Matchers specific to C++ code.
+ // All declarations should be in namespace or translation unit.
+ auto CCMatcher =
+ allOf(HasNSOrTUCtxMatcher, unless(IsInSpecialization),
+ unless(ast_matchers::isTemplateInstantiation()),
+ unless(isInstantiated()), unless(isFullySpecialized()));
+
+ // Matchers specific to code in extern "C" {...}.
+ auto ExternCMatcher = hasDeclContext(linkageSpecDecl());
+
+ // Matchers for variable declarations.
+ //
+ // In most cases, `ParmVarDecl` is filtered out by hasDeclContext(...)
+ // matcher since the declaration context is usually `MethodDecl`. However,
+ // this assumption does not hold for parameters of a function pointer
+ // parameter.
+ // For example, consider a function declaration:
+ // void Func(void (*)(float), int);
+ // The float parameter of the function pointer has an empty name, and its
+ // declaration context is an anonymous namespace; therefore, it won't be
+ // filtered out by our matchers above.
+ auto Vars = varDecl(CommonFilter, anyOf(ExternCMatcher, CCMatcher),
+ unless(parmVarDecl()));
+
+ // Matchers for C-style record declarations in extern "C" {...}.
+ auto CRecords = recordDecl(CommonFilter, ExternCMatcher, isDefinition());
+ // Matchers for C++ record declarations.
+ auto CXXRecords = cxxRecordDecl(CommonFilter, CCMatcher, isDefinition());
+
+ // Matchers for function declarations.
+ // We want to exclude friend declaration, but the `DeclContext` of a friend
+ // function declaration is not the class in which it is declared, so we need
+ // to explicitly check if the parent is a `friendDecl`.
+ auto Functions = functionDecl(CommonFilter, unless(hasParent(friendDecl())),
+ anyOf(ExternCMatcher, CCMatcher));
+
+ // Matcher for typedef and type alias declarations.
+ //
+ // typedef and type alias can come from C-style headers and C++ headers.
+ // For C-style headers, `DeclContxet` can be either `TranslationUnitDecl`
+ // or `LinkageSpecDecl`.
+ // For C++ headers, `DeclContext ` can be either `TranslationUnitDecl`
+ // or `NamespaceDecl`.
+ // With the following context matcher, we can match `typedefNameDecl` from
+ // both C-style headers and C++ headers (except for those in classes).
+ // "cc_matchers" are not included since template-related matchers are not
+ // applicable on `TypedefNameDecl`.
+ auto Typedefs =
+ typedefNameDecl(CommonFilter, anyOf(HasNSOrTUCtxMatcher,
+ hasDeclContext(linkageSpecDecl())));
+
+ // Matchers for enum declarations.
+ auto Enums = enumDecl(CommonFilter, isDefinition(),
+ anyOf(HasNSOrTUCtxMatcher, ExternCMatcher));
+
+ // Matchers for enum constant declarations.
+ // We only match the enum constants in non-scoped enum declarations which are
+ // inside toplevel translation unit or a namespace.
+ auto EnumConstants = enumConstantDecl(
+ CommonFilter, unless(isInScopedEnum()),
+ anyOf(hasDeclContext(enumDecl(HasNSOrTUCtxMatcher)), ExternCMatcher));
+
+ // Most of the time we care about all matchable decls, or all types.
+ auto Types = namedDecl(anyOf(CRecords, CXXRecords, Enums));
+ auto Decls = namedDecl(anyOf(CRecords, CXXRecords, Enums, Typedefs, Vars,
+ EnumConstants, Functions));
+
+ // We want eligible decls bound to "decl"...
+ MatchFinder->addMatcher(Decls.bind("decl"), this);
+
+ // ... and all uses of them bound to "use". These have many cases:
+ // Uses of values/functions: these generate a declRefExpr.
+ MatchFinder->addMatcher(
+ declRefExpr(isExpansionInMainFile(), to(Decls.bind("use"))), this);
+ // Uses of function templates:
+ MatchFinder->addMatcher(
+ declRefExpr(isExpansionInMainFile(),
+ to(functionDecl(hasParent(
+ functionTemplateDecl(has(Functions.bind("use"))))))),
+ this);
+
+ // Uses of most types: just look at what the typeLoc refers to.
+ MatchFinder->addMatcher(
+ typeLoc(isExpansionInMainFile(),
+ loc(qualType(hasDeclaration(Types.bind("use"))))),
+ this);
+ // Uses of typedefs: these are often transparent to hasDeclaration, so we need
+ // to handle them explicitly.
+ MatchFinder->addMatcher(
+ typeLoc(isExpansionInMainFile(),
+ loc(typedefType(hasDeclaration(Typedefs.bind("use"))))),
+ this);
+ // Uses of class templates:
+ // The typeLoc names the templateSpecializationType. Its declaration is the
+ // ClassTemplateDecl, which contains the CXXRecordDecl we want.
+ MatchFinder->addMatcher(
+ typeLoc(isExpansionInMainFile(),
+ loc(templateSpecializationType(hasDeclaration(
+ classTemplateSpecializationDecl(hasSpecializedTemplate(
+ classTemplateDecl(has(CXXRecords.bind("use"))))))))),
+ this);
+}
+
+void FindAllSymbols::run(const MatchFinder::MatchResult &Result) {
+ // Ignore Results in failing TUs.
+ if (Result.Context->getDiagnostics().hasErrorOccurred()) {
+ return;
+ }
+
+ SymbolInfo::Signals Signals;
+ const NamedDecl *ND;
+ if ((ND = Result.Nodes.getNodeAs<NamedDecl>("use")))
+ Signals.Used = 1;
+ else if ((ND = Result.Nodes.getNodeAs<NamedDecl>("decl")))
+ Signals.Seen = 1;
+ else
+ assert(false && "Must match a NamedDecl!");
+
+ const SourceManager *SM = Result.SourceManager;
+ if (auto Symbol = CreateSymbolInfo(ND, *SM, Collector)) {
+ Filename = SM->getFileEntryForID(SM->getMainFileID())->getName();
+ FileSymbols[*Symbol] += Signals;
+ }
+}
+
+void FindAllSymbols::onEndOfTranslationUnit() {
+ if (Filename != "") {
+ Reporter->reportSymbols(Filename, FileSymbols);
+ FileSymbols.clear();
+ Filename = "";
+ }
+}
+
+} // namespace find_all_symbols
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllSymbols.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllSymbols.h
new file mode 100644
index 0000000..fca849f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllSymbols.h
@@ -0,0 +1,63 @@
+//===-- FindAllSymbols.h - find all symbols----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_MATCHER_H
+#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_MATCHER_H
+
+#include "SymbolInfo.h"
+#include "SymbolReporter.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <string>
+
+namespace clang {
+namespace find_all_symbols {
+
+class HeaderMapCollector;
+
+/// \brief FindAllSymbols collects all classes, free standing functions and
+/// global variables with some extra information such as the path of the header
+/// file, the namespaces they are contained in, the type of variables and the
+/// parameter types of functions.
+///
+/// NOTE:
+/// - Symbols declared in main files are not collected since they can not be
+/// included.
+/// - Member functions are not collected because accessing them must go
+/// through the class. #include fixer only needs the class name to find
+/// headers.
+///
+class FindAllSymbols : public ast_matchers::MatchFinder::MatchCallback {
+public:
+ explicit FindAllSymbols(SymbolReporter *Reporter,
+ HeaderMapCollector *Collector = nullptr)
+ : Reporter(Reporter), Collector(Collector) {}
+
+ void registerMatchers(ast_matchers::MatchFinder *MatchFinder);
+
+ void run(const ast_matchers::MatchFinder::MatchResult &result) override;
+
+protected:
+ void onEndOfTranslationUnit() override;
+
+private:
+ // Current source file being processed, filled by first symbol found.
+ std::string Filename;
+ // Findings for the current source file, flushed on onEndOfTranslationUnit.
+ SymbolInfo::SignalMap FileSymbols;
+ // Reporter for SymbolInfo.
+ SymbolReporter *const Reporter;
+ // A remapping header file collector allowing clients include a different
+ // header.
+ HeaderMapCollector *const Collector;
+};
+
+} // namespace find_all_symbols
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_MATCHER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllSymbolsAction.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllSymbolsAction.cpp
new file mode 100644
index 0000000..bc00547
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllSymbolsAction.cpp
@@ -0,0 +1,37 @@
+//===-- FindAllSymbolsAction.cpp - find all symbols action --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FindAllSymbolsAction.h"
+#include "FindAllMacros.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace clang {
+namespace find_all_symbols {
+
+FindAllSymbolsAction::FindAllSymbolsAction(
+ SymbolReporter *Reporter,
+ const HeaderMapCollector::RegexHeaderMap *RegexHeaderMap)
+ : Reporter(Reporter), Collector(RegexHeaderMap), Handler(&Collector),
+ Matcher(Reporter, &Collector) {
+ Matcher.registerMatchers(&MatchFinder);
+}
+
+std::unique_ptr<ASTConsumer>
+FindAllSymbolsAction::CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef InFile) {
+ Compiler.getPreprocessor().addCommentHandler(&Handler);
+ Compiler.getPreprocessor().addPPCallbacks(llvm::make_unique<FindAllMacros>(
+ Reporter, &Compiler.getSourceManager(), &Collector));
+ return MatchFinder.newASTConsumer();
+}
+
+} // namespace find_all_symbols
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllSymbolsAction.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllSymbolsAction.h
new file mode 100644
index 0000000..7be9fe2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/FindAllSymbolsAction.h
@@ -0,0 +1,63 @@
+//===-- FindAllSymbolsAction.h - find all symbols action --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_SYMBOLS_ACTION_H
+#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_SYMBOLS_ACTION_H
+
+#include "FindAllSymbols.h"
+#include "HeaderMapCollector.h"
+#include "PragmaCommentHandler.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/StringRef.h"
+#include <memory>
+
+namespace clang {
+namespace find_all_symbols {
+
+class FindAllSymbolsAction : public clang::ASTFrontendAction {
+public:
+ explicit FindAllSymbolsAction(
+ SymbolReporter *Reporter,
+ const HeaderMapCollector::RegexHeaderMap *RegexHeaderMap = nullptr);
+
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &Compiler,
+ StringRef InFile) override;
+
+private:
+ SymbolReporter *const Reporter;
+ clang::ast_matchers::MatchFinder MatchFinder;
+ HeaderMapCollector Collector;
+ PragmaCommentHandler Handler;
+ FindAllSymbols Matcher;
+};
+
+class FindAllSymbolsActionFactory : public tooling::FrontendActionFactory {
+public:
+ FindAllSymbolsActionFactory(
+ SymbolReporter *Reporter,
+ const HeaderMapCollector::RegexHeaderMap *RegexHeaderMap = nullptr)
+ : Reporter(Reporter), RegexHeaderMap(RegexHeaderMap) {}
+
+ clang::FrontendAction *create() override {
+ return new FindAllSymbolsAction(Reporter, RegexHeaderMap);
+ }
+
+private:
+ SymbolReporter *const Reporter;
+ const HeaderMapCollector::RegexHeaderMap *const RegexHeaderMap;
+};
+
+} // namespace find_all_symbols
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_FIND_ALL_SYMBOLS_ACTION_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/HeaderMapCollector.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/HeaderMapCollector.cpp
new file mode 100644
index 0000000..379df81
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/HeaderMapCollector.cpp
@@ -0,0 +1,45 @@
+//===-- HeaderMapCoolector.h - find all symbols------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HeaderMapCollector.h"
+#include "llvm/Support/Regex.h"
+
+namespace clang {
+namespace find_all_symbols {
+
+HeaderMapCollector::HeaderMapCollector(
+ const RegexHeaderMap *RegexHeaderMappingTable) {
+ assert(RegexHeaderMappingTable);
+ this->RegexHeaderMappingTable.reserve(RegexHeaderMappingTable->size());
+ for (const auto &Entry : *RegexHeaderMappingTable) {
+ this->RegexHeaderMappingTable.emplace_back(llvm::Regex(Entry.first),
+ Entry.second);
+ }
+}
+
+llvm::StringRef
+HeaderMapCollector::getMappedHeader(llvm::StringRef Header) const {
+ auto Iter = HeaderMappingTable.find(Header);
+ if (Iter != HeaderMappingTable.end())
+ return Iter->second;
+ // If there is no complete header name mapping for this header, check the
+ // regex header mapping.
+ for (auto &Entry : RegexHeaderMappingTable) {
+#ifndef NDEBUG
+ std::string Dummy;
+ assert(Entry.first.isValid(Dummy) && "Regex should never be invalid!");
+#endif
+ if (Entry.first.match(Header))
+ return Entry.second;
+ }
+ return Header;
+}
+
+} // namespace find_all_symbols
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/HeaderMapCollector.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/HeaderMapCollector.h
new file mode 100644
index 0000000..65edd75
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/HeaderMapCollector.h
@@ -0,0 +1,57 @@
+//===-- HeaderMapCoolector.h - find all symbols------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_HEADER_MAP_COLLECTOR_H
+#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_HEADER_MAP_COLLECTOR_H
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Regex.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace find_all_symbols {
+
+/// \brief HeaderMappCollector collects all remapping header files. This maps
+/// complete header names or header name regex patterns to header names.
+class HeaderMapCollector {
+public:
+ typedef llvm::StringMap<std::string> HeaderMap;
+ typedef std::vector<std::pair<const char *, const char *>> RegexHeaderMap;
+
+ HeaderMapCollector() = default;
+ explicit HeaderMapCollector(const RegexHeaderMap *RegexHeaderMappingTable);
+
+ void addHeaderMapping(llvm::StringRef OrignalHeaderPath,
+ llvm::StringRef MappingHeaderPath) {
+ HeaderMappingTable[OrignalHeaderPath] = MappingHeaderPath;
+ };
+
+ /// Check if there is a mapping from \p Header or a regex pattern that matches
+ /// it to another header name.
+ /// \param Header A header name.
+ /// \return \p Header itself if there is no mapping for it; otherwise, return
+ /// a mapped header name.
+ llvm::StringRef getMappedHeader(llvm::StringRef Header) const;
+
+private:
+ /// A string-to-string map saving the mapping relationship.
+ HeaderMap HeaderMappingTable;
+
+ // A map from header patterns to header names.
+ // The header names are not owned. This is only threadsafe because the regexes
+ // never fail.
+ mutable std::vector<std::pair<llvm::Regex, const char *>>
+ RegexHeaderMappingTable;
+};
+
+} // namespace find_all_symbols
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_HEADER_MAP_COLLECTOR_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/PathConfig.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/PathConfig.cpp
new file mode 100644
index 0000000..de799b9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/PathConfig.cpp
@@ -0,0 +1,42 @@
+//===-- PathConfig.cpp - Process paths of symbols ---------------*- C++ -*-===//
+//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PathConfig.h"
+#include "llvm/Support/Path.h"
+
+namespace clang {
+namespace find_all_symbols {
+
+std::string getIncludePath(const SourceManager &SM, SourceLocation Loc,
+ const HeaderMapCollector *Collector) {
+ llvm::StringRef FilePath;
+ // Walk up the include stack to skip .inc files.
+ while (true) {
+ if (!Loc.isValid() || SM.isInMainFile(Loc))
+ return "";
+ FilePath = SM.getFilename(Loc);
+ if (FilePath.empty())
+ return "";
+ if (!FilePath.endswith(".inc"))
+ break;
+ FileID ID = SM.getFileID(Loc);
+ Loc = SM.getIncludeLoc(ID);
+ }
+
+ if (Collector)
+ FilePath = Collector->getMappedHeader(FilePath);
+ SmallString<256> CleanedFilePath = FilePath;
+ llvm::sys::path::remove_dots(CleanedFilePath, /*remove_dot_dot=*/false);
+
+ return CleanedFilePath.str();
+}
+
+} // namespace find_all_symbols
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/PathConfig.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/PathConfig.h
new file mode 100644
index 0000000..50de548
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/PathConfig.h
@@ -0,0 +1,37 @@
+//===-- PathConfig.h - Process paths of symbols -----------------*- C++ -*-===//
+//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PATH_CONFIG_H
+#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PATH_CONFIG_H
+
+#include "HeaderMapCollector.h"
+#include "clang/Basic/SourceManager.h"
+#include <string>
+
+namespace clang {
+namespace find_all_symbols {
+
+/// \brief This calculates the include path for \p Loc.
+///
+/// \param SM SourceManager.
+/// \param Loc A SourceLocation.
+/// \param Collector An optional header mapping collector.
+///
+/// \return The file path (or mapped file path if Collector is provided) of the
+/// header that includes \p Loc. If \p Loc comes from .inc header file, \p Loc
+/// is set to the location from which the .inc header file is included. If \p
+/// Loc is invalid or comes from a main file, this returns an empty string.
+std::string getIncludePath(const SourceManager &SM, SourceLocation Loc,
+ const HeaderMapCollector *Collector = nullptr);
+
+} // namespace find_all_symbols
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PATH_CONFIG_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/PragmaCommentHandler.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/PragmaCommentHandler.cpp
new file mode 100644
index 0000000..0242d38
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/PragmaCommentHandler.cpp
@@ -0,0 +1,37 @@
+//===-- PragmaCommentHandler.cpp - find all symbols -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PragmaCommentHandler.h"
+#include "FindAllSymbols.h"
+#include "HeaderMapCollector.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/Regex.h"
+
+namespace clang {
+namespace find_all_symbols {
+namespace {
+const char IWYUPragma[] = "// IWYU pragma: private, include ";
+} // namespace
+
+bool PragmaCommentHandler::HandleComment(Preprocessor &PP, SourceRange Range) {
+ StringRef Text =
+ Lexer::getSourceText(CharSourceRange::getCharRange(Range),
+ PP.getSourceManager(), PP.getLangOpts());
+ size_t Pos = Text.find(IWYUPragma);
+ if (Pos == StringRef::npos)
+ return false;
+ StringRef RemappingFilePath = Text.substr(Pos + std::strlen(IWYUPragma));
+ Collector->addHeaderMapping(
+ PP.getSourceManager().getFilename(Range.getBegin()),
+ RemappingFilePath.trim("\"<>"));
+ return false;
+}
+
+} // namespace find_all_symbols
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/PragmaCommentHandler.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/PragmaCommentHandler.h
new file mode 100644
index 0000000..9eb4972
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/PragmaCommentHandler.h
@@ -0,0 +1,41 @@
+//===-- PragmaCommentHandler.h - find all symbols----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PRAGMA_COMMENT_HANDLER_H
+#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PRAGMA_COMMENT_HANDLER_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Preprocessor.h"
+#include <map>
+
+namespace clang {
+namespace find_all_symbols {
+
+class HeaderMapCollector;
+
+/// \brief PragmaCommentHandler parses pragma comment on include files to
+/// determine when we should include a different header from the header that
+/// directly defines a symbol.
+///
+/// Currently it only supports IWYU private pragma:
+/// https://github.com/include-what-you-use/include-what-you-use/blob/master/docs/IWYUPragmas.md#iwyu-pragma-private
+class PragmaCommentHandler : public clang::CommentHandler {
+public:
+ PragmaCommentHandler(HeaderMapCollector *Collector) : Collector(Collector) {}
+
+ bool HandleComment(Preprocessor &PP, SourceRange Range) override;
+
+private:
+ HeaderMapCollector *const Collector;
+};
+
+} // namespace find_all_symbols
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_PRAGMA_COMMENT_HANDLER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp
new file mode 100644
index 0000000..4a49479
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp
@@ -0,0 +1,654 @@
+//===-- STLPostfixHeaderMap.h - hardcoded STL header map --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "STLPostfixHeaderMap.h"
+
+namespace clang {
+namespace find_all_symbols {
+
+const HeaderMapCollector::RegexHeaderMap *getSTLPostfixHeaderMap() {
+ static const HeaderMapCollector::RegexHeaderMap STLPostfixHeaderMap = {
+ {"include/__stddef_max_align_t.h$", "<cstddef>"},
+ {"include/__wmmintrin_aes.h$", "<wmmintrin.h>"},
+ {"include/__wmmintrin_pclmul.h$", "<wmmintrin.h>"},
+ {"include/adxintrin.h$", "<immintrin.h>"},
+ {"include/ammintrin.h$", "<ammintrin.h>"},
+ {"include/avx2intrin.h$", "<immintrin.h>"},
+ {"include/avx512bwintrin.h$", "<immintrin.h>"},
+ {"include/avx512cdintrin.h$", "<immintrin.h>"},
+ {"include/avx512dqintrin.h$", "<immintrin.h>"},
+ {"include/avx512erintrin.h$", "<immintrin.h>"},
+ {"include/avx512fintrin.h$", "<immintrin.h>"},
+ {"include/avx512ifmaintrin.h$", "<immintrin.h>"},
+ {"include/avx512ifmavlintrin.h$", "<immintrin.h>"},
+ {"include/avx512pfintrin.h$", "<immintrin.h>"},
+ {"include/avx512vbmiintrin.h$", "<immintrin.h>"},
+ {"include/avx512vbmivlintrin.h$", "<immintrin.h>"},
+ {"include/avx512vlbwintrin.h$", "<immintrin.h>"},
+ {"include/avx512vlcdintrin.h$", "<immintrin.h>"},
+ {"include/avx512vldqintrin.h$", "<immintrin.h>"},
+ {"include/avx512vlintrin.h$", "<immintrin.h>"},
+ {"include/avxintrin.h$", "<immintrin.h>"},
+ {"include/bmi2intrin.h$", "<x86intrin.h>"},
+ {"include/bmiintrin.h$", "<x86intrin.h>"},
+ {"include/emmintrin.h$", "<emmintrin.h>"},
+ {"include/f16cintrin.h$", "<emmintrin.h>"},
+ {"include/float.h$", "<cfloat>"},
+ {"include/fma4intrin.h$", "<x86intrin.h>"},
+ {"include/fmaintrin.h$", "<immintrin.h>"},
+ {"include/fxsrintrin.h$", "<immintrin.h>"},
+ {"include/ia32intrin.h$", "<x86intrin.h>"},
+ {"include/immintrin.h$", "<immintrin.h>"},
+ {"include/inttypes.h$", "<cinttypes>"},
+ {"include/limits.h$", "<climits>"},
+ {"include/lzcntintrin.h$", "<x86intrin.h>"},
+ {"include/mm3dnow.h$", "<mm3dnow.h>"},
+ {"include/mm_malloc.h$", "<mm_malloc.h>"},
+ {"include/mmintrin.h$", "<mmintrin>"},
+ {"include/mwaitxintrin.h$", "<x86intrin.h>"},
+ {"include/pkuintrin.h$", "<immintrin.h>"},
+ {"include/pmmintrin.h$", "<pmmintrin.h>"},
+ {"include/popcntintrin.h$", "<popcntintrin.h>"},
+ {"include/prfchwintrin.h$", "<x86intrin.h>"},
+ {"include/rdseedintrin.h$", "<x86intrin.h>"},
+ {"include/rtmintrin.h$", "<immintrin.h>"},
+ {"include/shaintrin.h$", "<immintrin.h>"},
+ {"include/smmintrin.h$", "<smmintrin.h>"},
+ {"include/stdalign.h$", "<cstdalign>"},
+ {"include/stdarg.h$", "<cstdarg>"},
+ {"include/stdbool.h$", "<cstdbool>"},
+ {"include/stddef.h$", "<cstddef>"},
+ {"include/stdint.h$", "<cstdint>"},
+ {"include/tbmintrin.h$", "<x86intrin.h>"},
+ {"include/tmmintrin.h$", "<tmmintrin.h>"},
+ {"include/wmmintrin.h$", "<wmmintrin.h>"},
+ {"include/x86intrin.h$", "<x86intrin.h>"},
+ {"include/xmmintrin.h$", "<xmmintrin.h>"},
+ {"include/xopintrin.h$", "<x86intrin.h>"},
+ {"include/xsavecintrin.h$", "<immintrin.h>"},
+ {"include/xsaveintrin.h$", "<immintrin.h>"},
+ {"include/xsaveoptintrin.h$", "<immintrin.h>"},
+ {"include/xsavesintrin.h$", "<immintrin.h>"},
+ {"include/xtestintrin.h$", "<immintrin.h>"},
+ {"include/_G_config.h$", "<cstdio>"},
+ {"include/assert.h$", "<cassert>"},
+ {"algorithm$", "<algorithm>"},
+ {"array$", "<array>"},
+ {"atomic$", "<atomic>"},
+ {"backward/auto_ptr.h$", "<memory>"},
+ {"backward/binders.h$", "<string>"},
+ {"bits/algorithmfwd.h$", "<algorithm>"},
+ {"bits/alloc_traits.h$", "<unordered_set>"},
+ {"bits/allocator.h$", "<string>"},
+ {"bits/atomic_base.h$", "<atomic>"},
+ {"bits/atomic_lockfree_defines.h$", "<exception>"},
+ {"bits/basic_ios.h$", "<ios>"},
+ {"bits/basic_ios.tcc$", "<ios>"},
+ {"bits/basic_string.h$", "<string>"},
+ {"bits/basic_string.tcc$", "<string>"},
+ {"bits/char_traits.h$", "<string>"},
+ {"bits/codecvt.h$", "<locale>"},
+ {"bits/concept_check.h$", "<numeric>"},
+ {"bits/cpp_type_traits.h$", "<cmath>"},
+ {"bits/cxxabi_forced.h$", "<cxxabi.h>"},
+ {"bits/deque.tcc$", "<deque>"},
+ {"bits/exception_defines.h$", "<exception>"},
+ {"bits/exception_ptr.h$", "<exception>"},
+ {"bits/forward_list.h$", "<forward_list>"},
+ {"bits/forward_list.tcc$", "<forward_list>"},
+ {"bits/fstream.tcc$", "<fstream>"},
+ {"bits/functexcept.h$", "<list>"},
+ {"bits/functional_hash.h$", "<string>"},
+ {"bits/gslice.h$", "<valarray>"},
+ {"bits/gslice_array.h$", "<valarray>"},
+ {"bits/hash_bytes.h$", "<typeinfo>"},
+ {"bits/hashtable.h$", "<unordered_set>"},
+ {"bits/hashtable_policy.h$", "<unordered_set>"},
+ {"bits/indirect_array.h$", "<valarray>"},
+ {"bits/ios_base.h$", "<ios>"},
+ {"bits/istream.tcc$", "<istream>"},
+ {"bits/list.tcc$", "<list>"},
+ {"bits/locale_classes.h$", "<locale>"},
+ {"bits/locale_classes.tcc$", "<locale>"},
+ {"bits/locale_facets.h$", "<locale>"},
+ {"bits/locale_facets.tcc$", "<locale>"},
+ {"bits/locale_facets_nonio.h$", "<locale>"},
+ {"bits/locale_facets_nonio.tcc$", "<locale>"},
+ {"bits/localefwd.h$", "<locale>"},
+ {"bits/mask_array.h$", "<valarray>"},
+ {"bits/memoryfwd.h$", "<memory>"},
+ {"bits/move.h$", "<utility>"},
+ {"bits/nested_exception.h$", "<exception>"},
+ {"bits/ostream.tcc$", "<ostream>"},
+ {"bits/ostream_insert.h$", "<ostream>"},
+ {"bits/postypes.h$", "<iosfwd>"},
+ {"bits/ptr_traits.h$", "<memory>"},
+ {"bits/random.h$", "<random>"},
+ {"bits/random.tcc$", "<random>"},
+ {"bits/range_access.h$", "<iterator>"},
+ {"bits/regex.h$", "<regex>"},
+ {"bits/regex_compiler.h$", "<regex>"},
+ {"bits/regex_constants.h$", "<regex>"},
+ {"bits/regex_cursor.h$", "<regex>"},
+ {"bits/regex_error.h$", "<regex>"},
+ {"bits/regex_grep_matcher.h$", "<regex>"},
+ {"bits/regex_grep_matcher.tcc$", "<regex>"},
+ {"bits/regex_nfa.h$", "<regex>"},
+ {"bits/shared_ptr.h$", "<memory>"},
+ {"bits/shared_ptr_base.h$", "<memory>"},
+ {"bits/slice_array.h$", "<valarray>"},
+ {"bits/sstream.tcc$", "<sstream>"},
+ {"bits/stl_algo.h$", "<algorithm>"},
+ {"bits/stl_algobase.h$", "<list>"},
+ {"bits/stl_bvector.h$", "<vector>"},
+ {"bits/stl_construct.h$", "<deque>"},
+ {"bits/stl_deque.h$", "<deque>"},
+ {"bits/stl_function.h$", "<string>"},
+ {"bits/stl_heap.h$", "<queue>"},
+ {"bits/stl_iterator.h$", "<iterator>"},
+ {"bits/stl_iterator_base_funcs.h$", "<iterator>"},
+ {"bits/stl_iterator_base_types.h$", "<numeric>"},
+ {"bits/stl_list.h$", "<list>"},
+ {"bits/stl_map.h$", "<map>"},
+ {"bits/stl_multimap.h$", "<map>"},
+ {"bits/stl_multiset.h$", "<set>"},
+ {"bits/stl_numeric.h$", "<numeric>"},
+ {"bits/stl_pair.h$", "<utility>"},
+ {"bits/stl_queue.h$", "<queue>"},
+ {"bits/stl_raw_storage_iter.h$", "<memory>"},
+ {"bits/stl_relops.h$", "<utility>"},
+ {"bits/stl_set.h$", "<set>"},
+ {"bits/stl_stack.h$", "<stack>"},
+ {"bits/stl_tempbuf.h$", "<memory>"},
+ {"bits/stl_tree.h$", "<map>"},
+ {"bits/stl_uninitialized.h$", "<deque>"},
+ {"bits/stl_vector.h$", "<vector>"},
+ {"bits/stream_iterator.h$", "<iterator>"},
+ {"bits/streambuf.tcc$", "<streambuf>"},
+ {"bits/streambuf_iterator.h$", "<iterator>"},
+ {"bits/stringfwd.h$", "<string>"},
+ {"bits/unique_ptr.h$", "<memory>"},
+ {"bits/unordered_map.h$", "<unordered_map>"},
+ {"bits/unordered_set.h$", "<unordered_set>"},
+ {"bits/uses_allocator.h$", "<tuple>"},
+ {"bits/valarray_after.h$", "<valarray>"},
+ {"bits/valarray_array.h$", "<valarray>"},
+ {"bits/valarray_array.tcc$", "<valarray>"},
+ {"bits/valarray_before.h$", "<valarray>"},
+ {"bits/vector.tcc$", "<vector>"},
+ {"bitset$", "<bitset>"},
+ {"ccomplex$", "<ccomplex>"},
+ {"cctype$", "<cctype>"},
+ {"cerrno$", "<cerrno>"},
+ {"cfenv$", "<cfenv>"},
+ {"cfloat$", "<cfloat>"},
+ {"chrono$", "<chrono>"},
+ {"cinttypes$", "<cinttypes>"},
+ {"climits$", "<climits>"},
+ {"clocale$", "<clocale>"},
+ {"cmath$", "<cmath>"},
+ {"complex$", "<complex>"},
+ {"complex.h$", "<complex.h>"},
+ {"condition_variable$", "<condition_variable>"},
+ {"csetjmp$", "<csetjmp>"},
+ {"csignal$", "<csignal>"},
+ {"cstdalign$", "<cstdalign>"},
+ {"cstdarg$", "<cstdarg>"},
+ {"cstdbool$", "<cstdbool>"},
+ {"cstdint$", "<cstdint>"},
+ {"cstdio$", "<cstdio>"},
+ {"cstdlib$", "<cstdlib>"},
+ {"cstring$", "<cstring>"},
+ {"ctgmath$", "<ctgmath>"},
+ {"ctime$", "<ctime>"},
+ {"cwchar$", "<cwchar>"},
+ {"cwctype$", "<cwctype>"},
+ {"cxxabi.h$", "<cxxabi.h>"},
+ {"debug/debug.h$", "<numeric>"},
+ {"debug/map.h$", "<map>"},
+ {"debug/multimap.h$", "<multimap>"},
+ {"debug/multiset.h$", "<multiset>"},
+ {"debug/set.h$", "<set>"},
+ {"deque$", "<deque>"},
+ {"exception$", "<exception>"},
+ {"ext/alloc_traits.h$", "<deque>"},
+ {"ext/atomicity.h$", "<memory>"},
+ {"ext/concurrence.h$", "<memory>"},
+ {"ext/new_allocator.h$", "<string>"},
+ {"ext/numeric_traits.h$", "<list>"},
+ {"ext/string_conversions.h$", "<string>"},
+ {"ext/type_traits.h$", "<cmath>"},
+ {"fenv.h$", "<fenv.h>"},
+ {"forward_list$", "<forward_list>"},
+ {"fstream$", "<fstream>"},
+ {"functional$", "<functional>"},
+ {"future$", "<future>"},
+ {"initializer_list$", "<initializer_list>"},
+ {"iomanip$", "<iomanip>"},
+ {"ios$", "<ios>"},
+ {"iosfwd$", "<iosfwd>"},
+ {"iostream$", "<iostream>"},
+ {"istream$", "<istream>"},
+ {"iterator$", "<iterator>"},
+ {"limits$", "<limits>"},
+ {"list$", "<list>"},
+ {"locale$", "<locale>"},
+ {"map$", "<map>"},
+ {"memory$", "<memory>"},
+ {"mutex$", "<mutex>"},
+ {"new$", "<new>"},
+ {"numeric$", "<numeric>"},
+ {"ostream$", "<ostream>"},
+ {"queue$", "<queue>"},
+ {"random$", "<random>"},
+ {"ratio$", "<ratio>"},
+ {"regex$", "<regex>"},
+ {"scoped_allocator$", "<scoped_allocator>"},
+ {"set$", "<set>"},
+ {"sstream$", "<sstream>"},
+ {"stack$", "<stack>"},
+ {"stdexcept$", "<stdexcept>"},
+ {"streambuf$", "<streambuf>"},
+ {"string$", "<string>"},
+ {"system_error$", "<system_error>"},
+ {"tgmath.h$", "<tgmath.h>"},
+ {"thread$", "<thread>"},
+ {"tuple$", "<tuple>"},
+ {"type_traits$", "<type_traits>"},
+ {"typeindex$", "<typeindex>"},
+ {"typeinfo$", "<typeinfo>"},
+ {"unordered_map$", "<unordered_map>"},
+ {"unordered_set$", "<unordered_set>"},
+ {"utility$", "<utility>"},
+ {"valarray$", "<valarray>"},
+ {"vector$", "<vector>"},
+ {"include/complex.h$", "<complex.h>"},
+ {"include/ctype.h$", "<cctype>"},
+ {"include/errno.h$", "<cerrno>"},
+ {"include/fenv.h$", "<fenv.h>"},
+ {"include/inttypes.h$", "<cinttypes>"},
+ {"include/libio.h$", "<cstdio>"},
+ {"include/limits.h$", "<climits>"},
+ {"include/locale.h$", "<clocale>"},
+ {"include/math.h$", "<cmath>"},
+ {"include/setjmp.h$", "<csetjmp>"},
+ {"include/signal.h$", "<csignal>"},
+ {"include/stdint.h$", "<cstdint>"},
+ {"include/stdio.h$", "<cstdio>"},
+ {"include/stdlib.h$", "<cstdlib>"},
+ {"include/string.h$", "<cstring>"},
+ {"include/time.h$", "<ctime>"},
+ {"include/wchar.h$", "<cwchar>"},
+ {"include/wctype.h$", "<cwctype>"},
+ {"bits/cmathcalls.h$", "<complex.h>"},
+ {"bits/errno.h$", "<cerrno>"},
+ {"bits/fenv.h$", "<fenv.h>"},
+ {"bits/huge_val.h$", "<cmath>"},
+ {"bits/huge_valf.h$", "<cmath>"},
+ {"bits/huge_vall.h$", "<cmath>"},
+ {"bits/inf.h$", "<cmath>"},
+ {"bits/local_lim.h$", "<climits>"},
+ {"bits/locale.h$", "<clocale>"},
+ {"bits/mathcalls.h$", "<math.h>"},
+ {"bits/mathdef.h$", "<cmath>"},
+ {"bits/nan.h$", "<cmath>"},
+ {"bits/posix1_lim.h$", "<climits>"},
+ {"bits/posix2_lim.h$", "<climits>"},
+ {"bits/setjmp.h$", "<csetjmp>"},
+ {"bits/sigaction.h$", "<csignal>"},
+ {"bits/sigcontext.h$", "<csignal>"},
+ {"bits/siginfo.h$", "<csignal>"},
+ {"bits/signum.h$", "<csignal>"},
+ {"bits/sigset.h$", "<csignal>"},
+ {"bits/sigstack.h$", "<csignal>"},
+ {"bits/stdio_lim.h$", "<cstdio>"},
+ {"bits/sys_errlist.h$", "<cstdio>"},
+ {"bits/time.h$", "<ctime>"},
+ {"bits/timex.h$", "<ctime>"},
+ {"bits/typesizes.h$", "<cstdio>"},
+ {"bits/wchar.h$", "<cwchar>"},
+ {"bits/wordsize.h$", "<csetjmp>"},
+ {"bits/xopen_lim.h$", "<climits>"},
+ {"include/xlocale.h$", "<cstring>"},
+ {"bits/atomic_word.h$", "<memory>"},
+ {"bits/basic_file.h$", "<fstream>"},
+ {"bits/c\\+\\+allocator.h$", "<string>"},
+ {"bits/c\\+\\+config.h$", "<iosfwd>"},
+ {"bits/c\\+\\+io.h$", "<ios>"},
+ {"bits/c\\+\\+locale.h$", "<locale>"},
+ {"bits/cpu_defines.h$", "<iosfwd>"},
+ {"bits/ctype_base.h$", "<locale>"},
+ {"bits/cxxabi_tweaks.h$", "<cxxabi.h>"},
+ {"bits/error_constants.h$", "<system_error>"},
+ {"bits/gthr-default.h$", "<memory>"},
+ {"bits/gthr.h$", "<memory>"},
+ {"bits/opt_random.h$", "<random>"},
+ {"bits/os_defines.h$", "<iosfwd>"},
+ // GNU C headers
+ {"include/aio.h$", "<aio.h>"},
+ {"include/aliases.h$", "<aliases.h>"},
+ {"include/alloca.h$", "<alloca.h>"},
+ {"include/ar.h$", "<ar.h>"},
+ {"include/argp.h$", "<argp.h>"},
+ {"include/argz.h$", "<argz.h>"},
+ {"include/arpa/nameser.h$", "<resolv.h>"},
+ {"include/arpa/nameser_compat.h$", "<resolv.h>"},
+ {"include/byteswap.h$", "<byteswap.h>"},
+ {"include/cpio.h$", "<cpio.h>"},
+ {"include/crypt.h$", "<crypt.h>"},
+ {"include/dirent.h$", "<dirent.h>"},
+ {"include/dlfcn.h$", "<dlfcn.h>"},
+ {"include/elf.h$", "<elf.h>"},
+ {"include/endian.h$", "<endian.h>"},
+ {"include/envz.h$", "<envz.h>"},
+ {"include/err.h$", "<err.h>"},
+ {"include/error.h$", "<error.h>"},
+ {"include/execinfo.h$", "<execinfo.h>"},
+ {"include/fcntl.h$", "<fcntl.h>"},
+ {"include/features.h$", "<features.h>"},
+ {"include/fenv.h$", "<fenv.h>"},
+ {"include/fmtmsg.h$", "<fmtmsg.h>"},
+ {"include/fnmatch.h$", "<fnmatch.h>"},
+ {"include/fstab.h$", "<fstab.h>"},
+ {"include/fts.h$", "<fts.h>"},
+ {"include/ftw.h$", "<ftw.h>"},
+ {"include/gconv.h$", "<gconv.h>"},
+ {"include/getopt.h$", "<getopt.h>"},
+ {"include/glob.h$", "<glob.h>"},
+ {"include/grp.h$", "<grp.h>"},
+ {"include/gshadow.h$", "<gshadow.h>"},
+ {"include/iconv.h$", "<iconv.h>"},
+ {"include/ifaddrs.h$", "<ifaddrs.h>"},
+ {"include/kdb.h$", "<kdb.h>"},
+ {"include/langinfo.h$", "<langinfo.h>"},
+ {"include/libgen.h$", "<libgen.h>"},
+ {"include/libintl.h$", "<libintl.h>"},
+ {"include/link.h$", "<link.h>"},
+ {"include/malloc.h$", "<malloc.h>"},
+ {"include/mcheck.h$", "<mcheck.h>"},
+ {"include/memory.h$", "<memory.h>"},
+ {"include/mntent.h$", "<mntent.h>"},
+ {"include/monetary.h$", "<monetary.h>"},
+ {"include/mqueue.h$", "<mqueue.h>"},
+ {"include/netdb.h$", "<netdb.h>"},
+ {"include/netinet/in.h$", "<netinet/in.h>"},
+ {"include/nl_types.h$", "<nl_types.h>"},
+ {"include/nss.h$", "<nss.h>"},
+ {"include/obstack.h$", "<obstack.h>"},
+ {"include/panel.h$", "<panel.h>"},
+ {"include/paths.h$", "<paths.h>"},
+ {"include/printf.h$", "<printf.h>"},
+ {"include/profile.h$", "<profile.h>"},
+ {"include/pthread.h$", "<pthread.h>"},
+ {"include/pty.h$", "<pty.h>"},
+ {"include/pwd.h$", "<pwd.h>"},
+ {"include/re_comp.h$", "<re_comp.h>"},
+ {"include/regex.h$", "<regex.h>"},
+ {"include/regexp.h$", "<regexp.h>"},
+ {"include/resolv.h$", "<resolv.h>"},
+ {"include/rpc/netdb.h$", "<netdb.h>"},
+ {"include/sched.h$", "<sched.h>"},
+ {"include/search.h$", "<search.h>"},
+ {"include/semaphore.h$", "<semaphore.h>"},
+ {"include/sgtty.h$", "<sgtty.h>"},
+ {"include/shadow.h$", "<shadow.h>"},
+ {"include/spawn.h$", "<spawn.h>"},
+ {"include/stab.h$", "<stab.h>"},
+ {"include/stdc-predef.h$", "<stdc-predef.h>"},
+ {"include/stdio_ext.h$", "<stdio_ext.h>"},
+ {"include/strings.h$", "<strings.h>"},
+ {"include/stropts.h$", "<stropts.h>"},
+ {"include/sudo_plugin.h$", "<sudo_plugin.h>"},
+ {"include/sysexits.h$", "<sysexits.h>"},
+ {"include/tar.h$", "<tar.h>"},
+ {"include/tcpd.h$", "<tcpd.h>"},
+ {"include/term.h$", "<term.h>"},
+ {"include/term_entry.h$", "<term_entry.h>"},
+ {"include/termcap.h$", "<termcap.h>"},
+ {"include/termios.h$", "<termios.h>"},
+ {"include/thread_db.h$", "<thread_db.h>"},
+ {"include/tic.h$", "<tic.h>"},
+ {"include/ttyent.h$", "<ttyent.h>"},
+ {"include/uchar.h$", "<uchar.h>"},
+ {"include/ucontext.h$", "<ucontext.h>"},
+ {"include/ulimit.h$", "<ulimit.h>"},
+ {"include/unctrl.h$", "<unctrl.h>"},
+ {"include/unistd.h$", "<unistd.h>"},
+ {"include/utime.h$", "<utime.h>"},
+ {"include/utmp.h$", "<utmp.h>"},
+ {"include/utmpx.h$", "<utmpx.h>"},
+ {"include/values.h$", "<values.h>"},
+ {"include/wordexp.h$", "<wordexp.h>"},
+ {"fpu_control.h$", "<fpu_control.h>"},
+ {"ieee754.h$", "<ieee754.h>"},
+ {"include/xlocale.h$", "<xlocale.h>"},
+ {"gnu/lib-names.h$", "<gnu/lib-names.h>"},
+ {"gnu/libc-version.h$", "<gnu/libc-version.h>"},
+ {"gnu/option-groups.h$", "<gnu/option-groups.h>"},
+ {"gnu/stubs-32.h$", "<gnu/stubs-32.h>"},
+ {"gnu/stubs-64.h$", "<gnu/stubs-64.h>"},
+ {"gnu/stubs-x32.h$", "<gnu/stubs-x32.h>"},
+ {"include/rpc/auth_des.h$", "<rpc/auth_des.h>"},
+ {"include/rpc/rpc_msg.h$", "<rpc/rpc_msg.h>"},
+ {"include/rpc/pmap_clnt.h$", "<rpc/pmap_clnt.h>"},
+ {"include/rpc/rpc.h$", "<rpc/rpc.h>"},
+ {"include/rpc/types.h$", "<rpc/types.h>"},
+ {"include/rpc/auth_unix.h$", "<rpc/auth_unix.h>"},
+ {"include/rpc/key_prot.h$", "<rpc/key_prot.h>"},
+ {"include/rpc/pmap_prot.h$", "<rpc/pmap_prot.h>"},
+ {"include/rpc/auth.h$", "<rpc/auth.h>"},
+ {"include/rpc/svc_auth.h$", "<rpc/svc_auth.h>"},
+ {"include/rpc/xdr.h$", "<rpc/xdr.h>"},
+ {"include/rpc/pmap_rmt.h$", "<rpc/pmap_rmt.h>"},
+ {"include/rpc/des_crypt.h$", "<rpc/des_crypt.h>"},
+ {"include/rpc/svc.h$", "<rpc/svc.h>"},
+ {"include/rpc/rpc_des.h$", "<rpc/rpc_des.h>"},
+ {"include/rpc/clnt.h$", "<rpc/clnt.h>"},
+ {"include/scsi/scsi.h$", "<scsi/scsi.h>"},
+ {"include/scsi/sg.h$", "<scsi/sg.h>"},
+ {"include/scsi/scsi_ioctl.h$", "<scsi/scsi_ioctl>"},
+ {"include/netrose/rose.h$", "<netrose/rose.h>"},
+ {"include/nfs/nfs.h$", "<nfs/nfs.h>"},
+ {"include/netatalk/at.h$", "<netatalk/at.h>"},
+ {"include/netinet/ether.h$", "<netinet/ether.h>"},
+ {"include/netinet/icmp6.h$", "<netinet/icmp6.h>"},
+ {"include/netinet/if_ether.h$", "<netinet/if_ether.h>"},
+ {"include/netinet/if_fddi.h$", "<netinet/if_fddi.h>"},
+ {"include/netinet/if_tr.h$", "<netinet/if_tr.h>"},
+ {"include/netinet/igmp.h$", "<netinet/igmp.h>"},
+ {"include/netinet/in.h$", "<netinet/in.h>"},
+ {"include/netinet/in_systm.h$", "<netinet/in_systm.h>"},
+ {"include/netinet/ip.h$", "<netinet/ip.h>"},
+ {"include/netinet/ip6.h$", "<netinet/ip6.h>"},
+ {"include/netinet/ip_icmp.h$", "<netinet/ip_icmp.h>"},
+ {"include/netinet/tcp.h$", "<netinet/tcp.h>"},
+ {"include/netinet/udp.h$", "<netinet/udp.h>"},
+ {"include/netrom/netrom.h$", "<netrom/netrom.h>"},
+ {"include/protocols/routed.h$", "<protocols/routed.h>"},
+ {"include/protocols/rwhod.h$", "<protocols/rwhod.h>"},
+ {"include/protocols/talkd.h$", "<protocols/talkd.h>"},
+ {"include/protocols/timed.h$", "<protocols/timed.h>"},
+ {"include/rpcsvc/klm_prot.x$", "<rpcsvc/klm_prot.x>"},
+ {"include/rpcsvc/rstat.h$", "<rpcsvc/rstat.h>"},
+ {"include/rpcsvc/spray.x$", "<rpcsvc/spray.x>"},
+ {"include/rpcsvc/nlm_prot.x$", "<rpcsvc/nlm_prot.x>"},
+ {"include/rpcsvc/nis_callback.x$", "<rpcsvc/nis_callback.x>"},
+ {"include/rpcsvc/yp.h$", "<rpcsvc/yp.h>"},
+ {"include/rpcsvc/yp.x$", "<rpcsvc/yp.x>"},
+ {"include/rpcsvc/nfs_prot.h$", "<rpcsvc/nfs_prot.h>"},
+ {"include/rpcsvc/rex.h$", "<rpcsvc/rex.h>"},
+ {"include/rpcsvc/yppasswd.h$", "<rpcsvc/yppasswd.h>"},
+ {"include/rpcsvc/rex.x$", "<rpcsvc/rex.x>"},
+ {"include/rpcsvc/nis_tags.h$", "<rpcsvc/nis_tags.h>"},
+ {"include/rpcsvc/nis_callback.h$", "<rpcsvc/nis_callback.h>"},
+ {"include/rpcsvc/nfs_prot.x$", "<rpcsvc/nfs_prot.x>"},
+ {"include/rpcsvc/bootparam_prot.x$", "<rpcsvc/bootparam_prot.x>"},
+ {"include/rpcsvc/rusers.x$", "<rpcsvc/rusers.x>"},
+ {"include/rpcsvc/rquota.x$", "<rpcsvc/rquota.x>"},
+ {"include/rpcsvc/nis.h$", "<rpcsvc/nis.h>"},
+ {"include/rpcsvc/nislib.h$", "<rpcsvc/nislib.h>"},
+ {"include/rpcsvc/ypupd.h$", "<rpcsvc/ypupd.h>"},
+ {"include/rpcsvc/bootparam.h$", "<rpcsvc/bootparam.h>"},
+ {"include/rpcsvc/spray.h$", "<rpcsvc/spray.h>"},
+ {"include/rpcsvc/key_prot.h$", "<rpcsvc/key_prot.h>"},
+ {"include/rpcsvc/klm_prot.h$", "<rpcsvc/klm_prot.h>"},
+ {"include/rpcsvc/sm_inter.h$", "<rpcsvc/sm_inter.h>"},
+ {"include/rpcsvc/nlm_prot.h$", "<rpcsvc/nlm_prot.h>"},
+ {"include/rpcsvc/yp_prot.h$", "<rpcsvc/yp_prot.h>"},
+ {"include/rpcsvc/ypclnt.h$", "<rpcsvc/ypclnt.h>"},
+ {"include/rpcsvc/rstat.x$", "<rpcsvc/rstat.x>"},
+ {"include/rpcsvc/rusers.h$", "<rpcsvc/rusers.h>"},
+ {"include/rpcsvc/key_prot.x$", "<rpcsvc/key_prot.x>"},
+ {"include/rpcsvc/sm_inter.x$", "<rpcsvc/sm_inter.x>"},
+ {"include/rpcsvc/rquota.h$", "<rpcsvc/rquota.h>"},
+ {"include/rpcsvc/nis.x$", "<rpcsvc/nis.x>"},
+ {"include/rpcsvc/bootparam_prot.h$", "<rpcsvc/bootparam_prot.h>"},
+ {"include/rpcsvc/mount.h$", "<rpcsvc/mount.h>"},
+ {"include/rpcsvc/mount.x$", "<rpcsvc/mount.x>"},
+ {"include/rpcsvc/nis_object.x$", "<rpcsvc/nis_object.x>"},
+ {"include/rpcsvc/yppasswd.x$", "<rpcsvc/yppasswd.x>"},
+ {"sys/acct.h$", "<sys/acct.h>"},
+ {"sys/auxv.h$", "<sys/auxv.h>"},
+ {"sys/cdefs.h$", "<sys/cdefs.h>"},
+ {"sys/debugreg.h$", "<sys/debugreg.h>"},
+ {"sys/dir.h$", "<sys/dir.h>"},
+ {"sys/elf.h$", "<sys/elf.h>"},
+ {"sys/epoll.h$", "<sys/epoll.h>"},
+ {"sys/eventfd.h$", "<sys/eventfd.h>"},
+ {"sys/fanotify.h$", "<sys/fanotify.h>"},
+ {"sys/file.h$", "<sys/file.h>"},
+ {"sys/fsuid.h$", "<sys/fsuid.h>"},
+ {"sys/gmon.h$", "<sys/gmon.h>"},
+ {"sys/gmon_out.h$", "<sys/gmon_out.h>"},
+ {"sys/inotify.h$", "<sys/inotify.h>"},
+ {"sys/io.h$", "<sys/io.h>"},
+ {"sys/ioctl.h$", "<sys/ioctl.h>"},
+ {"sys/ipc.h$", "<sys/ipc.h>"},
+ {"sys/kd.h$", "<sys/kd.h>"},
+ {"sys/kdaemon.h$", "<sys/kdaemon.h>"},
+ {"sys/klog.h$", "<sys/klog.h>"},
+ {"sys/mman.h$", "<sys/mman.h>"},
+ {"sys/mount.h$", "<sys/mount.h>"},
+ {"sys/msg.h$", "<sys/msg.h>"},
+ {"sys/mtio.h$", "<sys/mtio.h>"},
+ {"sys/param.h$", "<sys/param.h>"},
+ {"sys/pci.h$", "<sys/pci.h>"},
+ {"sys/perm.h$", "<sys/perm.h>"},
+ {"sys/personality.h$", "<sys/personality.h>"},
+ {"sys/poll.h$", "<sys/poll.h>"},
+ {"sys/prctl.h$", "<sys/prctl.h>"},
+ {"sys/procfs.h$", "<sys/procfs.h>"},
+ {"sys/profil.h$", "<sys/profil.h>"},
+ {"sys/ptrace.h$", "<sys/ptrace.h>"},
+ {"sys/queue.h$", "<sys/queue.h>"},
+ {"sys/quota.h$", "<sys/quota.h>"},
+ {"sys/raw.h$", "<sys/raw.h>"},
+ {"sys/reboot.h$", "<sys/reboot.h>"},
+ {"sys/reg.h$", "<sys/reg.h>"},
+ {"sys/resource.h$", "<sys/resource.h>"},
+ {"sys/select.h$", "<sys/select.h>"},
+ {"sys/sem.h$", "<sys/sem.h>"},
+ {"sys/sendfile.h$", "<sys/sendfile.h>"},
+ {"sys/shm.h$", "<sys/shm.h>"},
+ {"sys/signalfd.h$", "<sys/signalfd.h>"},
+ {"sys/socket.h$", "<sys/socket.h>"},
+ {"sys/stat.h$", "<sys/stat.h>"},
+ {"sys/statfs.h$", "<sys/statfs.h>"},
+ {"sys/statvfs.h$", "<sys/statvfs.h>"},
+ {"sys/swap.h$", "<sys/swap.h>"},
+ {"sys/syscall.h$", "<sys/syscall.h>"},
+ {"sys/sysctl.h$", "<sys/sysctl.h>"},
+ {"sys/sysinfo.h$", "<sys/sysinfo.h>"},
+ {"sys/syslog.h$", "<sys/syslog.h>"},
+ {"sys/sysmacros.h$", "<sys/sysmacros.h>"},
+ {"sys/termios.h$", "<sys/termios.h>"},
+ {"sys/time.h$", "<sys/select.h>"},
+ {"sys/timeb.h$", "<sys/timeb.h>"},
+ {"sys/timerfd.h$", "<sys/timerfd.h>"},
+ {"sys/times.h$", "<sys/times.h>"},
+ {"sys/timex.h$", "<sys/timex.h>"},
+ {"sys/ttychars.h$", "<sys/ttychars.h>"},
+ {"sys/ttydefaults.h$", "<sys/ttydefaults.h>"},
+ {"sys/types.h$", "<sys/types.h>"},
+ {"sys/ucontext.h$", "<sys/ucontext.h>"},
+ {"sys/uio.h$", "<sys/uio.h>"},
+ {"sys/un.h$", "<sys/un.h>"},
+ {"sys/user.h$", "<sys/user.h>"},
+ {"sys/ustat.h$", "<sys/ustat.h>"},
+ {"sys/utsname.h$", "<sys/utsname.h>"},
+ {"sys/vlimit.h$", "<sys/vlimit.h>"},
+ {"sys/vm86.h$", "<sys/vm86.h>"},
+ {"sys/vtimes.h$", "<sys/vtimes.h>"},
+ {"sys/wait.h$", "<sys/wait.h>"},
+ {"sys/xattr.h$", "<sys/xattr.h>"},
+ {"bits/epoll.h$", "<sys/epoll.h>"},
+ {"bits/eventfd.h$", "<sys/eventfd.h>"},
+ {"bits/inotify.h$", "<sys/inotify.h>"},
+ {"bits/ipc.h$", "<sys/ipc.h>"},
+ {"bits/ipctypes.h$", "<sys/ipc.h>"},
+ {"bits/mman-linux.h$", "<sys/mman.h>"},
+ {"bits/mman.h$", "<sys/mman.h>"},
+ {"bits/msq.h$", "<sys/msg.h>"},
+ {"bits/resource.h$", "<sys/resource.h>"},
+ {"bits/sem.h$", "<sys/sem.h>"},
+ {"bits/shm.h$", "<sys/shm.h>"},
+ {"bits/signalfd.h$", "<sys/signalfd.h>"},
+ {"bits/statfs.h$", "<sys/statfs.h>"},
+ {"bits/statvfs.h$", "<sys/statvfs.h>"},
+ {"bits/timerfd.h$", "<sys/timerfd.h>"},
+ {"bits/utsname.h$", "<sys/utsname.h>"},
+ {"bits/auxv.h$", "<sys/auxv.h>"},
+ {"bits/byteswap-16.h$", "<byteswap.h>"},
+ {"bits/byteswap.h$", "<byteswap.h>"},
+ {"bits/confname.h$", "<unistd.h>"},
+ {"bits/dirent.h$", "<dirent.h>"},
+ {"bits/dlfcn.h$", "<dlfcn.h>"},
+ {"bits/elfclass.h$", "<link.h>"},
+ {"bits/endian.h$", "<endian.h>"},
+ {"bits/environments.h$", "<unistd.h>"},
+ {"bits/fcntl-linux.h$", "<fcntl.h>"},
+ {"bits/fcntl.h$", "<fcntl.h>"},
+ {"bits/in.h$", "<netinet/in.h>"},
+ {"bits/ioctl-types.h$", "<sys/ioctl.h>"},
+ {"bits/ioctls.h$", "<sys/ioctl.h>"},
+ {"bits/link.h$", "<link.h>"},
+ {"bits/mqueue.h$", "<mqueue.h>"},
+ {"bits/netdb.h$", "<netdb.h>"},
+ {"bits/param.h$", "<sys/param.h>"},
+ {"bits/poll.h$", "<sys/poll.h>"},
+ {"bits/posix_opt.h$", "<bits/posix_opt.h>"},
+ {"bits/pthreadtypes.h$", "<pthread.h>"},
+ {"bits/sched.h$", "<sched.h>"},
+ {"bits/select.h$", "<sys/select.h>"},
+ {"bits/semaphore.h$", "<semaphore.h>"},
+ {"bits/sigthread.h$", "<pthread.h>"},
+ {"bits/sockaddr.h$", "<sys/socket.h>"},
+ {"bits/socket.h$", "<sys/socket.h>"},
+ {"bits/socket_type.h$", "<sys/socket.h>"},
+ {"bits/stab.def$", "<stab.h>"},
+ {"bits/stat.h$", "<sys/stat.h>"},
+ {"bits/stropts.h$", "<stropts.h>"},
+ {"bits/syscall.h$", "<sys/syscall.h>"},
+ {"bits/syslog-path.h$", "<sys/syslog.h>"},
+ {"bits/termios.h$", "<termios.h>"},
+ {"bits/types.h$", "<sys/types.h>"},
+ {"bits/typesizes.h$", "<sys/types.h>"},
+ {"bits/uio.h$", "<sys/uio.h>"},
+ {"bits/ustat.h$", "<sys/ustat.h>"},
+ {"bits/utmp.h$", "<utmp.h>"},
+ {"bits/utmpx.h$", "<utmpx.h>"},
+ {"bits/waitflags.h$", "<sys/wait.h>"},
+ {"bits/waitstatus.h$", "<sys/wait.h>"},
+ {"bits/xtitypes.h$", "<stropts.h>"},
+ };
+ return &STLPostfixHeaderMap;
+}
+
+} // namespace find_all_symbols
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/STLPostfixHeaderMap.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/STLPostfixHeaderMap.h
new file mode 100644
index 0000000..162580d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/STLPostfixHeaderMap.h
@@ -0,0 +1,23 @@
+//===-- STLPostfixHeaderMap.h - hardcoded header map for STL ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_TOOL_STL_POSTFIX_HEADER_MAP_H
+#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_TOOL_STL_POSTFIX_HEADER_MAP_H
+
+#include "HeaderMapCollector.h"
+
+namespace clang {
+namespace find_all_symbols {
+
+const HeaderMapCollector::RegexHeaderMap *getSTLPostfixHeaderMap();
+
+} // namespace find_all_symbols
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_TOOL_STL_POSTFIX_HEADER_MAP_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/SymbolInfo.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/SymbolInfo.cpp
new file mode 100644
index 0000000..00bfbe5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/SymbolInfo.cpp
@@ -0,0 +1,137 @@
+//===-- SymbolInfo.cpp - Symbol Info ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolInfo.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+
+using llvm::yaml::MappingTraits;
+using llvm::yaml::IO;
+using llvm::yaml::Input;
+using ContextType = clang::find_all_symbols::SymbolInfo::ContextType;
+using clang::find_all_symbols::SymbolInfo;
+using clang::find_all_symbols::SymbolAndSignals;
+using SymbolKind = clang::find_all_symbols::SymbolInfo::SymbolKind;
+
+LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(SymbolAndSignals)
+LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolInfo::Context)
+
+namespace llvm {
+namespace yaml {
+template <> struct MappingTraits<SymbolAndSignals> {
+ static void mapping(IO &io, SymbolAndSignals &Symbol) {
+ io.mapRequired("Name", Symbol.Symbol.Name);
+ io.mapRequired("Contexts", Symbol.Symbol.Contexts);
+ io.mapRequired("FilePath", Symbol.Symbol.FilePath);
+ io.mapRequired("Type", Symbol.Symbol.Type);
+ io.mapRequired("Seen", Symbol.Signals.Seen);
+ io.mapRequired("Used", Symbol.Signals.Used);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<ContextType> {
+ static void enumeration(IO &io, ContextType &value) {
+ io.enumCase(value, "Record", ContextType::Record);
+ io.enumCase(value, "Namespace", ContextType::Namespace);
+ io.enumCase(value, "EnumDecl", ContextType::EnumDecl);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<SymbolKind> {
+ static void enumeration(IO &io, SymbolKind &value) {
+ io.enumCase(value, "Variable", SymbolKind::Variable);
+ io.enumCase(value, "Function", SymbolKind::Function);
+ io.enumCase(value, "Class", SymbolKind::Class);
+ io.enumCase(value, "TypedefName", SymbolKind::TypedefName);
+ io.enumCase(value, "EnumDecl", SymbolKind::EnumDecl);
+ io.enumCase(value, "EnumConstantDecl", SymbolKind::EnumConstantDecl);
+ io.enumCase(value, "Macro", SymbolKind::Macro);
+ io.enumCase(value, "Unknown", SymbolKind::Unknown);
+ }
+};
+
+template <> struct MappingTraits<SymbolInfo::Context> {
+ static void mapping(IO &io, SymbolInfo::Context &Context) {
+ io.mapRequired("ContextType", Context.first);
+ io.mapRequired("ContextName", Context.second);
+ }
+};
+
+} // namespace yaml
+} // namespace llvm
+
+namespace clang {
+namespace find_all_symbols {
+
+SymbolInfo::SymbolInfo(llvm::StringRef Name, SymbolKind Type,
+ llvm::StringRef FilePath,
+ const std::vector<Context> &Contexts)
+ : Name(Name), Type(Type), FilePath(FilePath), Contexts(Contexts) {}
+
+bool SymbolInfo::operator==(const SymbolInfo &Symbol) const {
+ return std::tie(Name, Type, FilePath, Contexts) ==
+ std::tie(Symbol.Name, Symbol.Type, Symbol.FilePath, Symbol.Contexts);
+}
+
+bool SymbolInfo::operator<(const SymbolInfo &Symbol) const {
+ return std::tie(Name, Type, FilePath, Contexts) <
+ std::tie(Symbol.Name, Symbol.Type, Symbol.FilePath, Symbol.Contexts);
+}
+
+std::string SymbolInfo::getQualifiedName() const {
+ std::string QualifiedName = Name;
+ for (const auto &Context : Contexts) {
+ if (Context.first == ContextType::EnumDecl)
+ continue;
+ QualifiedName = Context.second + "::" + QualifiedName;
+ }
+ return QualifiedName;
+}
+
+SymbolInfo::Signals &SymbolInfo::Signals::operator+=(const Signals &RHS) {
+ Seen += RHS.Seen;
+ Used += RHS.Used;
+ return *this;
+}
+
+SymbolInfo::Signals SymbolInfo::Signals::operator+(const Signals &RHS) const {
+ Signals Result = *this;
+ Result += RHS;
+ return Result;
+}
+
+bool SymbolInfo::Signals::operator==(const Signals &RHS) const {
+ return std::tie(Seen, Used) == std::tie(RHS.Seen, RHS.Used);
+}
+
+bool SymbolAndSignals::operator==(const SymbolAndSignals& RHS) const {
+ return std::tie(Symbol, Signals) == std::tie(RHS.Symbol, RHS.Signals);
+}
+
+bool WriteSymbolInfosToStream(llvm::raw_ostream &OS,
+ const SymbolInfo::SignalMap &Symbols) {
+ llvm::yaml::Output yout(OS);
+ for (const auto &Symbol : Symbols) {
+ SymbolAndSignals S{Symbol.first, Symbol.second};
+ yout << S;
+ }
+ return true;
+}
+
+std::vector<SymbolAndSignals> ReadSymbolInfosFromYAML(llvm::StringRef Yaml) {
+ std::vector<SymbolAndSignals> Symbols;
+ llvm::yaml::Input yin(Yaml);
+ yin >> Symbols;
+ return Symbols;
+}
+
+} // namespace find_all_symbols
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/SymbolInfo.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/SymbolInfo.h
new file mode 100644
index 0000000..92d360d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/SymbolInfo.h
@@ -0,0 +1,143 @@
+//===-- SymbolInfo.h - Symbol Info ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_ALL_SYMBOLS_SYMBOLINFO_H
+#define LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_ALL_SYMBOLS_SYMBOLINFO_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <set>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace find_all_symbols {
+/// \brief Describes a named symbol from a header.
+/// Symbols with the same qualified name and type (e.g. function overloads)
+/// that appear in the same header are represented by a single SymbolInfo.
+///
+/// TODO: keep track of instances, e.g. overload locations and signatures.
+class SymbolInfo {
+public:
+ /// \brief The SymbolInfo Type.
+ enum class SymbolKind {
+ Function,
+ Class,
+ Variable,
+ TypedefName,
+ EnumDecl,
+ EnumConstantDecl,
+ Macro,
+ Unknown,
+ };
+
+ /// \brief The Context Type.
+ enum class ContextType {
+ Namespace, // Symbols declared in a namespace.
+ Record, // Symbols declared in a class.
+ EnumDecl, // Enum constants declared in a enum declaration.
+ };
+
+ /// \brief A pair of <ContextType, ContextName>.
+ typedef std::pair<ContextType, std::string> Context;
+
+ // \brief Signals are signals gathered by observing how a symbol is used.
+ // These are used to rank results.
+ struct Signals {
+ Signals() {}
+ Signals(unsigned Seen, unsigned Used) : Seen(Seen), Used(Used) {}
+
+ // Number of times this symbol was visible to a TU.
+ unsigned Seen = 0;
+
+ // Number of times this symbol was referenced a TU's main file.
+ unsigned Used = 0;
+
+ Signals &operator+=(const Signals &RHS);
+ Signals operator+(const Signals &RHS) const;
+ bool operator==(const Signals &RHS) const;
+ };
+
+ using SignalMap = std::map<SymbolInfo, Signals>;
+
+ // The default constructor is required by YAML traits in
+ // LLVM_YAML_IS_DOCUMENT_LIST_VECTOR.
+ SymbolInfo() : Type(SymbolKind::Unknown) {}
+
+ SymbolInfo(llvm::StringRef Name, SymbolKind Type, llvm::StringRef FilePath,
+ const std::vector<Context> &Contexts);
+
+ void SetFilePath(llvm::StringRef Path) { FilePath = Path; }
+
+ /// \brief Get symbol name.
+ llvm::StringRef getName() const { return Name; }
+
+ /// \brief Get the fully-qualified symbol name.
+ std::string getQualifiedName() const;
+
+ /// \brief Get symbol type.
+ SymbolKind getSymbolKind() const { return Type; }
+
+ /// \brief Get a relative file path where symbol comes from.
+ llvm::StringRef getFilePath() const { return FilePath; }
+
+ /// \brief Get symbol contexts.
+ const std::vector<SymbolInfo::Context> &getContexts() const {
+ return Contexts;
+ }
+
+ bool operator<(const SymbolInfo &Symbol) const;
+
+ bool operator==(const SymbolInfo &Symbol) const;
+
+private:
+ friend struct llvm::yaml::MappingTraits<struct SymbolAndSignals>;
+
+ /// \brief Identifier name.
+ std::string Name;
+
+ /// \brief Symbol type.
+ SymbolKind Type;
+
+ /// \brief The file path where the symbol comes from. It's a relative file
+ /// path based on the build directory.
+ std::string FilePath;
+
+ /// \brief Contains information about symbol contexts. Context information is
+ /// stored from the inner-most level to outer-most level.
+ ///
+ /// For example, if a symbol 'x' is declared as:
+ /// namespace na { namespace nb { class A { int x; } } }
+ /// The contexts would be { {RECORD, "A"}, {NAMESPACE, "nb"}, {NAMESPACE,
+ /// "na"} }.
+ /// The name of an anonymous namespace is "".
+ ///
+ /// If the symbol is declared in `TranslationUnitDecl`, it has no context.
+ std::vector<Context> Contexts;
+};
+
+struct SymbolAndSignals {
+ SymbolInfo Symbol;
+ SymbolInfo::Signals Signals;
+ bool operator==(const SymbolAndSignals& RHS) const;
+};
+
+/// \brief Write SymbolInfos to a stream (YAML format).
+bool WriteSymbolInfosToStream(llvm::raw_ostream &OS,
+ const SymbolInfo::SignalMap &Symbols);
+
+/// \brief Read SymbolInfos from a YAML document.
+std::vector<SymbolAndSignals> ReadSymbolInfosFromYAML(llvm::StringRef Yaml);
+
+} // namespace find_all_symbols
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_INCLUDE_FIXER_FIND_ALL_SYMBOLS_SYMBOLINFO_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/SymbolReporter.h b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/SymbolReporter.h
new file mode 100644
index 0000000..2398234
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/SymbolReporter.h
@@ -0,0 +1,30 @@
+//===--- SymbolReporter.h - Symbol Reporter ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_REPORTER_H
+#define LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_REPORTER_H
+
+#include "SymbolInfo.h"
+
+namespace clang {
+namespace find_all_symbols {
+
+/// \brief An interface for classes that collect symbols.
+class SymbolReporter {
+public:
+ virtual ~SymbolReporter() = default;
+
+ virtual void reportSymbols(llvm::StringRef FileName,
+ const SymbolInfo::SignalMap &Symbols) = 0;
+};
+
+} // namespace find_all_symbols
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_FIND_ALL_SYMBOLS_SYMBOL_REPORTER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/tool/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/tool/CMakeLists.txt
new file mode 100644
index 0000000..474dc51
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/tool/CMakeLists.txt
@@ -0,0 +1,23 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+add_clang_executable(find-all-symbols
+ FindAllSymbolsMain.cpp
+ )
+
+target_link_libraries(find-all-symbols
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFrontend
+ clangLex
+ clangTooling
+ findAllSymbols
+ )
+
+install(TARGETS find-all-symbols
+ RUNTIME DESTINATION bin)
+
+install(PROGRAMS run-find-all-symbols.py
+ DESTINATION share/clang
+ COMPONENT find-all-symbols)
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp
new file mode 100644
index 0000000..e09a5aa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/tool/FindAllSymbolsMain.cpp
@@ -0,0 +1,152 @@
+//===-- FindAllSymbolsMain.cpp - find all symbols tool ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FindAllSymbolsAction.h"
+#include "STLPostfixHeaderMap.h"
+#include "SymbolInfo.h"
+#include "SymbolReporter.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/raw_ostream.h"
+#include <map>
+#include <mutex>
+#include <set>
+#include <string>
+#include <system_error>
+#include <vector>
+
+using namespace clang::tooling;
+using namespace llvm;
+using SymbolInfo = clang::find_all_symbols::SymbolInfo;
+
+// Apply a custom category to all command-line options so that they are the
+// only ones displayed.
+static cl::OptionCategory FindAllSymbolsCategory("find_all_symbols options");
+
+// CommonOptionsParser declares HelpMessage with a description of the common
+// command-line options related to the compilation database and input files.
+// It's nice to have this help message in all tools.
+static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+
+// A help message for this specific tool can be added afterwards.
+static cl::extrahelp MoreHelp("\nMore help text...");
+
+static cl::opt<std::string> OutputDir("output-dir", cl::desc(R"(
+The output directory for saving the results.)"),
+ cl::init("."),
+ cl::cat(FindAllSymbolsCategory));
+
+static cl::opt<std::string> MergeDir("merge-dir", cl::desc(R"(
+The directory for merging symbols.)"),
+ cl::init(""),
+ cl::cat(FindAllSymbolsCategory));
+namespace clang {
+namespace find_all_symbols {
+
+class YamlReporter : public SymbolReporter {
+public:
+ void reportSymbols(StringRef FileName,
+ const SymbolInfo::SignalMap &Symbols) override {
+ int FD;
+ SmallString<128> ResultPath;
+ llvm::sys::fs::createUniqueFile(
+ OutputDir + "/" + llvm::sys::path::filename(FileName) + "-%%%%%%.yaml",
+ FD, ResultPath);
+ llvm::raw_fd_ostream OS(FD, /*shouldClose=*/true);
+ WriteSymbolInfosToStream(OS, Symbols);
+ }
+};
+
+bool Merge(llvm::StringRef MergeDir, llvm::StringRef OutputFile) {
+ std::error_code EC;
+ SymbolInfo::SignalMap Symbols;
+ std::mutex SymbolMutex;
+ auto AddSymbols = [&](ArrayRef<SymbolAndSignals> NewSymbols) {
+ // Synchronize set accesses.
+ std::unique_lock<std::mutex> LockGuard(SymbolMutex);
+ for (const auto &Symbol : NewSymbols) {
+ Symbols[Symbol.Symbol] += Symbol.Signals;
+ }
+ };
+
+ // Load all symbol files in MergeDir.
+ {
+ llvm::ThreadPool Pool;
+ for (llvm::sys::fs::directory_iterator Dir(MergeDir, EC), DirEnd;
+ Dir != DirEnd && !EC; Dir.increment(EC)) {
+ // Parse YAML files in parallel.
+ Pool.async(
+ [&AddSymbols](std::string Path) {
+ auto Buffer = llvm::MemoryBuffer::getFile(Path);
+ if (!Buffer) {
+ llvm::errs() << "Can't open " << Path << "\n";
+ return;
+ }
+ std::vector<SymbolAndSignals> Symbols =
+ ReadSymbolInfosFromYAML(Buffer.get()->getBuffer());
+ for (auto &Symbol : Symbols) {
+ // Only count one occurrence per file, to avoid spam.
+ Symbol.Signals.Seen = std::min(Symbol.Signals.Seen, 1u);
+ Symbol.Signals.Used = std::min(Symbol.Signals.Used, 1u);
+ }
+ // FIXME: Merge without creating such a heavy contention point.
+ AddSymbols(Symbols);
+ },
+ Dir->path());
+ }
+ }
+
+ llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_None);
+ if (EC) {
+ llvm::errs() << "Can't open '" << OutputFile << "': " << EC.message()
+ << '\n';
+ return false;
+ }
+ WriteSymbolInfosToStream(OS, Symbols);
+ return true;
+}
+
+} // namespace clang
+} // namespace find_all_symbols
+
+int main(int argc, const char **argv) {
+ CommonOptionsParser OptionsParser(argc, argv, FindAllSymbolsCategory);
+ ClangTool Tool(OptionsParser.getCompilations(),
+ OptionsParser.getSourcePathList());
+
+ std::vector<std::string> sources = OptionsParser.getSourcePathList();
+ if (sources.empty()) {
+ llvm::errs() << "Must specify at least one one source file.\n";
+ return 1;
+ }
+ if (!MergeDir.empty()) {
+ clang::find_all_symbols::Merge(MergeDir, sources[0]);
+ return 0;
+ }
+
+ clang::find_all_symbols::YamlReporter Reporter;
+
+ auto Factory =
+ llvm::make_unique<clang::find_all_symbols::FindAllSymbolsActionFactory>(
+ &Reporter, clang::find_all_symbols::getSTLPostfixHeaderMap());
+ return Tool.run(Factory.get());
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/tool/run-find-all-symbols.py b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/tool/run-find-all-symbols.py
new file mode 100755
index 0000000..461d959
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/find-all-symbols/tool/run-find-all-symbols.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+#
+#=- run-find-all-symbols.py - Parallel find-all-symbols runner -*- python -*-=#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+"""
+Parallel find-all-symbols runner
+================================
+
+Runs find-all-symbols over all files in a compilation database.
+
+Example invocations.
+- Run find-all-symbols on all files in the current working directory.
+ run-find-all-symbols.py <source-file>
+
+Compilation database setup:
+http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+"""
+
+import argparse
+import json
+import multiprocessing
+import os
+import Queue
+import shutil
+import subprocess
+import sys
+import tempfile
+import threading
+
+
+def find_compilation_database(path):
+ """Adjusts the directory until a compilation database is found."""
+ result = './'
+ while not os.path.isfile(os.path.join(result, path)):
+ if os.path.realpath(result) == '/':
+ print 'Error: could not find compilation database.'
+ sys.exit(1)
+ result += '../'
+ return os.path.realpath(result)
+
+
+def MergeSymbols(directory, args):
+ """Merge all symbol files (yaml) in a given directaory into a single file."""
+ invocation = [args.binary, '-merge-dir='+directory, args.saving_path]
+ subprocess.call(invocation)
+ print 'Merge is finished. Saving results in ' + args.saving_path
+
+
+def run_find_all_symbols(args, tmpdir, build_path, queue):
+ """Takes filenames out of queue and runs find-all-symbols on them."""
+ while True:
+ name = queue.get()
+ invocation = [args.binary, name, '-output-dir='+tmpdir, '-p='+build_path]
+ sys.stdout.write(' '.join(invocation) + '\n')
+ subprocess.call(invocation)
+ queue.task_done()
+
+
+def main():
+ parser = argparse.ArgumentParser(description='Runs find-all-symbols over all'
+ 'files in a compilation database.')
+ parser.add_argument('-binary', metavar='PATH',
+ default='./bin/find-all-symbols',
+ help='path to find-all-symbols binary')
+ parser.add_argument('-j', type=int, default=0,
+ help='number of instances to be run in parallel.')
+ parser.add_argument('-p', dest='build_path',
+ help='path used to read a compilation database.')
+ parser.add_argument('-saving-path', default='./find_all_symbols_db.yaml',
+ help='result saving path')
+ args = parser.parse_args()
+
+ db_path = 'compile_commands.json'
+
+ if args.build_path is not None:
+ build_path = args.build_path
+ else:
+ build_path = find_compilation_database(db_path)
+
+ tmpdir = tempfile.mkdtemp()
+
+ # Load the database and extract all files.
+ database = json.load(open(os.path.join(build_path, db_path)))
+ files = [entry['file'] for entry in database]
+
+ max_task = args.j
+ if max_task == 0:
+ max_task = multiprocessing.cpu_count()
+
+ try:
+ # Spin up a bunch of tidy-launching threads.
+ queue = Queue.Queue(max_task)
+ for _ in range(max_task):
+ t = threading.Thread(target=run_find_all_symbols,
+ args=(args, tmpdir, build_path, queue))
+ t.daemon = True
+ t.start()
+
+ # Fill the queue with files.
+ for name in files:
+ queue.put(name)
+
+ # Wait for all threads to be done.
+ queue.join()
+
+ MergeSymbols(tmpdir, args)
+
+
+ except KeyboardInterrupt:
+ # This is a sad hack. Unfortunately subprocess goes
+ # bonkers with ctrl-c and we start forking merrily.
+ print '\nCtrl-C detected, goodbye.'
+ os.kill(0, 9)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/plugin/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/include-fixer/plugin/CMakeLists.txt
new file mode 100644
index 0000000..df792ea
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/plugin/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_clang_library(clangIncludeFixerPlugin
+ IncludeFixerPlugin.cpp
+
+ LINK_LIBS
+ clangAST
+ clangBasic
+ clangFrontend
+ clangIncludeFixer
+ clangParse
+ clangSema
+ clangTooling
+ ${LLVM_PTHREAD_LIB}
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/plugin/IncludeFixerPlugin.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/plugin/IncludeFixerPlugin.cpp
new file mode 100644
index 0000000..0d6bdb7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/plugin/IncludeFixerPlugin.cpp
@@ -0,0 +1,100 @@
+//===- IncludeFixerPlugin.cpp - clang-include-fixer as a clang plugin -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../IncludeFixer.h"
+#include "../YamlSymbolIndex.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/Support/Path.h"
+
+namespace clang {
+namespace include_fixer {
+
+/// The core include fixer plugin action. This just provides the AST consumer
+/// and command line flag parsing for using include fixer as a clang plugin.
+class ClangIncludeFixerPluginAction : public PluginASTAction {
+ /// ASTConsumer to keep the symbol index alive. We don't really need an
+ /// ASTConsumer for this plugin (everything is funneled on the side through
+ /// Sema) but we have to keep the symbol index alive until sema is done.
+ struct ASTConsumerManagerWrapper : public ASTConsumer {
+ ASTConsumerManagerWrapper(std::shared_ptr<SymbolIndexManager> SIM)
+ : SymbolIndexMgr(std::move(SIM)) {}
+ std::shared_ptr<SymbolIndexManager> SymbolIndexMgr;
+ };
+
+public:
+ explicit ClangIncludeFixerPluginAction()
+ : SymbolIndexMgr(std::make_shared<SymbolIndexManager>()),
+ SemaSource(new IncludeFixerSemaSource(*SymbolIndexMgr,
+ /*MinimizeIncludePaths=*/true,
+ /*GenerateDiagnostics=*/true)) {}
+
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &CI, StringRef InFile) override {
+ CI.setExternalSemaSource(SemaSource);
+ SemaSource->setFilePath(InFile);
+ SemaSource->setCompilerInstance(&CI);
+ return llvm::make_unique<ASTConsumerManagerWrapper>(SymbolIndexMgr);
+ }
+
+ void ExecuteAction() override {} // Do nothing.
+
+ bool ParseArgs(const CompilerInstance &CI,
+ const std::vector<std::string> &Args) override {
+ StringRef DB = "yaml";
+ StringRef Input;
+
+ // Parse the extra command line args.
+ // FIXME: This is very limited at the moment.
+ for (StringRef Arg : Args) {
+ if (Arg.startswith("-db="))
+ DB = Arg.substr(strlen("-db="));
+ else if (Arg.startswith("-input="))
+ Input = Arg.substr(strlen("-input="));
+ }
+
+ std::string InputFile = CI.getFrontendOpts().Inputs[0].getFile();
+ auto CreateYamlIdx = [=]() -> std::unique_ptr<include_fixer::SymbolIndex> {
+ llvm::ErrorOr<std::unique_ptr<include_fixer::YamlSymbolIndex>> SymbolIdx(
+ nullptr);
+ if (DB == "yaml") {
+ if (!Input.empty()) {
+ SymbolIdx = include_fixer::YamlSymbolIndex::createFromFile(Input);
+ } else {
+ // If we don't have any input file, look in the directory of the first
+ // file and its parents.
+ SmallString<128> AbsolutePath(tooling::getAbsolutePath(InputFile));
+ StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
+ SymbolIdx = include_fixer::YamlSymbolIndex::createFromDirectory(
+ Directory, "find_all_symbols_db.yaml");
+ }
+ }
+ return std::move(*SymbolIdx);
+ };
+
+ SymbolIndexMgr->addSymbolIndex(std::move(CreateYamlIdx));
+ return true;
+ }
+
+private:
+ std::shared_ptr<SymbolIndexManager> SymbolIndexMgr;
+ IntrusiveRefCntPtr<IncludeFixerSemaSource> SemaSource;
+};
+} // namespace include_fixer
+} // namespace clang
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the include fixer plugin.
+volatile int ClangIncludeFixerPluginAnchorSource = 0;
+
+static clang::FrontendPluginRegistry::Add<
+ clang::include_fixer::ClangIncludeFixerPluginAction>
+ X("clang-include-fixer", "clang-include-fixer");
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/CMakeLists.txt
new file mode 100644
index 0000000..a641a36
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/CMakeLists.txt
@@ -0,0 +1,27 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+add_clang_tool(clang-include-fixer
+ ClangIncludeFixer.cpp
+ )
+
+target_link_libraries(clang-include-fixer
+ PRIVATE
+ clangBasic
+ clangFormat
+ clangFrontend
+ clangIncludeFixer
+ clangRewrite
+ clangTooling
+ clangToolingCore
+ findAllSymbols
+ )
+
+install(TARGETS clang-include-fixer
+ RUNTIME DESTINATION bin)
+
+install(PROGRAMS clang-include-fixer.el
+ DESTINATION share/clang
+ COMPONENT clang-include-fixer)
+install(PROGRAMS clang-include-fixer.py
+ DESTINATION share/clang
+ COMPONENT clang-include-fixer)
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/ClangIncludeFixer.cpp b/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/ClangIncludeFixer.cpp
new file mode 100644
index 0000000..2f2e45e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/ClangIncludeFixer.cpp
@@ -0,0 +1,471 @@
+//===-- ClangIncludeFixer.cpp - Standalone include fixer ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FuzzySymbolIndex.h"
+#include "InMemorySymbolIndex.h"
+#include "IncludeFixer.h"
+#include "IncludeFixerContext.h"
+#include "SymbolIndexManager.h"
+#include "YamlSymbolIndex.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace clang;
+using namespace llvm;
+using clang::include_fixer::IncludeFixerContext;
+
+LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(IncludeFixerContext)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(IncludeFixerContext::HeaderInfo)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(IncludeFixerContext::QuerySymbolInfo)
+
+namespace llvm {
+namespace yaml {
+
+template <> struct MappingTraits<tooling::Range> {
+ struct NormalizedRange {
+ NormalizedRange(const IO &) : Offset(0), Length(0) {}
+
+ NormalizedRange(const IO &, const tooling::Range &R)
+ : Offset(R.getOffset()), Length(R.getLength()) {}
+
+ tooling::Range denormalize(const IO &) {
+ return tooling::Range(Offset, Length);
+ }
+
+ unsigned Offset;
+ unsigned Length;
+ };
+ static void mapping(IO &IO, tooling::Range &Info) {
+ MappingNormalization<NormalizedRange, tooling::Range> Keys(IO, Info);
+ IO.mapRequired("Offset", Keys->Offset);
+ IO.mapRequired("Length", Keys->Length);
+ }
+};
+
+template <> struct MappingTraits<IncludeFixerContext::HeaderInfo> {
+ static void mapping(IO &io, IncludeFixerContext::HeaderInfo &Info) {
+ io.mapRequired("Header", Info.Header);
+ io.mapRequired("QualifiedName", Info.QualifiedName);
+ }
+};
+
+template <> struct MappingTraits<IncludeFixerContext::QuerySymbolInfo> {
+ static void mapping(IO &io, IncludeFixerContext::QuerySymbolInfo &Info) {
+ io.mapRequired("RawIdentifier", Info.RawIdentifier);
+ io.mapRequired("Range", Info.Range);
+ }
+};
+
+template <> struct MappingTraits<IncludeFixerContext> {
+ static void mapping(IO &IO, IncludeFixerContext &Context) {
+ IO.mapRequired("QuerySymbolInfos", Context.QuerySymbolInfos);
+ IO.mapRequired("HeaderInfos", Context.HeaderInfos);
+ IO.mapRequired("FilePath", Context.FilePath);
+ }
+};
+} // namespace yaml
+} // namespace llvm
+
+namespace {
+cl::OptionCategory IncludeFixerCategory("Tool options");
+
+enum DatabaseFormatTy {
+ fixed, ///< Hard-coded mapping.
+ yaml, ///< Yaml database created by find-all-symbols.
+ fuzzyYaml, ///< Yaml database with fuzzy-matched identifiers.
+};
+
+cl::opt<DatabaseFormatTy> DatabaseFormat(
+ "db", cl::desc("Specify input format"),
+ cl::values(clEnumVal(fixed, "Hard-coded mapping"),
+ clEnumVal(yaml, "Yaml database created by find-all-symbols"),
+ clEnumVal(fuzzyYaml, "Yaml database, with fuzzy-matched names")),
+ cl::init(yaml), cl::cat(IncludeFixerCategory));
+
+cl::opt<std::string> Input("input",
+ cl::desc("String to initialize the database"),
+ cl::cat(IncludeFixerCategory));
+
+cl::opt<std::string>
+ QuerySymbol("query-symbol",
+ cl::desc("Query a given symbol (e.g. \"a::b::foo\") in\n"
+ "database directly without parsing the file."),
+ cl::cat(IncludeFixerCategory));
+
+cl::opt<bool>
+ MinimizeIncludePaths("minimize-paths",
+ cl::desc("Whether to minimize added include paths"),
+ cl::init(true), cl::cat(IncludeFixerCategory));
+
+cl::opt<bool> Quiet("q", cl::desc("Reduce terminal output"), cl::init(false),
+ cl::cat(IncludeFixerCategory));
+
+cl::opt<bool>
+ STDINMode("stdin",
+ cl::desc("Override source file's content (in the overlaying\n"
+ "virtual file system) with input from <stdin> and run\n"
+ "the tool on the new content with the compilation\n"
+ "options of the source file. This mode is currently\n"
+ "used for editor integration."),
+ cl::init(false), cl::cat(IncludeFixerCategory));
+
+cl::opt<bool> OutputHeaders(
+ "output-headers",
+ cl::desc("Print the symbol being queried and all its relevant headers in\n"
+ "JSON format to stdout:\n"
+ " {\n"
+ " \"FilePath\": \"/path/to/foo.cc\",\n"
+ " \"QuerySymbolInfos\": [\n"
+ " {\"RawIdentifier\": \"foo\",\n"
+ " \"Range\": {\"Offset\": 0, \"Length\": 3}}\n"
+ " ],\n"
+ " \"HeaderInfos\": [ {\"Header\": \"\\\"foo_a.h\\\"\",\n"
+ " \"QualifiedName\": \"a::foo\"} ]\n"
+ " }"),
+ cl::init(false), cl::cat(IncludeFixerCategory));
+
+cl::opt<std::string> InsertHeader(
+ "insert-header",
+ cl::desc("Insert a specific header. This should run with STDIN mode.\n"
+ "The result is written to stdout. It is currently used for\n"
+ "editor integration. Support YAML/JSON format:\n"
+ " -insert-header=\"{\n"
+ " FilePath: \"/path/to/foo.cc\",\n"
+ " QuerySymbolInfos: [\n"
+ " {RawIdentifier: foo,\n"
+ " Range: {Offset: 0, Length: 3}}\n"
+ " ],\n"
+ " HeaderInfos: [ {Headers: \"\\\"foo_a.h\\\"\",\n"
+ " QualifiedName: \"a::foo\"} ]}\""),
+ cl::init(""), cl::cat(IncludeFixerCategory));
+
+cl::opt<std::string>
+ Style("style",
+ cl::desc("Fallback style for reformatting after inserting new\n"
+ "headers if there is no clang-format config file found."),
+ cl::init("llvm"), cl::cat(IncludeFixerCategory));
+
+std::unique_ptr<include_fixer::SymbolIndexManager>
+createSymbolIndexManager(StringRef FilePath) {
+ using find_all_symbols::SymbolInfo;
+
+ auto SymbolIndexMgr = llvm::make_unique<include_fixer::SymbolIndexManager>();
+ switch (DatabaseFormat) {
+ case fixed: {
+ // Parse input and fill the database with it.
+ // <symbol>=<header><, header...>
+ // Multiple symbols can be given, separated by semicolons.
+ std::map<std::string, std::vector<std::string>> SymbolsMap;
+ SmallVector<StringRef, 4> SemicolonSplits;
+ StringRef(Input).split(SemicolonSplits, ";");
+ std::vector<find_all_symbols::SymbolAndSignals> Symbols;
+ for (StringRef Pair : SemicolonSplits) {
+ auto Split = Pair.split('=');
+ std::vector<std::string> Headers;
+ SmallVector<StringRef, 4> CommaSplits;
+ Split.second.split(CommaSplits, ",");
+ for (size_t I = 0, E = CommaSplits.size(); I != E; ++I)
+ Symbols.push_back(
+ {SymbolInfo(Split.first.trim(), SymbolInfo::SymbolKind::Unknown,
+ CommaSplits[I].trim(), {}),
+ // Use fake "seen" signal for tests, so first header wins.
+ SymbolInfo::Signals(/*Seen=*/static_cast<unsigned>(E - I),
+ /*Used=*/0)});
+ }
+ SymbolIndexMgr->addSymbolIndex([=]() {
+ return llvm::make_unique<include_fixer::InMemorySymbolIndex>(Symbols);
+ });
+ break;
+ }
+ case yaml: {
+ auto CreateYamlIdx = [=]() -> std::unique_ptr<include_fixer::SymbolIndex> {
+ llvm::ErrorOr<std::unique_ptr<include_fixer::YamlSymbolIndex>> DB(
+ nullptr);
+ if (!Input.empty()) {
+ DB = include_fixer::YamlSymbolIndex::createFromFile(Input);
+ } else {
+ // If we don't have any input file, look in the directory of the
+ // first
+ // file and its parents.
+ SmallString<128> AbsolutePath(tooling::getAbsolutePath(FilePath));
+ StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
+ DB = include_fixer::YamlSymbolIndex::createFromDirectory(
+ Directory, "find_all_symbols_db.yaml");
+ }
+
+ if (!DB) {
+ llvm::errs() << "Couldn't find YAML db: " << DB.getError().message()
+ << '\n';
+ return nullptr;
+ }
+ return std::move(*DB);
+ };
+
+ SymbolIndexMgr->addSymbolIndex(std::move(CreateYamlIdx));
+ break;
+ }
+ case fuzzyYaml: {
+ // This mode is not very useful, because we don't correct the identifier.
+ // It's main purpose is to expose FuzzySymbolIndex to tests.
+ SymbolIndexMgr->addSymbolIndex(
+ []() -> std::unique_ptr<include_fixer::SymbolIndex> {
+ auto DB = include_fixer::FuzzySymbolIndex::createFromYAML(Input);
+ if (!DB) {
+ llvm::errs() << "Couldn't load fuzzy YAML db: "
+ << llvm::toString(DB.takeError()) << '\n';
+ return nullptr;
+ }
+ return std::move(*DB);
+ });
+ break;
+ }
+ }
+ return SymbolIndexMgr;
+}
+
+void writeToJson(llvm::raw_ostream &OS, const IncludeFixerContext& Context) {
+ OS << "{\n"
+ << " \"FilePath\": \""
+ << llvm::yaml::escape(Context.getFilePath()) << "\",\n"
+ << " \"QuerySymbolInfos\": [\n";
+ for (const auto &Info : Context.getQuerySymbolInfos()) {
+ OS << " {\"RawIdentifier\": \"" << Info.RawIdentifier << "\",\n";
+ OS << " \"Range\":{";
+ OS << "\"Offset\":" << Info.Range.getOffset() << ",";
+ OS << "\"Length\":" << Info.Range.getLength() << "}}";
+ if (&Info != &Context.getQuerySymbolInfos().back())
+ OS << ",\n";
+ }
+ OS << "\n ],\n";
+ OS << " \"HeaderInfos\": [\n";
+ const auto &HeaderInfos = Context.getHeaderInfos();
+ for (const auto &Info : HeaderInfos) {
+ OS << " {\"Header\": \"" << llvm::yaml::escape(Info.Header) << "\",\n"
+ << " \"QualifiedName\": \"" << Info.QualifiedName << "\"}";
+ if (&Info != &HeaderInfos.back())
+ OS << ",\n";
+ }
+ OS << "\n";
+ OS << " ]\n";
+ OS << "}\n";
+}
+
+int includeFixerMain(int argc, const char **argv) {
+ tooling::CommonOptionsParser options(argc, argv, IncludeFixerCategory);
+ tooling::ClangTool tool(options.getCompilations(),
+ options.getSourcePathList());
+
+ llvm::StringRef SourceFilePath = options.getSourcePathList().front();
+ // In STDINMode, we override the file content with the <stdin> input.
+ // Since `tool.mapVirtualFile` takes `StringRef`, we define `Code` outside of
+ // the if-block so that `Code` is not released after the if-block.
+ std::unique_ptr<llvm::MemoryBuffer> Code;
+ if (STDINMode) {
+ assert(options.getSourcePathList().size() == 1 &&
+ "Expect exactly one file path in STDINMode.");
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> CodeOrErr =
+ MemoryBuffer::getSTDIN();
+ if (std::error_code EC = CodeOrErr.getError()) {
+ errs() << EC.message() << "\n";
+ return 1;
+ }
+ Code = std::move(CodeOrErr.get());
+ if (Code->getBufferSize() == 0)
+ return 0; // Skip empty files.
+
+ tool.mapVirtualFile(SourceFilePath, Code->getBuffer());
+ }
+
+ if (!InsertHeader.empty()) {
+ if (!STDINMode) {
+ errs() << "Should be running in STDIN mode\n";
+ return 1;
+ }
+
+ llvm::yaml::Input yin(InsertHeader);
+ IncludeFixerContext Context;
+ yin >> Context;
+
+ const auto &HeaderInfos = Context.getHeaderInfos();
+ assert(!HeaderInfos.empty());
+ // We only accept one unique header.
+ // Check all elements in HeaderInfos have the same header.
+ bool IsUniqueHeader = std::equal(
+ HeaderInfos.begin()+1, HeaderInfos.end(), HeaderInfos.begin(),
+ [](const IncludeFixerContext::HeaderInfo &LHS,
+ const IncludeFixerContext::HeaderInfo &RHS) {
+ return LHS.Header == RHS.Header;
+ });
+ if (!IsUniqueHeader) {
+ errs() << "Expect exactly one unique header.\n";
+ return 1;
+ }
+
+ // If a header has multiple symbols, we won't add the missing namespace
+ // qualifiers because we don't know which one is exactly used.
+ //
+ // Check whether all elements in HeaderInfos have the same qualified name.
+ bool IsUniqueQualifiedName = std::equal(
+ HeaderInfos.begin() + 1, HeaderInfos.end(), HeaderInfos.begin(),
+ [](const IncludeFixerContext::HeaderInfo &LHS,
+ const IncludeFixerContext::HeaderInfo &RHS) {
+ return LHS.QualifiedName == RHS.QualifiedName;
+ });
+ auto InsertStyle = format::getStyle("file", Context.getFilePath(), Style);
+ if (!InsertStyle) {
+ llvm::errs() << llvm::toString(InsertStyle.takeError()) << "\n";
+ return 1;
+ }
+ auto Replacements = clang::include_fixer::createIncludeFixerReplacements(
+ Code->getBuffer(), Context, *InsertStyle,
+ /*AddQualifiers=*/IsUniqueQualifiedName);
+ if (!Replacements) {
+ errs() << "Failed to create replacements: "
+ << llvm::toString(Replacements.takeError()) << "\n";
+ return 1;
+ }
+
+ auto ChangedCode =
+ tooling::applyAllReplacements(Code->getBuffer(), *Replacements);
+ if (!ChangedCode) {
+ llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
+ return 1;
+ }
+ llvm::outs() << *ChangedCode;
+ return 0;
+ }
+
+ // Set up data source.
+ std::unique_ptr<include_fixer::SymbolIndexManager> SymbolIndexMgr =
+ createSymbolIndexManager(SourceFilePath);
+ if (!SymbolIndexMgr)
+ return 1;
+
+ // Query symbol mode.
+ if (!QuerySymbol.empty()) {
+ auto MatchedSymbols = SymbolIndexMgr->search(
+ QuerySymbol, /*IsNestedSearch=*/true, SourceFilePath);
+ for (auto &Symbol : MatchedSymbols) {
+ std::string HeaderPath = Symbol.getFilePath().str();
+ Symbol.SetFilePath(((HeaderPath[0] == '"' || HeaderPath[0] == '<')
+ ? HeaderPath
+ : "\"" + HeaderPath + "\""));
+ }
+
+ // We leave an empty symbol range as we don't know the range of the symbol
+ // being queried in this mode. include-fixer won't add namespace qualifiers
+ // if the symbol range is empty, which also fits this case.
+ IncludeFixerContext::QuerySymbolInfo Symbol;
+ Symbol.RawIdentifier = QuerySymbol;
+ auto Context =
+ IncludeFixerContext(SourceFilePath, {Symbol}, MatchedSymbols);
+ writeToJson(llvm::outs(), Context);
+ return 0;
+ }
+
+ // Now run our tool.
+ std::vector<include_fixer::IncludeFixerContext> Contexts;
+ include_fixer::IncludeFixerActionFactory Factory(*SymbolIndexMgr, Contexts,
+ Style, MinimizeIncludePaths);
+
+ if (tool.run(&Factory) != 0) {
+ // We suppress all Clang diagnostics (because they would be wrong,
+ // include-fixer does custom recovery) but still want to give some feedback
+ // in case there was a compiler error we couldn't recover from. The most
+ // common case for this is a #include in the file that couldn't be found.
+ llvm::errs() << "Fatal compiler error occurred while parsing file!"
+ " (incorrect include paths?)\n";
+ return 1;
+ }
+
+ assert(!Contexts.empty());
+
+ if (OutputHeaders) {
+ // FIXME: Print contexts of all processing files instead of the first one.
+ writeToJson(llvm::outs(), Contexts.front());
+ return 0;
+ }
+
+ std::vector<tooling::Replacements> FixerReplacements;
+ for (const auto &Context : Contexts) {
+ StringRef FilePath = Context.getFilePath();
+ auto InsertStyle = format::getStyle("file", FilePath, Style);
+ if (!InsertStyle) {
+ llvm::errs() << llvm::toString(InsertStyle.takeError()) << "\n";
+ return 1;
+ }
+ auto Buffer = llvm::MemoryBuffer::getFile(FilePath);
+ if (!Buffer) {
+ errs() << "Couldn't open file: " + FilePath.str() + ": "
+ << Buffer.getError().message() + "\n";
+ return 1;
+ }
+
+ auto Replacements = clang::include_fixer::createIncludeFixerReplacements(
+ Buffer.get()->getBuffer(), Context, *InsertStyle);
+ if (!Replacements) {
+ errs() << "Failed to create replacement: "
+ << llvm::toString(Replacements.takeError()) << "\n";
+ return 1;
+ }
+ FixerReplacements.push_back(*Replacements);
+ }
+
+ if (!Quiet) {
+ for (const auto &Context : Contexts) {
+ if (!Context.getHeaderInfos().empty()) {
+ llvm::errs() << "Added #include "
+ << Context.getHeaderInfos().front().Header << " for "
+ << Context.getFilePath() << "\n";
+ }
+ }
+ }
+
+ if (STDINMode) {
+ assert(FixerReplacements.size() == 1);
+ auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(),
+ FixerReplacements.front());
+ if (!ChangedCode) {
+ llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
+ return 1;
+ }
+ llvm::outs() << *ChangedCode;
+ return 0;
+ }
+
+ // Set up a new source manager for applying the resulting replacements.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
+ DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts);
+ TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts);
+ SourceManager SM(Diagnostics, tool.getFiles());
+ Diagnostics.setClient(&DiagnosticPrinter, false);
+
+ // Write replacements to disk.
+ Rewriter Rewrites(SM, LangOptions());
+ for (const auto &Replacement : FixerReplacements) {
+ if (!tooling::applyAllReplacements(Replacement, Rewrites)) {
+ llvm::errs() << "Failed to apply replacements.\n";
+ return 1;
+ }
+ }
+ return Rewrites.overwriteChangedFiles();
+}
+
+} // namespace
+
+int main(int argc, const char **argv) {
+ return includeFixerMain(argc, argv);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/clang-include-fixer-test.el b/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/clang-include-fixer-test.el
new file mode 100644
index 0000000..d66d530
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/clang-include-fixer-test.el
@@ -0,0 +1,65 @@
+;;; clang-include-fixer-test.el --- unit tests for clang-include-fixer.el -*- lexical-binding: t; -*-
+
+;;; Commentary:
+
+;; Unit tests for clang-include-fixer.el.
+
+;;; Code:
+
+(require 'clang-include-fixer)
+
+(require 'cc-mode)
+(require 'ert)
+
+(ert-deftest clang-include-fixer--insert-line ()
+ "Unit test for `clang-include-fixer--insert-line'."
+ (with-temp-buffer
+ (insert "aa\nab\nac\nad\n")
+ (let ((from (current-buffer)))
+ (with-temp-buffer
+ (insert "aa\nac\nad\n")
+ (let ((to (current-buffer)))
+ (should (clang-include-fixer--insert-line from to))
+ (should (equal (buffer-string) "aa\nab\nac\nad\n")))))
+ (should (equal (buffer-string) "aa\nab\nac\nad\n"))))
+
+(ert-deftest clang-include-fixer--insert-line-diff-on-empty-line ()
+ "Unit test for `clang-include-fixer--insert-line'."
+ (with-temp-buffer
+ (insert "aa\nab\n\nac\nad\n")
+ (let ((from (current-buffer)))
+ (with-temp-buffer
+ (insert "aa\n\nac\nad\n")
+ (let ((to (current-buffer)))
+ (should (clang-include-fixer--insert-line from to))
+ (should (equal (buffer-string) "aa\nab\n\nac\nad\n")))))
+ (should (equal (buffer-string) "aa\nab\n\nac\nad\n"))))
+
+(ert-deftest clang-include-fixer--symbol-at-point ()
+ "Unit test for `clang-include-fixer--symbol-at-point'."
+ (with-temp-buffer
+ (insert "a+bbb::cc")
+ (c++-mode)
+ (goto-char (point-min))
+ (should (equal (clang-include-fixer--symbol-at-point) "a"))
+ (forward-char)
+ ;; Emacs treats the character immediately following a symbol as part of the
+ ;; symbol.
+ (should (equal (clang-include-fixer--symbol-at-point) "a"))
+ (forward-char)
+ (should (equal (clang-include-fixer--symbol-at-point) "bbb::cc"))
+ (goto-char (point-max))
+ (should (equal (clang-include-fixer--symbol-at-point) "bbb::cc"))))
+
+(ert-deftest clang-include-fixer--highlight ()
+ (with-temp-buffer
+ (insert "util::Status foo;\n")
+ (setq buffer-file-coding-system 'utf-8-unix)
+ (should (equal nil (clang-include-fixer--highlight
+ '((Range . ((Offset . 0) (Length . 0)))))))
+ (let ((overlay (clang-include-fixer--highlight
+ '((Range . ((Offset . 1) (Length . 12)))))))
+ (should (equal 2 (overlay-start overlay)))
+ (should (equal 14 (overlay-end overlay))))))
+
+;;; clang-include-fixer-test.el ends here
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/clang-include-fixer.el b/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/clang-include-fixer.el
new file mode 100644
index 0000000..c3a3bba
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/clang-include-fixer.el
@@ -0,0 +1,450 @@
+;;; clang-include-fixer.el --- Emacs integration of the clang include fixer -*- lexical-binding: t; -*-
+
+;; Keywords: tools, c
+;; Package-Requires: ((cl-lib "0.5") (json "1.2") (let-alist "1.0.4"))
+
+;;; Commentary:
+
+;; This package allows Emacs users to invoke the 'clang-include-fixer' within
+;; Emacs. 'clang-include-fixer' provides an automated way of adding #include
+;; directives for missing symbols in one translation unit, see
+;; <http://clang.llvm.org/extra/include-fixer.html>.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'json)
+(require 'let-alist)
+
+(defgroup clang-include-fixer nil
+ "Clang-based include fixer."
+ :group 'tools)
+
+(defvar clang-include-fixer-add-include-hook nil
+ "A hook that will be called for every added include.
+The first argument is the filename of the include, the second argument is
+non-nil if the include is a system-header.")
+
+(defcustom clang-include-fixer-executable
+ "clang-include-fixer"
+ "Location of the clang-include-fixer executable.
+
+A string containing the name or the full path of the executable."
+ :group 'clang-include-fixer
+ :type '(file :must-match t)
+ :risky t)
+
+(defcustom clang-include-fixer-input-format
+ 'yaml
+ "Input format for clang-include-fixer.
+This string is passed as -db argument to
+`clang-include-fixer-executable'."
+ :group 'clang-include-fixer
+ :type '(radio
+ (const :tag "Hard-coded mapping" :fixed)
+ (const :tag "YAML" yaml)
+ (symbol :tag "Other"))
+ :risky t)
+
+(defcustom clang-include-fixer-init-string
+ ""
+ "Database initialization string for clang-include-fixer.
+This string is passed as -input argument to
+`clang-include-fixer-executable'."
+ :group 'clang-include-fixer
+ :type 'string
+ :risky t)
+
+(defface clang-include-fixer-highlight '((t :background "green"))
+ "Used for highlighting the symbol for which a header file is being added.")
+
+;;;###autoload
+(defun clang-include-fixer ()
+ "Invoke the Include Fixer to insert missing C++ headers."
+ (interactive)
+ (message (concat "Calling the include fixer. "
+ "This might take some seconds. Please wait."))
+ (clang-include-fixer--start #'clang-include-fixer--add-header
+ "-output-headers"))
+
+;;;###autoload
+(defun clang-include-fixer-at-point ()
+ "Invoke the Clang include fixer for the symbol at point."
+ (interactive)
+ (let ((symbol (clang-include-fixer--symbol-at-point)))
+ (unless symbol
+ (user-error "No symbol at current location"))
+ (clang-include-fixer-from-symbol symbol)))
+
+;;;###autoload
+(defun clang-include-fixer-from-symbol (symbol)
+ "Invoke the Clang include fixer for the SYMBOL.
+When called interactively, prompts the user for a symbol."
+ (interactive
+ (list (read-string "Symbol: " (clang-include-fixer--symbol-at-point))))
+ (clang-include-fixer--start #'clang-include-fixer--add-header
+ (format "-query-symbol=%s" symbol)))
+
+(defun clang-include-fixer--start (callback &rest args)
+ "Asynchronously start clang-include-fixer with parameters ARGS.
+The current file name is passed after ARGS as last argument. If
+the call was successful the returned result is stored in a
+temporary buffer, and CALLBACK is called with the temporary
+buffer as only argument."
+ (unless buffer-file-name
+ (user-error "clang-include-fixer works only in buffers that visit a file"))
+ (let ((process (if (fboundp 'make-process)
+ ;; Prefer using ‘make-process’ if available, because
+ ;; ‘start-process’ doesn’t allow us to separate the
+ ;; standard error from the output.
+ (clang-include-fixer--make-process callback args)
+ (clang-include-fixer--start-process callback args))))
+ (save-restriction
+ (widen)
+ (process-send-region process (point-min) (point-max)))
+ (process-send-eof process))
+ nil)
+
+(defun clang-include-fixer--make-process (callback args)
+ "Start a new clang-incude-fixer process using `make-process'.
+CALLBACK is called after the process finishes successfully; it is
+called with a single argument, the buffer where standard output
+has been inserted. ARGS is a list of additional command line
+arguments. Return the new process object."
+ (let ((stdin (current-buffer))
+ (stdout (generate-new-buffer "*clang-include-fixer output*"))
+ (stderr (generate-new-buffer "*clang-include-fixer errors*")))
+ (make-process :name "clang-include-fixer"
+ :buffer stdout
+ :command (clang-include-fixer--command args)
+ :coding 'utf-8-unix
+ :noquery t
+ :connection-type 'pipe
+ :sentinel (clang-include-fixer--sentinel stdin stdout stderr
+ callback)
+ :stderr stderr)))
+
+(defun clang-include-fixer--start-process (callback args)
+ "Start a new clang-incude-fixer process using `start-process'.
+CALLBACK is called after the process finishes successfully; it is
+called with a single argument, the buffer where standard output
+has been inserted. ARGS is a list of additional command line
+arguments. Return the new process object."
+ (let* ((stdin (current-buffer))
+ (stdout (generate-new-buffer "*clang-include-fixer output*"))
+ (process-connection-type nil)
+ (process (apply #'start-process "clang-include-fixer" stdout
+ (clang-include-fixer--command args))))
+ (set-process-coding-system process 'utf-8-unix 'utf-8-unix)
+ (set-process-query-on-exit-flag process nil)
+ (set-process-sentinel process
+ (clang-include-fixer--sentinel stdin stdout nil
+ callback))
+ process))
+
+(defun clang-include-fixer--command (args)
+ "Return the clang-include-fixer command line.
+Returns a list; the first element is the binary to
+execute (`clang-include-fixer-executable'), and the remaining
+elements are the command line arguments. Adds proper arguments
+for `clang-include-fixer-input-format' and
+`clang-include-fixer-init-string'. Appends the current buffer's
+file name; prepends ARGS directly in front of it."
+ (cl-check-type args list)
+ `(,clang-include-fixer-executable
+ ,(format "-db=%s" clang-include-fixer-input-format)
+ ,(format "-input=%s" clang-include-fixer-init-string)
+ "-stdin"
+ ,@args
+ ,(buffer-file-name)))
+
+(defun clang-include-fixer--sentinel (stdin stdout stderr callback)
+ "Return a process sentinel for clang-include-fixer processes.
+STDIN, STDOUT, and STDERR are buffers for the standard streams;
+only STDERR may be nil. CALLBACK is called in the case of
+success; it is called with a single argument, STDOUT. On
+failure, a buffer containing the error output is displayed."
+ (cl-check-type stdin buffer-live)
+ (cl-check-type stdout buffer-live)
+ (cl-check-type stderr (or null buffer-live))
+ (cl-check-type callback function)
+ (lambda (process event)
+ (cl-check-type process process)
+ (cl-check-type event string)
+ (unwind-protect
+ (if (string-equal event "finished\n")
+ (progn
+ (when stderr (kill-buffer stderr))
+ (with-current-buffer stdin
+ (funcall callback stdout))
+ (kill-buffer stdout))
+ (when stderr (kill-buffer stdout))
+ (message "clang-include-fixer failed")
+ (with-current-buffer (or stderr stdout)
+ (insert "\nProcess " (process-name process)
+ ?\s event))
+ (display-buffer (or stderr stdout))))
+ nil))
+
+(defun clang-include-fixer--replace-buffer (stdout)
+ "Replace current buffer by content of STDOUT."
+ (cl-check-type stdout buffer-live)
+ (barf-if-buffer-read-only)
+ (cond ((fboundp 'replace-buffer-contents) (replace-buffer-contents stdout))
+ ((clang-include-fixer--insert-line stdout (current-buffer)))
+ (t (erase-buffer) (insert-buffer-substring stdout)))
+ (message "Fix applied")
+ nil)
+
+(defun clang-include-fixer--insert-line (from to)
+ "Insert a single missing line from the buffer FROM into TO.
+FROM and TO must be buffers. If the contents of FROM and TO are
+equal, do nothing and return non-nil. If FROM contains a single
+line missing from TO, insert that line into TO so that the buffer
+contents are equal and return non-nil. Otherwise, do nothing and
+return nil. Buffer restrictions are ignored."
+ (cl-check-type from buffer-live)
+ (cl-check-type to buffer-live)
+ (with-current-buffer from
+ (save-excursion
+ (save-restriction
+ (widen)
+ (with-current-buffer to
+ (save-excursion
+ (save-restriction
+ (widen)
+ ;; Search for the first buffer difference.
+ (let ((chars (abs (compare-buffer-substrings to nil nil from nil nil))))
+ (if (zerop chars)
+ ;; Buffer contents are equal, nothing to do.
+ t
+ (goto-char chars)
+ ;; We might have ended up in the middle of a line if the
+ ;; current line partially matches. In this case we would
+ ;; have to insert more than a line. Move to the beginning of
+ ;; the line to avoid this situation.
+ (beginning-of-line)
+ (with-current-buffer from
+ (goto-char chars)
+ (beginning-of-line)
+ (let ((from-begin (point))
+ (from-end (progn (forward-line) (point)))
+ (to-point (with-current-buffer to (point))))
+ ;; Search for another buffer difference after the line in
+ ;; question. If there is none, we can proceed.
+ (when (zerop (compare-buffer-substrings from from-end nil
+ to to-point nil))
+ (with-current-buffer to
+ (insert-buffer-substring from from-begin from-end))
+ t))))))))))))
+
+(defun clang-include-fixer--add-header (stdout)
+ "Analyse the result of include-fixer stored in STDOUT.
+Add a missing header if there is any. If there are multiple
+possible headers the user can select one of them to be included.
+Temporarily highlight the affected symbols. Asynchronously call
+clang-include-fixer to insert the selected header."
+ (cl-check-type stdout buffer-live)
+ (let ((context (clang-include-fixer--parse-json stdout)))
+ (let-alist context
+ (cond
+ ((null .QuerySymbolInfos)
+ (message "The file is fine, no need to add a header."))
+ ((null .HeaderInfos)
+ (message "Couldn't find header for '%s'"
+ (let-alist (car .QuerySymbolInfos) .RawIdentifier)))
+ (t
+ ;; Users may C-g in prompts, make sure the process sentinel
+ ;; behaves correctly.
+ (with-local-quit
+ ;; Replace the HeaderInfos list by a single header selected by
+ ;; the user.
+ (clang-include-fixer--select-header context)
+ ;; Call clang-include-fixer again to insert the selected header.
+ (clang-include-fixer--start
+ (let ((old-tick (buffer-chars-modified-tick)))
+ (lambda (stdout)
+ (when (/= old-tick (buffer-chars-modified-tick))
+ ;; Replacing the buffer now would undo the user’s changes.
+ (user-error (concat "The buffer has been changed "
+ "before the header could be inserted")))
+ (clang-include-fixer--replace-buffer stdout)
+ (let-alist context
+ (let-alist (car .HeaderInfos)
+ (with-local-quit
+ (run-hook-with-args 'clang-include-fixer-add-include-hook
+ (substring .Header 1 -1)
+ (string= (substring .Header 0 1) "<")))))))
+ (format "-insert-header=%s"
+ (clang-include-fixer--encode-json context))))))))
+ nil)
+
+(defun clang-include-fixer--select-header (context)
+ "Prompt the user for a header if necessary.
+CONTEXT must be a clang-include-fixer context object in
+association list format. If it contains more than one HeaderInfo
+element, prompt the user to select one of the headers. CONTEXT
+is modified to include only the selected element."
+ (cl-check-type context cons)
+ (let-alist context
+ (if (cdr .HeaderInfos)
+ (clang-include-fixer--prompt-for-header context)
+ (message "Only one include is missing: %s"
+ (let-alist (car .HeaderInfos) .Header))))
+ nil)
+
+(defvar clang-include-fixer--history nil
+ "History for `clang-include-fixer--prompt-for-header'.")
+
+(defun clang-include-fixer--prompt-for-header (context)
+ "Prompt the user for a single header.
+The choices are taken from the HeaderInfo elements in CONTEXT.
+They are replaced by the single element selected by the user."
+ (let-alist context
+ (let ((symbol (clang-include-fixer--symbol-name .QuerySymbolInfos))
+ ;; Add temporary highlighting so that the user knows which
+ ;; symbols the current session is about.
+ (overlays (remove nil
+ (mapcar #'clang-include-fixer--highlight .QuerySymbolInfos))))
+ (unwind-protect
+ (save-excursion
+ ;; While prompting, go to the closest overlay so that the user sees
+ ;; some context.
+ (when overlays
+ (goto-char (clang-include-fixer--closest-overlay overlays)))
+ (cl-flet ((header (info) (let-alist info .Header)))
+ ;; The header-infos is already sorted by include-fixer.
+ (let* ((headers (mapcar #'header .HeaderInfos))
+ (header (completing-read
+ (clang-include-fixer--format-message
+ "Select include for '%s': " symbol)
+ headers nil :require-match nil
+ 'clang-include-fixer--history
+ ;; Specify a default to prevent the behavior
+ ;; described in
+ ;; https://github.com/DarwinAwardWinner/ido-completing-read-plus#why-does-ret-sometimes-not-select-the-first-completion-on-the-list--why-is-there-an-empty-entry-at-the-beginning-of-the-completion-list--what-happened-to-old-style-default-selection.
+ (car headers)))
+ (info (cl-find header .HeaderInfos :key #'header :test #'string=)))
+ (unless info (user-error "No header selected"))
+ (setcar .HeaderInfos info)
+ (setcdr .HeaderInfos nil))))
+ (mapc #'delete-overlay overlays)))))
+
+(defun clang-include-fixer--symbol-name (symbol-infos)
+ "Return the unique symbol name in SYMBOL-INFOS.
+Raise a signal if the symbol name is not unique."
+ (let ((symbols (delete-dups (mapcar (lambda (info)
+ (let-alist info .RawIdentifier))
+ symbol-infos))))
+ (when (cdr symbols)
+ (error "Multiple symbols %s returned" symbols))
+ (car symbols)))
+
+(defun clang-include-fixer--highlight (symbol-info)
+ "Add an overlay to highlight SYMBOL-INFO, if it points to a non-empty range.
+Return the overlay object, or nil."
+ (let-alist symbol-info
+ (unless (zerop .Range.Length)
+ (let ((overlay (make-overlay
+ (clang-include-fixer--filepos-to-bufferpos
+ .Range.Offset 'approximate)
+ (clang-include-fixer--filepos-to-bufferpos
+ (+ .Range.Offset .Range.Length) 'approximate))))
+ (overlay-put overlay 'face 'clang-include-fixer-highlight)
+ overlay))))
+
+(defun clang-include-fixer--closest-overlay (overlays)
+ "Return the start of the overlay in OVERLAYS that is closest to point."
+ (cl-check-type overlays cons)
+ (let ((point (point))
+ acc)
+ (dolist (overlay overlays acc)
+ (let ((start (overlay-start overlay)))
+ (when (or (null acc) (< (abs (- point start)) (abs (- point acc))))
+ (setq acc start))))))
+
+(defun clang-include-fixer--parse-json (buffer)
+ "Parse a JSON response from clang-include-fixer in BUFFER.
+Return the JSON object as an association list."
+ (with-current-buffer buffer
+ (save-excursion
+ (goto-char (point-min))
+ (let ((json-object-type 'alist)
+ (json-array-type 'list)
+ (json-key-type 'symbol)
+ (json-false :json-false)
+ (json-null nil)
+ (json-pre-element-read-function nil)
+ (json-post-element-read-function nil))
+ (json-read)))))
+
+(defun clang-include-fixer--encode-json (object)
+ "Return the JSON representation of OBJECT as a string."
+ (let ((json-encoding-separator ",")
+ (json-encoding-default-indentation " ")
+ (json-encoding-pretty-print nil)
+ (json-encoding-lisp-style-closings nil)
+ (json-encoding-object-sort-predicate nil))
+ (json-encode object)))
+
+(defun clang-include-fixer--symbol-at-point ()
+ "Return the qualified symbol at point.
+If there is no symbol at point, return nil."
+ ;; Let ‘bounds-of-thing-at-point’ to do the hard work and deal with edge
+ ;; cases.
+ (let ((bounds (bounds-of-thing-at-point 'symbol)))
+ (when bounds
+ (let ((beg (car bounds))
+ (end (cdr bounds)))
+ (save-excursion
+ ;; Extend the symbol range to the left. Skip over namespace
+ ;; delimiters and parent namespace names.
+ (goto-char beg)
+ (while (and (clang-include-fixer--skip-double-colon-backward)
+ (skip-syntax-backward "w_")))
+ ;; Skip over one more namespace delimiter, for absolute names.
+ (clang-include-fixer--skip-double-colon-backward)
+ (setq beg (point))
+ ;; Extend the symbol range to the right. Skip over namespace
+ ;; delimiters and child namespace names.
+ (goto-char end)
+ (while (and (clang-include-fixer--skip-double-colon-forward)
+ (skip-syntax-forward "w_")))
+ (setq end (point)))
+ (buffer-substring-no-properties beg end)))))
+
+(defun clang-include-fixer--skip-double-colon-forward ()
+ "Skip a double colon.
+When the next two characters are '::', skip them and return
+non-nil. Otherwise return nil."
+ (let ((end (+ (point) 2)))
+ (when (and (<= end (point-max))
+ (string-equal (buffer-substring-no-properties (point) end) "::"))
+ (goto-char end)
+ t)))
+
+(defun clang-include-fixer--skip-double-colon-backward ()
+ "Skip a double colon.
+When the previous two characters are '::', skip them and return
+non-nil. Otherwise return nil."
+ (let ((beg (- (point) 2)))
+ (when (and (>= beg (point-min))
+ (string-equal (buffer-substring-no-properties beg (point)) "::"))
+ (goto-char beg)
+ t)))
+
+;; ‘filepos-to-bufferpos’ is new in Emacs 25.1. Provide a fallback for older
+;; versions.
+(defalias 'clang-include-fixer--filepos-to-bufferpos
+ (if (fboundp 'filepos-to-bufferpos)
+ 'filepos-to-bufferpos
+ (lambda (byte &optional _quality _coding-system)
+ (byte-to-position (1+ byte)))))
+
+;; ‘format-message’ is new in Emacs 25.1. Provide a fallback for older
+;; versions.
+(defalias 'clang-include-fixer--format-message
+ (if (fboundp 'format-message) 'format-message 'format))
+
+(provide 'clang-include-fixer)
+;;; clang-include-fixer.el ends here
diff --git a/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/clang-include-fixer.py b/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/clang-include-fixer.py
new file mode 100644
index 0000000..0e9306d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/include-fixer/tool/clang-include-fixer.py
@@ -0,0 +1,208 @@
+# This file is a minimal clang-include-fixer vim-integration. To install:
+# - Change 'binary' if clang-include-fixer is not on the path (see below).
+# - Add to your .vimrc:
+#
+# noremap <leader>cf :pyf path/to/llvm/source/tools/clang/tools/extra/include-fixer/tool/clang-include-fixer.py<cr>
+#
+# This enables clang-include-fixer for NORMAL and VISUAL mode. Change "<leader>cf"
+# to another binding if you need clang-include-fixer on a different key.
+#
+# To set up clang-include-fixer, see http://clang.llvm.org/extra/include-fixer.html
+#
+# With this integration you can press the bound key and clang-include-fixer will
+# be run on the current buffer.
+#
+# It operates on the current, potentially unsaved buffer and does not create
+# or save any files. To revert a fix, just undo.
+
+import argparse
+import difflib
+import json
+import re
+import subprocess
+import vim
+
+# set g:clang_include_fixer_path to the path to clang-include-fixer if it is not
+# on the path.
+# Change this to the full path if clang-include-fixer is not on the path.
+binary = 'clang-include-fixer'
+if vim.eval('exists("g:clang_include_fixer_path")') == "1":
+ binary = vim.eval('g:clang_include_fixer_path')
+
+maximum_suggested_headers = 3
+if vim.eval('exists("g:clang_include_fixer_maximum_suggested_headers")') == "1":
+ maximum_suggested_headers = max(
+ 1,
+ vim.eval('g:clang_include_fixer_maximum_suggested_headers'))
+
+increment_num = 5
+if vim.eval('exists("g:clang_include_fixer_increment_num")') == "1":
+ increment_num = max(
+ 1,
+ vim.eval('g:clang_include_fixer_increment_num'))
+
+jump_to_include = False
+if vim.eval('exists("g:clang_include_fixer_jump_to_include")') == "1":
+ jump_to_include = vim.eval('g:clang_include_fixer_jump_to_include') != "0"
+
+query_mode = False
+if vim.eval('exists("g:clang_include_fixer_query_mode")') == "1":
+ query_mode = vim.eval('g:clang_include_fixer_query_mode') != "0"
+
+
+def GetUserSelection(message, headers, maximum_suggested_headers):
+ eval_message = message + '\n'
+ for idx, header in enumerate(headers[0:maximum_suggested_headers]):
+ eval_message += "({0}). {1}\n".format(idx + 1, header)
+ eval_message += "Enter (q) to quit;"
+ if maximum_suggested_headers < len(headers):
+ eval_message += " (m) to show {0} more candidates.".format(
+ min(increment_num, len(headers) - maximum_suggested_headers))
+
+ eval_message += "\nSelect (default 1): "
+ res = vim.eval("input('{0}')".format(eval_message))
+ if res == '':
+ # choose the top ranked header by default
+ idx = 1
+ elif res == 'q':
+ raise Exception(' Insertion cancelled...')
+ elif res == 'm':
+ return GetUserSelection(message,
+ headers, maximum_suggested_headers + increment_num)
+ else:
+ try:
+ idx = int(res)
+ if idx <= 0 or idx > len(headers):
+ raise Exception()
+ except Exception:
+ # Show a new prompt on invalid option instead of aborting so that users
+ # don't need to wait for another include-fixer run.
+ print >> sys.stderr, "Invalid option:", res
+ return GetUserSelection(message, headers, maximum_suggested_headers)
+ return headers[idx - 1]
+
+
+def execute(command, text):
+ p = subprocess.Popen(command,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+ return p.communicate(input=text)
+
+
+def InsertHeaderToVimBuffer(header, text):
+ command = [binary, "-stdin", "-insert-header=" + json.dumps(header),
+ vim.current.buffer.name]
+ stdout, stderr = execute(command, text)
+ if stderr:
+ raise Exception(stderr)
+ if stdout:
+ lines = stdout.splitlines()
+ sequence = difflib.SequenceMatcher(None, vim.current.buffer, lines)
+ line_num = None
+ for op in reversed(sequence.get_opcodes()):
+ if op[0] != 'equal':
+ vim.current.buffer[op[1]:op[2]] = lines[op[3]:op[4]]
+ if op[0] == 'insert':
+ # line_num in vim is 1-based.
+ line_num = op[1] + 1
+
+ if jump_to_include and line_num:
+ vim.current.window.cursor = (line_num, 0)
+
+
+# The vim internal implementation (expand("cword"/"cWORD")) doesn't support
+# our use case very well, we re-implement our own one.
+def get_symbol_under_cursor():
+ line = vim.eval("line(\".\")")
+ # column number in vim is 1-based.
+ col = int(vim.eval("col(\".\")")) - 1
+ line_text = vim.eval("getline({0})".format(line))
+ if len(line_text) == 0: return ""
+ symbol_pos_begin = col
+ p = re.compile('[a-zA-Z0-9:_]')
+ while symbol_pos_begin >= 0 and p.match(line_text[symbol_pos_begin]):
+ symbol_pos_begin -= 1
+
+ symbol_pos_end = col
+ while symbol_pos_end < len(line_text) and p.match(line_text[symbol_pos_end]):
+ symbol_pos_end += 1
+ return line_text[symbol_pos_begin+1:symbol_pos_end]
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description='Vim integration for clang-include-fixer')
+ parser.add_argument('-db', default='yaml',
+ help='clang-include-fixer input format.')
+ parser.add_argument('-input', default='',
+ help='String to initialize the database.')
+ # Don't throw exception when parsing unknown arguements to make the script
+ # work in neovim.
+ # Neovim (at least v0.2.1) somehow mangles the sys.argv in a weird way: it
+ # will pass additional arguments (e.g. "-c script_host.py") to sys.argv,
+ # which makes the script fail.
+ args, _ = parser.parse_known_args()
+
+ # Get the current text.
+ buf = vim.current.buffer
+ text = '\n'.join(buf)
+
+ if query_mode:
+ symbol = get_symbol_under_cursor()
+ if len(symbol) == 0:
+ print "Skip querying empty symbol."
+ return
+ command = [binary, "-stdin", "-query-symbol="+get_symbol_under_cursor(),
+ "-db=" + args.db, "-input=" + args.input,
+ vim.current.buffer.name]
+ else:
+ # Run command to get all headers.
+ command = [binary, "-stdin", "-output-headers", "-db=" + args.db,
+ "-input=" + args.input, vim.current.buffer.name]
+ stdout, stderr = execute(command, text)
+ if stderr:
+ print >> sys.stderr, "Error while running clang-include-fixer: " + stderr
+ return
+
+ include_fixer_context = json.loads(stdout)
+ query_symbol_infos = include_fixer_context["QuerySymbolInfos"]
+ if not query_symbol_infos:
+ print "The file is fine, no need to add a header."
+ return
+ symbol = query_symbol_infos[0]["RawIdentifier"]
+ # The header_infos is already sorted by include-fixer.
+ header_infos = include_fixer_context["HeaderInfos"]
+ # Deduplicate headers while keeping the order, so that the same header would
+ # not be suggested twice.
+ unique_headers = []
+ seen = set()
+ for header_info in header_infos:
+ header = header_info["Header"]
+ if header not in seen:
+ seen.add(header)
+ unique_headers.append(header)
+
+ if not unique_headers:
+ print "Couldn't find a header for {0}.".format(symbol)
+ return
+
+ try:
+ selected = unique_headers[0]
+ inserted_header_infos = header_infos
+ if len(unique_headers) > 1:
+ selected = GetUserSelection(
+ "choose a header file for {0}.".format(symbol),
+ unique_headers, maximum_suggested_headers)
+ inserted_header_infos = [
+ header for header in header_infos if header["Header"] == selected]
+ include_fixer_context["HeaderInfos"] = inserted_header_infos
+
+ InsertHeaderToVimBuffer(include_fixer_context, text)
+ print "Added #include {0} for {1}.".format(selected, symbol)
+ except Exception as error:
+ print >> sys.stderr, error.message
+ return
+
+
+if __name__ == '__main__':
+ main()
diff --git a/src/third_party/llvm-project/clang-tools-extra/modularize/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/modularize/CMakeLists.txt
new file mode 100644
index 0000000..4481ce0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/modularize/CMakeLists.txt
@@ -0,0 +1,26 @@
+set(LLVM_LINK_COMPONENTS
+ Option
+ Support
+ )
+
+add_clang_tool(modularize
+ Modularize.cpp
+ ModuleAssistant.cpp
+ ModularizeUtilities.cpp
+ CoverageChecker.cpp
+ PreprocessorTracker.cpp
+ )
+
+target_link_libraries(modularize
+ PRIVATE
+ clangAST
+ clangBasic
+ clangDriver
+ clangFrontend
+ clangLex
+ clangTooling
+ )
+
+install(TARGETS modularize
+ RUNTIME DESTINATION bin
+ COMPONENT clang-extras)
diff --git a/src/third_party/llvm-project/clang-tools-extra/modularize/CoverageChecker.cpp b/src/third_party/llvm-project/clang-tools-extra/modularize/CoverageChecker.cpp
new file mode 100644
index 0000000..4e2a23c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/modularize/CoverageChecker.cpp
@@ -0,0 +1,423 @@
+//===--- extra/module-map-checker/CoverageChecker.cpp -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a class that validates a module map by checking that
+// all headers in the corresponding directories are accounted for.
+//
+// This class uses a previously loaded module map object.
+// Starting at the module map file directory, or just the include
+// paths, if specified, it will collect the names of all the files it
+// considers headers (no extension, .h, or .inc--if you need more, modify the
+// ModularizeUtilities::isHeader function).
+// It then compares the headers against those referenced
+// in the module map, either explicitly named, or implicitly named via an
+// umbrella directory or umbrella file, as parsed by the ModuleMap object.
+// If headers are found which are not referenced or covered by an umbrella
+// directory or file, warning messages will be produced, and the doChecks
+// function will return an error code of 1. Other errors result in an error
+// code of 2. If no problems are found, an error code of 0 is returned.
+//
+// Note that in the case of umbrella headers, this tool invokes the compiler
+// to preprocess the file, and uses a callback to collect the header files
+// included by the umbrella header or any of its nested includes. If any
+// front end options are needed for these compiler invocations, these are
+// to be passed in via the CommandLine parameter.
+//
+// Warning message have the form:
+//
+// warning: module.modulemap does not account for file: Level3A.h
+//
+// Note that for the case of the module map referencing a file that does
+// not exist, the module map parser in Clang will (at the time of this
+// writing) display an error message.
+//
+// Potential problems with this program:
+//
+// 1. Might need a better header matching mechanism, or extensions to the
+// canonical file format used.
+//
+// 2. It might need to support additional header file extensions.
+//
+// Future directions:
+//
+// 1. Add an option to fix the problems found, writing a new module map.
+// Include an extra option to add unaccounted-for headers as excluded.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ModularizeUtilities.h"
+#include "clang/AST/ASTConsumer.h"
+#include "CoverageChecker.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Driver/Options.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace Modularize;
+using namespace clang;
+using namespace clang::driver;
+using namespace clang::driver::options;
+using namespace clang::tooling;
+namespace cl = llvm::cl;
+namespace sys = llvm::sys;
+
+// Preprocessor callbacks.
+// We basically just collect include files.
+class CoverageCheckerCallbacks : public PPCallbacks {
+public:
+ CoverageCheckerCallbacks(CoverageChecker &Checker) : Checker(Checker) {}
+ ~CoverageCheckerCallbacks() override {}
+
+ // Include directive callback.
+ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange, const FileEntry *File,
+ StringRef SearchPath, StringRef RelativePath,
+ const Module *Imported,
+ SrcMgr::CharacteristicKind FileType) override {
+ Checker.collectUmbrellaHeaderHeader(File->getName());
+ }
+
+private:
+ CoverageChecker &Checker;
+};
+
+// Frontend action stuff:
+
+// Consumer is responsible for setting up the callbacks.
+class CoverageCheckerConsumer : public ASTConsumer {
+public:
+ CoverageCheckerConsumer(CoverageChecker &Checker, Preprocessor &PP) {
+ // PP takes ownership.
+ PP.addPPCallbacks(llvm::make_unique<CoverageCheckerCallbacks>(Checker));
+ }
+};
+
+class CoverageCheckerAction : public SyntaxOnlyAction {
+public:
+ CoverageCheckerAction(CoverageChecker &Checker) : Checker(Checker) {}
+
+protected:
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) override {
+ return llvm::make_unique<CoverageCheckerConsumer>(Checker,
+ CI.getPreprocessor());
+ }
+
+private:
+ CoverageChecker &Checker;
+};
+
+class CoverageCheckerFrontendActionFactory : public FrontendActionFactory {
+public:
+ CoverageCheckerFrontendActionFactory(CoverageChecker &Checker)
+ : Checker(Checker) {}
+
+ CoverageCheckerAction *create() override {
+ return new CoverageCheckerAction(Checker);
+ }
+
+private:
+ CoverageChecker &Checker;
+};
+
+// CoverageChecker class implementation.
+
+// Constructor.
+CoverageChecker::CoverageChecker(StringRef ModuleMapPath,
+ std::vector<std::string> &IncludePaths,
+ ArrayRef<std::string> CommandLine,
+ clang::ModuleMap *ModuleMap)
+ : ModuleMapPath(ModuleMapPath), IncludePaths(IncludePaths),
+ CommandLine(CommandLine),
+ ModMap(ModuleMap) {}
+
+// Create instance of CoverageChecker, to simplify setting up
+// subordinate objects.
+std::unique_ptr<CoverageChecker> CoverageChecker::createCoverageChecker(
+ StringRef ModuleMapPath, std::vector<std::string> &IncludePaths,
+ ArrayRef<std::string> CommandLine, clang::ModuleMap *ModuleMap) {
+
+ return llvm::make_unique<CoverageChecker>(ModuleMapPath, IncludePaths,
+ CommandLine, ModuleMap);
+}
+
+// Do checks.
+// Starting from the directory of the module.modulemap file,
+// Find all header files, optionally looking only at files
+// covered by the include path options, and compare against
+// the headers referenced by the module.modulemap file.
+// Display warnings for unaccounted-for header files.
+// Returns error_code of 0 if there were no errors or warnings, 1 if there
+// were warnings, 2 if any other problem, such as if a bad
+// module map path argument was specified.
+std::error_code CoverageChecker::doChecks() {
+ std::error_code returnValue;
+
+ // Collect the headers referenced in the modules.
+ collectModuleHeaders();
+
+ // Collect the file system headers.
+ if (!collectFileSystemHeaders())
+ return std::error_code(2, std::generic_category());
+
+ // Do the checks. These save the problematic file names.
+ findUnaccountedForHeaders();
+
+ // Check for warnings.
+ if (!UnaccountedForHeaders.empty())
+ returnValue = std::error_code(1, std::generic_category());
+
+ return returnValue;
+}
+
+// The following functions are called by doChecks.
+
+// Collect module headers.
+// Walks the modules and collects referenced headers into
+// ModuleMapHeadersSet.
+void CoverageChecker::collectModuleHeaders() {
+ for (ModuleMap::module_iterator I = ModMap->module_begin(),
+ E = ModMap->module_end();
+ I != E; ++I) {
+ collectModuleHeaders(*I->second);
+ }
+}
+
+// Collect referenced headers from one module.
+// Collects the headers referenced in the given module into
+// ModuleMapHeadersSet.
+// FIXME: Doesn't collect files from umbrella header.
+bool CoverageChecker::collectModuleHeaders(const Module &Mod) {
+
+ if (const FileEntry *UmbrellaHeader = Mod.getUmbrellaHeader().Entry) {
+ // Collect umbrella header.
+ ModuleMapHeadersSet.insert(ModularizeUtilities::getCanonicalPath(
+ UmbrellaHeader->getName()));
+ // Preprocess umbrella header and collect the headers it references.
+ if (!collectUmbrellaHeaderHeaders(UmbrellaHeader->getName()))
+ return false;
+ }
+ else if (const DirectoryEntry *UmbrellaDir = Mod.getUmbrellaDir().Entry) {
+ // Collect headers in umbrella directory.
+ if (!collectUmbrellaHeaders(UmbrellaDir->getName()))
+ return false;
+ }
+
+ for (auto &HeaderKind : Mod.Headers)
+ for (auto &Header : HeaderKind)
+ ModuleMapHeadersSet.insert(ModularizeUtilities::getCanonicalPath(
+ Header.Entry->getName()));
+
+ for (auto MI = Mod.submodule_begin(), MIEnd = Mod.submodule_end();
+ MI != MIEnd; ++MI)
+ collectModuleHeaders(**MI);
+
+ return true;
+}
+
+// Collect headers from an umbrella directory.
+bool CoverageChecker::collectUmbrellaHeaders(StringRef UmbrellaDirName) {
+ // Initialize directory name.
+ SmallString<256> Directory(ModuleMapDirectory);
+ if (UmbrellaDirName.size())
+ sys::path::append(Directory, UmbrellaDirName);
+ if (Directory.size() == 0)
+ Directory = ".";
+ // Walk the directory.
+ std::error_code EC;
+ for (sys::fs::directory_iterator I(Directory.str(), EC), E; I != E;
+ I.increment(EC)) {
+ if (EC)
+ return false;
+ std::string File(I->path());
+ llvm::ErrorOr<sys::fs::basic_file_status> Status = I->status();
+ if (!Status)
+ return false;
+ sys::fs::file_type Type = Status->type();
+ // If the file is a directory, ignore the name and recurse.
+ if (Type == sys::fs::file_type::directory_file) {
+ if (!collectUmbrellaHeaders(File))
+ return false;
+ continue;
+ }
+ // If the file does not have a common header extension, ignore it.
+ if (!ModularizeUtilities::isHeader(File))
+ continue;
+ // Save header name.
+ ModuleMapHeadersSet.insert(ModularizeUtilities::getCanonicalPath(File));
+ }
+ return true;
+}
+
+// Collect headers rferenced from an umbrella file.
+bool
+CoverageChecker::collectUmbrellaHeaderHeaders(StringRef UmbrellaHeaderName) {
+
+ SmallString<256> PathBuf(ModuleMapDirectory);
+
+ // If directory is empty, it's the current directory.
+ if (ModuleMapDirectory.length() == 0)
+ sys::fs::current_path(PathBuf);
+
+ // Create the compilation database.
+ std::unique_ptr<CompilationDatabase> Compilations;
+ Compilations.reset(new FixedCompilationDatabase(Twine(PathBuf), CommandLine));
+
+ std::vector<std::string> HeaderPath;
+ HeaderPath.push_back(UmbrellaHeaderName);
+
+ // Create the tool and run the compilation.
+ ClangTool Tool(*Compilations, HeaderPath);
+ int HadErrors = Tool.run(new CoverageCheckerFrontendActionFactory(*this));
+
+ // If we had errors, exit early.
+ return !HadErrors;
+}
+
+// Called from CoverageCheckerCallbacks to track a header included
+// from an umbrella header.
+void CoverageChecker::collectUmbrellaHeaderHeader(StringRef HeaderName) {
+
+ SmallString<256> PathBuf(ModuleMapDirectory);
+ // If directory is empty, it's the current directory.
+ if (ModuleMapDirectory.length() == 0)
+ sys::fs::current_path(PathBuf);
+ // HeaderName will have an absolute path, so if it's the module map
+ // directory, we remove it, also skipping trailing separator.
+ if (HeaderName.startswith(PathBuf))
+ HeaderName = HeaderName.substr(PathBuf.size() + 1);
+ // Save header name.
+ ModuleMapHeadersSet.insert(ModularizeUtilities::getCanonicalPath(HeaderName));
+}
+
+// Collect file system header files.
+// This function scans the file system for header files,
+// starting at the directory of the module.modulemap file,
+// optionally filtering out all but the files covered by
+// the include path options.
+// Returns true if no errors.
+bool CoverageChecker::collectFileSystemHeaders() {
+
+ // Get directory containing the module.modulemap file.
+ // Might be relative to current directory, absolute, or empty.
+ ModuleMapDirectory = ModularizeUtilities::getDirectoryFromPath(ModuleMapPath);
+
+ // If no include paths specified, we do the whole tree starting
+ // at the module.modulemap directory.
+ if (IncludePaths.size() == 0) {
+ if (!collectFileSystemHeaders(StringRef("")))
+ return false;
+ }
+ else {
+ // Otherwise we only look at the sub-trees specified by the
+ // include paths.
+ for (std::vector<std::string>::const_iterator I = IncludePaths.begin(),
+ E = IncludePaths.end();
+ I != E; ++I) {
+ if (!collectFileSystemHeaders(*I))
+ return false;
+ }
+ }
+
+ // Sort it, because different file systems might order the file differently.
+ std::sort(FileSystemHeaders.begin(), FileSystemHeaders.end());
+
+ return true;
+}
+
+// Collect file system header files from the given path.
+// This function scans the file system for header files,
+// starting at the given directory, which is assumed to be
+// relative to the directory of the module.modulemap file.
+// \returns True if no errors.
+bool CoverageChecker::collectFileSystemHeaders(StringRef IncludePath) {
+
+ // Initialize directory name.
+ SmallString<256> Directory(ModuleMapDirectory);
+ if (IncludePath.size())
+ sys::path::append(Directory, IncludePath);
+ if (Directory.size() == 0)
+ Directory = ".";
+ if (IncludePath.startswith("/") || IncludePath.startswith("\\") ||
+ ((IncludePath.size() >= 2) && (IncludePath[1] == ':'))) {
+ llvm::errs() << "error: Include path \"" << IncludePath
+ << "\" is not relative to the module map file.\n";
+ return false;
+ }
+
+ // Recursively walk the directory tree.
+ std::error_code EC;
+ int Count = 0;
+ for (sys::fs::recursive_directory_iterator I(Directory.str(), EC), E; I != E;
+ I.increment(EC)) {
+ if (EC)
+ return false;
+ //std::string file(I->path());
+ StringRef file(I->path());
+ llvm::ErrorOr<sys::fs::basic_file_status> Status = I->status();
+ if (!Status)
+ return false;
+ sys::fs::file_type type = Status->type();
+ // If the file is a directory, ignore the name (but still recurses).
+ if (type == sys::fs::file_type::directory_file)
+ continue;
+ // Assume directories or files starting with '.' are private and not to
+ // be considered.
+ if ((file.find("\\.") != StringRef::npos) ||
+ (file.find("/.") != StringRef::npos))
+ continue;
+ // If the file does not have a common header extension, ignore it.
+ if (!ModularizeUtilities::isHeader(file))
+ continue;
+ // Save header name.
+ FileSystemHeaders.push_back(ModularizeUtilities::getCanonicalPath(file));
+ Count++;
+ }
+ if (Count == 0) {
+ llvm::errs() << "warning: No headers found in include path: \""
+ << IncludePath << "\"\n";
+ }
+ return true;
+}
+
+// Find headers unaccounted-for in module map.
+// This function compares the list of collected header files
+// against those referenced in the module map. Display
+// warnings for unaccounted-for header files.
+// Save unaccounted-for file list for possible.
+// fixing action.
+// FIXME: There probably needs to be some canonalization
+// of file names so that header path can be correctly
+// matched. Also, a map could be used for the headers
+// referenced in the module, but
+void CoverageChecker::findUnaccountedForHeaders() {
+ // Walk over file system headers.
+ for (std::vector<std::string>::const_iterator I = FileSystemHeaders.begin(),
+ E = FileSystemHeaders.end();
+ I != E; ++I) {
+ // Look for header in module map.
+ if (ModuleMapHeadersSet.insert(*I).second) {
+ UnaccountedForHeaders.push_back(*I);
+ llvm::errs() << "warning: " << ModuleMapPath
+ << " does not account for file: " << *I << "\n";
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/modularize/CoverageChecker.h b/src/third_party/llvm-project/clang-tools-extra/modularize/CoverageChecker.h
new file mode 100644
index 0000000..f6c8367
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/modularize/CoverageChecker.h
@@ -0,0 +1,164 @@
+//===-- CoverageChecker.h - Module map coverage checker -*- C++ -*-------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Definitions for CoverageChecker.
+///
+//===--------------------------------------------------------------------===//
+
+#ifndef COVERAGECHECKER_H
+#define COVERAGECHECKER_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/ModuleMap.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Host.h"
+#include <string>
+#include <vector>
+
+namespace Modularize {
+
+/// Module map checker class.
+/// This is the heart of the checker.
+/// The doChecks function does the main work.
+/// The data members store the options and internally collected data.
+class CoverageChecker {
+ // Checker arguments.
+
+ /// The module.modulemap file path. Can be relative or absolute.
+ llvm::StringRef ModuleMapPath;
+ /// The include paths to check for files.
+ /// (Note that other directories above these paths are ignored.
+ /// To expect all files to be accounted for from the module.modulemap
+ /// file directory on down, leave this empty.)
+ std::vector<std::string> IncludePaths;
+ /// The remaining arguments, to be passed to the front end.
+ llvm::ArrayRef<std::string> CommandLine;
+ /// The module map.
+ clang::ModuleMap *ModMap;
+
+ // Internal data.
+
+ /// Directory containing the module map.
+ /// Might be relative to the current directory, or absolute.
+ std::string ModuleMapDirectory;
+ /// Set of all the headers found in the module map.
+ llvm::StringSet<llvm::MallocAllocator> ModuleMapHeadersSet;
+ /// All the headers found in the file system starting at the
+ /// module map, or the union of those from the include paths.
+ std::vector<std::string> FileSystemHeaders;
+ /// Headers found in file system, but not in module map.
+ std::vector<std::string> UnaccountedForHeaders;
+
+public:
+ /// Constructor.
+ /// You can use the static createCoverageChecker to create an instance
+ /// of this object.
+ /// \param ModuleMapPath The module.modulemap file path.
+ /// Can be relative or absolute.
+ /// \param IncludePaths The include paths to check for files.
+ /// (Note that other directories above these paths are ignored.
+ /// To expect all files to be accounted for from the module.modulemap
+ /// file directory on down, leave this empty.)
+ /// \param CommandLine Compile command line arguments.
+ /// \param ModuleMap The module map to check.
+ CoverageChecker(llvm::StringRef ModuleMapPath,
+ std::vector<std::string> &IncludePaths,
+ llvm::ArrayRef<std::string> CommandLine,
+ clang::ModuleMap *ModuleMap);
+
+ /// Create instance of CoverageChecker.
+ /// \param ModuleMapPath The module.modulemap file path.
+ /// Can be relative or absolute.
+ /// \param IncludePaths The include paths to check for files.
+ /// (Note that other directories above these paths are ignored.
+ /// To expect all files to be accounted for from the module.modulemap
+ /// file directory on down, leave this empty.)
+ /// \param CommandLine Compile command line arguments.
+ /// \param ModuleMap The module map to check.
+ /// \returns Initialized CoverageChecker object.
+ static std::unique_ptr<CoverageChecker> createCoverageChecker(
+ llvm::StringRef ModuleMapPath, std::vector<std::string> &IncludePaths,
+ llvm::ArrayRef<std::string> CommandLine, clang::ModuleMap *ModuleMap);
+
+ /// Do checks.
+ /// Starting from the directory of the module.modulemap file,
+ /// Find all header files, optionally looking only at files
+ /// covered by the include path options, and compare against
+ /// the headers referenced by the module.modulemap file.
+ /// Display warnings for unaccounted-for header files.
+ /// \returns 0 if there were no errors or warnings, 1 if there
+ /// were warnings, 2 if any other problem, such as a bad
+ /// module map path argument was specified.
+ std::error_code doChecks();
+
+ // The following functions are called by doChecks.
+
+ /// Collect module headers.
+ /// Walks the modules and collects referenced headers into
+ /// ModuleMapHeadersSet.
+ void collectModuleHeaders();
+
+ /// Collect referenced headers from one module.
+ /// Collects the headers referenced in the given module into
+ /// ModuleMapHeadersSet.
+ /// \param Mod The module reference.
+ /// \return True if no errors.
+ bool collectModuleHeaders(const clang::Module &Mod);
+
+ /// Collect headers from an umbrella directory.
+ /// \param UmbrellaDirName The umbrella directory name.
+ /// \return True if no errors.
+ bool collectUmbrellaHeaders(llvm::StringRef UmbrellaDirName);
+
+ /// Collect headers rferenced from an umbrella file.
+ /// \param UmbrellaHeaderName The umbrella file path.
+ /// \return True if no errors.
+ bool collectUmbrellaHeaderHeaders(llvm::StringRef UmbrellaHeaderName);
+
+ /// Called from CoverageCheckerCallbacks to track a header included
+ /// from an umbrella header.
+ /// \param HeaderName The header file path.
+ void collectUmbrellaHeaderHeader(llvm::StringRef HeaderName);
+
+ /// Collect file system header files.
+ /// This function scans the file system for header files,
+ /// starting at the directory of the module.modulemap file,
+ /// optionally filtering out all but the files covered by
+ /// the include path options.
+ /// \returns True if no errors.
+ bool collectFileSystemHeaders();
+
+ /// Collect file system header files from the given path.
+ /// This function scans the file system for header files,
+ /// starting at the given directory, which is assumed to be
+ /// relative to the directory of the module.modulemap file.
+ /// \returns True if no errors.
+ bool collectFileSystemHeaders(llvm::StringRef IncludePath);
+
+ /// Find headers unaccounted-for in module map.
+ /// This function compares the list of collected header files
+ /// against those referenced in the module map. Display
+ /// warnings for unaccounted-for header files.
+ /// Save unaccounted-for file list for possible.
+ /// fixing action.
+ void findUnaccountedForHeaders();
+};
+
+} // end namespace Modularize
+
+#endif // COVERAGECHECKER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/modularize/Modularize.cpp b/src/third_party/llvm-project/clang-tools-extra/modularize/Modularize.cpp
new file mode 100644
index 0000000..83f2340
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/modularize/Modularize.cpp
@@ -0,0 +1,998 @@
+//===- extra/modularize/Modularize.cpp - Check modularized headers --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Introduction
+//
+// This file implements a tool that checks whether a set of headers provides
+// the consistent definitions required to use modules. It can also check an
+// existing module map for full coverage of the headers in a directory tree.
+//
+// For example, in examining headers, it detects whether the same entity
+// (say, a NULL macro or size_t typedef) is defined in multiple headers
+// or whether a header produces different definitions under
+// different circumstances. These conditions cause modules built from the
+// headers to behave poorly, and should be fixed before introducing a module
+// map.
+//
+// Modularize takes as input either one or more module maps (by default,
+// "module.modulemap") or one or more text files contatining lists of headers
+// to check.
+//
+// In the case of a module map, the module map must be well-formed in
+// terms of syntax. Modularize will extract the header file names
+// from the map. Only normal headers are checked, assuming headers
+// marked "private", "textual", or "exclude" are not to be checked
+// as a top-level include, assuming they either are included by
+// other headers which are checked, or they are not suitable for
+// modules.
+//
+// In the case of a file list, the list is a newline-separated list of headers
+// to check with respect to each other.
+// Lines beginning with '#' and empty lines are ignored.
+// Header file names followed by a colon and other space-separated
+// file names will include those extra files as dependencies.
+// The file names can be relative or full paths, but must be on the
+// same line.
+//
+// Modularize also accepts regular clang front-end arguments.
+//
+// Usage: modularize [(modularize options)]
+// [(include-files_list)|(module map)]+ [(front-end-options) ...]
+//
+// Options:
+// -prefix=(optional header path prefix)
+// Note that unless a "-prefix (header path)" option is specified,
+// non-absolute file paths in the header list file will be relative
+// to the header list file directory. Use -prefix to specify a
+// different directory.
+// -module-map-path=(module map)
+// Skip the checks, and instead act as a module.map generation
+// assistant, generating a module map file based on the header list.
+// An optional "-root-module=(rootName)" argument can specify a root
+// module to be created in the generated module.map file. Note that
+// you will likely need to edit this file to suit the needs of your
+// headers.
+// -problem-files-list=(problem files list file name)
+// For use only with module map assistant. Input list of files that
+// have problems with respect to modules. These will still be
+// included in the generated module map, but will be marked as
+// "excluded" headers.
+// -root-module=(root module name)
+// Specifies a root module to be created in the generated module.map
+// file.
+// -block-check-header-list-only
+// Only warn if #include directives are inside extern or namespace
+// blocks if the included header is in the header list.
+// -no-coverage-check
+// Don't do the coverage check.
+// -coverage-check-only
+// Only do the coverage check.
+// -display-file-lists
+// Display lists of good files (no compile errors), problem files,
+// and a combined list with problem files preceded by a '#'.
+// This can be used to quickly determine which files have problems.
+// The latter combined list might be useful in starting to modularize
+// a set of headers. You can start with a full list of headers,
+// use -display-file-lists option, and then use the combined list as
+// your intermediate list, uncommenting-out headers as you fix them.
+//
+// Note that by default, the modularize assumes .h files contain C++ source.
+// If your .h files in the file list contain another language, you should
+// append an appropriate -x option to your command line, i.e.: -x c
+//
+// Modularization Issue Checks
+//
+// In the process of checking headers for modularization issues, modularize
+// will do normal parsing, reporting normal errors and warnings,
+// but will also report special error messages like the following:
+//
+// error: '(symbol)' defined at multiple locations:
+// (file):(row):(column)
+// (file):(row):(column)
+//
+// error: header '(file)' has different contents depending on how it was
+// included
+//
+// The latter might be followed by messages like the following:
+//
+// note: '(symbol)' in (file) at (row):(column) not always provided
+//
+// Checks will also be performed for macro expansions, defined(macro)
+// expressions, and preprocessor conditional directives that evaluate
+// inconsistently, and can produce error messages like the following:
+//
+// (...)/SubHeader.h:11:5:
+// #if SYMBOL == 1
+// ^
+// error: Macro instance 'SYMBOL' has different values in this header,
+// depending on how it was included.
+// 'SYMBOL' expanded to: '1' with respect to these inclusion paths:
+// (...)/Header1.h
+// (...)/SubHeader.h
+// (...)/SubHeader.h:3:9:
+// #define SYMBOL 1
+// ^
+// Macro defined here.
+// 'SYMBOL' expanded to: '2' with respect to these inclusion paths:
+// (...)/Header2.h
+// (...)/SubHeader.h
+// (...)/SubHeader.h:7:9:
+// #define SYMBOL 2
+// ^
+// Macro defined here.
+//
+// Checks will also be performed for '#include' directives that are
+// nested inside 'extern "C/C++" {}' or 'namespace (name) {}' blocks,
+// and can produce error message like the following:
+//
+// IncludeInExtern.h:2:3
+// #include "Empty.h"
+// ^
+// error: Include directive within extern "C" {}.
+// IncludeInExtern.h:1:1
+// extern "C" {
+// ^
+// The "extern "C" {}" block is here.
+//
+// See PreprocessorTracker.cpp for additional details.
+//
+// Module Map Coverage Check
+//
+// The coverage check uses the Clang ModuleMap class to read and parse the
+// module map file. Starting at the module map file directory, or just the
+// include paths, if specified, it will collect the names of all the files it
+// considers headers (no extension, .h, or .inc--if you need more, modify the
+// isHeader function). It then compares the headers against those referenced
+// in the module map, either explicitly named, or implicitly named via an
+// umbrella directory or umbrella file, as parsed by the ModuleMap object.
+// If headers are found which are not referenced or covered by an umbrella
+// directory or file, warning messages will be produced, and this program
+// will return an error code of 1. Other errors result in an error code of 2.
+// If no problems are found, an error code of 0 is returned.
+//
+// Note that in the case of umbrella headers, this tool invokes the compiler
+// to preprocess the file, and uses a callback to collect the header files
+// included by the umbrella header or any of its nested includes. If any
+// front end options are needed for these compiler invocations, these
+// can be included on the command line after the module map file argument.
+//
+// Warning message have the form:
+//
+// warning: module.modulemap does not account for file: Level3A.h
+//
+// Note that for the case of the module map referencing a file that does
+// not exist, the module map parser in Clang will (at the time of this
+// writing) display an error message.
+//
+// Module Map Assistant - Module Map Generation
+//
+// Modularize also has an option ("-module-map-path=module.modulemap") that will
+// skip the checks, and instead act as a module.modulemap generation assistant,
+// generating a module map file based on the header list. An optional
+// "-root-module=(rootName)" argument can specify a root module to be
+// created in the generated module.modulemap file. Note that you will likely
+// need to edit this file to suit the needs of your headers.
+//
+// An example command line for generating a module.modulemap file:
+//
+// modularize -module-map-path=module.modulemap -root-module=myroot \
+// headerlist.txt
+//
+// Note that if the headers in the header list have partial paths, sub-modules
+// will be created for the subdirectires involved, assuming that the
+// subdirectories contain headers to be grouped into a module, but still with
+// individual modules for the headers in the subdirectory.
+//
+// See the ModuleAssistant.cpp file comments for additional details about the
+// implementation of the assistant mode.
+//
+// Future directions:
+//
+// Basically, we want to add new checks for whatever we can check with respect
+// to checking headers for module'ability.
+//
+// Some ideas:
+//
+// 1. Omit duplicate "not always provided" messages
+//
+// 2. Add options to disable any of the checks, in case
+// there is some problem with them, or the messages get too verbose.
+//
+// 3. Try to figure out the preprocessor conditional directives that
+// contribute to problems and tie them to the inconsistent definitions.
+//
+// 4. There are some legitimate uses of preprocessor macros that
+// modularize will flag as errors, such as repeatedly #include'ing
+// a file and using interleaving defined/undefined macros
+// to change declarations in the included file. Is there a way
+// to address this? Maybe have modularize accept a list of macros
+// to ignore. Otherwise you can just exclude the file, after checking
+// for legitimate errors.
+//
+// 5. What else?
+//
+// General clean-up and refactoring:
+//
+// 1. The Location class seems to be something that we might
+// want to design to be applicable to a wider range of tools, and stick it
+// somewhere into Tooling/ in mainline
+//
+//===----------------------------------------------------------------------===//
+
+#include "Modularize.h"
+#include "ModularizeUtilities.h"
+#include "PreprocessorTracker.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Driver/Options.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+#include <fstream>
+#include <iterator>
+#include <string>
+#include <vector>
+
+using namespace clang;
+using namespace clang::driver;
+using namespace clang::driver::options;
+using namespace clang::tooling;
+using namespace llvm;
+using namespace llvm::opt;
+using namespace Modularize;
+
+// Option to specify a file name for a list of header files to check.
+static cl::list<std::string>
+ ListFileNames(cl::Positional, cl::value_desc("list"),
+ cl::desc("<list of one or more header list files>"),
+ cl::CommaSeparated);
+
+// Collect all other arguments, which will be passed to the front end.
+static cl::list<std::string>
+ CC1Arguments(cl::ConsumeAfter,
+ cl::desc("<arguments to be passed to front end>..."));
+
+// Option to specify a prefix to be prepended to the header names.
+static cl::opt<std::string> HeaderPrefix(
+ "prefix", cl::init(""),
+ cl::desc(
+ "Prepend header file paths with this prefix."
+ " If not specified,"
+ " the files are considered to be relative to the header list file."));
+
+// Option for assistant mode, telling modularize to output a module map
+// based on the headers list, and where to put it.
+static cl::opt<std::string> ModuleMapPath(
+ "module-map-path", cl::init(""),
+ cl::desc("Turn on module map output and specify output path or file name."
+ " If no path is specified and if prefix option is specified,"
+ " use prefix for file path."));
+
+// Option to specify list of problem files for assistant.
+// This will cause assistant to exclude these files.
+static cl::opt<std::string> ProblemFilesList(
+ "problem-files-list", cl::init(""),
+ cl::desc(
+ "List of files with compilation or modularization problems for"
+ " assistant mode. This will be excluded."));
+
+// Option for assistant mode, telling modularize the name of the root module.
+static cl::opt<std::string>
+RootModule("root-module", cl::init(""),
+ cl::desc("Specify the name of the root module."));
+
+// Option for limiting the #include-inside-extern-or-namespace-block
+// check to only those headers explicitly listed in the header list.
+// This is a work-around for private includes that purposefully get
+// included inside blocks.
+static cl::opt<bool>
+BlockCheckHeaderListOnly("block-check-header-list-only", cl::init(false),
+cl::desc("Only warn if #include directives are inside extern or namespace"
+ " blocks if the included header is in the header list."));
+
+// Option for include paths for coverage check.
+static cl::list<std::string>
+IncludePaths("I", cl::desc("Include path for coverage check."),
+cl::ZeroOrMore, cl::value_desc("path"));
+
+// Option for disabling the coverage check.
+static cl::opt<bool>
+NoCoverageCheck("no-coverage-check", cl::init(false),
+cl::desc("Don't do the coverage check."));
+
+// Option for just doing the coverage check.
+static cl::opt<bool>
+CoverageCheckOnly("coverage-check-only", cl::init(false),
+cl::desc("Only do the coverage check."));
+
+// Option for displaying lists of good, bad, and mixed files.
+static cl::opt<bool>
+DisplayFileLists("display-file-lists", cl::init(false),
+cl::desc("Display lists of good files (no compile errors), problem files,"
+ " and a combined list with problem files preceded by a '#'."));
+
+// Save the program name for error messages.
+const char *Argv0;
+// Save the command line for comments.
+std::string CommandLine;
+
+// Helper function for finding the input file in an arguments list.
+static std::string findInputFile(const CommandLineArguments &CLArgs) {
+ std::unique_ptr<OptTable> Opts(createDriverOptTable());
+ const unsigned IncludedFlagsBitmask = options::CC1Option;
+ unsigned MissingArgIndex, MissingArgCount;
+ SmallVector<const char *, 256> Argv;
+ for (auto I = CLArgs.begin(), E = CLArgs.end(); I != E; ++I)
+ Argv.push_back(I->c_str());
+ InputArgList Args = Opts->ParseArgs(Argv, MissingArgIndex, MissingArgCount,
+ IncludedFlagsBitmask);
+ std::vector<std::string> Inputs = Args.getAllArgValues(OPT_INPUT);
+ return ModularizeUtilities::getCanonicalPath(Inputs.back());
+}
+
+// This arguments adjuster inserts "-include (file)" arguments for header
+// dependencies. It also inserts a "-w" option and a "-x c++",
+// if no other "-x" option is present.
+static ArgumentsAdjuster
+getModularizeArgumentsAdjuster(DependencyMap &Dependencies) {
+ return [&Dependencies](const CommandLineArguments &Args,
+ StringRef /*unused*/) {
+ std::string InputFile = findInputFile(Args);
+ DependentsVector &FileDependents = Dependencies[InputFile];
+ CommandLineArguments NewArgs(Args);
+ if (int Count = FileDependents.size()) {
+ for (int Index = 0; Index < Count; ++Index) {
+ NewArgs.push_back("-include");
+ std::string File(std::string("\"") + FileDependents[Index] +
+ std::string("\""));
+ NewArgs.push_back(FileDependents[Index]);
+ }
+ }
+ // Ignore warnings. (Insert after "clang_tool" at beginning.)
+ NewArgs.insert(NewArgs.begin() + 1, "-w");
+ // Since we are compiling .h files, assume C++ unless given a -x option.
+ if (std::find(NewArgs.begin(), NewArgs.end(), "-x") == NewArgs.end()) {
+ NewArgs.insert(NewArgs.begin() + 2, "-x");
+ NewArgs.insert(NewArgs.begin() + 3, "c++");
+ }
+ return NewArgs;
+ };
+}
+
+// FIXME: The Location class seems to be something that we might
+// want to design to be applicable to a wider range of tools, and stick it
+// somewhere into Tooling/ in mainline
+struct Location {
+ const FileEntry *File;
+ unsigned Line, Column;
+
+ Location() : File(), Line(), Column() {}
+
+ Location(SourceManager &SM, SourceLocation Loc) : File(), Line(), Column() {
+ Loc = SM.getExpansionLoc(Loc);
+ if (Loc.isInvalid())
+ return;
+
+ std::pair<FileID, unsigned> Decomposed = SM.getDecomposedLoc(Loc);
+ File = SM.getFileEntryForID(Decomposed.first);
+ if (!File)
+ return;
+
+ Line = SM.getLineNumber(Decomposed.first, Decomposed.second);
+ Column = SM.getColumnNumber(Decomposed.first, Decomposed.second);
+ }
+
+ operator bool() const { return File != nullptr; }
+
+ friend bool operator==(const Location &X, const Location &Y) {
+ return X.File == Y.File && X.Line == Y.Line && X.Column == Y.Column;
+ }
+
+ friend bool operator!=(const Location &X, const Location &Y) {
+ return !(X == Y);
+ }
+
+ friend bool operator<(const Location &X, const Location &Y) {
+ if (X.File != Y.File)
+ return X.File < Y.File;
+ if (X.Line != Y.Line)
+ return X.Line < Y.Line;
+ return X.Column < Y.Column;
+ }
+ friend bool operator>(const Location &X, const Location &Y) { return Y < X; }
+ friend bool operator<=(const Location &X, const Location &Y) {
+ return !(Y < X);
+ }
+ friend bool operator>=(const Location &X, const Location &Y) {
+ return !(X < Y);
+ }
+};
+
+struct Entry {
+ enum EntryKind {
+ EK_Tag,
+ EK_Value,
+ EK_Macro,
+
+ EK_NumberOfKinds
+ } Kind;
+
+ Location Loc;
+
+ StringRef getKindName() { return getKindName(Kind); }
+ static StringRef getKindName(EntryKind kind);
+};
+
+// Return a string representing the given kind.
+StringRef Entry::getKindName(Entry::EntryKind kind) {
+ switch (kind) {
+ case EK_Tag:
+ return "tag";
+ case EK_Value:
+ return "value";
+ case EK_Macro:
+ return "macro";
+ case EK_NumberOfKinds:
+ break;
+ }
+ llvm_unreachable("invalid Entry kind");
+}
+
+struct HeaderEntry {
+ std::string Name;
+ Location Loc;
+
+ friend bool operator==(const HeaderEntry &X, const HeaderEntry &Y) {
+ return X.Loc == Y.Loc && X.Name == Y.Name;
+ }
+ friend bool operator!=(const HeaderEntry &X, const HeaderEntry &Y) {
+ return !(X == Y);
+ }
+ friend bool operator<(const HeaderEntry &X, const HeaderEntry &Y) {
+ return X.Loc < Y.Loc || (X.Loc == Y.Loc && X.Name < Y.Name);
+ }
+ friend bool operator>(const HeaderEntry &X, const HeaderEntry &Y) {
+ return Y < X;
+ }
+ friend bool operator<=(const HeaderEntry &X, const HeaderEntry &Y) {
+ return !(Y < X);
+ }
+ friend bool operator>=(const HeaderEntry &X, const HeaderEntry &Y) {
+ return !(X < Y);
+ }
+};
+
+typedef std::vector<HeaderEntry> HeaderContents;
+
+class EntityMap : public StringMap<SmallVector<Entry, 2> > {
+public:
+ DenseMap<const FileEntry *, HeaderContents> HeaderContentMismatches;
+
+ void add(const std::string &Name, enum Entry::EntryKind Kind, Location Loc) {
+ // Record this entity in its header.
+ HeaderEntry HE = { Name, Loc };
+ CurHeaderContents[Loc.File].push_back(HE);
+
+ // Check whether we've seen this entry before.
+ SmallVector<Entry, 2> &Entries = (*this)[Name];
+ for (unsigned I = 0, N = Entries.size(); I != N; ++I) {
+ if (Entries[I].Kind == Kind && Entries[I].Loc == Loc)
+ return;
+ }
+
+ // We have not seen this entry before; record it.
+ Entry E = { Kind, Loc };
+ Entries.push_back(E);
+ }
+
+ void mergeCurHeaderContents() {
+ for (DenseMap<const FileEntry *, HeaderContents>::iterator
+ H = CurHeaderContents.begin(),
+ HEnd = CurHeaderContents.end();
+ H != HEnd; ++H) {
+ // Sort contents.
+ std::sort(H->second.begin(), H->second.end());
+
+ // Check whether we've seen this header before.
+ DenseMap<const FileEntry *, HeaderContents>::iterator KnownH =
+ AllHeaderContents.find(H->first);
+ if (KnownH == AllHeaderContents.end()) {
+ // We haven't seen this header before; record its contents.
+ AllHeaderContents.insert(*H);
+ continue;
+ }
+
+ // If the header contents are the same, we're done.
+ if (H->second == KnownH->second)
+ continue;
+
+ // Determine what changed.
+ std::set_symmetric_difference(
+ H->second.begin(), H->second.end(), KnownH->second.begin(),
+ KnownH->second.end(),
+ std::back_inserter(HeaderContentMismatches[H->first]));
+ }
+
+ CurHeaderContents.clear();
+ }
+
+private:
+ DenseMap<const FileEntry *, HeaderContents> CurHeaderContents;
+ DenseMap<const FileEntry *, HeaderContents> AllHeaderContents;
+};
+
+class CollectEntitiesVisitor
+ : public RecursiveASTVisitor<CollectEntitiesVisitor> {
+public:
+ CollectEntitiesVisitor(SourceManager &SM, EntityMap &Entities,
+ Preprocessor &PP, PreprocessorTracker &PPTracker,
+ int &HadErrors)
+ : SM(SM), Entities(Entities), PP(PP), PPTracker(PPTracker),
+ HadErrors(HadErrors) {}
+
+ bool TraverseStmt(Stmt *S) { return true; }
+ bool TraverseType(QualType T) { return true; }
+ bool TraverseTypeLoc(TypeLoc TL) { return true; }
+ bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { return true; }
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ return true;
+ }
+ bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo) {
+ return true;
+ }
+ bool TraverseTemplateName(TemplateName Template) { return true; }
+ bool TraverseTemplateArgument(const TemplateArgument &Arg) { return true; }
+ bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
+ return true;
+ }
+ bool TraverseTemplateArguments(const TemplateArgument *Args,
+ unsigned NumArgs) {
+ return true;
+ }
+ bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; }
+ bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init) {
+ return true;
+ }
+
+ // Check 'extern "*" {}' block for #include directives.
+ bool VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ // Bail if not a block.
+ if (!D->hasBraces())
+ return true;
+ SourceRange BlockRange = D->getSourceRange();
+ const char *LinkageLabel;
+ switch (D->getLanguage()) {
+ case LinkageSpecDecl::lang_c:
+ LinkageLabel = "extern \"C\" {}";
+ break;
+ case LinkageSpecDecl::lang_cxx:
+ LinkageLabel = "extern \"C++\" {}";
+ break;
+ }
+ if (!PPTracker.checkForIncludesInBlock(PP, BlockRange, LinkageLabel,
+ errs()))
+ HadErrors = 1;
+ return true;
+ }
+
+ // Check 'namespace (name) {}' block for #include directives.
+ bool VisitNamespaceDecl(const NamespaceDecl *D) {
+ SourceRange BlockRange = D->getSourceRange();
+ std::string Label("namespace ");
+ Label += D->getName();
+ Label += " {}";
+ if (!PPTracker.checkForIncludesInBlock(PP, BlockRange, Label.c_str(),
+ errs()))
+ HadErrors = 1;
+ return true;
+ }
+
+ // Collect definition entities.
+ bool VisitNamedDecl(NamedDecl *ND) {
+ // We only care about file-context variables.
+ if (!ND->getDeclContext()->isFileContext())
+ return true;
+
+ // Skip declarations that tend to be properly multiply-declared.
+ if (isa<NamespaceDecl>(ND) || isa<UsingDirectiveDecl>(ND) ||
+ isa<NamespaceAliasDecl>(ND) ||
+ isa<ClassTemplateSpecializationDecl>(ND) || isa<UsingDecl>(ND) ||
+ isa<ClassTemplateDecl>(ND) || isa<TemplateTypeParmDecl>(ND) ||
+ isa<TypeAliasTemplateDecl>(ND) || isa<UsingShadowDecl>(ND) ||
+ isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||
+ (isa<TagDecl>(ND) &&
+ !cast<TagDecl>(ND)->isThisDeclarationADefinition()))
+ return true;
+
+ // Skip anonymous declarations.
+ if (!ND->getDeclName())
+ return true;
+
+ // Get the qualified name.
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ ND->printQualifiedName(OS);
+ OS.flush();
+ if (Name.empty())
+ return true;
+
+ Location Loc(SM, ND->getLocation());
+ if (!Loc)
+ return true;
+
+ Entities.add(Name, isa<TagDecl>(ND) ? Entry::EK_Tag : Entry::EK_Value, Loc);
+ return true;
+ }
+
+private:
+ SourceManager &SM;
+ EntityMap &Entities;
+ Preprocessor &PP;
+ PreprocessorTracker &PPTracker;
+ int &HadErrors;
+};
+
+class CollectEntitiesConsumer : public ASTConsumer {
+public:
+ CollectEntitiesConsumer(EntityMap &Entities,
+ PreprocessorTracker &preprocessorTracker,
+ Preprocessor &PP, StringRef InFile, int &HadErrors)
+ : Entities(Entities), PPTracker(preprocessorTracker), PP(PP),
+ HadErrors(HadErrors) {
+ PPTracker.handlePreprocessorEntry(PP, InFile);
+ }
+
+ ~CollectEntitiesConsumer() override { PPTracker.handlePreprocessorExit(); }
+
+ void HandleTranslationUnit(ASTContext &Ctx) override {
+ SourceManager &SM = Ctx.getSourceManager();
+
+ // Collect declared entities.
+ CollectEntitiesVisitor(SM, Entities, PP, PPTracker, HadErrors)
+ .TraverseDecl(Ctx.getTranslationUnitDecl());
+
+ // Collect macro definitions.
+ for (Preprocessor::macro_iterator M = PP.macro_begin(),
+ MEnd = PP.macro_end();
+ M != MEnd; ++M) {
+ Location Loc(SM, M->second.getLatest()->getLocation());
+ if (!Loc)
+ continue;
+
+ Entities.add(M->first->getName().str(), Entry::EK_Macro, Loc);
+ }
+
+ // Merge header contents.
+ Entities.mergeCurHeaderContents();
+ }
+
+private:
+ EntityMap &Entities;
+ PreprocessorTracker &PPTracker;
+ Preprocessor &PP;
+ int &HadErrors;
+};
+
+class CollectEntitiesAction : public SyntaxOnlyAction {
+public:
+ CollectEntitiesAction(EntityMap &Entities,
+ PreprocessorTracker &preprocessorTracker,
+ int &HadErrors)
+ : Entities(Entities), PPTracker(preprocessorTracker),
+ HadErrors(HadErrors) {}
+
+protected:
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
+ return llvm::make_unique<CollectEntitiesConsumer>(
+ Entities, PPTracker, CI.getPreprocessor(), InFile, HadErrors);
+ }
+
+private:
+ EntityMap &Entities;
+ PreprocessorTracker &PPTracker;
+ int &HadErrors;
+};
+
+class ModularizeFrontendActionFactory : public FrontendActionFactory {
+public:
+ ModularizeFrontendActionFactory(EntityMap &Entities,
+ PreprocessorTracker &preprocessorTracker,
+ int &HadErrors)
+ : Entities(Entities), PPTracker(preprocessorTracker),
+ HadErrors(HadErrors) {}
+
+ CollectEntitiesAction *create() override {
+ return new CollectEntitiesAction(Entities, PPTracker, HadErrors);
+ }
+
+private:
+ EntityMap &Entities;
+ PreprocessorTracker &PPTracker;
+ int &HadErrors;
+};
+
+class CompileCheckVisitor
+ : public RecursiveASTVisitor<CompileCheckVisitor> {
+public:
+ CompileCheckVisitor() {}
+
+ bool TraverseStmt(Stmt *S) { return true; }
+ bool TraverseType(QualType T) { return true; }
+ bool TraverseTypeLoc(TypeLoc TL) { return true; }
+ bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { return true; }
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ return true;
+ }
+ bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo) {
+ return true;
+ }
+ bool TraverseTemplateName(TemplateName Template) { return true; }
+ bool TraverseTemplateArgument(const TemplateArgument &Arg) { return true; }
+ bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
+ return true;
+ }
+ bool TraverseTemplateArguments(const TemplateArgument *Args,
+ unsigned NumArgs) {
+ return true;
+ }
+ bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; }
+ bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
+ Expr *Init) {
+ return true;
+ }
+
+ // Check 'extern "*" {}' block for #include directives.
+ bool VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ return true;
+ }
+
+ // Check 'namespace (name) {}' block for #include directives.
+ bool VisitNamespaceDecl(const NamespaceDecl *D) {
+ return true;
+ }
+
+ // Collect definition entities.
+ bool VisitNamedDecl(NamedDecl *ND) {
+ return true;
+ }
+};
+
+class CompileCheckConsumer : public ASTConsumer {
+public:
+ CompileCheckConsumer() {}
+
+ void HandleTranslationUnit(ASTContext &Ctx) override {
+ CompileCheckVisitor().TraverseDecl(Ctx.getTranslationUnitDecl());
+ }
+};
+
+class CompileCheckAction : public SyntaxOnlyAction {
+public:
+ CompileCheckAction() {}
+
+protected:
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
+ return llvm::make_unique<CompileCheckConsumer>();
+ }
+};
+
+class CompileCheckFrontendActionFactory : public FrontendActionFactory {
+public:
+ CompileCheckFrontendActionFactory() {}
+
+ CompileCheckAction *create() override {
+ return new CompileCheckAction();
+ }
+};
+
+int main(int Argc, const char **Argv) {
+
+ // Save program name for error messages.
+ Argv0 = Argv[0];
+
+ // Save program arguments for use in module.modulemap comment.
+ CommandLine = sys::path::stem(sys::path::filename(Argv0));
+ for (int ArgIndex = 1; ArgIndex < Argc; ArgIndex++) {
+ CommandLine.append(" ");
+ CommandLine.append(Argv[ArgIndex]);
+ }
+
+ // This causes options to be parsed.
+ cl::ParseCommandLineOptions(Argc, Argv, "modularize.\n");
+
+ // No go if we have no header list file.
+ if (ListFileNames.size() == 0) {
+ cl::PrintHelpMessage();
+ return 1;
+ }
+
+ std::unique_ptr<ModularizeUtilities> ModUtil;
+ int HadErrors = 0;
+
+ ModUtil.reset(
+ ModularizeUtilities::createModularizeUtilities(
+ ListFileNames, HeaderPrefix, ProblemFilesList));
+
+ // Get header file names and dependencies.
+ if (ModUtil->loadAllHeaderListsAndDependencies())
+ HadErrors = 1;
+
+ // If we are in assistant mode, output the module map and quit.
+ if (ModuleMapPath.length() != 0) {
+ if (!createModuleMap(ModuleMapPath, ModUtil->HeaderFileNames,
+ ModUtil->ProblemFileNames,
+ ModUtil->Dependencies, HeaderPrefix, RootModule))
+ return 1; // Failed.
+ return 0; // Success - Skip checks in assistant mode.
+ }
+
+ // If we're doing module maps.
+ if (!NoCoverageCheck && ModUtil->HasModuleMap) {
+ // Do coverage check.
+ if (ModUtil->doCoverageCheck(IncludePaths, CommandLine))
+ HadErrors = 1;
+ }
+
+ // Bail early if only doing the coverage check.
+ if (CoverageCheckOnly)
+ return HadErrors;
+
+ // Create the compilation database.
+ SmallString<256> PathBuf;
+ sys::fs::current_path(PathBuf);
+ std::unique_ptr<CompilationDatabase> Compilations;
+ Compilations.reset(
+ new FixedCompilationDatabase(Twine(PathBuf), CC1Arguments));
+
+ // Create preprocessor tracker, to watch for macro and conditional problems.
+ std::unique_ptr<PreprocessorTracker> PPTracker(
+ PreprocessorTracker::create(ModUtil->HeaderFileNames,
+ BlockCheckHeaderListOnly));
+
+ // Coolect entities here.
+ EntityMap Entities;
+
+ // Because we can't easily determine which files failed
+ // during the tool run, if we're collecting the file lists
+ // for display, we do a first compile pass on individual
+ // files to find which ones don't compile stand-alone.
+ if (DisplayFileLists) {
+ // First, make a pass to just get compile errors.
+ for (auto &CompileCheckFile : ModUtil->HeaderFileNames) {
+ llvm::SmallVector<std::string, 32> CompileCheckFileArray;
+ CompileCheckFileArray.push_back(CompileCheckFile);
+ ClangTool CompileCheckTool(*Compilations, CompileCheckFileArray);
+ CompileCheckTool.appendArgumentsAdjuster(
+ getModularizeArgumentsAdjuster(ModUtil->Dependencies));
+ int CompileCheckFileErrors = 0;
+ CompileCheckFrontendActionFactory CompileCheckFactory;
+ CompileCheckFileErrors |= CompileCheckTool.run(&CompileCheckFactory);
+ if (CompileCheckFileErrors != 0) {
+ ModUtil->addUniqueProblemFile(CompileCheckFile); // Save problem file.
+ HadErrors |= 1;
+ }
+ else
+ ModUtil->addNoCompileErrorsFile(CompileCheckFile); // Save good file.
+ }
+ }
+
+ // Then we make another pass on the good files to do the rest of the work.
+ ClangTool Tool(*Compilations,
+ (DisplayFileLists ? ModUtil->GoodFileNames : ModUtil->HeaderFileNames));
+ Tool.appendArgumentsAdjuster(
+ getModularizeArgumentsAdjuster(ModUtil->Dependencies));
+ ModularizeFrontendActionFactory Factory(Entities, *PPTracker, HadErrors);
+ HadErrors |= Tool.run(&Factory);
+
+ // Create a place to save duplicate entity locations, separate bins per kind.
+ typedef SmallVector<Location, 8> LocationArray;
+ typedef SmallVector<LocationArray, Entry::EK_NumberOfKinds> EntryBinArray;
+ EntryBinArray EntryBins;
+ int KindIndex;
+ for (KindIndex = 0; KindIndex < Entry::EK_NumberOfKinds; ++KindIndex) {
+ LocationArray Array;
+ EntryBins.push_back(Array);
+ }
+
+ // Check for the same entity being defined in multiple places.
+ for (EntityMap::iterator E = Entities.begin(), EEnd = Entities.end();
+ E != EEnd; ++E) {
+ // If only one occurrence, exit early.
+ if (E->second.size() == 1)
+ continue;
+ // Clear entity locations.
+ for (EntryBinArray::iterator CI = EntryBins.begin(), CE = EntryBins.end();
+ CI != CE; ++CI) {
+ CI->clear();
+ }
+ // Walk the entities of a single name, collecting the locations,
+ // separated into separate bins.
+ for (unsigned I = 0, N = E->second.size(); I != N; ++I) {
+ EntryBins[E->second[I].Kind].push_back(E->second[I].Loc);
+ }
+ // Report any duplicate entity definition errors.
+ int KindIndex = 0;
+ for (EntryBinArray::iterator DI = EntryBins.begin(), DE = EntryBins.end();
+ DI != DE; ++DI, ++KindIndex) {
+ int ECount = DI->size();
+ // If only 1 occurrence of this entity, skip it, we only report duplicates.
+ if (ECount <= 1)
+ continue;
+ LocationArray::iterator FI = DI->begin();
+ StringRef kindName = Entry::getKindName((Entry::EntryKind)KindIndex);
+ errs() << "error: " << kindName << " '" << E->first()
+ << "' defined at multiple locations:\n";
+ for (LocationArray::iterator FE = DI->end(); FI != FE; ++FI) {
+ errs() << " " << FI->File->getName() << ":" << FI->Line << ":"
+ << FI->Column << "\n";
+ ModUtil->addUniqueProblemFile(FI->File->getName());
+ }
+ HadErrors = 1;
+ }
+ }
+
+ // Complain about macro instance in header files that differ based on how
+ // they are included.
+ if (PPTracker->reportInconsistentMacros(errs()))
+ HadErrors = 1;
+
+ // Complain about preprocessor conditional directives in header files that
+ // differ based on how they are included.
+ if (PPTracker->reportInconsistentConditionals(errs()))
+ HadErrors = 1;
+
+ // Complain about any headers that have contents that differ based on how
+ // they are included.
+ // FIXME: Could we provide information about which preprocessor conditionals
+ // are involved?
+ for (DenseMap<const FileEntry *, HeaderContents>::iterator
+ H = Entities.HeaderContentMismatches.begin(),
+ HEnd = Entities.HeaderContentMismatches.end();
+ H != HEnd; ++H) {
+ if (H->second.empty()) {
+ errs() << "internal error: phantom header content mismatch\n";
+ continue;
+ }
+
+ HadErrors = 1;
+ ModUtil->addUniqueProblemFile(H->first->getName());
+ errs() << "error: header '" << H->first->getName()
+ << "' has different contents depending on how it was included.\n";
+ for (unsigned I = 0, N = H->second.size(); I != N; ++I) {
+ errs() << "note: '" << H->second[I].Name << "' in "
+ << H->second[I].Loc.File->getName() << " at "
+ << H->second[I].Loc.Line << ":" << H->second[I].Loc.Column
+ << " not always provided\n";
+ }
+ }
+
+ if (DisplayFileLists) {
+ ModUtil->displayProblemFiles();
+ ModUtil->displayGoodFiles();
+ ModUtil->displayCombinedFiles();
+ }
+
+ return HadErrors;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/modularize/Modularize.h b/src/third_party/llvm-project/clang-tools-extra/modularize/Modularize.h
new file mode 100644
index 0000000..a3f2ad3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/modularize/Modularize.h
@@ -0,0 +1,54 @@
+//===--- Modularize.h - Common definitions for Modularize -*- C++ -*-----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Common definitions for Modularize.
+///
+//===--------------------------------------------------------------------===//
+
+#ifndef MODULARIZE_H
+#define MODULARIZE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+#include <vector>
+
+// Save the program name for error messages.
+extern const char *Argv0;
+// Save the command line for comments.
+extern std::string CommandLine;
+
+// Dependency types.
+typedef llvm::SmallVector<std::string, 4> DependentsVector;
+typedef llvm::StringMap<DependentsVector> DependencyMap;
+
+// Global function declarations.
+
+/// Create the module map file.
+/// \param ModuleMapPath The path to the module map file to be generated.
+/// \param HeaderFileNames The list of header files, absolute native paths.
+/// \param ProblemFileNames The list of problem header files.
+/// \param Dependencies Map of headers that depend on other headers.
+/// \param HeaderPrefix Tells the code where the headers are, if they
+/// aren's in the current directory, allowing the generator to strip
+/// the leading, non-relative beginning of the header paths.
+/// \brief RootModuleName If not empty, specifies that a root module
+/// should be created with this name.
+/// \returns True if successful.
+bool createModuleMap(llvm::StringRef ModuleMapPath,
+ llvm::ArrayRef<std::string> HeaderFileNames,
+ llvm::ArrayRef<std::string> ProblemFileNames,
+ DependencyMap &Dependencies, llvm::StringRef HeaderPrefix,
+ llvm::StringRef RootModuleName);
+
+#endif // MODULARIZE_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/modularize/ModularizeUtilities.cpp b/src/third_party/llvm-project/clang-tools-extra/modularize/ModularizeUtilities.cpp
new file mode 100644
index 0000000..85768d5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/modularize/ModularizeUtilities.cpp
@@ -0,0 +1,546 @@
+//===--- extra/modularize/ModularizeUtilities.cpp -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a class for loading and validating a module map or
+// header list by checking that all headers in the corresponding directories
+// are accounted for.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/Driver/Options.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "CoverageChecker.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include "ModularizeUtilities.h"
+
+using namespace clang;
+using namespace llvm;
+using namespace Modularize;
+
+namespace {
+// Subclass TargetOptions so we can construct it inline with
+// the minimal option, the triple.
+class ModuleMapTargetOptions : public clang::TargetOptions {
+public:
+ ModuleMapTargetOptions() { Triple = llvm::sys::getDefaultTargetTriple(); }
+};
+} // namespace
+
+// ModularizeUtilities class implementation.
+
+// Constructor.
+ModularizeUtilities::ModularizeUtilities(std::vector<std::string> &InputPaths,
+ llvm::StringRef Prefix,
+ llvm::StringRef ProblemFilesListPath)
+ : InputFilePaths(InputPaths), HeaderPrefix(Prefix),
+ ProblemFilesPath(ProblemFilesListPath), HasModuleMap(false),
+ MissingHeaderCount(0),
+ // Init clang stuff needed for loading the module map and preprocessing.
+ LangOpts(new LangOptions()), DiagIDs(new DiagnosticIDs()),
+ DiagnosticOpts(new DiagnosticOptions()),
+ DC(llvm::errs(), DiagnosticOpts.get()),
+ Diagnostics(
+ new DiagnosticsEngine(DiagIDs, DiagnosticOpts.get(), &DC, false)),
+ TargetOpts(new ModuleMapTargetOptions()),
+ Target(TargetInfo::CreateTargetInfo(*Diagnostics, TargetOpts)),
+ FileMgr(new FileManager(FileSystemOpts)),
+ SourceMgr(new SourceManager(*Diagnostics, *FileMgr, false)),
+ HeaderInfo(new HeaderSearch(std::make_shared<HeaderSearchOptions>(),
+ *SourceMgr, *Diagnostics, *LangOpts,
+ Target.get())) {}
+
+// Create instance of ModularizeUtilities, to simplify setting up
+// subordinate objects.
+ModularizeUtilities *ModularizeUtilities::createModularizeUtilities(
+ std::vector<std::string> &InputPaths, llvm::StringRef Prefix,
+ llvm::StringRef ProblemFilesListPath) {
+
+ return new ModularizeUtilities(InputPaths, Prefix, ProblemFilesListPath);
+}
+
+// Load all header lists and dependencies.
+std::error_code ModularizeUtilities::loadAllHeaderListsAndDependencies() {
+ // For each input file.
+ for (auto I = InputFilePaths.begin(), E = InputFilePaths.end(); I != E; ++I) {
+ llvm::StringRef InputPath = *I;
+ // If it's a module map.
+ if (InputPath.endswith(".modulemap")) {
+ // Load the module map.
+ if (std::error_code EC = loadModuleMap(InputPath))
+ return EC;
+ }
+ else {
+ // Else we assume it's a header list and load it.
+ if (std::error_code EC = loadSingleHeaderListsAndDependencies(InputPath)) {
+ errs() << "modularize: error: Unable to get header list '" << InputPath
+ << "': " << EC.message() << '\n';
+ return EC;
+ }
+ }
+ }
+ // If we have a problem files list.
+ if (ProblemFilesPath.size() != 0) {
+ // Load problem files list.
+ if (std::error_code EC = loadProblemHeaderList(ProblemFilesPath)) {
+ errs() << "modularize: error: Unable to get problem header list '" << ProblemFilesPath
+ << "': " << EC.message() << '\n';
+ return EC;
+ }
+ }
+ return std::error_code();
+}
+
+// Do coverage checks.
+// For each loaded module map, do header coverage check.
+// Starting from the directory of the module.map file,
+// Find all header files, optionally looking only at files
+// covered by the include path options, and compare against
+// the headers referenced by the module.map file.
+// Display warnings for unaccounted-for header files.
+// Returns 0 if there were no errors or warnings, 1 if there
+// were warnings, 2 if any other problem, such as a bad
+// module map path argument was specified.
+std::error_code ModularizeUtilities::doCoverageCheck(
+ std::vector<std::string> &IncludePaths,
+ llvm::ArrayRef<std::string> CommandLine) {
+ int ModuleMapCount = ModuleMaps.size();
+ int ModuleMapIndex;
+ std::error_code EC;
+ for (ModuleMapIndex = 0; ModuleMapIndex < ModuleMapCount; ++ModuleMapIndex) {
+ std::unique_ptr<clang::ModuleMap> &ModMap = ModuleMaps[ModuleMapIndex];
+ auto Checker = CoverageChecker::createCoverageChecker(
+ InputFilePaths[ModuleMapIndex], IncludePaths, CommandLine,
+ ModMap.get());
+ std::error_code LocalEC = Checker->doChecks();
+ if (LocalEC.value() > 0)
+ EC = LocalEC;
+ }
+ return EC;
+}
+
+// Load single header list and dependencies.
+std::error_code ModularizeUtilities::loadSingleHeaderListsAndDependencies(
+ llvm::StringRef InputPath) {
+
+ // By default, use the path component of the list file name.
+ SmallString<256> HeaderDirectory(InputPath);
+ llvm::sys::path::remove_filename(HeaderDirectory);
+ SmallString<256> CurrentDirectory;
+ llvm::sys::fs::current_path(CurrentDirectory);
+
+ // Get the prefix if we have one.
+ if (HeaderPrefix.size() != 0)
+ HeaderDirectory = HeaderPrefix;
+
+ // Read the header list file into a buffer.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> listBuffer =
+ MemoryBuffer::getFile(InputPath);
+ if (std::error_code EC = listBuffer.getError())
+ return EC;
+
+ // Parse the header list into strings.
+ SmallVector<StringRef, 32> Strings;
+ listBuffer.get()->getBuffer().split(Strings, "\n", -1, false);
+
+ // Collect the header file names from the string list.
+ for (SmallVectorImpl<StringRef>::iterator I = Strings.begin(),
+ E = Strings.end();
+ I != E; ++I) {
+ StringRef Line = I->trim();
+ // Ignore comments and empty lines.
+ if (Line.empty() || (Line[0] == '#'))
+ continue;
+ std::pair<StringRef, StringRef> TargetAndDependents = Line.split(':');
+ SmallString<256> HeaderFileName;
+ // Prepend header file name prefix if it's not absolute.
+ if (llvm::sys::path::is_absolute(TargetAndDependents.first))
+ llvm::sys::path::native(TargetAndDependents.first, HeaderFileName);
+ else {
+ if (HeaderDirectory.size() != 0)
+ HeaderFileName = HeaderDirectory;
+ else
+ HeaderFileName = CurrentDirectory;
+ llvm::sys::path::append(HeaderFileName, TargetAndDependents.first);
+ llvm::sys::path::native(HeaderFileName);
+ }
+ // Handle optional dependencies.
+ DependentsVector Dependents;
+ SmallVector<StringRef, 4> DependentsList;
+ TargetAndDependents.second.split(DependentsList, " ", -1, false);
+ int Count = DependentsList.size();
+ for (int Index = 0; Index < Count; ++Index) {
+ SmallString<256> Dependent;
+ if (llvm::sys::path::is_absolute(DependentsList[Index]))
+ Dependent = DependentsList[Index];
+ else {
+ if (HeaderDirectory.size() != 0)
+ Dependent = HeaderDirectory;
+ else
+ Dependent = CurrentDirectory;
+ llvm::sys::path::append(Dependent, DependentsList[Index]);
+ }
+ llvm::sys::path::native(Dependent);
+ Dependents.push_back(getCanonicalPath(Dependent.str()));
+ }
+ // Get canonical form.
+ HeaderFileName = getCanonicalPath(HeaderFileName);
+ // Save the resulting header file path and dependencies.
+ HeaderFileNames.push_back(HeaderFileName.str());
+ Dependencies[HeaderFileName.str()] = Dependents;
+ }
+ return std::error_code();
+}
+
+// Load problem header list.
+std::error_code ModularizeUtilities::loadProblemHeaderList(
+ llvm::StringRef InputPath) {
+
+ // By default, use the path component of the list file name.
+ SmallString<256> HeaderDirectory(InputPath);
+ llvm::sys::path::remove_filename(HeaderDirectory);
+ SmallString<256> CurrentDirectory;
+ llvm::sys::fs::current_path(CurrentDirectory);
+
+ // Get the prefix if we have one.
+ if (HeaderPrefix.size() != 0)
+ HeaderDirectory = HeaderPrefix;
+
+ // Read the header list file into a buffer.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> listBuffer =
+ MemoryBuffer::getFile(InputPath);
+ if (std::error_code EC = listBuffer.getError())
+ return EC;
+
+ // Parse the header list into strings.
+ SmallVector<StringRef, 32> Strings;
+ listBuffer.get()->getBuffer().split(Strings, "\n", -1, false);
+
+ // Collect the header file names from the string list.
+ for (SmallVectorImpl<StringRef>::iterator I = Strings.begin(),
+ E = Strings.end();
+ I != E; ++I) {
+ StringRef Line = I->trim();
+ // Ignore comments and empty lines.
+ if (Line.empty() || (Line[0] == '#'))
+ continue;
+ SmallString<256> HeaderFileName;
+ // Prepend header file name prefix if it's not absolute.
+ if (llvm::sys::path::is_absolute(Line))
+ llvm::sys::path::native(Line, HeaderFileName);
+ else {
+ if (HeaderDirectory.size() != 0)
+ HeaderFileName = HeaderDirectory;
+ else
+ HeaderFileName = CurrentDirectory;
+ llvm::sys::path::append(HeaderFileName, Line);
+ llvm::sys::path::native(HeaderFileName);
+ }
+ // Get canonical form.
+ HeaderFileName = getCanonicalPath(HeaderFileName);
+ // Save the resulting header file path.
+ ProblemFileNames.push_back(HeaderFileName.str());
+ }
+ return std::error_code();
+}
+
+// Load single module map and extract header file list.
+std::error_code ModularizeUtilities::loadModuleMap(
+ llvm::StringRef InputPath) {
+ // Get file entry for module.modulemap file.
+ const FileEntry *ModuleMapEntry =
+ SourceMgr->getFileManager().getFile(InputPath);
+
+ // return error if not found.
+ if (!ModuleMapEntry) {
+ llvm::errs() << "error: File \"" << InputPath << "\" not found.\n";
+ return std::error_code(1, std::generic_category());
+ }
+
+ // Because the module map parser uses a ForwardingDiagnosticConsumer,
+ // which doesn't forward the BeginSourceFile call, we do it explicitly here.
+ DC.BeginSourceFile(*LangOpts, nullptr);
+
+ // Figure out the home directory for the module map file.
+ const DirectoryEntry *Dir = ModuleMapEntry->getDir();
+ StringRef DirName(Dir->getName());
+ if (llvm::sys::path::filename(DirName) == "Modules") {
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.endswith(".framework"))
+ Dir = FileMgr->getDirectory(DirName);
+ // FIXME: This assert can fail if there's a race between the above check
+ // and the removal of the directory.
+ assert(Dir && "parent must exist");
+ }
+
+ std::unique_ptr<ModuleMap> ModMap;
+ ModMap.reset(new ModuleMap(*SourceMgr, *Diagnostics, *LangOpts,
+ Target.get(), *HeaderInfo));
+
+ // Parse module.modulemap file into module map.
+ if (ModMap->parseModuleMapFile(ModuleMapEntry, false, Dir)) {
+ return std::error_code(1, std::generic_category());
+ }
+
+ // Do matching end call.
+ DC.EndSourceFile();
+
+ // Reset missing header count.
+ MissingHeaderCount = 0;
+
+ if (!collectModuleMapHeaders(ModMap.get()))
+ return std::error_code(1, std::generic_category());
+
+ // Save module map.
+ ModuleMaps.push_back(std::move(ModMap));
+
+ // Indicate we are using module maps.
+ HasModuleMap = true;
+
+ // Return code of 1 for missing headers.
+ if (MissingHeaderCount)
+ return std::error_code(1, std::generic_category());
+
+ return std::error_code();
+}
+
+// Collect module map headers.
+// Walks the modules and collects referenced headers into
+// HeaderFileNames.
+bool ModularizeUtilities::collectModuleMapHeaders(clang::ModuleMap *ModMap) {
+ for (ModuleMap::module_iterator I = ModMap->module_begin(),
+ E = ModMap->module_end();
+ I != E; ++I) {
+ if (!collectModuleHeaders(*I->second))
+ return false;
+ }
+ return true;
+}
+
+// Collect referenced headers from one module.
+// Collects the headers referenced in the given module into
+// HeaderFileNames.
+bool ModularizeUtilities::collectModuleHeaders(const clang::Module &Mod) {
+
+ // Ignore explicit modules because they often have dependencies
+ // we can't know.
+ if (Mod.IsExplicit)
+ return true;
+
+ // Treat headers in umbrella directory as dependencies.
+ DependentsVector UmbrellaDependents;
+
+ // Recursively do submodules.
+ for (auto MI = Mod.submodule_begin(), MIEnd = Mod.submodule_end();
+ MI != MIEnd; ++MI)
+ collectModuleHeaders(**MI);
+
+ if (const FileEntry *UmbrellaHeader = Mod.getUmbrellaHeader().Entry) {
+ std::string HeaderPath = getCanonicalPath(UmbrellaHeader->getName());
+ // Collect umbrella header.
+ HeaderFileNames.push_back(HeaderPath);
+
+ // FUTURE: When needed, umbrella header header collection goes here.
+ }
+ else if (const DirectoryEntry *UmbrellaDir = Mod.getUmbrellaDir().Entry) {
+ // If there normal headers, assume these are umbrellas and skip collection.
+ if (Mod.Headers->size() == 0) {
+ // Collect headers in umbrella directory.
+ if (!collectUmbrellaHeaders(UmbrellaDir->getName(), UmbrellaDependents))
+ return false;
+ }
+ }
+
+ // We ignore HK_Private, HK_Textual, HK_PrivateTextual, and HK_Excluded,
+ // assuming they are marked as such either because of unsuitability for
+ // modules or because they are meant to be included by another header,
+ // and thus should be ignored by modularize.
+
+ int NormalHeaderCount = Mod.Headers[clang::Module::HK_Normal].size();
+
+ for (int Index = 0; Index < NormalHeaderCount; ++Index) {
+ DependentsVector NormalDependents;
+ // Collect normal header.
+ const clang::Module::Header &Header(
+ Mod.Headers[clang::Module::HK_Normal][Index]);
+ std::string HeaderPath = getCanonicalPath(Header.Entry->getName());
+ HeaderFileNames.push_back(HeaderPath);
+ }
+
+ int MissingCountThisModule = Mod.MissingHeaders.size();
+
+ for (int Index = 0; Index < MissingCountThisModule; ++Index) {
+ std::string MissingFile = Mod.MissingHeaders[Index].FileName;
+ SourceLocation Loc = Mod.MissingHeaders[Index].FileNameLoc;
+ errs() << Loc.printToString(*SourceMgr)
+ << ": error : Header not found: " << MissingFile << "\n";
+ }
+
+ MissingHeaderCount += MissingCountThisModule;
+
+ return true;
+}
+
+// Collect headers from an umbrella directory.
+bool ModularizeUtilities::collectUmbrellaHeaders(StringRef UmbrellaDirName,
+ DependentsVector &Dependents) {
+ // Initialize directory name.
+ SmallString<256> Directory(UmbrellaDirName);
+ // Walk the directory.
+ std::error_code EC;
+ for (llvm::sys::fs::directory_iterator I(Directory.str(), EC), E; I != E;
+ I.increment(EC)) {
+ if (EC)
+ return false;
+ std::string File(I->path());
+ llvm::ErrorOr<llvm::sys::fs::basic_file_status> Status = I->status();
+ if (!Status)
+ return false;
+ llvm::sys::fs::file_type Type = Status->type();
+ // If the file is a directory, ignore the name and recurse.
+ if (Type == llvm::sys::fs::file_type::directory_file) {
+ if (!collectUmbrellaHeaders(File, Dependents))
+ return false;
+ continue;
+ }
+ // If the file does not have a common header extension, ignore it.
+ if (!isHeader(File))
+ continue;
+ // Save header name.
+ std::string HeaderPath = getCanonicalPath(File);
+ Dependents.push_back(HeaderPath);
+ }
+ return true;
+}
+
+// Replace .. embedded in path for purposes of having
+// a canonical path.
+static std::string replaceDotDot(StringRef Path) {
+ SmallString<128> Buffer;
+ llvm::sys::path::const_iterator B = llvm::sys::path::begin(Path),
+ E = llvm::sys::path::end(Path);
+ while (B != E) {
+ if (B->compare(".") == 0) {
+ }
+ else if (B->compare("..") == 0)
+ llvm::sys::path::remove_filename(Buffer);
+ else
+ llvm::sys::path::append(Buffer, *B);
+ ++B;
+ }
+ if (Path.endswith("/") || Path.endswith("\\"))
+ Buffer.append(1, Path.back());
+ return Buffer.c_str();
+}
+
+// Convert header path to canonical form.
+// The canonical form is basically just use forward slashes, and remove "./".
+// \param FilePath The file path, relative to the module map directory.
+// \returns The file path in canonical form.
+std::string ModularizeUtilities::getCanonicalPath(StringRef FilePath) {
+ std::string Tmp(replaceDotDot(FilePath));
+ std::replace(Tmp.begin(), Tmp.end(), '\\', '/');
+ StringRef Tmp2(Tmp);
+ if (Tmp2.startswith("./"))
+ Tmp = Tmp2.substr(2);
+ return Tmp;
+}
+
+// Check for header file extension.
+// If the file extension is .h, .inc, or missing, it's
+// assumed to be a header.
+// \param FileName The file name. Must not be a directory.
+// \returns true if it has a header extension or no extension.
+bool ModularizeUtilities::isHeader(StringRef FileName) {
+ StringRef Extension = llvm::sys::path::extension(FileName);
+ if (Extension.size() == 0)
+ return true;
+ if (Extension.equals_lower(".h"))
+ return true;
+ if (Extension.equals_lower(".inc"))
+ return true;
+ return false;
+}
+
+// Get directory path component from file path.
+// \returns the component of the given path, which will be
+// relative if the given path is relative, absolute if the
+// given path is absolute, or "." if the path has no leading
+// path component.
+std::string ModularizeUtilities::getDirectoryFromPath(StringRef Path) {
+ SmallString<256> Directory(Path);
+ sys::path::remove_filename(Directory);
+ if (Directory.size() == 0)
+ return ".";
+ return Directory.str();
+}
+
+// Add unique problem file.
+// Also standardizes the path.
+void ModularizeUtilities::addUniqueProblemFile(std::string FilePath) {
+ FilePath = getCanonicalPath(FilePath);
+ // Don't add if already present.
+ for(auto &TestFilePath : ProblemFileNames) {
+ if (TestFilePath == FilePath)
+ return;
+ }
+ ProblemFileNames.push_back(FilePath);
+}
+
+// Add file with no compile errors.
+// Also standardizes the path.
+void ModularizeUtilities::addNoCompileErrorsFile(std::string FilePath) {
+ FilePath = getCanonicalPath(FilePath);
+ GoodFileNames.push_back(FilePath);
+}
+
+// List problem files.
+void ModularizeUtilities::displayProblemFiles() {
+ errs() << "\nThese are the files with possible errors:\n\n";
+ for (auto &ProblemFile : ProblemFileNames) {
+ errs() << ProblemFile << "\n";
+ }
+}
+
+// List files with no problems.
+void ModularizeUtilities::displayGoodFiles() {
+ errs() << "\nThese are the files with no detected errors:\n\n";
+ for (auto &GoodFile : HeaderFileNames) {
+ bool Good = true;
+ for (auto &ProblemFile : ProblemFileNames) {
+ if (ProblemFile == GoodFile) {
+ Good = false;
+ break;
+ }
+ }
+ if (Good)
+ errs() << GoodFile << "\n";
+ }
+}
+
+// List files with problem files commented out.
+void ModularizeUtilities::displayCombinedFiles() {
+ errs() <<
+ "\nThese are the combined files, with problem files preceded by #:\n\n";
+ for (auto &File : HeaderFileNames) {
+ bool Good = true;
+ for (auto &ProblemFile : ProblemFileNames) {
+ if (ProblemFile == File) {
+ Good = false;
+ break;
+ }
+ }
+ errs() << (Good ? "" : "#") << File << "\n";
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/modularize/ModularizeUtilities.h b/src/third_party/llvm-project/clang-tools-extra/modularize/ModularizeUtilities.h
new file mode 100644
index 0000000..4ad2b56
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/modularize/ModularizeUtilities.h
@@ -0,0 +1,225 @@
+//=====-- ModularizeUtilities.h - Utilities for modularize -*- C++ -*-======//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------------===//
+///
+/// \file
+/// \brief ModularizeUtilities class definition.
+///
+//===--------------------------------------------------------------------===//
+
+#ifndef MODULARIZEUTILITIES_H
+#define MODULARIZEUTILITIES_H
+
+#include "Modularize.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/ModuleMap.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringSet.h"
+#include <string>
+#include <vector>
+
+namespace Modularize {
+
+/// Modularize utilities class.
+/// Support functions and data for modularize.
+class ModularizeUtilities {
+public:
+ // Input arguments.
+
+ /// The input file paths.
+ std::vector<std::string> InputFilePaths;
+ /// The header prefix.
+ llvm::StringRef HeaderPrefix;
+ /// The path of problem files list file.
+ llvm::StringRef ProblemFilesPath;
+
+ // Output data.
+
+ /// List of top-level header files.
+ llvm::SmallVector<std::string, 32> HeaderFileNames;
+ /// Map of top-level header file dependencies.
+ DependencyMap Dependencies;
+ /// True if we have module maps.
+ bool HasModuleMap;
+ /// Missing header count.
+ int MissingHeaderCount;
+ /// List of header files with no problems during the first pass,
+ /// that is, no compile errors.
+ llvm::SmallVector<std::string, 32> GoodFileNames;
+ /// List of header files with problems.
+ llvm::SmallVector<std::string, 32> ProblemFileNames;
+
+ // Functions.
+
+ /// Constructor.
+ /// You can use the static createModularizeUtilities to create an instance
+ /// of this object.
+ /// \param InputPaths The input file paths.
+ /// \param Prefix The headear path prefix.
+ /// \param ProblemFilesListPath The problem header list path.
+ ModularizeUtilities(std::vector<std::string> &InputPaths,
+ llvm::StringRef Prefix,
+ llvm::StringRef ProblemFilesListPath);
+
+ /// Create instance of ModularizeUtilities.
+ /// \param InputPaths The input file paths.
+ /// \param Prefix The headear path prefix.
+ /// \param ProblemFilesListPath The problem header list path.
+ /// \returns Initialized ModularizeUtilities object.
+ static ModularizeUtilities *createModularizeUtilities(
+ std::vector<std::string> &InputPaths,
+ llvm::StringRef Prefix,
+ llvm::StringRef ProblemFilesListPath);
+
+ /// Load header list and dependencies.
+ /// \returns std::error_code.
+ std::error_code loadAllHeaderListsAndDependencies();
+
+ /// Do coverage checks.
+ /// For each loaded module map, do header coverage check.
+ /// Starting from the directory of the module.map file,
+ /// Find all header files, optionally looking only at files
+ /// covered by the include path options, and compare against
+ /// the headers referenced by the module.map file.
+ /// Display warnings for unaccounted-for header files.
+ /// \param IncludePaths The include paths to check for files.
+ /// (Note that other directories above these paths are ignored.
+ /// To expect all files to be accounted for from the module.modulemap
+ /// file directory on down, leave this empty.)
+ /// \param CommandLine Compile command line arguments.
+ /// \returns 0 if there were no errors or warnings, 1 if there
+ /// were warnings, 2 if any other problem, such as a bad
+ /// module map path argument was specified.
+ std::error_code doCoverageCheck(std::vector<std::string> &IncludePaths,
+ llvm::ArrayRef<std::string> CommandLine);
+
+ /// Add unique problem file.
+ /// Also standardizes the path.
+ /// \param FilePath Problem file path.
+ void addUniqueProblemFile(std::string FilePath);
+
+ /// Add file with no compile errors.
+ /// Also standardizes the path.
+ /// \param FilePath Problem file path.
+ void addNoCompileErrorsFile(std::string FilePath);
+
+ /// List problem files.
+ void displayProblemFiles();
+
+ /// List files with no problems.
+ void displayGoodFiles();
+
+ /// List files with problem files commented out.
+ void displayCombinedFiles();
+
+ // Internal.
+
+protected:
+
+ /// Load single header list and dependencies.
+ /// \param InputPath The input file path.
+ /// \returns std::error_code.
+ std::error_code loadSingleHeaderListsAndDependencies(
+ llvm::StringRef InputPath);
+
+ /// Load problem header list.
+ /// \param InputPath The input file path.
+ /// \returns std::error_code.
+ std::error_code loadProblemHeaderList(
+ llvm::StringRef InputPath);
+
+ /// Load single module map and extract header file list.
+ /// \param InputPath The input file path.
+ /// \returns std::error_code.
+ std::error_code loadModuleMap(
+ llvm::StringRef InputPath);
+
+ /// Collect module Map headers.
+ /// Walks the modules and collects referenced headers into
+ /// HeaderFileNames.
+ /// \param ModMap A loaded module map object.
+ /// \return True if no errors.
+ bool collectModuleMapHeaders(clang::ModuleMap *ModMap);
+
+ /// Collect referenced headers from one module.
+ /// Collects the headers referenced in the given module into
+ /// HeaderFileNames.
+ /// \param Mod The module reference.
+ /// \return True if no errors.
+ bool collectModuleHeaders(const clang::Module &Mod);
+
+ /// Collect headers from an umbrella directory.
+ /// \param UmbrellaDirName The umbrella directory name.
+ /// \return True if no errors.
+ bool collectUmbrellaHeaders(llvm::StringRef UmbrellaDirName,
+ DependentsVector &Dependents);
+
+public:
+
+ // Utility functions.
+
+ /// Convert header path to canonical form.
+ /// The canonical form is basically just use forward slashes,
+ /// and remove "./".
+ /// \param FilePath The file path.
+ /// \returns The file path in canonical form.
+ static std::string getCanonicalPath(llvm::StringRef FilePath);
+
+ /// Check for header file extension.
+ /// If the file extension is .h, .inc, or missing, it's
+ /// assumed to be a header.
+ /// \param FileName The file name. Must not be a directory.
+ /// \returns true if it has a header extension or no extension.
+ static bool isHeader(llvm::StringRef FileName);
+
+ /// Get directory path component from file path.
+ /// \returns the component of the given path, which will be
+ /// relative if the given path is relative, absolute if the
+ /// given path is absolute, or "." if the path has no leading
+ /// path component.
+ static std::string getDirectoryFromPath(llvm::StringRef Path);
+
+ // Internal data.
+
+ /// Options controlling the language variant.
+ std::shared_ptr<clang::LangOptions> LangOpts;
+ /// Diagnostic IDs.
+ const llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs;
+ /// Options controlling the diagnostic engine.
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagnosticOpts;
+ /// Diagnostic consumer.
+ clang::TextDiagnosticPrinter DC;
+ /// Diagnostic engine.
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> Diagnostics;
+ /// Options controlling the target.
+ std::shared_ptr<clang::TargetOptions> TargetOpts;
+ /// Target information.
+ llvm::IntrusiveRefCntPtr<clang::TargetInfo> Target;
+ /// Options controlling the file system manager.
+ clang::FileSystemOptions FileSystemOpts;
+ /// File system manager.
+ llvm::IntrusiveRefCntPtr<clang::FileManager> FileMgr;
+ /// Source manager.
+ llvm::IntrusiveRefCntPtr<clang::SourceManager> SourceMgr;
+ /// Header search manager.
+ std::unique_ptr<clang::HeaderSearch> HeaderInfo;
+ // The loaded module map objects.
+ std::vector<std::unique_ptr<clang::ModuleMap>> ModuleMaps;
+};
+
+} // end namespace Modularize
+
+#endif // MODULARIZEUTILITIES_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/modularize/ModuleAssistant.cpp b/src/third_party/llvm-project/clang-tools-extra/modularize/ModuleAssistant.cpp
new file mode 100644
index 0000000..7f1cb15
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/modularize/ModuleAssistant.cpp
@@ -0,0 +1,316 @@
+//===--- ModuleAssistant.cpp - Module map generation manager -*- C++ -*---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file defines the module generation entry point function,
+// createModuleMap, a Module class for representing a module,
+// and various implementation functions for doing the underlying
+// work, described below.
+//
+// The "Module" class represents a module, with members for storing the module
+// name, associated header file names, and sub-modules, and an "output"
+// function that recursively writes the module definitions.
+//
+// The "createModuleMap" function implements the top-level logic of the
+// assistant mode. It calls a loadModuleDescriptions function to walk
+// the header list passed to it and creates a tree of Module objects
+// representing the module hierarchy, represented by a "Module" object,
+// the "RootModule". This root module may or may not represent an actual
+// module in the module map, depending on the "--root-module" option passed
+// to modularize. It then calls a writeModuleMap function to set up the
+// module map file output and walk the module tree, outputting the module
+// map file using a stream obtained and managed by an
+// llvm::ToolOutputFile object.
+//
+//===---------------------------------------------------------------------===//
+
+#include "Modularize.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include <vector>
+
+// Local definitions:
+
+namespace {
+
+// Internal class definitions:
+
+// Represents a module.
+class Module {
+public:
+ Module(llvm::StringRef Name, bool Problem);
+ Module();
+ ~Module();
+ bool output(llvm::raw_fd_ostream &OS, int Indent);
+ Module *findSubModule(llvm::StringRef SubName);
+
+public:
+ std::string Name;
+ std::vector<std::string> HeaderFileNames;
+ std::vector<Module *> SubModules;
+ bool IsProblem;
+};
+
+} // end anonymous namespace.
+
+// Module functions:
+
+// Constructors.
+Module::Module(llvm::StringRef Name, bool Problem)
+ : Name(Name), IsProblem(Problem) {}
+Module::Module() : IsProblem(false) {}
+
+// Destructor.
+Module::~Module() {
+ // Free submodules.
+ while (!SubModules.empty()) {
+ Module *last = SubModules.back();
+ SubModules.pop_back();
+ delete last;
+ }
+}
+
+// Write a module hierarchy to the given output stream.
+bool Module::output(llvm::raw_fd_ostream &OS, int Indent) {
+ // If this is not the nameless root module, start a module definition.
+ if (Name.size() != 0) {
+ OS.indent(Indent);
+ OS << "module " << Name << " {\n";
+ Indent += 2;
+ }
+
+ // Output submodules.
+ for (auto I = SubModules.begin(), E = SubModules.end(); I != E; ++I) {
+ if (!(*I)->output(OS, Indent))
+ return false;
+ }
+
+ // Output header files.
+ for (auto I = HeaderFileNames.begin(), E = HeaderFileNames.end(); I != E;
+ ++I) {
+ OS.indent(Indent);
+ if (IsProblem || strstr((*I).c_str(), ".inl"))
+ OS << "exclude header \"" << *I << "\"\n";
+ else
+ OS << "header \"" << *I << "\"\n";
+ }
+
+ // If this module has header files, output export directive.
+ if (HeaderFileNames.size() != 0) {
+ OS.indent(Indent);
+ OS << "export *\n";
+ }
+
+ // If this is not the nameless root module, close the module definition.
+ if (Name.size() != 0) {
+ Indent -= 2;
+ OS.indent(Indent);
+ OS << "}\n";
+ }
+
+ return true;
+}
+
+// Lookup a sub-module.
+Module *Module::findSubModule(llvm::StringRef SubName) {
+ for (auto I = SubModules.begin(), E = SubModules.end(); I != E; ++I) {
+ if ((*I)->Name == SubName)
+ return *I;
+ }
+ return nullptr;
+}
+
+// Implementation functions:
+
+// Reserved keywords in module.modulemap syntax.
+// Keep in sync with keywords in module map parser in Lex/ModuleMap.cpp,
+// such as in ModuleMapParser::consumeToken().
+static const char *const ReservedNames[] = {
+ "config_macros", "export", "module", "conflict", "framework",
+ "requires", "exclude", "header", "private", "explicit",
+ "link", "umbrella", "extern", "use", nullptr // Flag end.
+};
+
+// Convert module name to a non-keyword.
+// Prepends a '_' to the name if and only if the name is a keyword.
+static std::string
+ensureNoCollisionWithReservedName(llvm::StringRef MightBeReservedName) {
+ std::string SafeName = MightBeReservedName;
+ for (int Index = 0; ReservedNames[Index] != nullptr; ++Index) {
+ if (MightBeReservedName == ReservedNames[Index]) {
+ SafeName.insert(0, "_");
+ break;
+ }
+ }
+ return SafeName;
+}
+
+// Convert module name to a non-keyword.
+// Prepends a '_' to the name if and only if the name is a keyword.
+static std::string
+ensureVaidModuleName(llvm::StringRef MightBeInvalidName) {
+ std::string SafeName = MightBeInvalidName;
+ std::replace(SafeName.begin(), SafeName.end(), '-', '_');
+ std::replace(SafeName.begin(), SafeName.end(), '.', '_');
+ if (isdigit(SafeName[0]))
+ SafeName = "_" + SafeName;
+ return SafeName;
+}
+
+// Add one module, given a header file path.
+static bool addModuleDescription(Module *RootModule,
+ llvm::StringRef HeaderFilePath,
+ llvm::StringRef HeaderPrefix,
+ DependencyMap &Dependencies,
+ bool IsProblemFile) {
+ Module *CurrentModule = RootModule;
+ DependentsVector &FileDependents = Dependencies[HeaderFilePath];
+ std::string FilePath;
+ // Strip prefix.
+ // HeaderFilePath should be compared to natively-canonicalized Prefix.
+ llvm::SmallString<256> NativePath, NativePrefix;
+ llvm::sys::path::native(HeaderFilePath, NativePath);
+ llvm::sys::path::native(HeaderPrefix, NativePrefix);
+ if (NativePath.startswith(NativePrefix))
+ FilePath = NativePath.substr(NativePrefix.size() + 1);
+ else
+ FilePath = HeaderFilePath;
+ int Count = FileDependents.size();
+ // Headers that go into modules must not depend on other files being
+ // included first. If there are any dependents, warn user and omit.
+ if (Count != 0) {
+ llvm::errs() << "warning: " << FilePath
+ << " depends on other headers being included first,"
+ " meaning the module.modulemap won't compile."
+ " This header will be omitted from the module map.\n";
+ return true;
+ }
+ // Make canonical.
+ std::replace(FilePath.begin(), FilePath.end(), '\\', '/');
+ // Insert module into tree, using subdirectories as submodules.
+ for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(FilePath),
+ E = llvm::sys::path::end(FilePath);
+ I != E; ++I) {
+ if ((*I)[0] == '.')
+ continue;
+ std::string Stem = llvm::sys::path::stem(*I);
+ Stem = ensureNoCollisionWithReservedName(Stem);
+ Stem = ensureVaidModuleName(Stem);
+ Module *SubModule = CurrentModule->findSubModule(Stem);
+ if (!SubModule) {
+ SubModule = new Module(Stem, IsProblemFile);
+ CurrentModule->SubModules.push_back(SubModule);
+ }
+ CurrentModule = SubModule;
+ }
+ // Add header file name to headers.
+ CurrentModule->HeaderFileNames.push_back(FilePath);
+ return true;
+}
+
+// Create the internal module tree representation.
+static Module *loadModuleDescriptions(
+ llvm::StringRef RootModuleName, llvm::ArrayRef<std::string> HeaderFileNames,
+ llvm::ArrayRef<std::string> ProblemFileNames,
+ DependencyMap &Dependencies, llvm::StringRef HeaderPrefix) {
+
+ // Create root module.
+ auto *RootModule = new Module(RootModuleName, false);
+
+ llvm::SmallString<256> CurrentDirectory;
+ llvm::sys::fs::current_path(CurrentDirectory);
+
+ // If no header prefix, use current directory.
+ if (HeaderPrefix.size() == 0)
+ HeaderPrefix = CurrentDirectory;
+
+ // Walk the header file names and output the module map.
+ for (llvm::ArrayRef<std::string>::iterator I = HeaderFileNames.begin(),
+ E = HeaderFileNames.end();
+ I != E; ++I) {
+ std::string Header(*I);
+ bool IsProblemFile = false;
+ for (auto &ProblemFile : ProblemFileNames) {
+ if (ProblemFile == Header) {
+ IsProblemFile = true;
+ break;
+ }
+ }
+ // Add as a module.
+ if (!addModuleDescription(RootModule, Header, HeaderPrefix, Dependencies, IsProblemFile))
+ return nullptr;
+ }
+
+ return RootModule;
+}
+
+// Kick off the writing of the module map.
+static bool writeModuleMap(llvm::StringRef ModuleMapPath,
+ llvm::StringRef HeaderPrefix, Module *RootModule) {
+ llvm::SmallString<256> HeaderDirectory(ModuleMapPath);
+ llvm::sys::path::remove_filename(HeaderDirectory);
+ llvm::SmallString<256> FilePath;
+
+ // Get the module map file path to be used.
+ if ((HeaderDirectory.size() == 0) && (HeaderPrefix.size() != 0)) {
+ FilePath = HeaderPrefix;
+ // Prepend header file name prefix if it's not absolute.
+ llvm::sys::path::append(FilePath, ModuleMapPath);
+ llvm::sys::path::native(FilePath);
+ } else {
+ FilePath = ModuleMapPath;
+ llvm::sys::path::native(FilePath);
+ }
+
+ // Set up module map output file.
+ std::error_code EC;
+ llvm::ToolOutputFile Out(FilePath, EC, llvm::sys::fs::F_Text);
+ if (EC) {
+ llvm::errs() << Argv0 << ": error opening " << FilePath << ":"
+ << EC.message() << "\n";
+ return false;
+ }
+
+ // Get output stream from tool output buffer/manager.
+ llvm::raw_fd_ostream &OS = Out.os();
+
+ // Output file comment.
+ OS << "// " << ModuleMapPath << "\n";
+ OS << "// Generated by: " << CommandLine << "\n\n";
+
+ // Write module hierarchy from internal representation.
+ if (!RootModule->output(OS, 0))
+ return false;
+
+ // Tell ToolOutputFile that we want to keep the file.
+ Out.keep();
+
+ return true;
+}
+
+// Global functions:
+
+// Module map generation entry point.
+bool createModuleMap(llvm::StringRef ModuleMapPath,
+ llvm::ArrayRef<std::string> HeaderFileNames,
+ llvm::ArrayRef<std::string> ProblemFileNames,
+ DependencyMap &Dependencies, llvm::StringRef HeaderPrefix,
+ llvm::StringRef RootModuleName) {
+ // Load internal representation of modules.
+ std::unique_ptr<Module> RootModule(
+ loadModuleDescriptions(
+ RootModuleName, HeaderFileNames, ProblemFileNames, Dependencies,
+ HeaderPrefix));
+ if (!RootModule.get())
+ return false;
+
+ // Write module map file.
+ return writeModuleMap(ModuleMapPath, HeaderPrefix, RootModule.get());
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/modularize/PreprocessorTracker.cpp b/src/third_party/llvm-project/clang-tools-extra/modularize/PreprocessorTracker.cpp
new file mode 100644
index 0000000..6cb34c7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/modularize/PreprocessorTracker.cpp
@@ -0,0 +1,1394 @@
+//===--- PreprocessorTracker.cpp - Preprocessor tracking -*- C++ -*------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------------===//
+//
+// The Basic Idea (Macro and Conditional Checking)
+//
+// Basically we install a PPCallbacks-derived object to track preprocessor
+// activity, namely when a header file is entered/exited, when a macro
+// is expanded, when "defined" is used, and when #if, #elif, #ifdef,
+// and #ifndef are used. We save the state of macro and "defined"
+// expressions in a map, keyed on a name/file/line/column quadruple.
+// The map entries store the different states (values) that a macro expansion,
+// "defined" expression, or condition expression has in the course of
+// processing for the one location in the one header containing it,
+// plus a list of the nested include stacks for the states. When a macro
+// or "defined" expression evaluates to the same value, which is the
+// desired case, only one state is stored. Similarly, for conditional
+// directives, we save the condition expression states in a separate map.
+//
+// This information is collected as modularize compiles all the headers
+// given to it to process. After all the compilations are performed,
+// a check is performed for any entries in the maps that contain more
+// than one different state, and for these an output message is generated.
+//
+// For example:
+//
+// (...)/SubHeader.h:11:5:
+// #if SYMBOL == 1
+// ^
+// error: Macro instance 'SYMBOL' has different values in this header,
+// depending on how it was included.
+// 'SYMBOL' expanded to: '1' with respect to these inclusion paths:
+// (...)/Header1.h
+// (...)/SubHeader.h
+// (...)/SubHeader.h:3:9:
+// #define SYMBOL 1
+// ^
+// Macro defined here.
+// 'SYMBOL' expanded to: '2' with respect to these inclusion paths:
+// (...)/Header2.h
+// (...)/SubHeader.h
+// (...)/SubHeader.h:7:9:
+// #define SYMBOL 2
+// ^
+// Macro defined here.
+//
+// The Basic Idea ('Extern "C/C++" {}' Or 'namespace {}') With Nested
+// '#include' Checking)
+//
+// To check for '#include' directives nested inside 'Extern "C/C++" {}'
+// or 'namespace {}' blocks, we keep track of the '#include' directives
+// while running the preprocessor, and later during a walk of the AST
+// we call a function to check for any '#include' directies inside
+// an 'Extern "C/C++" {}' or 'namespace {}' block, given its source
+// range.
+//
+// Design and Implementation Details (Macro and Conditional Checking)
+//
+// A PreprocessorTrackerImpl class implements the PreprocessorTracker
+// interface. It uses a PreprocessorCallbacks class derived from PPCallbacks
+// to track preprocessor activity, namely entering/exiting a header, macro
+// expansions, use of "defined" expressions, and #if, #elif, #ifdef, and
+// #ifndef conditional directives. PreprocessorTrackerImpl stores a map
+// of MacroExpansionTracker objects keyed on a name/file/line/column
+// value represented by a light-weight PPItemKey value object. This
+// is the key top-level data structure tracking the values of macro
+// expansion instances. Similarly, it stores a map of ConditionalTracker
+// objects with the same kind of key, for tracking preprocessor conditional
+// directives.
+//
+// The MacroExpansionTracker object represents one macro reference or use
+// of a "defined" expression in a header file. It stores a handle to a
+// string representing the unexpanded macro instance, a handle to a string
+// representing the unpreprocessed source line containing the unexpanded
+// macro instance, and a vector of one or more MacroExpansionInstance
+// objects.
+//
+// The MacroExpansionInstance object represents one or more expansions
+// of a macro reference, for the case where the macro expands to the same
+// value. MacroExpansionInstance stores a handle to a string representing
+// the expanded macro value, a PPItemKey representing the file/line/column
+// where the macro was defined, a handle to a string representing the source
+// line containing the macro definition, and a vector of InclusionPathHandle
+// values that represents the hierarchies of include files for each case
+// where the particular header containing the macro reference was referenced
+// or included.
+
+// In the normal case where a macro instance always expands to the same
+// value, the MacroExpansionTracker object will only contain one
+// MacroExpansionInstance representing all the macro expansion instances.
+// If a case was encountered where a macro instance expands to a value
+// that is different from that seen before, or the macro was defined in
+// a different place, a new MacroExpansionInstance object representing
+// that case will be added to the vector in MacroExpansionTracker. If a
+// macro instance expands to a value already seen before, the
+// InclusionPathHandle representing that case's include file hierarchy
+// will be added to the existing MacroExpansionInstance object.
+
+// For checking conditional directives, the ConditionalTracker class
+// functions similarly to MacroExpansionTracker, but tracks an #if,
+// #elif, #ifdef, or #ifndef directive in a header file. It stores
+// a vector of one or two ConditionalExpansionInstance objects,
+// representing the cases where the conditional expression evaluates
+// to true or false. This latter object stores the evaluated value
+// of the condition expression (a bool) and a vector of
+// InclusionPathHandles.
+//
+// To reduce the instances of string and object copying, the
+// PreprocessorTrackerImpl class uses a StringPool to save all stored
+// strings, and defines a StringHandle type to abstract the references
+// to the strings.
+//
+// PreprocessorTrackerImpl also maintains a list representing the unique
+// headers, which is just a vector of StringHandle's for the header file
+// paths. A HeaderHandle abstracts a reference to a header, and is simply
+// the index of the stored header file path.
+//
+// A HeaderInclusionPath class abstracts a unique hierarchy of header file
+// inclusions. It simply stores a vector of HeaderHandles ordered from the
+// top-most header (the one from the header list passed to modularize) down
+// to the header containing the macro reference. PreprocessorTrackerImpl
+// stores a vector of these objects. An InclusionPathHandle typedef
+// abstracts a reference to one of the HeaderInclusionPath objects, and is
+// simply the index of the stored HeaderInclusionPath object. The
+// MacroExpansionInstance object stores a vector of these handles so that
+// the reporting function can display the include hierarchies for the macro
+// expansion instances represented by that object, to help the user
+// understand how the header was included. (A future enhancement might
+// be to associate a line number for the #include directives, but I
+// think not doing so is good enough for the present.)
+//
+// A key reason for using these opaque handles was to try to keep all the
+// internal objects light-weight value objects, in order to reduce string
+// and object copying overhead, and to abstract this implementation detail.
+//
+// The key data structures are built up while modularize runs the headers
+// through the compilation. A PreprocessorTracker instance is created and
+// passed down to the AST action and consumer objects in modularize. For
+// each new compilation instance, the consumer calls the
+// PreprocessorTracker's handleNewPreprocessorEntry function, which sets
+// up a PreprocessorCallbacks object for the preprocessor. At the end of
+// the compilation instance, the PreprocessorTracker's
+// handleNewPreprocessorExit function handles cleaning up with respect
+// to the preprocessing instance.
+//
+// The PreprocessorCallbacks object uses an overidden FileChanged callback
+// to determine when a header is entered and exited (including exiting the
+// header during #include directives). It calls PreprocessorTracker's
+// handleHeaderEntry and handleHeaderExit functions upon entering and
+// exiting a header. These functions manage a stack of header handles
+// representing by a vector, pushing and popping header handles as headers
+// are entered and exited. When a HeaderInclusionPath object is created,
+// it simply copies this stack.
+//
+// The PreprocessorCallbacks object uses an overridden MacroExpands callback
+// to track when a macro expansion is performed. It calls a couple of helper
+// functions to get the unexpanded and expanded macro values as strings, but
+// then calls PreprocessorTrackerImpl's addMacroExpansionInstance function to
+// do the rest of the work. The getMacroExpandedString function uses the
+// preprocessor's getSpelling to convert tokens to strings using the
+// information passed to the MacroExpands callback, and simply concatenates
+// them. It makes recursive calls to itself to handle nested macro
+// definitions, and also handles function-style macros.
+//
+// PreprocessorTrackerImpl's addMacroExpansionInstance function looks for
+// an existing MacroExpansionTracker entry in its map of MacroExampleTracker
+// objects. If none exists, it adds one with one MacroExpansionInstance and
+// returns. If a MacroExpansionTracker object already exists, it looks for
+// an existing MacroExpansionInstance object stored in the
+// MacroExpansionTracker object, one that matches the macro expanded value
+// and the macro definition location. If a matching MacroExpansionInstance
+// object is found, it just adds the current HeaderInclusionPath object to
+// it. If not found, it creates and stores a new MacroExpantionInstance
+// object. The addMacroExpansionInstance function calls a couple of helper
+// functions to get the pre-formatted location and source line strings for
+// the macro reference and the macro definition stored as string handles.
+// These helper functions use the current source manager from the
+// preprocessor. This is done in advance at this point in time because the
+// source manager doesn't exist at the time of the reporting.
+//
+// For conditional check, the PreprocessorCallbacks class overrides the
+// PPCallbacks handlers for #if, #elif, #ifdef, and #ifndef. These handlers
+// call the addConditionalExpansionInstance method of
+// PreprocessorTrackerImpl. The process is similar to that of macros, but
+// with some different data and error messages. A lookup is performed for
+// the conditional, and if a ConditionalTracker object doesn't yet exist for
+// the conditional, a new one is added, including adding a
+// ConditionalExpansionInstance object to it to represent the condition
+// expression state. If a ConditionalTracker for the conditional does
+// exist, a lookup is made for a ConditionalExpansionInstance object
+// matching the condition expression state. If one exists, a
+// HeaderInclusionPath is added to it. Otherwise a new
+// ConditionalExpansionInstance entry is made. If a ConditionalTracker
+// has two ConditionalExpansionInstance objects, it means there was a
+// conflict, meaning the conditional expression evaluated differently in
+// one or more cases.
+//
+// After modularize has performed all the compilations, it enters a phase
+// of error reporting. This new feature adds to this reporting phase calls
+// to the PreprocessorTracker's reportInconsistentMacros and
+// reportInconsistentConditionals functions. These functions walk the maps
+// of MacroExpansionTracker's and ConditionalTracker's respectively. If
+// any of these objects have more than one MacroExpansionInstance or
+// ConditionalExpansionInstance objects, it formats and outputs an error
+// message like the example shown previously, using the stored data.
+//
+// A potential issue is that there is some overlap between the #if/#elif
+// conditional and macro reporting. I could disable the #if and #elif,
+// leaving just the #ifdef and #ifndef, since these don't overlap. Or,
+// to make clearer the separate reporting phases, I could add an output
+// message marking the phases.
+//
+// Design and Implementation Details ('Extern "C/C++" {}' Or
+// 'namespace {}') With Nested '#include' Checking)
+//
+// We override the InclusionDirective in PPCallbacks to record information
+// about each '#include' directive encountered during preprocessing.
+// We co-opt the PPItemKey class to store the information about each
+// '#include' directive, including the source file name containing the
+// directive, the name of the file being included, and the source line
+// and column of the directive. We store these object in a vector,
+// after first check to see if an entry already exists.
+//
+// Later, while the AST is being walked for other checks, we provide
+// visit handlers for 'extern "C/C++" {}' and 'namespace (name) {}'
+// blocks, checking to see if any '#include' directives occurred
+// within the blocks, reporting errors if any found.
+//
+// Future Directions
+//
+// We probably should add options to disable any of the checks, in case
+// there is some problem with them, or the messages get too verbose.
+//
+// With the map of all the macro and conditional expansion instances,
+// it might be possible to add to the existing modularize error messages
+// (the second part referring to definitions being different), attempting
+// to tie them to the last macro conflict encountered with respect to the
+// order of the code encountered.
+//
+//===--------------------------------------------------------------------===//
+
+#include "clang/Lex/LexDiagnostic.h"
+#include "PreprocessorTracker.h"
+#include "clang/Lex/MacroArgs.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/StringPool.h"
+#include "llvm/Support/raw_ostream.h"
+#include "ModularizeUtilities.h"
+
+namespace Modularize {
+
+// Some handle types
+typedef llvm::PooledStringPtr StringHandle;
+
+typedef int HeaderHandle;
+const HeaderHandle HeaderHandleInvalid = -1;
+
+typedef int InclusionPathHandle;
+const InclusionPathHandle InclusionPathHandleInvalid = -1;
+
+// Some utility functions.
+
+// Get a "file:line:column" source location string.
+static std::string getSourceLocationString(clang::Preprocessor &PP,
+ clang::SourceLocation Loc) {
+ if (Loc.isInvalid())
+ return std::string("(none)");
+ else
+ return Loc.printToString(PP.getSourceManager());
+}
+
+// Get just the file name from a source location.
+static std::string getSourceLocationFile(clang::Preprocessor &PP,
+ clang::SourceLocation Loc) {
+ std::string Source(getSourceLocationString(PP, Loc));
+ size_t Offset = Source.find(':', 2);
+ if (Offset == std::string::npos)
+ return Source;
+ return Source.substr(0, Offset);
+}
+
+// Get just the line and column from a source location.
+static void getSourceLocationLineAndColumn(clang::Preprocessor &PP,
+ clang::SourceLocation Loc, int &Line,
+ int &Column) {
+ clang::PresumedLoc PLoc = PP.getSourceManager().getPresumedLoc(Loc);
+ if (PLoc.isInvalid()) {
+ Line = 0;
+ Column = 0;
+ return;
+ }
+ Line = PLoc.getLine();
+ Column = PLoc.getColumn();
+}
+
+// Retrieve source snippet from file image.
+static std::string getSourceString(clang::Preprocessor &PP,
+ clang::SourceRange Range) {
+ clang::SourceLocation BeginLoc = Range.getBegin();
+ clang::SourceLocation EndLoc = Range.getEnd();
+ const char *BeginPtr = PP.getSourceManager().getCharacterData(BeginLoc);
+ const char *EndPtr = PP.getSourceManager().getCharacterData(EndLoc);
+ size_t Length = EndPtr - BeginPtr;
+ return llvm::StringRef(BeginPtr, Length).trim().str();
+}
+
+// Retrieve source line from file image given a location.
+static std::string getSourceLine(clang::Preprocessor &PP,
+ clang::SourceLocation Loc) {
+ const llvm::MemoryBuffer *MemBuffer =
+ PP.getSourceManager().getBuffer(PP.getSourceManager().getFileID(Loc));
+ const char *Buffer = MemBuffer->getBufferStart();
+ const char *BufferEnd = MemBuffer->getBufferEnd();
+ const char *BeginPtr = PP.getSourceManager().getCharacterData(Loc);
+ const char *EndPtr = BeginPtr;
+ while (BeginPtr > Buffer) {
+ if (*BeginPtr == '\n') {
+ BeginPtr++;
+ break;
+ }
+ BeginPtr--;
+ }
+ while (EndPtr < BufferEnd) {
+ if (*EndPtr == '\n') {
+ break;
+ }
+ EndPtr++;
+ }
+ size_t Length = EndPtr - BeginPtr;
+ return llvm::StringRef(BeginPtr, Length).str();
+}
+
+// Retrieve source line from file image given a file ID and line number.
+static std::string getSourceLine(clang::Preprocessor &PP, clang::FileID FileID,
+ int Line) {
+ const llvm::MemoryBuffer *MemBuffer = PP.getSourceManager().getBuffer(FileID);
+ const char *Buffer = MemBuffer->getBufferStart();
+ const char *BufferEnd = MemBuffer->getBufferEnd();
+ const char *BeginPtr = Buffer;
+ const char *EndPtr = BufferEnd;
+ int LineCounter = 1;
+ if (Line == 1)
+ BeginPtr = Buffer;
+ else {
+ while (Buffer < BufferEnd) {
+ if (*Buffer == '\n') {
+ if (++LineCounter == Line) {
+ BeginPtr = Buffer++ + 1;
+ break;
+ }
+ }
+ Buffer++;
+ }
+ }
+ while (Buffer < BufferEnd) {
+ if (*Buffer == '\n') {
+ EndPtr = Buffer;
+ break;
+ }
+ Buffer++;
+ }
+ size_t Length = EndPtr - BeginPtr;
+ return llvm::StringRef(BeginPtr, Length).str();
+}
+
+// Get the string for the Unexpanded macro instance.
+// The soureRange is expected to end at the last token
+// for the macro instance, which in the case of a function-style
+// macro will be a ')', but for an object-style macro, it
+// will be the macro name itself.
+static std::string getMacroUnexpandedString(clang::SourceRange Range,
+ clang::Preprocessor &PP,
+ llvm::StringRef MacroName,
+ const clang::MacroInfo *MI) {
+ clang::SourceLocation BeginLoc(Range.getBegin());
+ const char *BeginPtr = PP.getSourceManager().getCharacterData(BeginLoc);
+ size_t Length;
+ std::string Unexpanded;
+ if (MI->isFunctionLike()) {
+ clang::SourceLocation EndLoc(Range.getEnd());
+ const char *EndPtr = PP.getSourceManager().getCharacterData(EndLoc) + 1;
+ Length = (EndPtr - BeginPtr) + 1; // +1 is ')' width.
+ } else
+ Length = MacroName.size();
+ return llvm::StringRef(BeginPtr, Length).trim().str();
+}
+
+// Get the expansion for a macro instance, given the information
+// provided by PPCallbacks.
+// FIXME: This doesn't support function-style macro instances
+// passed as arguments to another function-style macro. However,
+// since it still expands the inner arguments, it still
+// allows modularize to effectively work with respect to macro
+// consistency checking, although it displays the incorrect
+// expansion in error messages.
+static std::string getMacroExpandedString(clang::Preprocessor &PP,
+ llvm::StringRef MacroName,
+ const clang::MacroInfo *MI,
+ const clang::MacroArgs *Args) {
+ std::string Expanded;
+ // Walk over the macro Tokens.
+ for (const auto &T : MI->tokens()) {
+ clang::IdentifierInfo *II = T.getIdentifierInfo();
+ int ArgNo = (II && Args ? MI->getParameterNum(II) : -1);
+ if (ArgNo == -1) {
+ // This isn't an argument, just add it.
+ if (II == nullptr)
+ Expanded += PP.getSpelling(T); // Not an identifier.
+ else {
+ // Token is for an identifier.
+ std::string Name = II->getName().str();
+ // Check for nexted macro references.
+ clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
+ if (MacroInfo && (Name != MacroName))
+ Expanded += getMacroExpandedString(PP, Name, MacroInfo, nullptr);
+ else
+ Expanded += Name;
+ }
+ continue;
+ }
+ // We get here if it's a function-style macro with arguments.
+ const clang::Token *ResultArgToks;
+ const clang::Token *ArgTok = Args->getUnexpArgument(ArgNo);
+ if (Args->ArgNeedsPreexpansion(ArgTok, PP))
+ ResultArgToks = &(const_cast<clang::MacroArgs *>(Args))
+ ->getPreExpArgument(ArgNo, PP)[0];
+ else
+ ResultArgToks = ArgTok; // Use non-preexpanded Tokens.
+ // If the arg token didn't expand into anything, ignore it.
+ if (ResultArgToks->is(clang::tok::eof))
+ continue;
+ unsigned NumToks = clang::MacroArgs::getArgLength(ResultArgToks);
+ // Append the resulting argument expansions.
+ for (unsigned ArgumentIndex = 0; ArgumentIndex < NumToks; ++ArgumentIndex) {
+ const clang::Token &AT = ResultArgToks[ArgumentIndex];
+ clang::IdentifierInfo *II = AT.getIdentifierInfo();
+ if (II == nullptr)
+ Expanded += PP.getSpelling(AT); // Not an identifier.
+ else {
+ // It's an identifier. Check for further expansion.
+ std::string Name = II->getName().str();
+ clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
+ if (MacroInfo)
+ Expanded += getMacroExpandedString(PP, Name, MacroInfo, nullptr);
+ else
+ Expanded += Name;
+ }
+ }
+ }
+ return Expanded;
+}
+
+namespace {
+
+// ConditionValueKind strings.
+const char *
+ConditionValueKindStrings[] = {
+ "(not evaluated)", "false", "true"
+};
+
+bool operator<(const StringHandle &H1, const StringHandle &H2) {
+ const char *S1 = (H1 ? *H1 : "");
+ const char *S2 = (H2 ? *H2 : "");
+ int Diff = strcmp(S1, S2);
+ return Diff < 0;
+}
+bool operator>(const StringHandle &H1, const StringHandle &H2) {
+ const char *S1 = (H1 ? *H1 : "");
+ const char *S2 = (H2 ? *H2 : "");
+ int Diff = strcmp(S1, S2);
+ return Diff > 0;
+}
+
+// Preprocessor item key.
+//
+// This class represents a location in a source file, for use
+// as a key representing a unique name/file/line/column quadruplet,
+// which in this case is used to identify a macro expansion instance,
+// but could be used for other things as well.
+// The file is a header file handle, the line is a line number,
+// and the column is a column number.
+class PPItemKey {
+public:
+ PPItemKey(clang::Preprocessor &PP, StringHandle Name, HeaderHandle File,
+ clang::SourceLocation Loc)
+ : Name(Name), File(File) {
+ getSourceLocationLineAndColumn(PP, Loc, Line, Column);
+ }
+ PPItemKey(StringHandle Name, HeaderHandle File, int Line, int Column)
+ : Name(Name), File(File), Line(Line), Column(Column) {}
+ PPItemKey(const PPItemKey &Other)
+ : Name(Other.Name), File(Other.File), Line(Other.Line),
+ Column(Other.Column) {}
+ PPItemKey() : File(HeaderHandleInvalid), Line(0), Column(0) {}
+ bool operator==(const PPItemKey &Other) const {
+ if (Name != Other.Name)
+ return false;
+ if (File != Other.File)
+ return false;
+ if (Line != Other.Line)
+ return false;
+ return Column == Other.Column;
+ }
+ bool operator<(const PPItemKey &Other) const {
+ if (Name < Other.Name)
+ return true;
+ else if (Name > Other.Name)
+ return false;
+ if (File < Other.File)
+ return true;
+ else if (File > Other.File)
+ return false;
+ if (Line < Other.Line)
+ return true;
+ else if (Line > Other.Line)
+ return false;
+ return Column < Other.Column;
+ }
+ StringHandle Name;
+ HeaderHandle File;
+ int Line;
+ int Column;
+};
+
+// Header inclusion path.
+class HeaderInclusionPath {
+public:
+ HeaderInclusionPath(std::vector<HeaderHandle> HeaderInclusionPath)
+ : Path(HeaderInclusionPath) {}
+ HeaderInclusionPath(const HeaderInclusionPath &Other) : Path(Other.Path) {}
+ HeaderInclusionPath() {}
+ std::vector<HeaderHandle> Path;
+};
+
+// Macro expansion instance.
+//
+// This class represents an instance of a macro expansion with a
+// unique value. It also stores the unique header inclusion paths
+// for use in telling the user the nested include path to the header.
+class MacroExpansionInstance {
+public:
+ MacroExpansionInstance(StringHandle MacroExpanded,
+ PPItemKey &DefinitionLocation,
+ StringHandle DefinitionSourceLine,
+ InclusionPathHandle H)
+ : MacroExpanded(MacroExpanded), DefinitionLocation(DefinitionLocation),
+ DefinitionSourceLine(DefinitionSourceLine) {
+ InclusionPathHandles.push_back(H);
+ }
+ MacroExpansionInstance() {}
+
+ // Check for the presence of a header inclusion path handle entry.
+ // Return false if not found.
+ bool haveInclusionPathHandle(InclusionPathHandle H) {
+ for (auto I = InclusionPathHandles.begin(), E = InclusionPathHandles.end();
+ I != E; ++I) {
+ if (*I == H)
+ return true;
+ }
+ return InclusionPathHandleInvalid;
+ }
+ // Add a new header inclusion path entry, if not already present.
+ void addInclusionPathHandle(InclusionPathHandle H) {
+ if (!haveInclusionPathHandle(H))
+ InclusionPathHandles.push_back(H);
+ }
+
+ // A string representing the macro instance after preprocessing.
+ StringHandle MacroExpanded;
+ // A file/line/column triplet representing the macro definition location.
+ PPItemKey DefinitionLocation;
+ // A place to save the macro definition line string.
+ StringHandle DefinitionSourceLine;
+ // The header inclusion path handles for all the instances.
+ std::vector<InclusionPathHandle> InclusionPathHandles;
+};
+
+// Macro expansion instance tracker.
+//
+// This class represents one macro expansion, keyed by a PPItemKey.
+// It stores a string representing the macro reference in the source,
+// and a list of ConditionalExpansionInstances objects representing
+// the unique values the condition expands to in instances of the header.
+class MacroExpansionTracker {
+public:
+ MacroExpansionTracker(StringHandle MacroUnexpanded,
+ StringHandle MacroExpanded,
+ StringHandle InstanceSourceLine,
+ PPItemKey &DefinitionLocation,
+ StringHandle DefinitionSourceLine,
+ InclusionPathHandle InclusionPathHandle)
+ : MacroUnexpanded(MacroUnexpanded),
+ InstanceSourceLine(InstanceSourceLine) {
+ addMacroExpansionInstance(MacroExpanded, DefinitionLocation,
+ DefinitionSourceLine, InclusionPathHandle);
+ }
+ MacroExpansionTracker() {}
+
+ // Find a matching macro expansion instance.
+ MacroExpansionInstance *
+ findMacroExpansionInstance(StringHandle MacroExpanded,
+ PPItemKey &DefinitionLocation) {
+ for (auto I = MacroExpansionInstances.begin(),
+ E = MacroExpansionInstances.end();
+ I != E; ++I) {
+ if ((I->MacroExpanded == MacroExpanded) &&
+ (I->DefinitionLocation == DefinitionLocation)) {
+ return &*I; // Found.
+ }
+ }
+ return nullptr; // Not found.
+ }
+
+ // Add a macro expansion instance.
+ void addMacroExpansionInstance(StringHandle MacroExpanded,
+ PPItemKey &DefinitionLocation,
+ StringHandle DefinitionSourceLine,
+ InclusionPathHandle InclusionPathHandle) {
+ MacroExpansionInstances.push_back(
+ MacroExpansionInstance(MacroExpanded, DefinitionLocation,
+ DefinitionSourceLine, InclusionPathHandle));
+ }
+
+ // Return true if there is a mismatch.
+ bool hasMismatch() { return MacroExpansionInstances.size() > 1; }
+
+ // A string representing the macro instance without expansion.
+ StringHandle MacroUnexpanded;
+ // A place to save the macro instance source line string.
+ StringHandle InstanceSourceLine;
+ // The macro expansion instances.
+ // If all instances of the macro expansion expand to the same value,
+ // This vector will only have one instance.
+ std::vector<MacroExpansionInstance> MacroExpansionInstances;
+};
+
+// Conditional expansion instance.
+//
+// This class represents an instance of a condition exoression result
+// with a unique value. It also stores the unique header inclusion paths
+// for use in telling the user the nested include path to the header.
+class ConditionalExpansionInstance {
+public:
+ ConditionalExpansionInstance(clang::PPCallbacks::ConditionValueKind ConditionValue, InclusionPathHandle H)
+ : ConditionValue(ConditionValue) {
+ InclusionPathHandles.push_back(H);
+ }
+ ConditionalExpansionInstance() {}
+
+ // Check for the presence of a header inclusion path handle entry.
+ // Return false if not found.
+ bool haveInclusionPathHandle(InclusionPathHandle H) {
+ for (auto I = InclusionPathHandles.begin(), E = InclusionPathHandles.end();
+ I != E; ++I) {
+ if (*I == H)
+ return true;
+ }
+ return InclusionPathHandleInvalid;
+ }
+ // Add a new header inclusion path entry, if not already present.
+ void addInclusionPathHandle(InclusionPathHandle H) {
+ if (!haveInclusionPathHandle(H))
+ InclusionPathHandles.push_back(H);
+ }
+
+ // A flag representing the evaluated condition value.
+ clang::PPCallbacks::ConditionValueKind ConditionValue;
+ // The header inclusion path handles for all the instances.
+ std::vector<InclusionPathHandle> InclusionPathHandles;
+};
+
+// Conditional directive instance tracker.
+//
+// This class represents one conditional directive, keyed by a PPItemKey.
+// It stores a string representing the macro reference in the source,
+// and a list of ConditionExpansionInstance objects representing
+// the unique value the condition expression expands to in instances of
+// the header.
+class ConditionalTracker {
+public:
+ ConditionalTracker(clang::tok::PPKeywordKind DirectiveKind,
+ clang::PPCallbacks::ConditionValueKind ConditionValue,
+ StringHandle ConditionUnexpanded,
+ InclusionPathHandle InclusionPathHandle)
+ : DirectiveKind(DirectiveKind), ConditionUnexpanded(ConditionUnexpanded) {
+ addConditionalExpansionInstance(ConditionValue, InclusionPathHandle);
+ }
+ ConditionalTracker() {}
+
+ // Find a matching condition expansion instance.
+ ConditionalExpansionInstance *
+ findConditionalExpansionInstance(clang::PPCallbacks::ConditionValueKind ConditionValue) {
+ for (auto I = ConditionalExpansionInstances.begin(),
+ E = ConditionalExpansionInstances.end();
+ I != E; ++I) {
+ if (I->ConditionValue == ConditionValue) {
+ return &*I; // Found.
+ }
+ }
+ return nullptr; // Not found.
+ }
+
+ // Add a conditional expansion instance.
+ void
+ addConditionalExpansionInstance(clang::PPCallbacks::ConditionValueKind ConditionValue,
+ InclusionPathHandle InclusionPathHandle) {
+ ConditionalExpansionInstances.push_back(
+ ConditionalExpansionInstance(ConditionValue, InclusionPathHandle));
+ }
+
+ // Return true if there is a mismatch.
+ bool hasMismatch() { return ConditionalExpansionInstances.size() > 1; }
+
+ // The kind of directive.
+ clang::tok::PPKeywordKind DirectiveKind;
+ // A string representing the macro instance without expansion.
+ StringHandle ConditionUnexpanded;
+ // The condition expansion instances.
+ // If all instances of the conditional expression expand to the same value,
+ // This vector will only have one instance.
+ std::vector<ConditionalExpansionInstance> ConditionalExpansionInstances;
+};
+
+class PreprocessorTrackerImpl;
+
+// Preprocessor callbacks for modularize.
+//
+// This class derives from the Clang PPCallbacks class to track preprocessor
+// actions, such as changing files and handling preprocessor directives and
+// macro expansions. It has to figure out when a new header file is entered
+// and left, as the provided handler is not particularly clear about it.
+class PreprocessorCallbacks : public clang::PPCallbacks {
+public:
+ PreprocessorCallbacks(PreprocessorTrackerImpl &ppTracker,
+ clang::Preprocessor &PP, llvm::StringRef rootHeaderFile)
+ : PPTracker(ppTracker), PP(PP), RootHeaderFile(rootHeaderFile) {}
+ ~PreprocessorCallbacks() override {}
+
+ // Overridden handlers.
+ void InclusionDirective(clang::SourceLocation HashLoc,
+ const clang::Token &IncludeTok,
+ llvm::StringRef FileName, bool IsAngled,
+ clang::CharSourceRange FilenameRange,
+ const clang::FileEntry *File,
+ llvm::StringRef SearchPath,
+ llvm::StringRef RelativePath,
+ const clang::Module *Imported,
+ clang::SrcMgr::CharacteristicKind FileType) override;
+ void FileChanged(clang::SourceLocation Loc,
+ clang::PPCallbacks::FileChangeReason Reason,
+ clang::SrcMgr::CharacteristicKind FileType,
+ clang::FileID PrevFID = clang::FileID()) override;
+ void MacroExpands(const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MD, clang::SourceRange Range,
+ const clang::MacroArgs *Args) override;
+ void Defined(const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MD,
+ clang::SourceRange Range) override;
+ void If(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
+ clang::PPCallbacks::ConditionValueKind ConditionResult) override;
+ void Elif(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
+ clang::PPCallbacks::ConditionValueKind ConditionResult,
+ clang::SourceLocation IfLoc) override;
+ void Ifdef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MD) override;
+ void Ifndef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MD) override;
+
+private:
+ PreprocessorTrackerImpl &PPTracker;
+ clang::Preprocessor &PP;
+ std::string RootHeaderFile;
+};
+
+// Preprocessor macro expansion item map types.
+typedef std::map<PPItemKey, MacroExpansionTracker> MacroExpansionMap;
+typedef std::map<PPItemKey, MacroExpansionTracker>::iterator
+MacroExpansionMapIter;
+
+// Preprocessor conditional expansion item map types.
+typedef std::map<PPItemKey, ConditionalTracker> ConditionalExpansionMap;
+typedef std::map<PPItemKey, ConditionalTracker>::iterator
+ConditionalExpansionMapIter;
+
+// Preprocessor tracker for modularize.
+//
+// This class stores information about all the headers processed in the
+// course of running modularize.
+class PreprocessorTrackerImpl : public PreprocessorTracker {
+public:
+ PreprocessorTrackerImpl(llvm::SmallVector<std::string, 32> &Headers,
+ bool DoBlockCheckHeaderListOnly)
+ : BlockCheckHeaderListOnly(DoBlockCheckHeaderListOnly),
+ CurrentInclusionPathHandle(InclusionPathHandleInvalid),
+ InNestedHeader(false) {
+ // Use canonical header path representation.
+ for (llvm::ArrayRef<std::string>::iterator I = Headers.begin(),
+ E = Headers.end();
+ I != E; ++I) {
+ HeaderList.push_back(getCanonicalPath(*I));
+ }
+ }
+
+ ~PreprocessorTrackerImpl() override {}
+
+ // Handle entering a preprocessing session.
+ void handlePreprocessorEntry(clang::Preprocessor &PP,
+ llvm::StringRef rootHeaderFile) override {
+ HeadersInThisCompile.clear();
+ assert((HeaderStack.size() == 0) && "Header stack should be empty.");
+ pushHeaderHandle(addHeader(rootHeaderFile));
+ PP.addPPCallbacks(llvm::make_unique<PreprocessorCallbacks>(*this, PP,
+ rootHeaderFile));
+ }
+ // Handle exiting a preprocessing session.
+ void handlePreprocessorExit() override { HeaderStack.clear(); }
+
+ // Handle include directive.
+ // This function is called every time an include directive is seen by the
+ // preprocessor, for the purpose of later checking for 'extern "" {}' or
+ // "namespace {}" blocks containing #include directives.
+ void handleIncludeDirective(llvm::StringRef DirectivePath, int DirectiveLine,
+ int DirectiveColumn,
+ llvm::StringRef TargetPath) override {
+ // If it's not a header in the header list, ignore it with respect to
+ // the check.
+ if (BlockCheckHeaderListOnly && !isHeaderListHeader(TargetPath))
+ return;
+ HeaderHandle CurrentHeaderHandle = findHeaderHandle(DirectivePath);
+ StringHandle IncludeHeaderHandle = addString(TargetPath);
+ for (std::vector<PPItemKey>::const_iterator I = IncludeDirectives.begin(),
+ E = IncludeDirectives.end();
+ I != E; ++I) {
+ // If we already have an entry for this directive, return now.
+ if ((I->File == CurrentHeaderHandle) && (I->Line == DirectiveLine))
+ return;
+ }
+ PPItemKey IncludeDirectiveItem(IncludeHeaderHandle, CurrentHeaderHandle,
+ DirectiveLine, DirectiveColumn);
+ IncludeDirectives.push_back(IncludeDirectiveItem);
+ }
+
+ // Check for include directives within the given source line range.
+ // Report errors if any found. Returns true if no include directives
+ // found in block.
+ bool checkForIncludesInBlock(clang::Preprocessor &PP,
+ clang::SourceRange BlockSourceRange,
+ const char *BlockIdentifierMessage,
+ llvm::raw_ostream &OS) override {
+ clang::SourceLocation BlockStartLoc = BlockSourceRange.getBegin();
+ clang::SourceLocation BlockEndLoc = BlockSourceRange.getEnd();
+ // Use block location to get FileID of both the include directive
+ // and block statement.
+ clang::FileID FileID = PP.getSourceManager().getFileID(BlockStartLoc);
+ std::string SourcePath = getSourceLocationFile(PP, BlockStartLoc);
+ SourcePath = ModularizeUtilities::getCanonicalPath(SourcePath);
+ HeaderHandle SourceHandle = findHeaderHandle(SourcePath);
+ if (SourceHandle == -1)
+ return true;
+ int BlockStartLine, BlockStartColumn, BlockEndLine, BlockEndColumn;
+ bool returnValue = true;
+ getSourceLocationLineAndColumn(PP, BlockStartLoc, BlockStartLine,
+ BlockStartColumn);
+ getSourceLocationLineAndColumn(PP, BlockEndLoc, BlockEndLine,
+ BlockEndColumn);
+ for (std::vector<PPItemKey>::const_iterator I = IncludeDirectives.begin(),
+ E = IncludeDirectives.end();
+ I != E; ++I) {
+ // If we find an entry within the block, report an error.
+ if ((I->File == SourceHandle) && (I->Line >= BlockStartLine) &&
+ (I->Line < BlockEndLine)) {
+ returnValue = false;
+ OS << SourcePath << ":" << I->Line << ":" << I->Column << ":\n";
+ OS << getSourceLine(PP, FileID, I->Line) << "\n";
+ if (I->Column > 0)
+ OS << std::string(I->Column - 1, ' ') << "^\n";
+ OS << "error: Include directive within " << BlockIdentifierMessage
+ << ".\n";
+ OS << SourcePath << ":" << BlockStartLine << ":" << BlockStartColumn
+ << ":\n";
+ OS << getSourceLine(PP, BlockStartLoc) << "\n";
+ if (BlockStartColumn > 0)
+ OS << std::string(BlockStartColumn - 1, ' ') << "^\n";
+ OS << "The \"" << BlockIdentifierMessage << "\" block is here.\n";
+ }
+ }
+ return returnValue;
+ }
+
+ // Handle entering a header source file.
+ void handleHeaderEntry(clang::Preprocessor &PP, llvm::StringRef HeaderPath) {
+ // Ignore <built-in> and <command-line> to reduce message clutter.
+ if (HeaderPath.startswith("<"))
+ return;
+ HeaderHandle H = addHeader(HeaderPath);
+ if (H != getCurrentHeaderHandle())
+ pushHeaderHandle(H);
+ // Check for nested header.
+ if (!InNestedHeader)
+ InNestedHeader = !HeadersInThisCompile.insert(H).second;
+ }
+
+ // Handle exiting a header source file.
+ void handleHeaderExit(llvm::StringRef HeaderPath) {
+ // Ignore <built-in> and <command-line> to reduce message clutter.
+ if (HeaderPath.startswith("<"))
+ return;
+ HeaderHandle H = findHeaderHandle(HeaderPath);
+ HeaderHandle TH;
+ if (isHeaderHandleInStack(H)) {
+ do {
+ TH = getCurrentHeaderHandle();
+ popHeaderHandle();
+ } while ((TH != H) && (HeaderStack.size() != 0));
+ }
+ InNestedHeader = false;
+ }
+
+ // Lookup/add string.
+ StringHandle addString(llvm::StringRef Str) { return Strings.intern(Str); }
+
+ // Convert to a canonical path.
+ std::string getCanonicalPath(llvm::StringRef path) const {
+ std::string CanonicalPath(path);
+ std::replace(CanonicalPath.begin(), CanonicalPath.end(), '\\', '/');
+ return CanonicalPath;
+ }
+
+ // Return true if the given header is in the header list.
+ bool isHeaderListHeader(llvm::StringRef HeaderPath) const {
+ std::string CanonicalPath = getCanonicalPath(HeaderPath);
+ for (llvm::ArrayRef<std::string>::iterator I = HeaderList.begin(),
+ E = HeaderList.end();
+ I != E; ++I) {
+ if (*I == CanonicalPath)
+ return true;
+ }
+ return false;
+ }
+
+ // Get the handle of a header file entry.
+ // Return HeaderHandleInvalid if not found.
+ HeaderHandle findHeaderHandle(llvm::StringRef HeaderPath) const {
+ std::string CanonicalPath = getCanonicalPath(HeaderPath);
+ HeaderHandle H = 0;
+ for (auto I = HeaderPaths.begin(), E = HeaderPaths.end(); I != E;
+ ++I, ++H) {
+ if (**I == CanonicalPath)
+ return H;
+ }
+ return HeaderHandleInvalid;
+ }
+
+ // Add a new header file entry, or return existing handle.
+ // Return the header handle.
+ HeaderHandle addHeader(llvm::StringRef HeaderPath) {
+ std::string CanonicalPath = getCanonicalPath(HeaderPath);
+ HeaderHandle H = findHeaderHandle(CanonicalPath);
+ if (H == HeaderHandleInvalid) {
+ H = HeaderPaths.size();
+ HeaderPaths.push_back(addString(CanonicalPath));
+ }
+ return H;
+ }
+
+ // Return a header file path string given its handle.
+ StringHandle getHeaderFilePath(HeaderHandle H) const {
+ if ((H >= 0) && (H < (HeaderHandle)HeaderPaths.size()))
+ return HeaderPaths[H];
+ return StringHandle();
+ }
+
+ // Returns a handle to the inclusion path.
+ InclusionPathHandle pushHeaderHandle(HeaderHandle H) {
+ HeaderStack.push_back(H);
+ return CurrentInclusionPathHandle = addInclusionPathHandle(HeaderStack);
+ }
+ // Pops the last header handle from the stack;
+ void popHeaderHandle() {
+ // assert((HeaderStack.size() != 0) && "Header stack already empty.");
+ if (HeaderStack.size() != 0) {
+ HeaderStack.pop_back();
+ CurrentInclusionPathHandle = addInclusionPathHandle(HeaderStack);
+ }
+ }
+ // Get the top handle on the header stack.
+ HeaderHandle getCurrentHeaderHandle() const {
+ if (HeaderStack.size() != 0)
+ return HeaderStack.back();
+ return HeaderHandleInvalid;
+ }
+
+ // Check for presence of header handle in the header stack.
+ bool isHeaderHandleInStack(HeaderHandle H) const {
+ for (auto I = HeaderStack.begin(), E = HeaderStack.end(); I != E; ++I) {
+ if (*I == H)
+ return true;
+ }
+ return false;
+ }
+
+ // Get the handle of a header inclusion path entry.
+ // Return InclusionPathHandleInvalid if not found.
+ InclusionPathHandle
+ findInclusionPathHandle(const std::vector<HeaderHandle> &Path) const {
+ InclusionPathHandle H = 0;
+ for (auto I = InclusionPaths.begin(), E = InclusionPaths.end(); I != E;
+ ++I, ++H) {
+ if (I->Path == Path)
+ return H;
+ }
+ return HeaderHandleInvalid;
+ }
+ // Add a new header inclusion path entry, or return existing handle.
+ // Return the header inclusion path entry handle.
+ InclusionPathHandle
+ addInclusionPathHandle(const std::vector<HeaderHandle> &Path) {
+ InclusionPathHandle H = findInclusionPathHandle(Path);
+ if (H == HeaderHandleInvalid) {
+ H = InclusionPaths.size();
+ InclusionPaths.push_back(HeaderInclusionPath(Path));
+ }
+ return H;
+ }
+ // Return the current inclusion path handle.
+ InclusionPathHandle getCurrentInclusionPathHandle() const {
+ return CurrentInclusionPathHandle;
+ }
+
+ // Return an inclusion path given its handle.
+ const std::vector<HeaderHandle> &
+ getInclusionPath(InclusionPathHandle H) const {
+ if ((H >= 0) && (H <= (InclusionPathHandle)InclusionPaths.size()))
+ return InclusionPaths[H].Path;
+ static std::vector<HeaderHandle> Empty;
+ return Empty;
+ }
+
+ // Add a macro expansion instance.
+ void addMacroExpansionInstance(clang::Preprocessor &PP, HeaderHandle H,
+ clang::SourceLocation InstanceLoc,
+ clang::SourceLocation DefinitionLoc,
+ clang::IdentifierInfo *II,
+ llvm::StringRef MacroUnexpanded,
+ llvm::StringRef MacroExpanded,
+ InclusionPathHandle InclusionPathHandle) {
+ if (InNestedHeader)
+ return;
+ StringHandle MacroName = addString(II->getName());
+ PPItemKey InstanceKey(PP, MacroName, H, InstanceLoc);
+ PPItemKey DefinitionKey(PP, MacroName, H, DefinitionLoc);
+ auto I = MacroExpansions.find(InstanceKey);
+ // If existing instance of expansion not found, add one.
+ if (I == MacroExpansions.end()) {
+ std::string InstanceSourceLine =
+ getSourceLocationString(PP, InstanceLoc) + ":\n" +
+ getSourceLine(PP, InstanceLoc) + "\n";
+ std::string DefinitionSourceLine =
+ getSourceLocationString(PP, DefinitionLoc) + ":\n" +
+ getSourceLine(PP, DefinitionLoc) + "\n";
+ MacroExpansions[InstanceKey] = MacroExpansionTracker(
+ addString(MacroUnexpanded), addString(MacroExpanded),
+ addString(InstanceSourceLine), DefinitionKey,
+ addString(DefinitionSourceLine), InclusionPathHandle);
+ } else {
+ // We've seen the macro before. Get its tracker.
+ MacroExpansionTracker &CondTracker = I->second;
+ // Look up an existing instance value for the macro.
+ MacroExpansionInstance *MacroInfo =
+ CondTracker.findMacroExpansionInstance(addString(MacroExpanded),
+ DefinitionKey);
+ // If found, just add the inclusion path to the instance.
+ if (MacroInfo)
+ MacroInfo->addInclusionPathHandle(InclusionPathHandle);
+ else {
+ // Otherwise add a new instance with the unique value.
+ std::string DefinitionSourceLine =
+ getSourceLocationString(PP, DefinitionLoc) + ":\n" +
+ getSourceLine(PP, DefinitionLoc) + "\n";
+ CondTracker.addMacroExpansionInstance(
+ addString(MacroExpanded), DefinitionKey,
+ addString(DefinitionSourceLine), InclusionPathHandle);
+ }
+ }
+ }
+
+ // Add a conditional expansion instance.
+ void
+ addConditionalExpansionInstance(clang::Preprocessor &PP, HeaderHandle H,
+ clang::SourceLocation InstanceLoc,
+ clang::tok::PPKeywordKind DirectiveKind,
+ clang::PPCallbacks::ConditionValueKind ConditionValue,
+ llvm::StringRef ConditionUnexpanded,
+ InclusionPathHandle InclusionPathHandle) {
+ // Ignore header guards, assuming the header guard is the only conditional.
+ if (InNestedHeader)
+ return;
+ StringHandle ConditionUnexpandedHandle(addString(ConditionUnexpanded));
+ PPItemKey InstanceKey(PP, ConditionUnexpandedHandle, H, InstanceLoc);
+ auto I = ConditionalExpansions.find(InstanceKey);
+ // If existing instance of condition not found, add one.
+ if (I == ConditionalExpansions.end()) {
+ std::string InstanceSourceLine =
+ getSourceLocationString(PP, InstanceLoc) + ":\n" +
+ getSourceLine(PP, InstanceLoc) + "\n";
+ ConditionalExpansions[InstanceKey] =
+ ConditionalTracker(DirectiveKind, ConditionValue,
+ ConditionUnexpandedHandle, InclusionPathHandle);
+ } else {
+ // We've seen the conditional before. Get its tracker.
+ ConditionalTracker &CondTracker = I->second;
+ // Look up an existing instance value for the condition.
+ ConditionalExpansionInstance *MacroInfo =
+ CondTracker.findConditionalExpansionInstance(ConditionValue);
+ // If found, just add the inclusion path to the instance.
+ if (MacroInfo)
+ MacroInfo->addInclusionPathHandle(InclusionPathHandle);
+ else {
+ // Otherwise add a new instance with the unique value.
+ CondTracker.addConditionalExpansionInstance(ConditionValue,
+ InclusionPathHandle);
+ }
+ }
+ }
+
+ // Report on inconsistent macro instances.
+ // Returns true if any mismatches.
+ bool reportInconsistentMacros(llvm::raw_ostream &OS) override {
+ bool ReturnValue = false;
+ // Walk all the macro expansion trackers in the map.
+ for (auto I = MacroExpansions.begin(), E = MacroExpansions.end(); I != E;
+ ++I) {
+ const PPItemKey &ItemKey = I->first;
+ MacroExpansionTracker &MacroExpTracker = I->second;
+ // If no mismatch (only one instance value) continue.
+ if (!MacroExpTracker.hasMismatch())
+ continue;
+ // Tell caller we found one or more errors.
+ ReturnValue = true;
+ // Start the error message.
+ OS << *MacroExpTracker.InstanceSourceLine;
+ if (ItemKey.Column > 0)
+ OS << std::string(ItemKey.Column - 1, ' ') << "^\n";
+ OS << "error: Macro instance '" << *MacroExpTracker.MacroUnexpanded
+ << "' has different values in this header, depending on how it was "
+ "included.\n";
+ // Walk all the instances.
+ for (auto IMT = MacroExpTracker.MacroExpansionInstances.begin(),
+ EMT = MacroExpTracker.MacroExpansionInstances.end();
+ IMT != EMT; ++IMT) {
+ MacroExpansionInstance &MacroInfo = *IMT;
+ OS << " '" << *MacroExpTracker.MacroUnexpanded << "' expanded to: '"
+ << *MacroInfo.MacroExpanded
+ << "' with respect to these inclusion paths:\n";
+ // Walk all the inclusion path hierarchies.
+ for (auto IIP = MacroInfo.InclusionPathHandles.begin(),
+ EIP = MacroInfo.InclusionPathHandles.end();
+ IIP != EIP; ++IIP) {
+ const std::vector<HeaderHandle> &ip = getInclusionPath(*IIP);
+ auto Count = (int)ip.size();
+ for (int Index = 0; Index < Count; ++Index) {
+ HeaderHandle H = ip[Index];
+ OS << std::string((Index * 2) + 4, ' ') << *getHeaderFilePath(H)
+ << "\n";
+ }
+ }
+ // For a macro that wasn't defined, we flag it by using the
+ // instance location.
+ // If there is a definition...
+ if (MacroInfo.DefinitionLocation.Line != ItemKey.Line) {
+ OS << *MacroInfo.DefinitionSourceLine;
+ if (MacroInfo.DefinitionLocation.Column > 0)
+ OS << std::string(MacroInfo.DefinitionLocation.Column - 1, ' ')
+ << "^\n";
+ OS << "Macro defined here.\n";
+ } else
+ OS << "(no macro definition)"
+ << "\n";
+ }
+ }
+ return ReturnValue;
+ }
+
+ // Report on inconsistent conditional instances.
+ // Returns true if any mismatches.
+ bool reportInconsistentConditionals(llvm::raw_ostream &OS) override {
+ bool ReturnValue = false;
+ // Walk all the conditional trackers in the map.
+ for (auto I = ConditionalExpansions.begin(),
+ E = ConditionalExpansions.end();
+ I != E; ++I) {
+ const PPItemKey &ItemKey = I->first;
+ ConditionalTracker &CondTracker = I->second;
+ if (!CondTracker.hasMismatch())
+ continue;
+ // Tell caller we found one or more errors.
+ ReturnValue = true;
+ // Start the error message.
+ OS << *HeaderPaths[ItemKey.File] << ":" << ItemKey.Line << ":"
+ << ItemKey.Column << "\n";
+ OS << "#" << getDirectiveSpelling(CondTracker.DirectiveKind) << " "
+ << *CondTracker.ConditionUnexpanded << "\n";
+ OS << "^\n";
+ OS << "error: Conditional expression instance '"
+ << *CondTracker.ConditionUnexpanded
+ << "' has different values in this header, depending on how it was "
+ "included.\n";
+ // Walk all the instances.
+ for (auto IMT = CondTracker.ConditionalExpansionInstances.begin(),
+ EMT = CondTracker.ConditionalExpansionInstances.end();
+ IMT != EMT; ++IMT) {
+ ConditionalExpansionInstance &MacroInfo = *IMT;
+ OS << " '" << *CondTracker.ConditionUnexpanded << "' expanded to: '"
+ << ConditionValueKindStrings[MacroInfo.ConditionValue]
+ << "' with respect to these inclusion paths:\n";
+ // Walk all the inclusion path hierarchies.
+ for (auto IIP = MacroInfo.InclusionPathHandles.begin(),
+ EIP = MacroInfo.InclusionPathHandles.end();
+ IIP != EIP; ++IIP) {
+ const std::vector<HeaderHandle> &ip = getInclusionPath(*IIP);
+ auto Count = (int)ip.size();
+ for (int Index = 0; Index < Count; ++Index) {
+ HeaderHandle H = ip[Index];
+ OS << std::string((Index * 2) + 4, ' ') << *getHeaderFilePath(H)
+ << "\n";
+ }
+ }
+ }
+ }
+ return ReturnValue;
+ }
+
+ // Get directive spelling.
+ static const char *getDirectiveSpelling(clang::tok::PPKeywordKind kind) {
+ switch (kind) {
+ case clang::tok::pp_if:
+ return "if";
+ case clang::tok::pp_elif:
+ return "elif";
+ case clang::tok::pp_ifdef:
+ return "ifdef";
+ case clang::tok::pp_ifndef:
+ return "ifndef";
+ default:
+ return "(unknown)";
+ }
+ }
+
+private:
+ llvm::SmallVector<std::string, 32> HeaderList;
+ // Only do extern, namespace check for headers in HeaderList.
+ bool BlockCheckHeaderListOnly;
+ llvm::StringPool Strings;
+ std::vector<StringHandle> HeaderPaths;
+ std::vector<HeaderHandle> HeaderStack;
+ std::vector<HeaderInclusionPath> InclusionPaths;
+ InclusionPathHandle CurrentInclusionPathHandle;
+ llvm::SmallSet<HeaderHandle, 32> HeadersInThisCompile;
+ std::vector<PPItemKey> IncludeDirectives;
+ MacroExpansionMap MacroExpansions;
+ ConditionalExpansionMap ConditionalExpansions;
+ bool InNestedHeader;
+};
+
+} // namespace
+
+// PreprocessorTracker functions.
+
+// PreprocessorTracker desctructor.
+PreprocessorTracker::~PreprocessorTracker() {}
+
+// Create instance of PreprocessorTracker.
+PreprocessorTracker *PreprocessorTracker::create(
+ llvm::SmallVector<std::string, 32> &Headers,
+ bool DoBlockCheckHeaderListOnly) {
+ return new PreprocessorTrackerImpl(Headers, DoBlockCheckHeaderListOnly);
+}
+
+// Preprocessor callbacks for modularize.
+
+// Handle include directive.
+void PreprocessorCallbacks::InclusionDirective(
+ clang::SourceLocation HashLoc, const clang::Token &IncludeTok,
+ llvm::StringRef FileName, bool IsAngled,
+ clang::CharSourceRange FilenameRange, const clang::FileEntry *File,
+ llvm::StringRef SearchPath, llvm::StringRef RelativePath,
+ const clang::Module *Imported, clang::SrcMgr::CharacteristicKind FileType) {
+ int DirectiveLine, DirectiveColumn;
+ std::string HeaderPath = getSourceLocationFile(PP, HashLoc);
+ getSourceLocationLineAndColumn(PP, HashLoc, DirectiveLine, DirectiveColumn);
+ PPTracker.handleIncludeDirective(HeaderPath, DirectiveLine, DirectiveColumn,
+ FileName);
+}
+
+// Handle file entry/exit.
+void PreprocessorCallbacks::FileChanged(
+ clang::SourceLocation Loc, clang::PPCallbacks::FileChangeReason Reason,
+ clang::SrcMgr::CharacteristicKind FileType, clang::FileID PrevFID) {
+ switch (Reason) {
+ case EnterFile:
+ PPTracker.handleHeaderEntry(PP, getSourceLocationFile(PP, Loc));
+ break;
+ case ExitFile: {
+ const clang::FileEntry *F =
+ PP.getSourceManager().getFileEntryForID(PrevFID);
+ if (F)
+ PPTracker.handleHeaderExit(F->getName());
+ } break;
+ case SystemHeaderPragma:
+ case RenameFile:
+ break;
+ }
+}
+
+// Handle macro expansion.
+void PreprocessorCallbacks::MacroExpands(const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MD,
+ clang::SourceRange Range,
+ const clang::MacroArgs *Args) {
+ clang::SourceLocation Loc = Range.getBegin();
+ // Ignore macro argument expansions.
+ if (!Loc.isFileID())
+ return;
+ clang::IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
+ const clang::MacroInfo *MI = MD.getMacroInfo();
+ std::string MacroName = II->getName().str();
+ std::string Unexpanded(getMacroUnexpandedString(Range, PP, MacroName, MI));
+ std::string Expanded(getMacroExpandedString(PP, MacroName, MI, Args));
+ PPTracker.addMacroExpansionInstance(
+ PP, PPTracker.getCurrentHeaderHandle(), Loc, MI->getDefinitionLoc(), II,
+ Unexpanded, Expanded, PPTracker.getCurrentInclusionPathHandle());
+}
+
+void PreprocessorCallbacks::Defined(const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MD,
+ clang::SourceRange Range) {
+ clang::SourceLocation Loc(Range.getBegin());
+ clang::IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
+ const clang::MacroInfo *MI = MD.getMacroInfo();
+ std::string MacroName = II->getName().str();
+ std::string Unexpanded(getSourceString(PP, Range));
+ PPTracker.addMacroExpansionInstance(
+ PP, PPTracker.getCurrentHeaderHandle(), Loc,
+ (MI ? MI->getDefinitionLoc() : Loc), II, Unexpanded,
+ (MI ? "true" : "false"), PPTracker.getCurrentInclusionPathHandle());
+}
+
+void PreprocessorCallbacks::If(clang::SourceLocation Loc,
+ clang::SourceRange ConditionRange,
+ clang::PPCallbacks::ConditionValueKind ConditionResult) {
+ std::string Unexpanded(getSourceString(PP, ConditionRange));
+ PPTracker.addConditionalExpansionInstance(
+ PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_if,
+ ConditionResult, Unexpanded, PPTracker.getCurrentInclusionPathHandle());
+}
+
+void PreprocessorCallbacks::Elif(clang::SourceLocation Loc,
+ clang::SourceRange ConditionRange,
+ clang::PPCallbacks::ConditionValueKind ConditionResult,
+ clang::SourceLocation IfLoc) {
+ std::string Unexpanded(getSourceString(PP, ConditionRange));
+ PPTracker.addConditionalExpansionInstance(
+ PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_elif,
+ ConditionResult, Unexpanded, PPTracker.getCurrentInclusionPathHandle());
+}
+
+void PreprocessorCallbacks::Ifdef(clang::SourceLocation Loc,
+ const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MD) {
+ clang::PPCallbacks::ConditionValueKind IsDefined =
+ (MD ? clang::PPCallbacks::CVK_True : clang::PPCallbacks::CVK_False );
+ PPTracker.addConditionalExpansionInstance(
+ PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_ifdef,
+ IsDefined, PP.getSpelling(MacroNameTok),
+ PPTracker.getCurrentInclusionPathHandle());
+}
+
+void PreprocessorCallbacks::Ifndef(clang::SourceLocation Loc,
+ const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MD) {
+ clang::PPCallbacks::ConditionValueKind IsNotDefined =
+ (!MD ? clang::PPCallbacks::CVK_True : clang::PPCallbacks::CVK_False );
+ PPTracker.addConditionalExpansionInstance(
+ PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_ifndef,
+ IsNotDefined, PP.getSpelling(MacroNameTok),
+ PPTracker.getCurrentInclusionPathHandle());
+}
+} // end namespace Modularize
diff --git a/src/third_party/llvm-project/clang-tools-extra/modularize/PreprocessorTracker.h b/src/third_party/llvm-project/clang-tools-extra/modularize/PreprocessorTracker.h
new file mode 100644
index 0000000..a283d9f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/modularize/PreprocessorTracker.h
@@ -0,0 +1,87 @@
+//===- PreprocessorTracker.h - Tracks preprocessor activities -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Macro expansions and preprocessor conditional consistency checker.
+///
+//===--------------------------------------------------------------------===//
+
+#ifndef MODULARIZE_PREPROCESSOR_TRACKER_H
+#define MODULARIZE_PREPROCESSOR_TRACKER_H
+
+#include "clang/Lex/Preprocessor.h"
+
+namespace Modularize {
+
+/// \brief Preprocessor tracker for modularize.
+///
+/// The PreprocessorTracker class defines an API for
+/// checking macro expansions and preprocessor conditional expressions
+/// in a header file for consistency among one or more compilations of
+/// the header in a #include scenario. This is for helping a user
+/// find which macro expansions or conditionals might be problematic with
+/// respect to using the headers in the modules scenario, because they
+/// evaluate to different values depending on how or where a header
+/// is included.
+///
+/// The handlePreprocessorEntry function implementation will register
+/// a PPCallbacks object in the given Preprocessor object. The calls to
+/// the callbacks will collect information about the macro expansions
+/// and preprocessor conditionals encountered, for later analysis and
+/// reporting of inconsistencies between runs performed by calls to
+/// the reportInconsistentMacros and reportInconsistentConditionals
+/// functions respectively. The handlePreprocessorExit informs the
+/// implementation that a preprocessing session is complete, allowing
+/// it to do any needed compilation completion activities in the checker.
+class PreprocessorTracker {
+public:
+ virtual ~PreprocessorTracker();
+
+ // Handle entering a preprocessing session.
+ // (Called after a Preprocessor object is created, but before preprocessing.)
+ virtual void handlePreprocessorEntry(clang::Preprocessor &PP,
+ llvm::StringRef RootHeaderFile) = 0;
+ // Handle exiting a preprocessing session.
+ // (Called after preprocessing is complete, but before the Preprocessor
+ // object is destroyed.)
+ virtual void handlePreprocessorExit() = 0;
+
+ // Handle include directive.
+ // This function is called every time an include directive is seen by the
+ // preprocessor, for the purpose of later checking for 'extern "" {}' or
+ // "namespace {}" blocks containing #include directives.
+ virtual void handleIncludeDirective(llvm::StringRef DirectivePath,
+ int DirectiveLine, int DirectiveColumn,
+ llvm::StringRef TargetPath) = 0;
+
+ // Check for include directives within the given source line range.
+ // Report errors if any found. Returns true if no include directives
+ // found in block.
+ virtual bool checkForIncludesInBlock(clang::Preprocessor &PP,
+ clang::SourceRange BlockSourceRange,
+ const char *BlockIdentifierMessage,
+ llvm::raw_ostream &OS) = 0;
+
+ // Report on inconsistent macro instances.
+ // Returns true if any mismatches.
+ virtual bool reportInconsistentMacros(llvm::raw_ostream &OS) = 0;
+
+ // Report on inconsistent conditional directive instances.
+ // Returns true if any mismatches.
+ virtual bool reportInconsistentConditionals(llvm::raw_ostream &OS) = 0;
+
+ // Create instance of PreprocessorTracker.
+ static PreprocessorTracker *create(
+ llvm::SmallVector<std::string, 32> &Headers,
+ bool DoBlockCheckHeaderListOnly);
+};
+
+} // end namespace Modularize
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/pp-trace/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/pp-trace/CMakeLists.txt
new file mode 100644
index 0000000..fbbe865
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/pp-trace/CMakeLists.txt
@@ -0,0 +1,17 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_executable(pp-trace
+ PPTrace.cpp
+ PPCallbacksTracker.cpp
+ )
+
+target_link_libraries(pp-trace
+ PRIVATE
+ clangAST
+ clangBasic
+ clangFrontend
+ clangLex
+ clangTooling
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/pp-trace/PPCallbacksTracker.cpp b/src/third_party/llvm-project/clang-tools-extra/pp-trace/PPCallbacksTracker.cpp
new file mode 100644
index 0000000..2530dc2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/pp-trace/PPCallbacksTracker.cpp
@@ -0,0 +1,654 @@
+//===--- PPCallbacksTracker.cpp - Preprocessor tracker -*--*---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Implementations for preprocessor tracking.
+///
+/// See the header for details.
+///
+//===----------------------------------------------------------------------===//
+
+#include "PPCallbacksTracker.h"
+#include "clang/Lex/MacroArgs.h"
+#include "llvm/Support/raw_ostream.h"
+
+// Utility functions.
+
+// Get a "file:line:column" source location string.
+static std::string getSourceLocationString(clang::Preprocessor &PP,
+ clang::SourceLocation Loc) {
+ if (Loc.isInvalid())
+ return std::string("(none)");
+
+ if (Loc.isFileID()) {
+ clang::PresumedLoc PLoc = PP.getSourceManager().getPresumedLoc(Loc);
+
+ if (PLoc.isInvalid()) {
+ return std::string("(invalid)");
+ }
+
+ std::string Str;
+ llvm::raw_string_ostream SS(Str);
+
+ // The macro expansion and spelling pos is identical for file locs.
+ SS << "\"" << PLoc.getFilename() << ':' << PLoc.getLine() << ':'
+ << PLoc.getColumn() << "\"";
+
+ std::string Result = SS.str();
+
+ // YAML treats backslash as escape, so use forward slashes.
+ std::replace(Result.begin(), Result.end(), '\\', '/');
+
+ return Result;
+ }
+
+ return std::string("(nonfile)");
+}
+
+// Enum string tables.
+
+// FileChangeReason strings.
+static const char *const FileChangeReasonStrings[] = {
+ "EnterFile", "ExitFile", "SystemHeaderPragma", "RenameFile"
+};
+
+// CharacteristicKind strings.
+static const char *const CharacteristicKindStrings[] = { "C_User", "C_System",
+ "C_ExternCSystem" };
+
+// MacroDirective::Kind strings.
+static const char *const MacroDirectiveKindStrings[] = {
+ "MD_Define","MD_Undefine", "MD_Visibility"
+};
+
+// PragmaIntroducerKind strings.
+static const char *const PragmaIntroducerKindStrings[] = { "PIK_HashPragma",
+ "PIK__Pragma",
+ "PIK___pragma" };
+
+// PragmaMessageKind strings.
+static const char *const PragmaMessageKindStrings[] = {
+ "PMK_Message", "PMK_Warning", "PMK_Error"
+};
+
+// ConditionValueKind strings.
+static const char *const ConditionValueKindStrings[] = {
+ "CVK_NotEvaluated", "CVK_False", "CVK_True"
+};
+
+// Mapping strings.
+static const char *const MappingStrings[] = { "0", "MAP_IGNORE",
+ "MAP_REMARK", "MAP_WARNING",
+ "MAP_ERROR", "MAP_FATAL" };
+
+// PPCallbacksTracker functions.
+
+PPCallbacksTracker::PPCallbacksTracker(llvm::SmallSet<std::string, 4> &Ignore,
+ std::vector<CallbackCall> &CallbackCalls,
+ clang::Preprocessor &PP)
+ : CallbackCalls(CallbackCalls), Ignore(Ignore), PP(PP) {}
+
+PPCallbacksTracker::~PPCallbacksTracker() {}
+
+// Callback functions.
+
+// Callback invoked whenever a source file is entered or exited.
+void PPCallbacksTracker::FileChanged(
+ clang::SourceLocation Loc, clang::PPCallbacks::FileChangeReason Reason,
+ clang::SrcMgr::CharacteristicKind FileType, clang::FileID PrevFID) {
+ beginCallback("FileChanged");
+ appendArgument("Loc", Loc);
+ appendArgument("Reason", Reason, FileChangeReasonStrings);
+ appendArgument("FileType", FileType, CharacteristicKindStrings);
+ appendArgument("PrevFID", PrevFID);
+}
+
+// Callback invoked whenever a source file is skipped as the result
+// of header guard optimization.
+void
+PPCallbacksTracker::FileSkipped(const clang::FileEntry &SkippedFile,
+ const clang::Token &FilenameTok,
+ clang::SrcMgr::CharacteristicKind FileType) {
+ beginCallback("FileSkipped");
+ appendArgument("ParentFile", &SkippedFile);
+ appendArgument("FilenameTok", FilenameTok);
+ appendArgument("FileType", FileType, CharacteristicKindStrings);
+}
+
+// Callback invoked whenever an inclusion directive results in a
+// file-not-found error.
+bool
+PPCallbacksTracker::FileNotFound(llvm::StringRef FileName,
+ llvm::SmallVectorImpl<char> &RecoveryPath) {
+ beginCallback("FileNotFound");
+ appendFilePathArgument("FileName", FileName);
+ return false;
+}
+
+// Callback invoked whenever an inclusion directive of
+// any kind (#include, #import, etc.) has been processed, regardless
+// of whether the inclusion will actually result in an inclusion.
+void PPCallbacksTracker::InclusionDirective(
+ clang::SourceLocation HashLoc, const clang::Token &IncludeTok,
+ llvm::StringRef FileName, bool IsAngled,
+ clang::CharSourceRange FilenameRange, const clang::FileEntry *File,
+ llvm::StringRef SearchPath, llvm::StringRef RelativePath,
+ const clang::Module *Imported, clang::SrcMgr::CharacteristicKind FileType) {
+ beginCallback("InclusionDirective");
+ appendArgument("IncludeTok", IncludeTok);
+ appendFilePathArgument("FileName", FileName);
+ appendArgument("IsAngled", IsAngled);
+ appendArgument("FilenameRange", FilenameRange);
+ appendArgument("File", File);
+ appendFilePathArgument("SearchPath", SearchPath);
+ appendFilePathArgument("RelativePath", RelativePath);
+ appendArgument("Imported", Imported);
+}
+
+// Callback invoked whenever there was an explicit module-import
+// syntax.
+void PPCallbacksTracker::moduleImport(clang::SourceLocation ImportLoc,
+ clang::ModuleIdPath Path,
+ const clang::Module *Imported) {
+ beginCallback("moduleImport");
+ appendArgument("ImportLoc", ImportLoc);
+ appendArgument("Path", Path);
+ appendArgument("Imported", Imported);
+}
+
+// Callback invoked when the end of the main file is reached.
+// No subsequent callbacks will be made.
+void PPCallbacksTracker::EndOfMainFile() { beginCallback("EndOfMainFile"); }
+
+// Callback invoked when a #ident or #sccs directive is read.
+void PPCallbacksTracker::Ident(clang::SourceLocation Loc, llvm::StringRef Str) {
+ beginCallback("Ident");
+ appendArgument("Loc", Loc);
+ appendArgument("Str", Str);
+}
+
+// Callback invoked when start reading any pragma directive.
+void
+PPCallbacksTracker::PragmaDirective(clang::SourceLocation Loc,
+ clang::PragmaIntroducerKind Introducer) {
+ beginCallback("PragmaDirective");
+ appendArgument("Loc", Loc);
+ appendArgument("Introducer", Introducer, PragmaIntroducerKindStrings);
+}
+
+// Callback invoked when a #pragma comment directive is read.
+void PPCallbacksTracker::PragmaComment(clang::SourceLocation Loc,
+ const clang::IdentifierInfo *Kind,
+ llvm::StringRef Str) {
+ beginCallback("PragmaComment");
+ appendArgument("Loc", Loc);
+ appendArgument("Kind", Kind);
+ appendArgument("Str", Str);
+}
+
+// Callback invoked when a #pragma detect_mismatch directive is
+// read.
+void PPCallbacksTracker::PragmaDetectMismatch(clang::SourceLocation Loc,
+ llvm::StringRef Name,
+ llvm::StringRef Value) {
+ beginCallback("PragmaDetectMismatch");
+ appendArgument("Loc", Loc);
+ appendArgument("Name", Name);
+ appendArgument("Value", Value);
+}
+
+// Callback invoked when a #pragma clang __debug directive is read.
+void PPCallbacksTracker::PragmaDebug(clang::SourceLocation Loc,
+ llvm::StringRef DebugType) {
+ beginCallback("PragmaDebug");
+ appendArgument("Loc", Loc);
+ appendArgument("DebugType", DebugType);
+}
+
+// Callback invoked when a #pragma message directive is read.
+void PPCallbacksTracker::PragmaMessage(
+ clang::SourceLocation Loc, llvm::StringRef Namespace,
+ clang::PPCallbacks::PragmaMessageKind Kind, llvm::StringRef Str) {
+ beginCallback("PragmaMessage");
+ appendArgument("Loc", Loc);
+ appendArgument("Namespace", Namespace);
+ appendArgument("Kind", Kind, PragmaMessageKindStrings);
+ appendArgument("Str", Str);
+}
+
+// Callback invoked when a #pragma gcc dianostic push directive
+// is read.
+void PPCallbacksTracker::PragmaDiagnosticPush(clang::SourceLocation Loc,
+ llvm::StringRef Namespace) {
+ beginCallback("PragmaDiagnosticPush");
+ appendArgument("Loc", Loc);
+ appendArgument("Namespace", Namespace);
+}
+
+// Callback invoked when a #pragma gcc dianostic pop directive
+// is read.
+void PPCallbacksTracker::PragmaDiagnosticPop(clang::SourceLocation Loc,
+ llvm::StringRef Namespace) {
+ beginCallback("PragmaDiagnosticPop");
+ appendArgument("Loc", Loc);
+ appendArgument("Namespace", Namespace);
+}
+
+// Callback invoked when a #pragma gcc dianostic directive is read.
+void PPCallbacksTracker::PragmaDiagnostic(clang::SourceLocation Loc,
+ llvm::StringRef Namespace,
+ clang::diag::Severity Mapping,
+ llvm::StringRef Str) {
+ beginCallback("PragmaDiagnostic");
+ appendArgument("Loc", Loc);
+ appendArgument("Namespace", Namespace);
+ appendArgument("Mapping", (unsigned)Mapping, MappingStrings);
+ appendArgument("Str", Str);
+}
+
+// Called when an OpenCL extension is either disabled or
+// enabled with a pragma.
+void PPCallbacksTracker::PragmaOpenCLExtension(
+ clang::SourceLocation NameLoc, const clang::IdentifierInfo *Name,
+ clang::SourceLocation StateLoc, unsigned State) {
+ beginCallback("PragmaOpenCLExtension");
+ appendArgument("NameLoc", NameLoc);
+ appendArgument("Name", Name);
+ appendArgument("StateLoc", StateLoc);
+ appendArgument("State", (int)State);
+}
+
+// Callback invoked when a #pragma warning directive is read.
+void PPCallbacksTracker::PragmaWarning(clang::SourceLocation Loc,
+ llvm::StringRef WarningSpec,
+ llvm::ArrayRef<int> Ids) {
+ beginCallback("PragmaWarning");
+ appendArgument("Loc", Loc);
+ appendArgument("WarningSpec", WarningSpec);
+
+ std::string Str;
+ llvm::raw_string_ostream SS(Str);
+ SS << "[";
+ for (int i = 0, e = Ids.size(); i != e; ++i) {
+ if (i)
+ SS << ", ";
+ SS << Ids[i];
+ }
+ SS << "]";
+ appendArgument("Ids", SS.str());
+}
+
+// Callback invoked when a #pragma warning(push) directive is read.
+void PPCallbacksTracker::PragmaWarningPush(clang::SourceLocation Loc,
+ int Level) {
+ beginCallback("PragmaWarningPush");
+ appendArgument("Loc", Loc);
+ appendArgument("Level", Level);
+}
+
+// Callback invoked when a #pragma warning(pop) directive is read.
+void PPCallbacksTracker::PragmaWarningPop(clang::SourceLocation Loc) {
+ beginCallback("PragmaWarningPop");
+ appendArgument("Loc", Loc);
+}
+
+// Called by Preprocessor::HandleMacroExpandedIdentifier when a
+// macro invocation is found.
+void
+PPCallbacksTracker::MacroExpands(const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MacroDefinition,
+ clang::SourceRange Range,
+ const clang::MacroArgs *Args) {
+ beginCallback("MacroExpands");
+ appendArgument("MacroNameTok", MacroNameTok);
+ appendArgument("MacroDefinition", MacroDefinition);
+ appendArgument("Range", Range);
+ appendArgument("Args", Args);
+}
+
+// Hook called whenever a macro definition is seen.
+void
+PPCallbacksTracker::MacroDefined(const clang::Token &MacroNameTok,
+ const clang::MacroDirective *MacroDirective) {
+ beginCallback("MacroDefined");
+ appendArgument("MacroNameTok", MacroNameTok);
+ appendArgument("MacroDirective", MacroDirective);
+}
+
+// Hook called whenever a macro #undef is seen.
+void PPCallbacksTracker::MacroUndefined(
+ const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MacroDefinition,
+ const clang::MacroDirective *Undef) {
+ beginCallback("MacroUndefined");
+ appendArgument("MacroNameTok", MacroNameTok);
+ appendArgument("MacroDefinition", MacroDefinition);
+}
+
+// Hook called whenever the 'defined' operator is seen.
+void PPCallbacksTracker::Defined(const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MacroDefinition,
+ clang::SourceRange Range) {
+ beginCallback("Defined");
+ appendArgument("MacroNameTok", MacroNameTok);
+ appendArgument("MacroDefinition", MacroDefinition);
+ appendArgument("Range", Range);
+}
+
+// Hook called when a source range is skipped.
+void PPCallbacksTracker::SourceRangeSkipped(clang::SourceRange Range,
+ clang::SourceLocation EndifLoc) {
+ beginCallback("SourceRangeSkipped");
+ appendArgument("Range", clang::SourceRange(Range.getBegin(), EndifLoc));
+}
+
+// Hook called whenever an #if is seen.
+void PPCallbacksTracker::If(clang::SourceLocation Loc,
+ clang::SourceRange ConditionRange,
+ ConditionValueKind ConditionValue) {
+ beginCallback("If");
+ appendArgument("Loc", Loc);
+ appendArgument("ConditionRange", ConditionRange);
+ appendArgument("ConditionValue", ConditionValue, ConditionValueKindStrings);
+}
+
+// Hook called whenever an #elif is seen.
+void PPCallbacksTracker::Elif(clang::SourceLocation Loc,
+ clang::SourceRange ConditionRange,
+ ConditionValueKind ConditionValue,
+ clang::SourceLocation IfLoc) {
+ beginCallback("Elif");
+ appendArgument("Loc", Loc);
+ appendArgument("ConditionRange", ConditionRange);
+ appendArgument("ConditionValue", ConditionValue, ConditionValueKindStrings);
+ appendArgument("IfLoc", IfLoc);
+}
+
+// Hook called whenever an #ifdef is seen.
+void PPCallbacksTracker::Ifdef(clang::SourceLocation Loc,
+ const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MacroDefinition) {
+ beginCallback("Ifdef");
+ appendArgument("Loc", Loc);
+ appendArgument("MacroNameTok", MacroNameTok);
+ appendArgument("MacroDefinition", MacroDefinition);
+}
+
+// Hook called whenever an #ifndef is seen.
+void PPCallbacksTracker::Ifndef(clang::SourceLocation Loc,
+ const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MacroDefinition) {
+ beginCallback("Ifndef");
+ appendArgument("Loc", Loc);
+ appendArgument("MacroNameTok", MacroNameTok);
+ appendArgument("MacroDefinition", MacroDefinition);
+}
+
+// Hook called whenever an #else is seen.
+void PPCallbacksTracker::Else(clang::SourceLocation Loc,
+ clang::SourceLocation IfLoc) {
+ beginCallback("Else");
+ appendArgument("Loc", Loc);
+ appendArgument("IfLoc", IfLoc);
+}
+
+// Hook called whenever an #endif is seen.
+void PPCallbacksTracker::Endif(clang::SourceLocation Loc,
+ clang::SourceLocation IfLoc) {
+ beginCallback("Endif");
+ appendArgument("Loc", Loc);
+ appendArgument("IfLoc", IfLoc);
+}
+
+// Helper functions.
+
+// Start a new callback.
+void PPCallbacksTracker::beginCallback(const char *Name) {
+ DisableTrace = Ignore.count(std::string(Name));
+ if (DisableTrace)
+ return;
+ CallbackCalls.push_back(CallbackCall(Name));
+}
+
+// Append a bool argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name, bool Value) {
+ appendArgument(Name, (Value ? "true" : "false"));
+}
+
+// Append an int argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name, int Value) {
+ std::string Str;
+ llvm::raw_string_ostream SS(Str);
+ SS << Value;
+ appendArgument(Name, SS.str());
+}
+
+// Append a string argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name, const char *Value) {
+ if (DisableTrace)
+ return;
+ CallbackCalls.back().Arguments.push_back(Argument(Name, Value));
+}
+
+// Append a string object argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name,
+ llvm::StringRef Value) {
+ appendArgument(Name, Value.str());
+}
+
+// Append a string object argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name,
+ const std::string &Value) {
+ appendArgument(Name, Value.c_str());
+}
+
+// Append a token argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name,
+ const clang::Token &Value) {
+ appendArgument(Name, PP.getSpelling(Value));
+}
+
+// Append an enum argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name, int Value,
+ const char *const Strings[]) {
+ appendArgument(Name, Strings[Value]);
+}
+
+// Append a FileID argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name, clang::FileID Value) {
+ if (Value.isInvalid()) {
+ appendArgument(Name, "(invalid)");
+ return;
+ }
+ const clang::FileEntry *FileEntry =
+ PP.getSourceManager().getFileEntryForID(Value);
+ if (!FileEntry) {
+ appendArgument(Name, "(getFileEntryForID failed)");
+ return;
+ }
+ appendFilePathArgument(Name, FileEntry->getName());
+}
+
+// Append a FileEntry argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name,
+ const clang::FileEntry *Value) {
+ if (!Value) {
+ appendArgument(Name, "(null)");
+ return;
+ }
+ appendFilePathArgument(Name, Value->getName());
+}
+
+// Append a SourceLocation argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name,
+ clang::SourceLocation Value) {
+ if (Value.isInvalid()) {
+ appendArgument(Name, "(invalid)");
+ return;
+ }
+ appendArgument(Name, getSourceLocationString(PP, Value).c_str());
+}
+
+// Append a SourceRange argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name,
+ clang::SourceRange Value) {
+ if (DisableTrace)
+ return;
+ if (Value.isInvalid()) {
+ appendArgument(Name, "(invalid)");
+ return;
+ }
+ std::string Str;
+ llvm::raw_string_ostream SS(Str);
+ SS << "[" << getSourceLocationString(PP, Value.getBegin()) << ", "
+ << getSourceLocationString(PP, Value.getEnd()) << "]";
+ appendArgument(Name, SS.str());
+}
+
+// Append a CharSourceRange argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name,
+ clang::CharSourceRange Value) {
+ if (Value.isInvalid()) {
+ appendArgument(Name, "(invalid)");
+ return;
+ }
+ appendArgument(Name, getSourceString(Value).str().c_str());
+}
+
+// Append a SourceLocation argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name,
+ clang::ModuleIdPath Value) {
+ if (DisableTrace)
+ return;
+ std::string Str;
+ llvm::raw_string_ostream SS(Str);
+ SS << "[";
+ for (int I = 0, E = Value.size(); I != E; ++I) {
+ if (I)
+ SS << ", ";
+ SS << "{"
+ << "Name: " << Value[I].first->getName() << ", "
+ << "Loc: " << getSourceLocationString(PP, Value[I].second) << "}";
+ }
+ SS << "]";
+ appendArgument(Name, SS.str());
+}
+
+// Append an IdentifierInfo argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name,
+ const clang::IdentifierInfo *Value) {
+ if (!Value) {
+ appendArgument(Name, "(null)");
+ return;
+ }
+ appendArgument(Name, Value->getName().str().c_str());
+}
+
+// Append a MacroDirective argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name,
+ const clang::MacroDirective *Value) {
+ if (!Value) {
+ appendArgument(Name, "(null)");
+ return;
+ }
+ appendArgument(Name, MacroDirectiveKindStrings[Value->getKind()]);
+}
+
+// Append a MacroDefinition argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name,
+ const clang::MacroDefinition &Value) {
+ std::string Str;
+ llvm::raw_string_ostream SS(Str);
+ SS << "[";
+ bool Any = false;
+ if (Value.getLocalDirective()) {
+ SS << "(local)";
+ Any = true;
+ }
+ for (auto *MM : Value.getModuleMacros()) {
+ if (Any) SS << ", ";
+ SS << MM->getOwningModule()->getFullModuleName();
+ }
+ SS << "]";
+ appendArgument(Name, SS.str());
+}
+
+// Append a MacroArgs argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name,
+ const clang::MacroArgs *Value) {
+ if (!Value) {
+ appendArgument(Name, "(null)");
+ return;
+ }
+ std::string Str;
+ llvm::raw_string_ostream SS(Str);
+ SS << "[";
+
+ // Each argument is is a series of contiguous Tokens, terminated by a eof.
+ // Go through each argument printing tokens until we reach eof.
+ for (unsigned I = 0; I < Value->getNumMacroArguments(); ++I) {
+ const clang::Token *Current = Value->getUnexpArgument(I);
+ if (I)
+ SS << ", ";
+ bool First = true;
+ while (Current->isNot(clang::tok::eof)) {
+ if (!First)
+ SS << " ";
+ // We need to be careful here because the arguments might not be legal in
+ // YAML, so we use the token name for anything but identifiers and
+ // numeric literals.
+ if (Current->isAnyIdentifier() ||
+ Current->is(clang::tok::numeric_constant)) {
+ SS << PP.getSpelling(*Current);
+ } else {
+ SS << "<" << Current->getName() << ">";
+ }
+ ++Current;
+ First = false;
+ }
+ }
+ SS << "]";
+ appendArgument(Name, SS.str());
+}
+
+// Append a Module argument to the top trace item.
+void PPCallbacksTracker::appendArgument(const char *Name,
+ const clang::Module *Value) {
+ if (!Value) {
+ appendArgument(Name, "(null)");
+ return;
+ }
+ appendArgument(Name, Value->Name.c_str());
+}
+
+// Append a double-quoted argument to the top trace item.
+void PPCallbacksTracker::appendQuotedArgument(const char *Name,
+ const std::string &Value) {
+ std::string Str;
+ llvm::raw_string_ostream SS(Str);
+ SS << "\"" << Value << "\"";
+ appendArgument(Name, SS.str());
+}
+
+// Append a double-quoted file path argument to the top trace item.
+void PPCallbacksTracker::appendFilePathArgument(const char *Name,
+ llvm::StringRef Value) {
+ std::string Path(Value);
+ // YAML treats backslash as escape, so use forward slashes.
+ std::replace(Path.begin(), Path.end(), '\\', '/');
+ appendQuotedArgument(Name, Path);
+}
+
+// Get the raw source string of the range.
+llvm::StringRef
+PPCallbacksTracker::getSourceString(clang::CharSourceRange Range) {
+ const char *B = PP.getSourceManager().getCharacterData(Range.getBegin());
+ const char *E = PP.getSourceManager().getCharacterData(Range.getEnd());
+ return llvm::StringRef(B, E - B);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/pp-trace/PPCallbacksTracker.h b/src/third_party/llvm-project/clang-tools-extra/pp-trace/PPCallbacksTracker.h
new file mode 100644
index 0000000..b46210e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/pp-trace/PPCallbacksTracker.h
@@ -0,0 +1,249 @@
+//===--- PPCallbacksTracker.h - Preprocessor tracking -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Classes and definitions for preprocessor tracking.
+///
+/// The core definition is the PPCallbacksTracker class, derived from Clang's
+/// PPCallbacks class from the Lex library, which overrides all the callbacks
+/// and collects information about each callback call, saving it in a
+/// data structure built up of CallbackCall and Argument objects, which
+/// record the preprocessor callback name and arguments in high-level string
+/// form for later inspection.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef PPTRACE_PPCALLBACKSTRACKER_H
+#define PPTRACE_PPCALLBACKSTRACKER_H
+
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+#include <vector>
+
+/// \brief This class represents one callback function argument by name
+/// and value.
+class Argument {
+public:
+ Argument(llvm::StringRef Name, llvm::StringRef Value)
+ : Name(Name), Value(Value) {}
+ Argument() = default;
+
+ std::string Name;
+ std::string Value;
+};
+
+/// \brief This class represents one callback call by name and an array
+/// of arguments.
+class CallbackCall {
+public:
+ CallbackCall(llvm::StringRef Name) : Name(Name) {}
+ CallbackCall() = default;
+
+ std::string Name;
+ std::vector<Argument> Arguments;
+};
+
+/// \brief This class overrides the PPCallbacks class for tracking preprocessor
+/// activity by means of its callback functions.
+///
+/// This object is given a vector for storing the trace information, built up
+/// of CallbackCall and subordinate Argument objects for representing the
+/// callback calls and their arguments. It's a reference so the vector can
+/// exist beyond the lifetime of this object, because it's deleted by the
+/// preprocessor automatically in its destructor.
+///
+/// This class supports a mechanism for inhibiting trace output for
+/// specific callbacks by name, for the purpose of eliminating output for
+/// callbacks of no interest that might clutter the output.
+///
+/// Following the constructor and destructor function declarations, the
+/// overidden callback functions are defined. The remaining functions are
+/// helpers for recording the trace data, to reduce the coupling between it
+/// and the recorded data structure.
+class PPCallbacksTracker : public clang::PPCallbacks {
+public:
+ /// \brief Note that all of the arguments are references, and owned
+ /// by the caller.
+ /// \param Ignore - Set of names of callbacks to ignore.
+ /// \param CallbackCalls - Trace buffer.
+ /// \param PP - The preprocessor. Needed for getting some argument strings.
+ PPCallbacksTracker(llvm::SmallSet<std::string, 4> &Ignore,
+ std::vector<CallbackCall> &CallbackCalls,
+ clang::Preprocessor &PP);
+
+ ~PPCallbacksTracker() override;
+
+ // Overidden callback functions.
+
+ void FileChanged(clang::SourceLocation Loc,
+ clang::PPCallbacks::FileChangeReason Reason,
+ clang::SrcMgr::CharacteristicKind FileType,
+ clang::FileID PrevFID = clang::FileID()) override;
+ void FileSkipped(const clang::FileEntry &SkippedFile,
+ const clang::Token &FilenameTok,
+ clang::SrcMgr::CharacteristicKind FileType) override;
+ bool FileNotFound(llvm::StringRef FileName,
+ llvm::SmallVectorImpl<char> &RecoveryPath) override;
+ void InclusionDirective(clang::SourceLocation HashLoc,
+ const clang::Token &IncludeTok,
+ llvm::StringRef FileName, bool IsAngled,
+ clang::CharSourceRange FilenameRange,
+ const clang::FileEntry *File,
+ llvm::StringRef SearchPath,
+ llvm::StringRef RelativePath,
+ const clang::Module *Imported,
+ clang::SrcMgr::CharacteristicKind FileType) override;
+ void moduleImport(clang::SourceLocation ImportLoc, clang::ModuleIdPath Path,
+ const clang::Module *Imported) override;
+ void EndOfMainFile() override;
+ void Ident(clang::SourceLocation Loc, llvm::StringRef str) override;
+ void PragmaDirective(clang::SourceLocation Loc,
+ clang::PragmaIntroducerKind Introducer) override;
+ void PragmaComment(clang::SourceLocation Loc,
+ const clang::IdentifierInfo *Kind,
+ llvm::StringRef Str) override;
+ void PragmaDetectMismatch(clang::SourceLocation Loc, llvm::StringRef Name,
+ llvm::StringRef Value) override;
+ void PragmaDebug(clang::SourceLocation Loc,
+ llvm::StringRef DebugType) override;
+ void PragmaMessage(clang::SourceLocation Loc, llvm::StringRef Namespace,
+ clang::PPCallbacks::PragmaMessageKind Kind,
+ llvm::StringRef Str) override;
+ void PragmaDiagnosticPush(clang::SourceLocation Loc,
+ llvm::StringRef Namespace) override;
+ void PragmaDiagnosticPop(clang::SourceLocation Loc,
+ llvm::StringRef Namespace) override;
+ void PragmaDiagnostic(clang::SourceLocation Loc, llvm::StringRef Namespace,
+ clang::diag::Severity mapping,
+ llvm::StringRef Str) override;
+ void PragmaOpenCLExtension(clang::SourceLocation NameLoc,
+ const clang::IdentifierInfo *Name,
+ clang::SourceLocation StateLoc,
+ unsigned State) override;
+ void PragmaWarning(clang::SourceLocation Loc, llvm::StringRef WarningSpec,
+ llvm::ArrayRef<int> Ids) override;
+ void PragmaWarningPush(clang::SourceLocation Loc, int Level) override;
+ void PragmaWarningPop(clang::SourceLocation Loc) override;
+ void MacroExpands(const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MD, clang::SourceRange Range,
+ const clang::MacroArgs *Args) override;
+ void MacroDefined(const clang::Token &MacroNameTok,
+ const clang::MacroDirective *MD) override;
+ void MacroUndefined(const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MD,
+ const clang::MacroDirective *Undef) override;
+ void Defined(const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MD,
+ clang::SourceRange Range) override;
+ void SourceRangeSkipped(clang::SourceRange Range,
+ clang::SourceLocation EndifLoc) override;
+ void If(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
+ ConditionValueKind ConditionValue) override;
+ void Elif(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
+ ConditionValueKind ConditionValue, clang::SourceLocation IfLoc) override;
+ void Ifdef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MD) override;
+ void Ifndef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
+ const clang::MacroDefinition &MD) override;
+ void Else(clang::SourceLocation Loc,
+ clang::SourceLocation IfLoc) override;
+ void Endif(clang::SourceLocation Loc,
+ clang::SourceLocation IfLoc) override;
+
+ // Helper functions.
+
+ /// \brief Start a new callback.
+ void beginCallback(const char *Name);
+
+ /// \brief Append a string to the top trace item.
+ void append(const char *Str);
+
+ /// \brief Append a bool argument to the top trace item.
+ void appendArgument(const char *Name, bool Value);
+
+ /// \brief Append an int argument to the top trace item.
+ void appendArgument(const char *Name, int Value);
+
+ /// \brief Append a string argument to the top trace item.
+ void appendArgument(const char *Name, const char *Value);
+
+ /// \brief Append a string reference object argument to the top trace item.
+ void appendArgument(const char *Name, llvm::StringRef Value);
+
+ /// \brief Append a string object argument to the top trace item.
+ void appendArgument(const char *Name, const std::string &Value);
+
+ /// \brief Append a token argument to the top trace item.
+ void appendArgument(const char *Name, const clang::Token &Value);
+
+ /// \brief Append an enum argument to the top trace item.
+ void appendArgument(const char *Name, int Value, const char *const Strings[]);
+
+ /// \brief Append a FileID argument to the top trace item.
+ void appendArgument(const char *Name, clang::FileID Value);
+
+ /// \brief Append a FileEntry argument to the top trace item.
+ void appendArgument(const char *Name, const clang::FileEntry *Value);
+
+ /// \brief Append a SourceLocation argument to the top trace item.
+ void appendArgument(const char *Name, clang::SourceLocation Value);
+
+ /// \brief Append a SourceRange argument to the top trace item.
+ void appendArgument(const char *Name, clang::SourceRange Value);
+
+ /// \brief Append a CharSourceRange argument to the top trace item.
+ void appendArgument(const char *Name, clang::CharSourceRange Value);
+
+ /// \brief Append a ModuleIdPath argument to the top trace item.
+ void appendArgument(const char *Name, clang::ModuleIdPath Value);
+
+ /// \brief Append an IdentifierInfo argument to the top trace item.
+ void appendArgument(const char *Name, const clang::IdentifierInfo *Value);
+
+ /// \brief Append a MacroDirective argument to the top trace item.
+ void appendArgument(const char *Name, const clang::MacroDirective *Value);
+
+ /// \brief Append a MacroDefinition argument to the top trace item.
+ void appendArgument(const char *Name, const clang::MacroDefinition &Value);
+
+ /// \brief Append a MacroArgs argument to the top trace item.
+ void appendArgument(const char *Name, const clang::MacroArgs *Value);
+
+ /// \brief Append a Module argument to the top trace item.
+ void appendArgument(const char *Name, const clang::Module *Value);
+
+ /// \brief Append a double-quoted argument to the top trace item.
+ void appendQuotedArgument(const char *Name, const std::string &Value);
+
+ /// \brief Append a double-quoted file path argument to the top trace item.
+ void appendFilePathArgument(const char *Name, llvm::StringRef Value);
+
+ /// \brief Get the raw source string of the range.
+ llvm::StringRef getSourceString(clang::CharSourceRange Range);
+
+ /// \brief Callback trace information.
+ /// We use a reference so the trace will be preserved for the caller
+ /// after this object is destructed.
+ std::vector<CallbackCall> &CallbackCalls;
+
+ /// \brief Names of callbacks to ignore.
+ llvm::SmallSet<std::string, 4> &Ignore;
+
+ /// \brief Inhibit trace while this is set.
+ bool DisableTrace;
+
+ clang::Preprocessor &PP;
+};
+
+#endif // PPTRACE_PPCALLBACKSTRACKER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/pp-trace/PPTrace.cpp b/src/third_party/llvm-project/clang-tools-extra/pp-trace/PPTrace.cpp
new file mode 100644
index 0000000..d49bc20
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/pp-trace/PPTrace.cpp
@@ -0,0 +1,233 @@
+//===--- tools/pp-trace/PPTrace.cpp - Clang preprocessor tracer -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements pp-trace, a tool for displaying a textual trace
+// of the Clang preprocessor activity. It's based on a derivation of the
+// PPCallbacks class, that once registerd with Clang, receives callback calls
+// to its virtual members, and outputs the information passed to the callbacks
+// in a high-level YAML format.
+//
+// The pp-trace tool also serves as the basis for a test of the PPCallbacks
+// mechanism.
+//
+// The pp-trace tool supports the following general command line format:
+//
+// pp-trace [pp-trace options] (source file) [compiler options]
+//
+// Basically you put the pp-trace options first, then the source file or files,
+// and then any options you want to pass to the compiler.
+//
+// These are the pp-trace options:
+//
+// -ignore (callback list) Don't display output for a comma-separated
+// list of callbacks, i.e.:
+// -ignore "FileChanged,InclusionDirective"
+//
+// -output (file) Output trace to the given file in a YAML
+// format, e.g.:
+//
+// ---
+// - Callback: Name
+// Argument1: Value1
+// Argument2: Value2
+// (etc.)
+// ...
+//
+// Future Directions:
+//
+// 1. Add option opposite to "-ignore" that specifys a comma-separated option
+// list of callbacs. Perhaps "-only" or "-exclusive".
+//
+//===----------------------------------------------------------------------===//
+
+#include "PPCallbacksTracker.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Driver/Options.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include <algorithm>
+#include <fstream>
+#include <iterator>
+#include <string>
+#include <vector>
+
+using namespace clang;
+using namespace clang::driver;
+using namespace clang::driver::options;
+using namespace clang::tooling;
+using namespace llvm;
+using namespace llvm::opt;
+
+// Options:
+
+// Collect the source files.
+static cl::list<std::string> SourcePaths(cl::Positional,
+ cl::desc("<source0> [... <sourceN>]"),
+ cl::OneOrMore);
+
+// Option to specify a list or one or more callback names to ignore.
+static cl::opt<std::string> IgnoreCallbacks(
+ "ignore", cl::init(""),
+ cl::desc("Ignore callbacks, i.e. \"Callback1, Callback2...\"."));
+
+// Option to specify the trace output file name.
+static cl::opt<std::string> OutputFileName(
+ "output", cl::init(""),
+ cl::desc("Output trace to the given file name or '-' for stdout."));
+
+// Collect all other arguments, which will be passed to the front end.
+static cl::list<std::string>
+ CC1Arguments(cl::ConsumeAfter,
+ cl::desc("<arguments to be passed to front end>..."));
+
+// Frontend action stuff:
+
+namespace {
+// Consumer is responsible for setting up the callbacks.
+class PPTraceConsumer : public ASTConsumer {
+public:
+ PPTraceConsumer(SmallSet<std::string, 4> &Ignore,
+ std::vector<CallbackCall> &CallbackCalls, Preprocessor &PP) {
+ // PP takes ownership.
+ PP.addPPCallbacks(llvm::make_unique<PPCallbacksTracker>(Ignore,
+ CallbackCalls, PP));
+ }
+};
+
+class PPTraceAction : public SyntaxOnlyAction {
+public:
+ PPTraceAction(SmallSet<std::string, 4> &Ignore,
+ std::vector<CallbackCall> &CallbackCalls)
+ : Ignore(Ignore), CallbackCalls(CallbackCalls) {}
+
+protected:
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
+ return llvm::make_unique<PPTraceConsumer>(Ignore, CallbackCalls,
+ CI.getPreprocessor());
+ }
+
+private:
+ SmallSet<std::string, 4> &Ignore;
+ std::vector<CallbackCall> &CallbackCalls;
+};
+
+class PPTraceFrontendActionFactory : public FrontendActionFactory {
+public:
+ PPTraceFrontendActionFactory(SmallSet<std::string, 4> &Ignore,
+ std::vector<CallbackCall> &CallbackCalls)
+ : Ignore(Ignore), CallbackCalls(CallbackCalls) {}
+
+ PPTraceAction *create() override {
+ return new PPTraceAction(Ignore, CallbackCalls);
+ }
+
+private:
+ SmallSet<std::string, 4> &Ignore;
+ std::vector<CallbackCall> &CallbackCalls;
+};
+} // namespace
+
+// Output the trace given its data structure and a stream.
+static int outputPPTrace(std::vector<CallbackCall> &CallbackCalls,
+ llvm::raw_ostream &OS) {
+ // Mark start of document.
+ OS << "---\n";
+
+ for (std::vector<CallbackCall>::const_iterator I = CallbackCalls.begin(),
+ E = CallbackCalls.end();
+ I != E; ++I) {
+ const CallbackCall &Callback = *I;
+ OS << "- Callback: " << Callback.Name << "\n";
+
+ for (auto AI = Callback.Arguments.begin(), AE = Callback.Arguments.end();
+ AI != AE; ++AI) {
+ const Argument &Arg = *AI;
+ OS << " " << Arg.Name << ": " << Arg.Value << "\n";
+ }
+ }
+
+ // Mark end of document.
+ OS << "...\n";
+
+ return 0;
+}
+
+// Program entry point.
+int main(int Argc, const char **Argv) {
+
+ // Parse command line.
+ cl::ParseCommandLineOptions(Argc, Argv, "pp-trace.\n");
+
+ // Parse the IgnoreCallbacks list into strings.
+ SmallVector<StringRef, 32> IgnoreCallbacksStrings;
+ StringRef(IgnoreCallbacks).split(IgnoreCallbacksStrings, ",",
+ /*MaxSplit=*/ -1, /*KeepEmpty=*/false);
+ SmallSet<std::string, 4> Ignore;
+ for (SmallVector<StringRef, 32>::iterator I = IgnoreCallbacksStrings.begin(),
+ E = IgnoreCallbacksStrings.end();
+ I != E; ++I)
+ Ignore.insert(*I);
+
+ // Create the compilation database.
+ SmallString<256> PathBuf;
+ sys::fs::current_path(PathBuf);
+ std::unique_ptr<CompilationDatabase> Compilations;
+ Compilations.reset(
+ new FixedCompilationDatabase(Twine(PathBuf), CC1Arguments));
+
+ // Store the callback trace information here.
+ std::vector<CallbackCall> CallbackCalls;
+
+ // Create the tool and run the compilation.
+ ClangTool Tool(*Compilations, SourcePaths);
+ PPTraceFrontendActionFactory Factory(Ignore, CallbackCalls);
+ int HadErrors = Tool.run(&Factory);
+
+ // If we had errors, exit early.
+ if (HadErrors)
+ return HadErrors;
+
+ // Do the output.
+ if (!OutputFileName.size()) {
+ HadErrors = outputPPTrace(CallbackCalls, llvm::outs());
+ } else {
+ // Set up output file.
+ std::error_code EC;
+ llvm::ToolOutputFile Out(OutputFileName, EC, llvm::sys::fs::F_Text);
+ if (EC) {
+ llvm::errs() << "pp-trace: error creating " << OutputFileName << ":"
+ << EC.message() << "\n";
+ return 1;
+ }
+
+ HadErrors = outputPPTrace(CallbackCalls, Out.os());
+
+ // Tell ToolOutputFile that we want to keep the file.
+ if (HadErrors == 0)
+ Out.keep();
+ }
+
+ return HadErrors;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/.clang-format b/src/third_party/llvm-project/clang-tools-extra/test/.clang-format
new file mode 100644
index 0000000..4799b66
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/.clang-format
@@ -0,0 +1,2 @@
+BasedOnStyle: LLVM
+ColumnLimit: 0
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/test/CMakeLists.txt
new file mode 100644
index 0000000..fafe6c0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/CMakeLists.txt
@@ -0,0 +1,91 @@
+# Test runner infrastructure for Clang-based tools. This configures the Clang
+# test trees for use by Lit, and delegates to LLVM's lit test handlers.
+#
+# Note that currently we don't support stand-alone builds of Clang, you must
+# be building Clang from within a combined LLVM+Clang checkout..
+
+set(CLANG_TOOLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
+set(CLANG_TOOLS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/..")
+
+if (CMAKE_CFG_INTDIR STREQUAL ".")
+ set(LLVM_BUILD_MODE ".")
+else ()
+ set(LLVM_BUILD_MODE "%(build_mode)s")
+endif ()
+
+string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} CLANG_TOOLS_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR})
+
+llvm_canonicalize_cmake_booleans(
+ CLANG_ENABLE_STATIC_ANALYZER)
+
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ )
+
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
+ )
+
+option(CLANG_TOOLS_TEST_USE_VG "Run Clang tools' tests under Valgrind" OFF)
+if(CLANG_TOOLS_TEST_USE_VG)
+ set(CLANG_TOOLS_TEST_EXTRA_ARGS ${CLANG_TEST_EXTRA_ARGS} "--vg")
+endif()
+
+set(CLANG_TOOLS_TEST_DEPS
+ # For the clang-apply-replacements test that uses clang-rename.
+ clang-rename
+
+ # For the clang-doc tests that emit bitcode files.
+ llvm-bcanalyzer
+
+ # Individual tools we test.
+ clang-apply-replacements
+ clang-change-namespace
+ clangd
+ clang-doc
+ clang-include-fixer
+ clang-move
+ clang-query
+ clang-reorder-fields
+ find-all-symbols
+ modularize
+ pp-trace
+
+ # These individual tools have no tests, add them here to make them compile
+ # together with check-clang-tools, so that we won't break them in the future.
+ global-symbol-builder
+
+ # Unit tests
+ ExtraToolsUnitTests
+ )
+
+if(CLANG_ENABLE_STATIC_ANALYZER)
+ list(APPEND CLANG_TOOLS_TEST_DEPS
+ # For the clang-tidy libclang integration test.
+ c-index-test
+ # clang-tidy tests require it.
+ clang-headers
+
+ clang-tidy
+ )
+endif()
+
+set(llvm_utils
+ FileCheck count not
+ )
+
+foreach(t ${llvm_utils})
+ if(TARGET ${t})
+ list(APPEND CLANG_TOOLS_TEST_DEPS ${t})
+ endif()
+endforeach()
+
+add_lit_testsuite(check-clang-tools "Running the Clang extra tools' regression tests"
+ ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${CLANG_TOOLS_TEST_DEPS}
+ ARGS ${CLANG_TOOLS_TEST_EXTRA_ARGS}
+ )
+
+set_target_properties(check-clang-tools PROPERTIES FOLDER "Clang extra tools' tests")
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/Unit/lit.cfg b/src/third_party/llvm-project/clang-tools-extra/test/Unit/lit.cfg
new file mode 100644
index 0000000..b40e1ca
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/Unit/lit.cfg
@@ -0,0 +1,37 @@
+# -*- Python -*-
+
+import platform
+
+import lit.formats
+
+config.name = "Extra Tools Unit Tests"
+config.suffixes = [] # Seems not to matter for google tests?
+
+# Test Source and Exec root dirs both point to the same directory where google
+# test binaries are built.
+
+config.test_source_root = config.extra_tools_obj_dir
+config.test_exec_root = config.test_source_root
+
+# All GoogleTests are named to have 'Tests' as their suffix. The '.' option is
+# a special value for GoogleTest indicating that it should look through the
+# entire testsuite recursively for tests (alternatively, one could provide a
+# ;-separated list of subdirectories).
+config.test_format = lit.formats.GoogleTest('.', 'Tests')
+
+if platform.system() == 'Darwin':
+ shlibpath_var = 'DYLD_LIBRARY_PATH'
+elif platform.system() == 'Windows':
+ shlibpath_var = 'PATH'
+else:
+ shlibpath_var = 'LD_LIBRARY_PATH'
+
+# Point the dynamic loader at dynamic libraries in 'lib'.
+shlibpath = os.path.pathsep.join((config.shlibdir, config.llvm_libs_dir,
+ config.environment.get(shlibpath_var,'')))
+
+# Win32 seeks DLLs along %PATH%.
+if sys.platform in ['win32', 'cygwin'] and os.path.isdir(config.shlibdir):
+ shlibpath = os.path.pathsep.join((config.shlibdir, shlibpath))
+
+config.environment[shlibpath_var] = shlibpath
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/Unit/lit.site.cfg.in b/src/third_party/llvm-project/clang-tools-extra/test/Unit/lit.site.cfg.in
new file mode 100644
index 0000000..69a5cd5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/Unit/lit.site.cfg.in
@@ -0,0 +1,9 @@
+@LIT_SITE_CFG_IN_HEADER@
+
+config.extra_tools_obj_dir = "@CLANG_TOOLS_BINARY_DIR@/unittests"
+config.extra_tools_src_dir = "@CLANG_TOOLS_SOURCE_DIR@/unittests"
+config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
+config.shlibdir = "@SHLIBDIR@"
+config.target_triple = "@TARGET_TRIPLE@"
+
+lit_config.load_config(config, "@CLANG_TOOLS_SOURCE_DIR@/test/Unit/lit.cfg")
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/Inputs/fake-std.h b/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/Inputs/fake-std.h
new file mode 100644
index 0000000..24d3f97
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/Inputs/fake-std.h
@@ -0,0 +1,5 @@
+namespace std {
+ class STD {};
+}
+
+using namespace std;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/lambda-function.cpp b/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/lambda-function.cpp
new file mode 100644
index 0000000..452983e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/lambda-function.cpp
@@ -0,0 +1,37 @@
+// RUN: clang-change-namespace -old_namespace "na::nb" -new_namespace "x::y" --file_pattern ".*" %s -- -std=c++11 | sed 's,// CHECK.*,,' | FileCheck %s
+
+template <class T>
+class function;
+template <class R, class... ArgTypes>
+class function<R(ArgTypes...)> {
+public:
+ template <typename Functor>
+ function(Functor f) {}
+ R operator()(ArgTypes...) const {}
+};
+
+namespace x {
+// CHECK: namespace x {
+class X {};
+}
+
+namespace na {
+namespace nb {
+// CHECK: namespace x {
+// CHECK-NEXT: namespace y {
+void f(function<void(int)> func, int param) { func(param); }
+void g() { f([](int x) {}, 1); }
+
+// x::X in function type parameter list will have translation unit context, so
+// we simply replace it with fully-qualified name.
+using TX = function<x::X(x::X)>;
+// CHECK: using TX = function<X(x::X)>;
+
+class A {};
+using TA = function<A(A)>;
+// CHECK: using TA = function<A(A)>;
+
+// CHECK: } // namespace y
+// CHECK-NEXT: } // namespace x
+}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/macro.cpp b/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/macro.cpp
new file mode 100644
index 0000000..ba47de6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/macro.cpp
@@ -0,0 +1,29 @@
+// RUN: cp %S/macro.cpp %T/macro.cpp
+// RUN: echo "#define USING using na::nc::X" > %T/macro.h
+//
+// RUN: clang-change-namespace -old_namespace "na::nb" -new_namespace "x::y" --file_pattern "macro.cpp" --i %T/macro.cpp --
+// RUN: FileCheck -input-file=%T/macro.cpp -check-prefix=CHECK-CC %s
+// RUN: FileCheck -input-file=%T/macro.h -check-prefix=CHECK-HEADER %s
+//
+// RUN: cp %S/macro.cpp %T/macro.cpp
+// RUN: echo "#define USING using na::nc::X" > %T/macro.h
+// RUN: clang-change-namespace -old_namespace "na::nb" -new_namespace "x::y" --file_pattern ".*" --i %T/macro.cpp --
+// RUN: FileCheck -input-file=%T/macro.cpp -check-prefix=CHECK-CC %s
+// RUN: FileCheck -input-file=%T/macro.h -check-prefix=CHECK-CHANGED-HEADER %s
+#include "macro.h"
+namespace na { namespace nc { class X{}; } }
+
+namespace na {
+namespace nb {
+USING;
+}
+}
+// CHECK-CC: namespace x {
+// CHECK-CC: namespace y {
+// CHECK-CC: USING;
+// CHECK-CC: } // namespace y
+// CHECK-CC: } // namespace x
+
+// CHECK-HEADER: #define USING using na::nc::X
+
+// CHECK-CHANGED-HEADER: #define USING using ::na::nc::X
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/simple-move.cpp b/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/simple-move.cpp
new file mode 100644
index 0000000..ea3c3d3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/simple-move.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-change-namespace -old_namespace "na::nb" -new_namespace "x::y" --file_pattern ".*" %s -- | sed 's,// CHECK.*,,' | FileCheck %s
+// CHECK: namespace x {
+// CHECK-NEXT: namespace y {
+namespace na {
+namespace nb {
+class A {};
+// CHECK: } // namespace y
+// CHECK-NEXT: } // namespace x
+}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/white-list.cpp b/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/white-list.cpp
new file mode 100644
index 0000000..48e3a78
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/change-namespace/white-list.cpp
@@ -0,0 +1,19 @@
+// RUN: echo "^std::.*$" > %T/white-list.txt
+// RUN: clang-change-namespace -old_namespace "na::nb" -new_namespace "x::y" --file_pattern ".*" --whitelist_file %T/white-list.txt %s -- | sed 's,// CHECK.*,,' | FileCheck %s
+
+#include "Inputs/fake-std.h"
+
+// CHECK: namespace x {
+// CHECK-NEXT: namespace y {
+namespace na {
+namespace nb {
+void f() {
+ std::STD x1;
+ STD x2;
+// CHECK: {{^}} std::STD x1;{{$}}
+// CHECK-NEXT: {{^}} STD x2;{{$}}
+}
+// CHECK: } // namespace y
+// CHECK-NEXT: } // namespace x
+}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/ClangRenameClassReplacements.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/ClangRenameClassReplacements.cpp
new file mode 100644
index 0000000..2b478bb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/ClangRenameClassReplacements.cpp
@@ -0,0 +1,11 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t/fixes
+// RUN: cat %s > %t.cpp
+// RUN: clang-rename -offset=254 -new-name=Bar -export-fixes=%t/fixes/clang-rename.yaml %t.cpp --
+// RUN: clang-apply-replacements %t
+// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
+
+class Foo {}; // CHECK: class Bar {};
+
+// Use grep -FUbo 'Foo' <file> to get the correct offset of Cla when changing
+// this file.
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/basic/basic.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/basic/basic.h
new file mode 100644
index 0000000..4850968
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/basic/basic.h
@@ -0,0 +1,32 @@
+#ifndef BASIC_H
+#define BASIC_H
+
+
+class Parent {
+public:
+ virtual void func() {}
+};
+
+class Derived : public Parent {
+public:
+ virtual void func() {}
+ // CHECK: virtual void func() override {}
+};
+
+extern void ext(int (&)[5], const Parent &);
+
+void func(int t) {
+ int ints[5];
+ for (unsigned i = 0; i < 5; ++i) {
+ int &e = ints[i];
+ e = t;
+ // CHECK: for (auto & elem : ints) {
+ // CHECK-NEXT: elem = t;
+ }
+
+ Derived d;
+
+ ext(ints, d);
+}
+
+#endif // BASIC_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/basic/file1.yaml b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/basic/file1.yaml
new file mode 100644
index 0000000..3a5375e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/basic/file1.yaml
@@ -0,0 +1,25 @@
+---
+MainSourceFile: source1.cpp
+Diagnostics:
+ - DiagnosticName: test-basic
+ Message: Fix
+ FilePath: $(path)/basic.h
+ FileOffset: 242
+ Replacements:
+ - FilePath: $(path)/basic.h
+ Offset: 242
+ Length: 26
+ ReplacementText: 'auto & elem : ints'
+ - FilePath: $(path)/basic.h
+ Offset: 276
+ Length: 22
+ ReplacementText: ''
+ - FilePath: $(path)/basic.h
+ Offset: 298
+ Length: 1
+ ReplacementText: elem
+ - FilePath: $(path)/../basic/basic.h
+ Offset: 148
+ Length: 0
+ ReplacementText: 'override '
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/basic/file2.yaml b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/basic/file2.yaml
new file mode 100644
index 0000000..8f6f65a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/basic/file2.yaml
@@ -0,0 +1,13 @@
+---
+MainSourceFile: source2.cpp
+Diagnostics:
+ - DiagnosticName: test-basic
+ Message: Fix
+ FilePath: $(path)/basic.h
+ FileOffset: 148
+ Replacements:
+ - FilePath: $(path)/../basic/basic.h
+ Offset: 298
+ Length: 1
+ ReplacementText: elem
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/common.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/common.h
new file mode 100644
index 0000000..630a39a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/common.h
@@ -0,0 +1,17 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+extern void ext(int (&)[5]);
+
+void func(int t) {
+ int ints[5];
+ for (unsigned i = 0; i < 5; ++i) {
+ ints[i] = t;
+ }
+
+ int *i = 0;
+
+ ext(ints);
+}
+
+#endif // COMMON_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/expected.txt b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/expected.txt
new file mode 100644
index 0000000..b66f577
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/expected.txt
@@ -0,0 +1,12 @@
+The new replacement overlaps with an existing replacement.
+New replacement: $(path)/common.h: 106:+26:"int & elem : ints"
+Existing replacement: $(path)/common.h: 106:+26:"auto & i : ints"
+The new replacement overlaps with an existing replacement.
+New replacement: $(path)/common.h: 140:+7:"i"
+Existing replacement: $(path)/common.h: 140:+7:"elem"
+The new replacement overlaps with an existing replacement.
+New replacement: $(path)/common.h: 169:+0:"(int*)"
+Existing replacement: $(path)/common.h: 160:+12:""
+The new replacement overlaps with an existing replacement.
+New replacement: $(path)/common.h: 169:+1:"nullptr"
+Existing replacement: $(path)/common.h: 160:+12:""
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/file1.yaml b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/file1.yaml
new file mode 100644
index 0000000..8505273
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/file1.yaml
@@ -0,0 +1,21 @@
+---
+MainSourceFile: source1.cpp
+Diagnostics:
+ - DiagnosticName: test-conflict
+ Message: Fix
+ FilePath: $(path)/common.h
+ FileOffset: 106
+ Replacements:
+ - FilePath: $(path)/common.h
+ Offset: 106
+ Length: 26
+ ReplacementText: 'auto & i : ints'
+ - FilePath: $(path)/common.h
+ Offset: 140
+ Length: 7
+ ReplacementText: i
+ - FilePath: $(path)/common.h
+ Offset: 160
+ Length: 12
+ ReplacementText: ''
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/file2.yaml b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/file2.yaml
new file mode 100644
index 0000000..32b35ac
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/file2.yaml
@@ -0,0 +1,21 @@
+---
+MainSourceFile: source2.cpp
+Diagnostics:
+ - DiagnosticName: test-conflict
+ Message: Fix
+ FilePath: $(path)/common.h
+ FileOffset: 106
+ Replacements:
+ - FilePath: $(path)/common.h
+ Offset: 106
+ Length: 26
+ ReplacementText: 'int & elem : ints'
+ - FilePath: $(path)/common.h
+ Offset: 140
+ Length: 7
+ ReplacementText: elem
+ - FilePath: $(path)/common.h
+ Offset: 169
+ Length: 1
+ ReplacementText: nullptr
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/file3.yaml b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/file3.yaml
new file mode 100644
index 0000000..88543e0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/conflict/file3.yaml
@@ -0,0 +1,13 @@
+---
+MainSourceFile: source1.cpp
+Diagnostics:
+ - DiagnosticName: test-conflict
+ Message: Fix
+ FilePath: $(path)/common.h
+ FileOffset: 169
+ Replacements:
+ - FilePath: $(path)/common.h
+ Offset: 169
+ Length: 0
+ ReplacementText: "(int*)"
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/crlf/crlf.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/crlf/crlf.cpp
new file mode 100644
index 0000000..26f7996
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/crlf/crlf.cpp
@@ -0,0 +1,6 @@
+
+// This file intentionally uses a CRLF newlines!
+
+void foo() {
+ int *x = 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/crlf/crlf.cpp.expected b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/crlf/crlf.cpp.expected
new file mode 100644
index 0000000..ad8e907
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/crlf/crlf.cpp.expected
@@ -0,0 +1,6 @@
+
+// This file intentionally uses a CRLF newlines!
+
+void foo() {
+ int *x = nullptr;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/crlf/file1.yaml b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/crlf/file1.yaml
new file mode 100644
index 0000000..06b058e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/crlf/file1.yaml
@@ -0,0 +1,13 @@
+---
+MainSourceFile: source1.cpp
+Diagnostics:
+ - DiagnosticName: test-crlf
+ Message: Fix
+ FilePath: $(path)/crlf.cpp
+ FileOffset: 79
+ Replacements:
+ - FilePath: $(path)/crlf.cpp
+ Offset: 79
+ Length: 1
+ ReplacementText: nullptr
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/format/no.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/format/no.cpp
new file mode 100644
index 0000000..5bc9081
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/format/no.cpp
@@ -0,0 +1,6 @@
+class C {};
+
+void f() { // This comment necessary to prevent formatting as void f() { ... }
+ C *a = new C();
+ // CHECK: {{^\ \ auto\ a\ \=\ new\ C\(\);}}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/format/no.yaml b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/format/no.yaml
new file mode 100644
index 0000000..3118cc6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/format/no.yaml
@@ -0,0 +1,13 @@
+---
+MainSourceFile: no.cpp
+Diagnostics:
+ - DiagnosticName: test-no
+ Message: Fix
+ FilePath: $(path)/no.cpp
+ FileOffset: 94
+ Replacements:
+ - FilePath: $(path)/no.cpp
+ Offset: 94
+ Length: 3
+ ReplacementText: 'auto '
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/format/yes.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/format/yes.cpp
new file mode 100644
index 0000000..8f600c3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/format/yes.cpp
@@ -0,0 +1,22 @@
+class MyType012345678901234567890123456789 {};
+
+void g(int, int*, int, int*, int, int*, int);
+
+void f() {
+ MyType012345678901234567890123456789 *a =
+ new MyType012345678901234567890123456789();
+ // CHECK: {{^\ \ auto\ a\ \=\ new\ MyType012345678901234567890123456789\(\);}}
+
+ int iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii;
+ int jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj;
+ int kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk;
+ int mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm;
+ g(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii, 0, jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj,
+ 0, kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk, 0, mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm);
+ // CHECK: g(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii, nullptr,
+ // CHECK-NEXT: jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj, nullptr,
+ // CHECK-NEXT: kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk, nullptr,
+ // CHECK-NEXT: mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm);
+
+ delete a;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/format/yes.yaml b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/format/yes.yaml
new file mode 100644
index 0000000..6ded4db
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/format/yes.yaml
@@ -0,0 +1,27 @@
+# These replacements are out of order on purpose to test that they get sorted
+# so that formatting happens correctly.
+---
+MainSourceFile: yes.cpp
+Diagnostics:
+ - DiagnosticName: test-yes
+ Message: Fix
+ FilePath: $(path)/yes.cpp
+ FileOffset: 494
+ Replacements:
+ - FilePath: $(path)/yes.cpp
+ Offset: 494
+ Length: 1
+ ReplacementText: nullptr
+ - FilePath: $(path)/yes.cpp
+ Offset: 410
+ Length: 1
+ ReplacementText: nullptr
+ - FilePath: $(path)/yes.cpp
+ Offset: 454
+ Length: 1
+ ReplacementText: nullptr
+ - FilePath: $(path)/yes.cpp
+ Offset: 108
+ Length: 38
+ ReplacementText: 'auto '
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/identical/file1.yaml b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/identical/file1.yaml
new file mode 100644
index 0000000..1ef5651
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/identical/file1.yaml
@@ -0,0 +1,18 @@
+---
+MainSourceFile: identical.cpp
+Diagnostics:
+ - DiagnosticName: test-identical-insertion
+ Message: Fix
+ FilePath: $(path)/identical.cpp
+ FileOffset: 12
+ Replacements:
+ - FilePath: $(path)/identical.cpp
+ Offset: 12
+ Length: 0
+ ReplacementText: '0'
+ - FilePath: $(path)/identical.cpp
+ Offset: 12
+ Length: 0
+ ReplacementText: '0'
+...
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/identical/identical.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/identical/identical.cpp
new file mode 100644
index 0000000..bdaab4f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/identical/identical.cpp
@@ -0,0 +1,2 @@
+class MyType {};
+// CHECK: class MyType00 {};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/invalid-files/invalid-files.yaml b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/invalid-files/invalid-files.yaml
new file mode 100644
index 0000000..f84964d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/invalid-files/invalid-files.yaml
@@ -0,0 +1,12 @@
+---
+MainSourceFile: ''
+Replacements:
+ - FilePath: idontexist.h
+ Offset: 2669
+ Length: 0
+ ReplacementText: ' override'
+ - FilePath: idontexist.h
+ Offset: 2669
+ Length: 0
+ ReplacementText: ' override'
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/order-dependent/expected.txt b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/order-dependent/expected.txt
new file mode 100644
index 0000000..cf38b34
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/order-dependent/expected.txt
@@ -0,0 +1,3 @@
+The new insertion has the same insert location as an existing replacement.
+New replacement: $(path)/order-dependent.cpp: 12:+0:"1"
+Existing replacement: $(path)/order-dependent.cpp: 12:+0:"0"
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/order-dependent/file1.yaml b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/order-dependent/file1.yaml
new file mode 100644
index 0000000..a823438
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/order-dependent/file1.yaml
@@ -0,0 +1,13 @@
+---
+MainSourceFile: order-dependent.cpp
+Diagnostics:
+ - DiagnosticName: test-order-dependent-insertion
+ Message: Fix
+ FilePath: $(path)/order-dependent.cpp
+ FileOffset: 12
+ Replacements:
+ - FilePath: $(path)/order-dependent.cpp
+ Offset: 12
+ Length: 0
+ ReplacementText: '0'
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/order-dependent/file2.yaml b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/order-dependent/file2.yaml
new file mode 100644
index 0000000..634d3ca
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/order-dependent/file2.yaml
@@ -0,0 +1,13 @@
+---
+MainSourceFile: order-dependent.cpp
+Diagnostics:
+ - DiagnosticName: test-order-dependent-insertion
+ Message: Fix
+ FilePath: $(path)/order-dependent.cpp
+ FileOffset: 12
+ Replacements:
+ - FilePath: $(path)/order-dependent.cpp
+ Offset: 12
+ Length: 0
+ ReplacementText: '1'
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/order-dependent/order-dependent.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/order-dependent/order-dependent.cpp
new file mode 100644
index 0000000..5b98860
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/Inputs/order-dependent/order-dependent.cpp
@@ -0,0 +1 @@
+class MyType {};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/basic.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/basic.cpp
new file mode 100644
index 0000000..4f19a96
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/basic.cpp
@@ -0,0 +1,17 @@
+// RUN: mkdir -p %T/Inputs/basic
+// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/basic/basic.h > %T/Inputs/basic/basic.h
+// RUN: sed "s#\$(path)#%/T/Inputs/basic#" %S/Inputs/basic/file1.yaml > %T/Inputs/basic/file1.yaml
+// RUN: sed "s#\$(path)#%/T/Inputs/basic#" %S/Inputs/basic/file2.yaml > %T/Inputs/basic/file2.yaml
+// RUN: clang-apply-replacements %T/Inputs/basic
+// RUN: FileCheck -input-file=%T/Inputs/basic/basic.h %S/Inputs/basic/basic.h
+//
+// Check that the yaml files are *not* deleted after running clang-apply-replacements without remove-change-desc-files.
+// RUN: ls -1 %T/Inputs/basic | FileCheck %s --check-prefix=YAML
+//
+// Check that the yaml files *are* deleted after running clang-apply-replacements with remove-change-desc-files.
+// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/basic/basic.h > %T/Inputs/basic/basic.h
+// RUN: clang-apply-replacements -remove-change-desc-files %T/Inputs/basic
+// RUN: ls -1 %T/Inputs/basic | FileCheck %s --check-prefix=NO_YAML
+//
+// YAML: {{^file.\.yaml$}}
+// NO_YAML-NOT: {{^file.\.yaml$}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/conflict.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/conflict.cpp
new file mode 100644
index 0000000..c1f2342
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/conflict.cpp
@@ -0,0 +1,17 @@
+// RUN: mkdir -p %T/Inputs/conflict
+// RUN: sed "s#\$(path)#%/S/Inputs/conflict#" %S/Inputs/conflict/file1.yaml > %T/Inputs/conflict/file1.yaml
+// RUN: sed "s#\$(path)#%/S/Inputs/conflict#" %S/Inputs/conflict/file2.yaml > %T/Inputs/conflict/file2.yaml
+// RUN: sed "s#\$(path)#%/S/Inputs/conflict#" %S/Inputs/conflict/file3.yaml > %T/Inputs/conflict/file3.yaml
+// RUN: sed "s#\$(path)#%/S/Inputs/conflict#" %S/Inputs/conflict/expected.txt > %T/Inputs/conflict/expected.txt
+// RUN: not clang-apply-replacements %T/Inputs/conflict > %T/Inputs/conflict/output.txt 2>&1
+// RUN: diff -b %T/Inputs/conflict/output.txt %T/Inputs/conflict/expected.txt
+//
+// Check that the yaml files are *not* deleted after running clang-apply-replacements without remove-change-desc-files even when there is a failure.
+// RUN: ls -1 %T/Inputs/conflict | FileCheck %s --check-prefix=YAML
+//
+// Check that the yaml files *are* deleted after running clang-apply-replacements with remove-change-desc-files even when there is a failure.
+// RUN: not clang-apply-replacements %T/Inputs/conflict -remove-change-desc-files > %T/Inputs/conflict/output.txt 2>&1
+// RUN: ls -1 %T/Inputs/conflict | FileCheck %s --check-prefix=NO_YAML
+//
+// YAML: {{^file.\.yaml$}}
+// NO_YAML-NOT: {{^file.\.yaml$}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/crlf.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/crlf.cpp
new file mode 100644
index 0000000..15ba5b5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/crlf.cpp
@@ -0,0 +1,5 @@
+// RUN: mkdir -p %T/Inputs/crlf
+// RUN: cat %S/Inputs/crlf/crlf.cpp > %T/Inputs/crlf/crlf.cpp
+// RUN: sed "s#\$(path)#%/T/Inputs/crlf#" %S/Inputs/crlf/file1.yaml > %T/Inputs/crlf/file1.yaml
+// RUN: clang-apply-replacements %T/Inputs/crlf
+// RUN: diff %T/Inputs/crlf/crlf.cpp %S/Inputs/crlf/crlf.cpp.expected
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/format.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/format.cpp
new file mode 100644
index 0000000..7de320d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/format.cpp
@@ -0,0 +1,15 @@
+// RUN: mkdir -p %T/Inputs/format
+//
+// yes.cpp requires formatting after replacements are applied. no.cpp does not.
+// The presence of no.cpp ensures that files that don't need formatting still
+// have their new state written to disk after applying replacements.
+//
+// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/format/yes.cpp > %T/Inputs/format/yes.cpp
+// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/format/no.cpp > %T/Inputs/format/no.cpp
+// RUN: sed "s#\$(path)#%/T/Inputs/format#" %S/Inputs/format/yes.yaml > %T/Inputs/format/yes.yaml
+// RUN: sed "s#\$(path)#%/T/Inputs/format#" %S/Inputs/format/no.yaml > %T/Inputs/format/no.yaml
+// RUN: clang-apply-replacements -format %T/Inputs/format
+// RUN: FileCheck --strict-whitespace -input-file=%T/Inputs/format/yes.cpp %S/Inputs/format/yes.cpp
+// RUN: FileCheck --strict-whitespace -input-file=%T/Inputs/format/no.cpp %S/Inputs/format/no.cpp
+//
+// RUN not clang-apply-replacements -format=blah %T/Inputs/format
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/identical.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/identical.cpp
new file mode 100644
index 0000000..b513f3e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/identical.cpp
@@ -0,0 +1,5 @@
+// RUN: mkdir -p %T/Inputs/identical
+// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/identical/identical.cpp > %T/Inputs/identical/identical.cpp
+// RUN: sed "s#\$(path)#%/T/Inputs/identical#" %S/Inputs/identical/file1.yaml > %T/Inputs/identical/file1.yaml
+// RUN: clang-apply-replacements %T/Inputs/identical
+// RUN: FileCheck -input-file=%T/Inputs/identical/identical.cpp %S/Inputs/identical/identical.cpp
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/invalid-files.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/invalid-files.cpp
new file mode 100644
index 0000000..b0eb9ef
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/invalid-files.cpp
@@ -0,0 +1,6 @@
+// RUN: mkdir -p %T/invalid-files
+// RUN: cp %S/Inputs/invalid-files/invalid-files.yaml %T/invalid-files/invalid-files.yaml
+// RUN: clang-apply-replacements %T/invalid-files
+//
+// Check that the yaml files are *not* deleted after running clang-apply-replacements without remove-change-desc-files.
+// RUN: ls %T/invalid-files/invalid-files.yaml
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/order-dependent.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/order-dependent.cpp
new file mode 100644
index 0000000..769f4f7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-apply-replacements/order-dependent.cpp
@@ -0,0 +1,7 @@
+// RUN: mkdir -p %T/Inputs/order-dependent
+// RUN: grep -Ev "// *[A-Z-]+:" %S/Inputs/order-dependent/order-dependent.cpp > %T/Inputs/order-dependent/order-dependent.cpp
+// RUN: sed "s#\$(path)#%/T/Inputs/order-dependent#" %S/Inputs/order-dependent/file1.yaml > %T/Inputs/order-dependent/file1.yaml
+// RUN: sed "s#\$(path)#%/T/Inputs/order-dependent#" %S/Inputs/order-dependent/file2.yaml > %T/Inputs/order-dependent/file2.yaml
+// RUN: sed "s#\$(path)#%/T/Inputs/order-dependent#" %S/Inputs/order-dependent/expected.txt > %T/Inputs/order-dependent/expected.txt
+// RUN: not clang-apply-replacements %T/Inputs/order-dependent > %T/Inputs/order-dependent/output.txt 2>&1
+// RUN: diff -b %T/Inputs/order-dependent/output.txt %T/Inputs/order-dependent/expected.txt
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/bc-comment.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/bc-comment.cpp
new file mode 100644
index 0000000..fa3ea7f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/bc-comment.cpp
@@ -0,0 +1,202 @@
+// THIS IS A GENERATED TEST. DO NOT EDIT.
+// To regenerate, see clang-doc/gen_test.py docstring.
+//
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+
+/// \brief Brief description.
+///
+/// Extended description that
+/// continues onto the next line.
+///
+/// <ul class="test">
+/// <li> Testing.
+/// </ul>
+///
+/// \verbatim
+/// The description continues.
+/// \endverbatim
+/// --
+/// \param [out] I is a parameter.
+/// \param J is a parameter.
+/// \return void
+void F(int I, int J);
+
+/// Bonus comment on definition
+void F(int I, int J) {}
+
+// RUN: clang-doc --dump-intermediate --doxygen -p %t %t/test.cpp -output=%t/docs
+
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/7574630614A535710E5A6ABCFFF98BCA2D06A4CA.bc | FileCheck %s --check-prefix CHECK-0
+// CHECK-0: <BLOCKINFO_BLOCK/>
+// CHECK-0-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-0-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-0-NEXT: </VersionBlock>
+// CHECK-0-NEXT: <FunctionBlock NumWords=429 BlockCodeSize=4>
+// CHECK-0-NEXT: <USR abbrevid=4 op0=20 op1=117 op2=116 op3=99 op4=6 op5=20 op6=165 op7=53 op8=113 op9=14 op10=90 op11=106 op12=188 op13=255 op14=249 op15=139 op16=202 op17=45 op18=6 op19=164 op20=202/>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=1/> blob data = 'F'
+// CHECK-0-NEXT: <CommentBlock NumWords=354 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'FullComment'
+// CHECK-0-NEXT: <CommentBlock NumWords=13 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+// CHECK-0-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=31 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'BlockCommandComment'
+// CHECK-0-NEXT: <Name abbrevid=6 op0=5/> blob data = 'brief'
+// CHECK-0-NEXT: <CommentBlock NumWords=19 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+// CHECK-0-NEXT: <CommentBlock NumWords=11 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: <Text abbrevid=5 op0=19/> blob data = ' Brief description.'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=37 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+// CHECK-0-NEXT: <CommentBlock NumWords=13 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: <Text abbrevid=5 op0=26/> blob data = ' Extended description that'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=14 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: <Text abbrevid=5 op0=30/> blob data = ' continues onto the next line.'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=76 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+// CHECK-0-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=14 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'HTMLStartTagComment'
+// CHECK-0-NEXT: <Name abbrevid=6 op0=2/> blob data = 'ul'
+// CHECK-0-NEXT: <AttrKey abbrevid=12 op0=5/> blob data = 'class'
+// CHECK-0-NEXT: <AttrVal abbrevid=13 op0=4/> blob data = '{{.*}}'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=9 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'HTMLStartTagComment'
+// CHECK-0-NEXT: <Name abbrevid=6 op0=2/> blob data = 'li'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=9 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: <Text abbrevid=5 op0=9/> blob data = ' Testing.'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=9 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=17/> blob data = 'HTMLEndTagComment'
+// CHECK-0-NEXT: <Name abbrevid=6 op0=2/> blob data = 'ul'
+// CHECK-0-NEXT: <SelfClosing abbrevid=10 op0=1/>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=13 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+// CHECK-0-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=32 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=20/> blob data = 'VerbatimBlockComment'
+// CHECK-0-NEXT: <Name abbrevid=6 op0=8/> blob data = 'verbatim'
+// CHECK-0-NEXT: <CloseName abbrevid=9 op0=11/> blob data = 'endverbatim'
+// CHECK-0-NEXT: <CommentBlock NumWords=16 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=24/> blob data = 'VerbatimBlockLineComment'
+// CHECK-0-NEXT: <Text abbrevid=5 op0=27/> blob data = ' The description continues.'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=22 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+// CHECK-0-NEXT: <CommentBlock NumWords=7 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: <Text abbrevid=5 op0=3/> blob data = ' --'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=39 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'ParamCommandComment'
+// CHECK-0-NEXT: <Direction abbrevid=7 op0=5/> blob data = '[out]'
+// CHECK-0-NEXT: <ParamName abbrevid=8 op0=1/> blob data = 'I'
+// CHECK-0-NEXT: <Explicit abbrevid=11 op0=1/>
+// CHECK-0-NEXT: <CommentBlock NumWords=25 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+// CHECK-0-NEXT: <CommentBlock NumWords=10 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: <Text abbrevid=5 op0=16/> blob data = ' is a parameter.'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=38 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'ParamCommandComment'
+// CHECK-0-NEXT: <Direction abbrevid=7 op0=4/> blob data = '[in]'
+// CHECK-0-NEXT: <ParamName abbrevid=8 op0=1/> blob data = 'J'
+// CHECK-0-NEXT: <CommentBlock NumWords=25 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+// CHECK-0-NEXT: <CommentBlock NumWords=10 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: <Text abbrevid=5 op0=16/> blob data = ' is a parameter.'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=28 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'BlockCommandComment'
+// CHECK-0-NEXT: <Name abbrevid=6 op0=6/> blob data = 'return'
+// CHECK-0-NEXT: <CommentBlock NumWords=16 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+// CHECK-0-NEXT: <CommentBlock NumWords=8 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: <Text abbrevid=5 op0=5/> blob data = ' void'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <CommentBlock NumWords=28 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'FullComment'
+// CHECK-0-NEXT: <CommentBlock NumWords=21 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+// CHECK-0-NEXT: <CommentBlock NumWords=13 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: <Text abbrevid=5 op0=28/> blob data = ' Bonus comment on definition'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <DefLocation abbrevid=6 op0=28 op1=4/> blob data = '{{.*}}'
+// CHECK-0-NEXT: <Location abbrevid=7 op0=25 op1=4/> blob data = '{{.*}}'
+// CHECK-0-NEXT: <TypeBlock NumWords=6 BlockCodeSize=4>
+// CHECK-0-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+// CHECK-0-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-0-NEXT: </ReferenceBlock>
+// CHECK-0-NEXT: </TypeBlock>
+// CHECK-0-NEXT: <FieldTypeBlock NumWords=8 BlockCodeSize=4>
+// CHECK-0-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+// CHECK-0-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-0-NEXT: </ReferenceBlock>
+// CHECK-0-NEXT: <Name abbrevid=4 op0=1/> blob data = 'I'
+// CHECK-0-NEXT: </FieldTypeBlock>
+// CHECK-0-NEXT: <FieldTypeBlock NumWords=8 BlockCodeSize=4>
+// CHECK-0-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+// CHECK-0-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-0-NEXT: </ReferenceBlock>
+// CHECK-0-NEXT: <Name abbrevid=4 op0=1/> blob data = 'J'
+// CHECK-0-NEXT: </FieldTypeBlock>
+// CHECK-0-NEXT: </FunctionBlock>
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/bc-namespace.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/bc-namespace.cpp
new file mode 100644
index 0000000..b1c0363
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/bc-namespace.cpp
@@ -0,0 +1,139 @@
+// THIS IS A GENERATED TEST. DO NOT EDIT.
+// To regenerate, see clang-doc/gen_test.py docstring.
+//
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+
+namespace A {
+
+void f();
+
+} // namespace A
+
+namespace A {
+
+void f(){};
+
+namespace B {
+
+enum E { X };
+
+E func(int i) { return X; }
+
+} // namespace B
+} // namespace A
+
+// RUN: clang-doc --dump-intermediate --doxygen -p %t %t/test.cpp -output=%t/docs
+
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/E9ABF7E7E2425B626723D41E76E4BC7E7A5BD775.bc | FileCheck %s --check-prefix CHECK-0
+// CHECK-0: <BLOCKINFO_BLOCK/>
+// CHECK-0-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-0-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-0-NEXT: </VersionBlock>
+// CHECK-0-NEXT: <EnumBlock NumWords=38 BlockCodeSize=4>
+// CHECK-0-NEXT: <USR abbrevid=4 op0=20 op1=233 op2=171 op3=247 op4=231 op5=226 op6=66 op7=91 op8=98 op9=103 op10=35 op11=212 op12=30 op13=118 op14=228 op15=188 op16=126 op17=122 op18=91 op19=215 op20=117/>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-0-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-0-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
+// CHECK-0-NEXT: <RefType abbrevid=6 op0=1/>
+// CHECK-0-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-0-NEXT: </ReferenceBlock>
+// CHECK-0-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-0-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK-0-NEXT: <RefType abbrevid=6 op0=1/>
+// CHECK-0-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-0-NEXT: </ReferenceBlock>
+// CHECK-0-NEXT: <DefLocation abbrevid=6 op0=21 op1=4/> blob data = '{{.*}}'
+// CHECK-0-NEXT: <Member abbrevid=8 op0=1/> blob data = 'X'
+// CHECK-0-NEXT: </EnumBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/39D3C95A5F7CE2BA4937BD7B01BAE09EBC2AD8AC.bc | FileCheck %s --check-prefix CHECK-1
+// CHECK-1: <BLOCKINFO_BLOCK/>
+// CHECK-1-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-1-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-1-NEXT: </VersionBlock>
+// CHECK-1-NEXT: <FunctionBlock NumWords=35 BlockCodeSize=4>
+// CHECK-1-NEXT: <USR abbrevid=4 op0=20 op1=57 op2=211 op3=201 op4=90 op5=95 op6=124 op7=226 op8=186 op9=73 op10=55 op11=189 op12=123 op13=1 op14=186 op15=224 op16=158 op17=188 op18=42 op19=216 op20=172/>
+// CHECK-1-NEXT: <Name abbrevid=5 op0=1/> blob data = 'f'
+// CHECK-1-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-1-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+// CHECK-1-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK-1-NEXT: <RefType abbrevid=6 op0=1/>
+// CHECK-1-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-1-NEXT: </ReferenceBlock>
+// CHECK-1-NEXT: <DefLocation abbrevid=6 op0=17 op1=4/> blob data = '{{.*}}'
+// CHECK-1-NEXT: <Location abbrevid=7 op0=11 op1=4/> blob data = '{{.*}}'
+// CHECK-1-NEXT: <TypeBlock NumWords=6 BlockCodeSize=4>
+// CHECK-1-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-1-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+// CHECK-1-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-1-NEXT: </ReferenceBlock>
+// CHECK-1-NEXT: </TypeBlock>
+// CHECK-1-NEXT: </FunctionBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/9A82CB33ED0FDF81EE383D31CD0957D153C5E840.bc | FileCheck %s --check-prefix CHECK-2
+// CHECK-2: <BLOCKINFO_BLOCK/>
+// CHECK-2-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-2-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-2-NEXT: </VersionBlock>
+// CHECK-2-NEXT: <FunctionBlock NumWords=56 BlockCodeSize=4>
+// CHECK-2-NEXT: <USR abbrevid=4 op0=20 op1=154 op2=130 op3=203 op4=51 op5=237 op6=15 op7=223 op8=129 op9=238 op10=56 op11=61 op12=49 op13=205 op14=9 op15=87 op16=209 op17=83 op18=197 op19=232 op20=64/>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=4/> blob data = 'func'
+// CHECK-2-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-2-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
+// CHECK-2-NEXT: <RefType abbrevid=6 op0=1/>
+// CHECK-2-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-2-NEXT: </ReferenceBlock>
+// CHECK-2-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-2-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK-2-NEXT: <RefType abbrevid=6 op0=1/>
+// CHECK-2-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-2-NEXT: </ReferenceBlock>
+// CHECK-2-NEXT: <DefLocation abbrevid=6 op0=23 op1=4/> blob data = '{{.*}}'
+// CHECK-2-NEXT: <TypeBlock NumWords=8 BlockCodeSize=4>
+// CHECK-2-NEXT: <ReferenceBlock NumWords=5 BlockCodeSize=4>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=12/> blob data = 'enum A::B::E'
+// CHECK-2-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-2-NEXT: </ReferenceBlock>
+// CHECK-2-NEXT: </TypeBlock>
+// CHECK-2-NEXT: <FieldTypeBlock NumWords=8 BlockCodeSize=4>
+// CHECK-2-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+// CHECK-2-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-2-NEXT: </ReferenceBlock>
+// CHECK-2-NEXT: <Name abbrevid=4 op0=1/> blob data = 'i'
+// CHECK-2-NEXT: </FieldTypeBlock>
+// CHECK-2-NEXT: </FunctionBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/8D042EFFC98B373450BC6B5B90A330C25A150E9C.bc | FileCheck %s --check-prefix CHECK-3
+// CHECK-3: <BLOCKINFO_BLOCK/>
+// CHECK-3-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-3-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-3-NEXT: </VersionBlock>
+// CHECK-3-NEXT: <NamespaceBlock NumWords=9 BlockCodeSize=4>
+// CHECK-3-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+// CHECK-3-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK-3-NEXT: </NamespaceBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/E21AF79E2A9D02554BA090D10DF39FE273F5CDB5.bc | FileCheck %s --check-prefix CHECK-4
+// CHECK-4: <BLOCKINFO_BLOCK/>
+// CHECK-4-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-4-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-4-NEXT: </VersionBlock>
+// CHECK-4-NEXT: <NamespaceBlock NumWords=21 BlockCodeSize=4>
+// CHECK-4-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/>
+// CHECK-4-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
+// CHECK-4-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-4-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+// CHECK-4-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK-4-NEXT: <RefType abbrevid=6 op0=1/>
+// CHECK-4-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-4-NEXT: </ReferenceBlock>
+// CHECK-4-NEXT: </NamespaceBlock>
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/bc-record.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/bc-record.cpp
new file mode 100644
index 0000000..7a09118
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/bc-record.cpp
@@ -0,0 +1,321 @@
+// THIS IS A GENERATED TEST. DO NOT EDIT.
+// To regenerate, see clang-doc/gen_test.py docstring.
+//
+// This test requires Linux due to system-dependent USR for the inner class.
+// REQUIRES: system-linux
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+
+void H() {
+ class I {};
+}
+
+union A { int X; int Y; };
+
+enum B { X, Y };
+
+enum class Bc { A, B };
+
+struct C { int i; };
+
+class D {};
+
+class E {
+public:
+ E() {}
+ ~E() {}
+
+protected:
+ void ProtectedMethod();
+};
+
+void E::ProtectedMethod() {}
+
+class F : virtual private D, public E {};
+
+class X {
+ class Y {};
+};
+
+// RUN: clang-doc --dump-intermediate --doxygen -p %t %t/test.cpp -output=%t/docs
+
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/289584A8E0FF4178A794622A547AA622503967A1.bc | FileCheck %s --check-prefix CHECK-0
+// CHECK-0: <BLOCKINFO_BLOCK/>
+// CHECK-0-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-0-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-0-NEXT: </VersionBlock>
+// CHECK-0-NEXT: <RecordBlock NumWords=12 BlockCodeSize=4>
+// CHECK-0-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-0-NEXT: <DefLocation abbrevid=6 op0=25 op1=4/> blob data = '{{.*}}'
+// CHECK-0-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-0-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/3FB542274573CAEAD54CEBFFCAEE3D77FB9713D8.bc | FileCheck %s --check-prefix CHECK-1
+// CHECK-1: <BLOCKINFO_BLOCK/>
+// CHECK-1-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-1-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-1-NEXT: </VersionBlock>
+// CHECK-1-NEXT: <RecordBlock NumWords=24 BlockCodeSize=4>
+// CHECK-1-NEXT: <USR abbrevid=4 op0=20 op1=63 op2=181 op3=66 op4=39 op5=69 op6=115 op7=202 op8=234 op9=213 op10=76 op11=235 op12=255 op13=202 op14=238 op15=61 op16=119 op17=251 op18=151 op19=19 op20=216/>
+// CHECK-1-NEXT: <Name abbrevid=5 op0=1/> blob data = 'I'
+// CHECK-1-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-1-NEXT: <USR abbrevid=4 op0=20 op1=182 op2=172 op3=76 op4=92 op5=159 op6=46 op7=163 op8=242 op9=179 op10=236 op11=225 op12=163 op13=61 op14=52 op15=159 op16=78 op17=229 op18=2 op19=178 op20=78/>
+// CHECK-1-NEXT: <Name abbrevid=5 op0=1/> blob data = 'H'
+// CHECK-1-NEXT: <RefType abbrevid=6 op0=3/>
+// CHECK-1-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-1-NEXT: </ReferenceBlock>
+// CHECK-1-NEXT: <DefLocation abbrevid=6 op0=12 op1=4/> blob data = '{{.*}}'
+// CHECK-1-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-1-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/5093D428CDC62096A67547BA52566E4FB9404EEE.bc | FileCheck %s --check-prefix CHECK-2
+// CHECK-2: <BLOCKINFO_BLOCK/>
+// CHECK-2-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-2-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-2-NEXT: </VersionBlock>
+// CHECK-2-NEXT: <FunctionBlock NumWords=50 BlockCodeSize=4>
+// CHECK-2-NEXT: <USR abbrevid=4 op0=20 op1=80 op2=147 op3=212 op4=40 op5=205 op6=198 op7=32 op8=150 op9=166 op10=117 op11=71 op12=186 op13=82 op14=86 op15=110 op16=79 op17=185 op18=64 op19=78 op20=238/>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=15/> blob data = 'ProtectedMethod'
+// CHECK-2-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-2-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-2-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-2-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-2-NEXT: </ReferenceBlock>
+// CHECK-2-NEXT: <IsMethod abbrevid=9 op0=1/>
+// CHECK-2-NEXT: <DefLocation abbrevid=6 op0=34 op1=4/> blob data = '{{.*}}'
+// CHECK-2-NEXT: <Location abbrevid=7 op0=31 op1=4/> blob data = '{{.*}}'
+// CHECK-2-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-2-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-2-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-2-NEXT: <Field abbrevid=7 op0=2/>
+// CHECK-2-NEXT: </ReferenceBlock>
+// CHECK-2-NEXT: <TypeBlock NumWords=6 BlockCodeSize=4>
+// CHECK-2-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+// CHECK-2-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-2-NEXT: </ReferenceBlock>
+// CHECK-2-NEXT: </TypeBlock>
+// CHECK-2-NEXT: </FunctionBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/CA7C7935730B5EACD25F080E9C83FA087CCDC75E.bc | FileCheck %s --check-prefix CHECK-3
+// CHECK-3: <BLOCKINFO_BLOCK/>
+// CHECK-3-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-3-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-3-NEXT: </VersionBlock>
+// CHECK-3-NEXT: <RecordBlock NumWords=12 BlockCodeSize=4>
+// CHECK-3-NEXT: <USR abbrevid=4 op0=20 op1=202 op2=124 op3=121 op4=53 op5=115 op6=11 op7=94 op8=172 op9=210 op10=95 op11=8 op12=14 op13=156 op14=131 op15=250 op16=8 op17=124 op18=205 op19=199 op20=94/>
+// CHECK-3-NEXT: <Name abbrevid=5 op0=1/> blob data = 'X'
+// CHECK-3-NEXT: <DefLocation abbrevid=6 op0=38 op1=4/> blob data = '{{.*}}'
+// CHECK-3-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-3-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/B6AC4C5C9F2EA3F2B3ECE1A33D349F4EE502B24E.bc | FileCheck %s --check-prefix CHECK-4
+// CHECK-4: <BLOCKINFO_BLOCK/>
+// CHECK-4-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-4-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-4-NEXT: </VersionBlock>
+// CHECK-4-NEXT: <FunctionBlock NumWords=20 BlockCodeSize=4>
+// CHECK-4-NEXT: <USR abbrevid=4 op0=20 op1=182 op2=172 op3=76 op4=92 op5=159 op6=46 op7=163 op8=242 op9=179 op10=236 op11=225 op12=163 op13=61 op14=52 op15=159 op16=78 op17=229 op18=2 op19=178 op20=78/>
+// CHECK-4-NEXT: <Name abbrevid=5 op0=1/> blob data = 'H'
+// CHECK-4-NEXT: <DefLocation abbrevid=6 op0=11 op1=4/> blob data = '{{.*}}'
+// CHECK-4-NEXT: <TypeBlock NumWords=6 BlockCodeSize=4>
+// CHECK-4-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-4-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+// CHECK-4-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-4-NEXT: </ReferenceBlock>
+// CHECK-4-NEXT: </TypeBlock>
+// CHECK-4-NEXT: </FunctionBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/06B5F6A19BA9F6A832E127C9968282B94619B210.bc | FileCheck %s --check-prefix CHECK-5
+// CHECK-5: <BLOCKINFO_BLOCK/>
+// CHECK-5-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-5-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-5-NEXT: </VersionBlock>
+// CHECK-5-NEXT: <RecordBlock NumWords=22 BlockCodeSize=4>
+// CHECK-5-NEXT: <USR abbrevid=4 op0=20 op1=6 op2=181 op3=246 op4=161 op5=155 op6=169 op7=246 op8=168 op9=50 op10=225 op11=39 op12=201 op13=150 op14=130 op15=130 op16=185 op17=70 op18=25 op19=178 op20=16/>
+// CHECK-5-NEXT: <Name abbrevid=5 op0=1/> blob data = 'C'
+// CHECK-5-NEXT: <DefLocation abbrevid=6 op0=21 op1=4/> blob data = '{{.*}}'
+// CHECK-5-NEXT: <MemberTypeBlock NumWords=8 BlockCodeSize=4>
+// CHECK-5-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-5-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+// CHECK-5-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-5-NEXT: </ReferenceBlock>
+// CHECK-5-NEXT: <Name abbrevid=4 op0=1/> blob data = 'i'
+// CHECK-5-NEXT: <Access abbrevid=5 op0=3/>
+// CHECK-5-NEXT: </MemberTypeBlock>
+// CHECK-5-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/BD2BDEBD423F80BACCEA75DE6D6622D355FC2D17.bc | FileCheck %s --check-prefix CHECK-6
+// CHECK-6: <BLOCKINFO_BLOCK/>
+// CHECK-6-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-6-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-6-NEXT: </VersionBlock>
+// CHECK-6-NEXT: <FunctionBlock NumWords=44 BlockCodeSize=4>
+// CHECK-6-NEXT: <USR abbrevid=4 op0=20 op1=189 op2=43 op3=222 op4=189 op5=66 op6=63 op7=128 op8=186 op9=204 op10=234 op11=117 op12=222 op13=109 op14=102 op15=34 op16=211 op17=85 op18=252 op19=45 op20=23/>
+// CHECK-6-NEXT: <Name abbrevid=5 op0=2/> blob data = '~E'
+// CHECK-6-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-6-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-6-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-6-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-6-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-6-NEXT: </ReferenceBlock>
+// CHECK-6-NEXT: <IsMethod abbrevid=9 op0=1/>
+// CHECK-6-NEXT: <DefLocation abbrevid=6 op0=28 op1=4/> blob data = '{{.*}}'
+// CHECK-6-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-6-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-6-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-6-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-6-NEXT: <Field abbrevid=7 op0=2/>
+// CHECK-6-NEXT: </ReferenceBlock>
+// CHECK-6-NEXT: <TypeBlock NumWords=6 BlockCodeSize=4>
+// CHECK-6-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-6-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+// CHECK-6-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-6-NEXT: </ReferenceBlock>
+// CHECK-6-NEXT: </TypeBlock>
+// CHECK-6-NEXT: </FunctionBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/DEB4AC1CD9253CD9EF7FBE6BCAC506D77984ABD4.bc | FileCheck %s --check-prefix CHECK-7
+// CHECK-7: <BLOCKINFO_BLOCK/>
+// CHECK-7-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-7-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-7-NEXT: </VersionBlock>
+// CHECK-7-NEXT: <FunctionBlock NumWords=44 BlockCodeSize=4>
+// CHECK-7-NEXT: <USR abbrevid=4 op0=20 op1=222 op2=180 op3=172 op4=28 op5=217 op6=37 op7=60 op8=217 op9=239 op10=127 op11=190 op12=107 op13=202 op14=197 op15=6 op16=215 op17=121 op18=132 op19=171 op20=212/>
+// CHECK-7-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-7-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-7-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-7-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-7-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-7-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-7-NEXT: </ReferenceBlock>
+// CHECK-7-NEXT: <IsMethod abbrevid=9 op0=1/>
+// CHECK-7-NEXT: <DefLocation abbrevid=6 op0=27 op1=4/> blob data = '{{.*}}'
+// CHECK-7-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-7-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-7-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-7-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-7-NEXT: <Field abbrevid=7 op0=2/>
+// CHECK-7-NEXT: </ReferenceBlock>
+// CHECK-7-NEXT: <TypeBlock NumWords=6 BlockCodeSize=4>
+// CHECK-7-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-7-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+// CHECK-7-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-7-NEXT: </ReferenceBlock>
+// CHECK-7-NEXT: </TypeBlock>
+// CHECK-7-NEXT: </FunctionBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/641AB4A3D36399954ACDE29C7A8833032BF40472.bc | FileCheck %s --check-prefix CHECK-8
+// CHECK-8: <BLOCKINFO_BLOCK/>
+// CHECK-8-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-8-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-8-NEXT: </VersionBlock>
+// CHECK-8-NEXT: <RecordBlock NumWords=24 BlockCodeSize=4>
+// CHECK-8-NEXT: <USR abbrevid=4 op0=20 op1=100 op2=26 op3=180 op4=163 op5=211 op6=99 op7=153 op8=149 op9=74 op10=205 op11=226 op12=156 op13=122 op14=136 op15=51 op16=3 op17=43 op18=244 op19=4 op20=114/>
+// CHECK-8-NEXT: <Name abbrevid=5 op0=1/> blob data = 'Y'
+// CHECK-8-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-8-NEXT: <USR abbrevid=4 op0=20 op1=202 op2=124 op3=121 op4=53 op5=115 op6=11 op7=94 op8=172 op9=210 op10=95 op11=8 op12=14 op13=156 op14=131 op15=250 op16=8 op17=124 op18=205 op19=199 op20=94/>
+// CHECK-8-NEXT: <Name abbrevid=5 op0=1/> blob data = 'X'
+// CHECK-8-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-8-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-8-NEXT: </ReferenceBlock>
+// CHECK-8-NEXT: <DefLocation abbrevid=6 op0=39 op1=4/> blob data = '{{.*}}'
+// CHECK-8-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-8-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/FC07BD34D5E77782C263FA944447929EA8753740.bc | FileCheck %s --check-prefix CHECK-9
+// CHECK-9: <BLOCKINFO_BLOCK/>
+// CHECK-9-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-9-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-9-NEXT: </VersionBlock>
+// CHECK-9-NEXT: <EnumBlock NumWords=16 BlockCodeSize=4>
+// CHECK-9-NEXT: <USR abbrevid=4 op0=20 op1=252 op2=7 op3=189 op4=52 op5=213 op6=231 op7=119 op8=130 op9=194 op10=99 op11=250 op12=148 op13=68 op14=71 op15=146 op16=158 op17=168 op18=117 op19=55 op20=64/>
+// CHECK-9-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
+// CHECK-9-NEXT: <DefLocation abbrevid=6 op0=17 op1=4/> blob data = '{{.*}}'
+// CHECK-9-NEXT: <Member abbrevid=8 op0=1/> blob data = 'X'
+// CHECK-9-NEXT: <Member abbrevid=8 op0=1/> blob data = 'Y'
+// CHECK-9-NEXT: </EnumBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/0921737541208B8FA9BB42B60F78AC1D779AA054.bc | FileCheck %s --check-prefix CHECK-10
+// CHECK-10: <BLOCKINFO_BLOCK/>
+// CHECK-10-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-10-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-10-NEXT: </VersionBlock>
+// CHECK-10-NEXT: <RecordBlock NumWords=12 BlockCodeSize=4>
+// CHECK-10-NEXT: <USR abbrevid=4 op0=20 op1=9 op2=33 op3=115 op4=117 op5=65 op6=32 op7=139 op8=143 op9=169 op10=187 op11=66 op12=182 op13=15 op14=120 op15=172 op16=29 op17=119 op18=154 op19=160 op20=84/>
+// CHECK-10-NEXT: <Name abbrevid=5 op0=1/> blob data = 'D'
+// CHECK-10-NEXT: <DefLocation abbrevid=6 op0=23 op1=4/> blob data = '{{.*}}'
+// CHECK-10-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-10-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/E3B54702FABFF4037025BA194FC27C47006330B5.bc | FileCheck %s --check-prefix CHECK-11
+// CHECK-11: <BLOCKINFO_BLOCK/>
+// CHECK-11-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-11-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-11-NEXT: </VersionBlock>
+// CHECK-11-NEXT: <RecordBlock NumWords=37 BlockCodeSize=4>
+// CHECK-11-NEXT: <USR abbrevid=4 op0=20 op1=227 op2=181 op3=71 op4=2 op5=250 op6=191 op7=244 op8=3 op9=112 op10=37 op11=186 op12=25 op13=79 op14=194 op15=124 op16=71 op17=0 op18=99 op19=48 op20=181/>
+// CHECK-11-NEXT: <Name abbrevid=5 op0=1/> blob data = 'F'
+// CHECK-11-NEXT: <DefLocation abbrevid=6 op0=36 op1=4/> blob data = '{{.*}}'
+// CHECK-11-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-11-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-11-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-11-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-11-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-11-NEXT: <Field abbrevid=7 op0=2/>
+// CHECK-11-NEXT: </ReferenceBlock>
+// CHECK-11-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-11-NEXT: <USR abbrevid=4 op0=20 op1=9 op2=33 op3=115 op4=117 op5=65 op6=32 op7=139 op8=143 op9=169 op10=187 op11=66 op12=182 op13=15 op14=120 op15=172 op16=29 op17=119 op18=154 op19=160 op20=84/>
+// CHECK-11-NEXT: <Name abbrevid=5 op0=1/> blob data = 'D'
+// CHECK-11-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-11-NEXT: <Field abbrevid=7 op0=3/>
+// CHECK-11-NEXT: </ReferenceBlock>
+// CHECK-11-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/ACE81AFA6627B4CEF2B456FB6E1252925674AF7E.bc | FileCheck %s --check-prefix CHECK-12
+// CHECK-12: <BLOCKINFO_BLOCK/>
+// CHECK-12-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-12-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-12-NEXT: </VersionBlock>
+// CHECK-12-NEXT: <RecordBlock NumWords=33 BlockCodeSize=4>
+// CHECK-12-NEXT: <USR abbrevid=4 op0=20 op1=172 op2=232 op3=26 op4=250 op5=102 op6=39 op7=180 op8=206 op9=242 op10=180 op11=86 op12=251 op13=110 op14=18 op15=82 op16=146 op17=86 op18=116 op19=175 op20=126/>
+// CHECK-12-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK-12-NEXT: <DefLocation abbrevid=6 op0=15 op1=4/> blob data = '{{.*}}'
+// CHECK-12-NEXT: <TagType abbrevid=8 op0=2/>
+// CHECK-12-NEXT: <MemberTypeBlock NumWords=8 BlockCodeSize=4>
+// CHECK-12-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-12-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+// CHECK-12-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-12-NEXT: </ReferenceBlock>
+// CHECK-12-NEXT: <Name abbrevid=4 op0=1/> blob data = 'X'
+// CHECK-12-NEXT: <Access abbrevid=5 op0=3/>
+// CHECK-12-NEXT: </MemberTypeBlock>
+// CHECK-12-NEXT: <MemberTypeBlock NumWords=8 BlockCodeSize=4>
+// CHECK-12-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-12-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+// CHECK-12-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-12-NEXT: </ReferenceBlock>
+// CHECK-12-NEXT: <Name abbrevid=4 op0=1/> blob data = 'Y'
+// CHECK-12-NEXT: <Access abbrevid=5 op0=3/>
+// CHECK-12-NEXT: </MemberTypeBlock>
+// CHECK-12-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/1E3438A08BA22025C0B46289FF0686F92C8924C5.bc | FileCheck %s --check-prefix CHECK-13
+// CHECK-13: <BLOCKINFO_BLOCK/>
+// CHECK-13-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-13-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-13-NEXT: </VersionBlock>
+// CHECK-13-NEXT: <EnumBlock NumWords=16 BlockCodeSize=4>
+// CHECK-13-NEXT: <USR abbrevid=4 op0=20 op1=30 op2=52 op3=56 op4=160 op5=139 op6=162 op7=32 op8=37 op9=192 op10=180 op11=98 op12=137 op13=255 op14=6 op15=134 op16=249 op17=44 op18=137 op19=36 op20=197/>
+// CHECK-13-NEXT: <Name abbrevid=5 op0=2/> blob data = 'Bc'
+// CHECK-13-NEXT: <DefLocation abbrevid=6 op0=19 op1=4/> blob data = '{{.*}}'
+// CHECK-13-NEXT: <Scoped abbrevid=9 op0=1/>
+// CHECK-13-NEXT: <Member abbrevid=8 op0=1/> blob data = 'A'
+// CHECK-13-NEXT: <Member abbrevid=8 op0=1/> blob data = 'B'
+// CHECK-13-NEXT: </EnumBlock>
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/mapper-comment.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/mapper-comment.cpp
new file mode 100644
index 0000000..da691b1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/mapper-comment.cpp
@@ -0,0 +1,72 @@
+// THIS IS A GENERATED TEST. DO NOT EDIT.
+// To regenerate, see clang-doc/gen_test.py docstring.
+//
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+
+/// \brief Brief description.
+///
+/// Extended description that
+/// continues onto the next line.
+///
+/// <ul class="test">
+/// <li> Testing.
+/// </ul>
+///
+/// \verbatim
+/// The description continues.
+/// \endverbatim
+/// --
+/// \param [out] I is a parameter.
+/// \param J is a parameter.
+/// \return void
+void F(int I, int J);
+
+/// Bonus comment on definition
+void F(int I, int J) {}
+
+// RUN: clang-doc --dump-mapper --doxygen -p %t %t/test.cpp -output=%t/docs
+
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/7574630614A535710E5A6ABCFFF98BCA2D06A4CA.bc | FileCheck %s --check-prefix CHECK-0
+// CHECK-0: <BLOCKINFO_BLOCK/>
+// CHECK-0-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-0-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-0-NEXT: </VersionBlock>
+// CHECK-0-NEXT: <FunctionBlock NumWords=70 BlockCodeSize=4>
+// CHECK-0-NEXT: <USR abbrevid=4 op0=20 op1=117 op2=116 op3=99 op4=6 op5=20 op6=165 op7=53 op8=113 op9=14 op10=90 op11=106 op12=188 op13=255 op14=249 op15=139 op16=202 op17=45 op18=6 op19=164 op20=202/>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=1/> blob data = 'F'
+// CHECK-0-NEXT: <CommentBlock NumWords=28 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'FullComment'
+// CHECK-0-NEXT: <CommentBlock NumWords=21 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+// CHECK-0-NEXT: <CommentBlock NumWords=13 BlockCodeSize=4>
+// CHECK-0-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+// CHECK-0-NEXT: <Text abbrevid=5 op0=28/> blob data = ' Bonus comment on definition'
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: </CommentBlock>
+// CHECK-0-NEXT: <DefLocation abbrevid=6 op0=28 op1=4/> blob data = '{{.*}}'
+// CHECK-0-NEXT: <TypeBlock NumWords=6 BlockCodeSize=4>
+// CHECK-0-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+// CHECK-0-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-0-NEXT: </ReferenceBlock>
+// CHECK-0-NEXT: </TypeBlock>
+// CHECK-0-NEXT: <FieldTypeBlock NumWords=8 BlockCodeSize=4>
+// CHECK-0-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+// CHECK-0-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-0-NEXT: </ReferenceBlock>
+// CHECK-0-NEXT: <Name abbrevid=4 op0=1/> blob data = 'I'
+// CHECK-0-NEXT: </FieldTypeBlock>
+// CHECK-0-NEXT: <FieldTypeBlock NumWords=8 BlockCodeSize=4>
+// CHECK-0-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+// CHECK-0-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-0-NEXT: </ReferenceBlock>
+// CHECK-0-NEXT: <Name abbrevid=4 op0=1/> blob data = 'J'
+// CHECK-0-NEXT: </FieldTypeBlock>
+// CHECK-0-NEXT: </FunctionBlock>
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/mapper-namespace.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/mapper-namespace.cpp
new file mode 100644
index 0000000..aeda908
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/mapper-namespace.cpp
@@ -0,0 +1,138 @@
+// THIS IS A GENERATED TEST. DO NOT EDIT.
+// To regenerate, see clang-doc/gen_test.py docstring.
+//
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+
+namespace A {
+
+void f();
+
+} // namespace A
+
+namespace A {
+
+void f(){};
+
+namespace B {
+
+enum E { X };
+
+E func(int i) { return X; }
+
+} // namespace B
+} // namespace A
+
+// RUN: clang-doc --dump-mapper --doxygen -p %t %t/test.cpp -output=%t/docs
+
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/E9ABF7E7E2425B626723D41E76E4BC7E7A5BD775.bc | FileCheck %s --check-prefix CHECK-0
+// CHECK-0: <BLOCKINFO_BLOCK/>
+// CHECK-0-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-0-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-0-NEXT: </VersionBlock>
+// CHECK-0-NEXT: <EnumBlock NumWords=38 BlockCodeSize=4>
+// CHECK-0-NEXT: <USR abbrevid=4 op0=20 op1=233 op2=171 op3=247 op4=231 op5=226 op6=66 op7=91 op8=98 op9=103 op10=35 op11=212 op12=30 op13=118 op14=228 op15=188 op16=126 op17=122 op18=91 op19=215 op20=117/>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-0-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-0-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
+// CHECK-0-NEXT: <RefType abbrevid=6 op0=1/>
+// CHECK-0-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-0-NEXT: </ReferenceBlock>
+// CHECK-0-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-0-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK-0-NEXT: <RefType abbrevid=6 op0=1/>
+// CHECK-0-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-0-NEXT: </ReferenceBlock>
+// CHECK-0-NEXT: <DefLocation abbrevid=6 op0=21 op1=4/> blob data = '{{.*}}'
+// CHECK-0-NEXT: <Member abbrevid=8 op0=1/> blob data = 'X'
+// CHECK-0-NEXT: </EnumBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/39D3C95A5F7CE2BA4937BD7B01BAE09EBC2AD8AC.bc | FileCheck %s --check-prefix CHECK-1
+// CHECK-1: <BLOCKINFO_BLOCK/>
+// CHECK-1-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-1-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-1-NEXT: </VersionBlock>
+// CHECK-1-NEXT: <FunctionBlock NumWords=32 BlockCodeSize=4>
+// CHECK-1-NEXT: <USR abbrevid=4 op0=20 op1=57 op2=211 op3=201 op4=90 op5=95 op6=124 op7=226 op8=186 op9=73 op10=55 op11=189 op12=123 op13=1 op14=186 op15=224 op16=158 op17=188 op18=42 op19=216 op20=172/>
+// CHECK-1-NEXT: <Name abbrevid=5 op0=1/> blob data = 'f'
+// CHECK-1-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-1-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+// CHECK-1-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK-1-NEXT: <RefType abbrevid=6 op0=1/>
+// CHECK-1-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-1-NEXT: </ReferenceBlock>
+// CHECK-1-NEXT: <DefLocation abbrevid=6 op0=17 op1=4/> blob data = '{{.*}}'
+// CHECK-1-NEXT: <TypeBlock NumWords=6 BlockCodeSize=4>
+// CHECK-1-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-1-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+// CHECK-1-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-1-NEXT: </ReferenceBlock>
+// CHECK-1-NEXT: </TypeBlock>
+// CHECK-1-NEXT: </FunctionBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/9A82CB33ED0FDF81EE383D31CD0957D153C5E840.bc | FileCheck %s --check-prefix CHECK-2
+// CHECK-2: <BLOCKINFO_BLOCK/>
+// CHECK-2-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-2-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-2-NEXT: </VersionBlock>
+// CHECK-2-NEXT: <FunctionBlock NumWords=56 BlockCodeSize=4>
+// CHECK-2-NEXT: <USR abbrevid=4 op0=20 op1=154 op2=130 op3=203 op4=51 op5=237 op6=15 op7=223 op8=129 op9=238 op10=56 op11=61 op12=49 op13=205 op14=9 op15=87 op16=209 op17=83 op18=197 op19=232 op20=64/>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=4/> blob data = 'func'
+// CHECK-2-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-2-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
+// CHECK-2-NEXT: <RefType abbrevid=6 op0=1/>
+// CHECK-2-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-2-NEXT: </ReferenceBlock>
+// CHECK-2-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-2-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK-2-NEXT: <RefType abbrevid=6 op0=1/>
+// CHECK-2-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-2-NEXT: </ReferenceBlock>
+// CHECK-2-NEXT: <DefLocation abbrevid=6 op0=23 op1=4/> blob data = '{{.*}}'
+// CHECK-2-NEXT: <TypeBlock NumWords=8 BlockCodeSize=4>
+// CHECK-2-NEXT: <ReferenceBlock NumWords=5 BlockCodeSize=4>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=12/> blob data = 'enum A::B::E'
+// CHECK-2-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-2-NEXT: </ReferenceBlock>
+// CHECK-2-NEXT: </TypeBlock>
+// CHECK-2-NEXT: <FieldTypeBlock NumWords=8 BlockCodeSize=4>
+// CHECK-2-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+// CHECK-2-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-2-NEXT: </ReferenceBlock>
+// CHECK-2-NEXT: <Name abbrevid=4 op0=1/> blob data = 'i'
+// CHECK-2-NEXT: </FieldTypeBlock>
+// CHECK-2-NEXT: </FunctionBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/8D042EFFC98B373450BC6B5B90A330C25A150E9C.bc | FileCheck %s --check-prefix CHECK-3
+// CHECK-3: <BLOCKINFO_BLOCK/>
+// CHECK-3-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-3-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-3-NEXT: </VersionBlock>
+// CHECK-3-NEXT: <NamespaceBlock NumWords=9 BlockCodeSize=4>
+// CHECK-3-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+// CHECK-3-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK-3-NEXT: </NamespaceBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/E21AF79E2A9D02554BA090D10DF39FE273F5CDB5.bc | FileCheck %s --check-prefix CHECK-4
+// CHECK-4: <BLOCKINFO_BLOCK/>
+// CHECK-4-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-4-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-4-NEXT: </VersionBlock>
+// CHECK-4-NEXT: <NamespaceBlock NumWords=21 BlockCodeSize=4>
+// CHECK-4-NEXT: <USR abbrevid=4 op0=20 op1=226 op2=26 op3=247 op4=158 op5=42 op6=157 op7=2 op8=85 op9=75 op10=160 op11=144 op12=209 op13=13 op14=243 op15=159 op16=226 op17=115 op18=245 op19=205 op20=181/>
+// CHECK-4-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
+// CHECK-4-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-4-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+// CHECK-4-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK-4-NEXT: <RefType abbrevid=6 op0=1/>
+// CHECK-4-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-4-NEXT: </ReferenceBlock>
+// CHECK-4-NEXT: </NamespaceBlock>
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/mapper-record.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/mapper-record.cpp
new file mode 100644
index 0000000..82a5e2f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/mapper-record.cpp
@@ -0,0 +1,317 @@
+// THIS IS A GENERATED TEST. DO NOT EDIT.
+// To regenerate, see clang-doc/gen_test.py docstring.
+//
+// This test requires Linux due to system-dependent USR for the inner class.
+// REQUIRES: system-linux
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+
+void H() {
+ class I {};
+}
+
+union A { int X; int Y; };
+
+enum B { X, Y };
+
+enum class Bc { A, B };
+
+struct C { int i; };
+
+class D {};
+
+class E {
+public:
+ E() {}
+ ~E() {}
+
+protected:
+ void ProtectedMethod();
+};
+
+void E::ProtectedMethod() {}
+
+class F : virtual private D, public E {};
+
+class X {
+ class Y {};
+};
+
+// RUN: clang-doc --dump-mapper --doxygen -p %t %t/test.cpp -output=%t/docs
+
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/289584A8E0FF4178A794622A547AA622503967A1.bc | FileCheck %s --check-prefix CHECK-0
+// CHECK-0: <BLOCKINFO_BLOCK/>
+// CHECK-0-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-0-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-0-NEXT: </VersionBlock>
+// CHECK-0-NEXT: <RecordBlock NumWords=12 BlockCodeSize=4>
+// CHECK-0-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-0-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-0-NEXT: <DefLocation abbrevid=6 op0=25 op1=4/> blob data = '{{.*}}'
+// CHECK-0-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-0-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/3FB542274573CAEAD54CEBFFCAEE3D77FB9713D8.bc | FileCheck %s --check-prefix CHECK-1
+// CHECK-1: <BLOCKINFO_BLOCK/>
+// CHECK-1-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-1-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-1-NEXT: </VersionBlock>
+// CHECK-1-NEXT: <RecordBlock NumWords=24 BlockCodeSize=4>
+// CHECK-1-NEXT: <USR abbrevid=4 op0=20 op1=63 op2=181 op3=66 op4=39 op5=69 op6=115 op7=202 op8=234 op9=213 op10=76 op11=235 op12=255 op13=202 op14=238 op15=61 op16=119 op17=251 op18=151 op19=19 op20=216/>
+// CHECK-1-NEXT: <Name abbrevid=5 op0=1/> blob data = 'I'
+// CHECK-1-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-1-NEXT: <USR abbrevid=4 op0=20 op1=182 op2=172 op3=76 op4=92 op5=159 op6=46 op7=163 op8=242 op9=179 op10=236 op11=225 op12=163 op13=61 op14=52 op15=159 op16=78 op17=229 op18=2 op19=178 op20=78/>
+// CHECK-1-NEXT: <Name abbrevid=5 op0=1/> blob data = 'H'
+// CHECK-1-NEXT: <RefType abbrevid=6 op0=3/>
+// CHECK-1-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-1-NEXT: </ReferenceBlock>
+// CHECK-1-NEXT: <DefLocation abbrevid=6 op0=12 op1=4/> blob data = '{{.*}}'
+// CHECK-1-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-1-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/5093D428CDC62096A67547BA52566E4FB9404EEE.bc | FileCheck %s --check-prefix CHECK-2
+// CHECK-2: <BLOCKINFO_BLOCK/>
+// CHECK-2-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-2-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-2-NEXT: </VersionBlock>
+// CHECK-2-NEXT: <FunctionBlock NumWords=47 BlockCodeSize=4>
+// CHECK-2-NEXT: <USR abbrevid=4 op0=20 op1=80 op2=147 op3=212 op4=40 op5=205 op6=198 op7=32 op8=150 op9=166 op10=117 op11=71 op12=186 op13=82 op14=86 op15=110 op16=79 op17=185 op18=64 op19=78 op20=238/>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=15/> blob data = 'ProtectedMethod'
+// CHECK-2-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-2-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-2-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-2-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-2-NEXT: </ReferenceBlock>
+// CHECK-2-NEXT: <IsMethod abbrevid=9 op0=1/>
+// CHECK-2-NEXT: <DefLocation abbrevid=6 op0=34 op1=4/> blob data = '{{.*}}'
+// CHECK-2-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-2-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-2-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-2-NEXT: <Field abbrevid=7 op0=2/>
+// CHECK-2-NEXT: </ReferenceBlock>
+// CHECK-2-NEXT: <TypeBlock NumWords=6 BlockCodeSize=4>
+// CHECK-2-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-2-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+// CHECK-2-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-2-NEXT: </ReferenceBlock>
+// CHECK-2-NEXT: </TypeBlock>
+// CHECK-2-NEXT: </FunctionBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/CA7C7935730B5EACD25F080E9C83FA087CCDC75E.bc | FileCheck %s --check-prefix CHECK-3
+// CHECK-3: <BLOCKINFO_BLOCK/>
+// CHECK-3-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-3-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-3-NEXT: </VersionBlock>
+// CHECK-3-NEXT: <RecordBlock NumWords=12 BlockCodeSize=4>
+// CHECK-3-NEXT: <USR abbrevid=4 op0=20 op1=202 op2=124 op3=121 op4=53 op5=115 op6=11 op7=94 op8=172 op9=210 op10=95 op11=8 op12=14 op13=156 op14=131 op15=250 op16=8 op17=124 op18=205 op19=199 op20=94/>
+// CHECK-3-NEXT: <Name abbrevid=5 op0=1/> blob data = 'X'
+// CHECK-3-NEXT: <DefLocation abbrevid=6 op0=38 op1=4/> blob data = '{{.*}}'
+// CHECK-3-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-3-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/B6AC4C5C9F2EA3F2B3ECE1A33D349F4EE502B24E.bc | FileCheck %s --check-prefix CHECK-4
+// CHECK-4: <BLOCKINFO_BLOCK/>
+// CHECK-4-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-4-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-4-NEXT: </VersionBlock>
+// CHECK-4-NEXT: <FunctionBlock NumWords=20 BlockCodeSize=4>
+// CHECK-4-NEXT: <USR abbrevid=4 op0=20 op1=182 op2=172 op3=76 op4=92 op5=159 op6=46 op7=163 op8=242 op9=179 op10=236 op11=225 op12=163 op13=61 op14=52 op15=159 op16=78 op17=229 op18=2 op19=178 op20=78/>
+// CHECK-4-NEXT: <Name abbrevid=5 op0=1/> blob data = 'H'
+// CHECK-4-NEXT: <DefLocation abbrevid=6 op0=11 op1=4/> blob data = '{{.*}}'
+// CHECK-4-NEXT: <TypeBlock NumWords=6 BlockCodeSize=4>
+// CHECK-4-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-4-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+// CHECK-4-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-4-NEXT: </ReferenceBlock>
+// CHECK-4-NEXT: </TypeBlock>
+// CHECK-4-NEXT: </FunctionBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/06B5F6A19BA9F6A832E127C9968282B94619B210.bc | FileCheck %s --check-prefix CHECK-5
+// CHECK-5: <BLOCKINFO_BLOCK/>
+// CHECK-5-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-5-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-5-NEXT: </VersionBlock>
+// CHECK-5-NEXT: <RecordBlock NumWords=22 BlockCodeSize=4>
+// CHECK-5-NEXT: <USR abbrevid=4 op0=20 op1=6 op2=181 op3=246 op4=161 op5=155 op6=169 op7=246 op8=168 op9=50 op10=225 op11=39 op12=201 op13=150 op14=130 op15=130 op16=185 op17=70 op18=25 op19=178 op20=16/>
+// CHECK-5-NEXT: <Name abbrevid=5 op0=1/> blob data = 'C'
+// CHECK-5-NEXT: <DefLocation abbrevid=6 op0=21 op1=4/> blob data = '{{.*}}'
+// CHECK-5-NEXT: <MemberTypeBlock NumWords=8 BlockCodeSize=4>
+// CHECK-5-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-5-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+// CHECK-5-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-5-NEXT: </ReferenceBlock>
+// CHECK-5-NEXT: <Name abbrevid=4 op0=1/> blob data = 'i'
+// CHECK-5-NEXT: </MemberTypeBlock>
+// CHECK-5-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/BD2BDEBD423F80BACCEA75DE6D6622D355FC2D17.bc | FileCheck %s --check-prefix CHECK-6
+// CHECK-6: <BLOCKINFO_BLOCK/>
+// CHECK-6-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-6-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-6-NEXT: </VersionBlock>
+// CHECK-6-NEXT: <FunctionBlock NumWords=44 BlockCodeSize=4>
+// CHECK-6-NEXT: <USR abbrevid=4 op0=20 op1=189 op2=43 op3=222 op4=189 op5=66 op6=63 op7=128 op8=186 op9=204 op10=234 op11=117 op12=222 op13=109 op14=102 op15=34 op16=211 op17=85 op18=252 op19=45 op20=23/>
+// CHECK-6-NEXT: <Name abbrevid=5 op0=2/> blob data = '~E'
+// CHECK-6-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-6-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-6-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-6-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-6-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-6-NEXT: </ReferenceBlock>
+// CHECK-6-NEXT: <IsMethod abbrevid=9 op0=1/>
+// CHECK-6-NEXT: <DefLocation abbrevid=6 op0=28 op1=4/> blob data = '{{.*}}'
+// CHECK-6-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-6-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-6-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-6-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-6-NEXT: <Field abbrevid=7 op0=2/>
+// CHECK-6-NEXT: </ReferenceBlock>
+// CHECK-6-NEXT: <TypeBlock NumWords=6 BlockCodeSize=4>
+// CHECK-6-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-6-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+// CHECK-6-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-6-NEXT: </ReferenceBlock>
+// CHECK-6-NEXT: </TypeBlock>
+// CHECK-6-NEXT: </FunctionBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/DEB4AC1CD9253CD9EF7FBE6BCAC506D77984ABD4.bc | FileCheck %s --check-prefix CHECK-7
+// CHECK-7: <BLOCKINFO_BLOCK/>
+// CHECK-7-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-7-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-7-NEXT: </VersionBlock>
+// CHECK-7-NEXT: <FunctionBlock NumWords=44 BlockCodeSize=4>
+// CHECK-7-NEXT: <USR abbrevid=4 op0=20 op1=222 op2=180 op3=172 op4=28 op5=217 op6=37 op7=60 op8=217 op9=239 op10=127 op11=190 op12=107 op13=202 op14=197 op15=6 op16=215 op17=121 op18=132 op19=171 op20=212/>
+// CHECK-7-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-7-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-7-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-7-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-7-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-7-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-7-NEXT: </ReferenceBlock>
+// CHECK-7-NEXT: <IsMethod abbrevid=9 op0=1/>
+// CHECK-7-NEXT: <DefLocation abbrevid=6 op0=27 op1=4/> blob data = '{{.*}}'
+// CHECK-7-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-7-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-7-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-7-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-7-NEXT: <Field abbrevid=7 op0=2/>
+// CHECK-7-NEXT: </ReferenceBlock>
+// CHECK-7-NEXT: <TypeBlock NumWords=6 BlockCodeSize=4>
+// CHECK-7-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-7-NEXT: <Name abbrevid=5 op0=4/> blob data = 'void'
+// CHECK-7-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-7-NEXT: </ReferenceBlock>
+// CHECK-7-NEXT: </TypeBlock>
+// CHECK-7-NEXT: </FunctionBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/641AB4A3D36399954ACDE29C7A8833032BF40472.bc | FileCheck %s --check-prefix CHECK-8
+// CHECK-8: <BLOCKINFO_BLOCK/>
+// CHECK-8-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-8-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-8-NEXT: </VersionBlock>
+// CHECK-8-NEXT: <RecordBlock NumWords=24 BlockCodeSize=4>
+// CHECK-8-NEXT: <USR abbrevid=4 op0=20 op1=100 op2=26 op3=180 op4=163 op5=211 op6=99 op7=153 op8=149 op9=74 op10=205 op11=226 op12=156 op13=122 op14=136 op15=51 op16=3 op17=43 op18=244 op19=4 op20=114/>
+// CHECK-8-NEXT: <Name abbrevid=5 op0=1/> blob data = 'Y'
+// CHECK-8-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-8-NEXT: <USR abbrevid=4 op0=20 op1=202 op2=124 op3=121 op4=53 op5=115 op6=11 op7=94 op8=172 op9=210 op10=95 op11=8 op12=14 op13=156 op14=131 op15=250 op16=8 op17=124 op18=205 op19=199 op20=94/>
+// CHECK-8-NEXT: <Name abbrevid=5 op0=1/> blob data = 'X'
+// CHECK-8-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-8-NEXT: <Field abbrevid=7 op0=1/>
+// CHECK-8-NEXT: </ReferenceBlock>
+// CHECK-8-NEXT: <DefLocation abbrevid=6 op0=39 op1=4/> blob data = '{{.*}}'
+// CHECK-8-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-8-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/FC07BD34D5E77782C263FA944447929EA8753740.bc | FileCheck %s --check-prefix CHECK-9
+// CHECK-9: <BLOCKINFO_BLOCK/>
+// CHECK-9-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-9-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-9-NEXT: </VersionBlock>
+// CHECK-9-NEXT: <EnumBlock NumWords=16 BlockCodeSize=4>
+// CHECK-9-NEXT: <USR abbrevid=4 op0=20 op1=252 op2=7 op3=189 op4=52 op5=213 op6=231 op7=119 op8=130 op9=194 op10=99 op11=250 op12=148 op13=68 op14=71 op15=146 op16=158 op17=168 op18=117 op19=55 op20=64/>
+// CHECK-9-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
+// CHECK-9-NEXT: <DefLocation abbrevid=6 op0=17 op1=4/> blob data = '{{.*}}'
+// CHECK-9-NEXT: <Member abbrevid=8 op0=1/> blob data = 'X'
+// CHECK-9-NEXT: <Member abbrevid=8 op0=1/> blob data = 'Y'
+// CHECK-9-NEXT: </EnumBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/0921737541208B8FA9BB42B60F78AC1D779AA054.bc | FileCheck %s --check-prefix CHECK-10
+// CHECK-10: <BLOCKINFO_BLOCK/>
+// CHECK-10-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-10-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-10-NEXT: </VersionBlock>
+// CHECK-10-NEXT: <RecordBlock NumWords=12 BlockCodeSize=4>
+// CHECK-10-NEXT: <USR abbrevid=4 op0=20 op1=9 op2=33 op3=115 op4=117 op5=65 op6=32 op7=139 op8=143 op9=169 op10=187 op11=66 op12=182 op13=15 op14=120 op15=172 op16=29 op17=119 op18=154 op19=160 op20=84/>
+// CHECK-10-NEXT: <Name abbrevid=5 op0=1/> blob data = 'D'
+// CHECK-10-NEXT: <DefLocation abbrevid=6 op0=23 op1=4/> blob data = '{{.*}}'
+// CHECK-10-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-10-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/E3B54702FABFF4037025BA194FC27C47006330B5.bc | FileCheck %s --check-prefix CHECK-11
+// CHECK-11: <BLOCKINFO_BLOCK/>
+// CHECK-11-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-11-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-11-NEXT: </VersionBlock>
+// CHECK-11-NEXT: <RecordBlock NumWords=37 BlockCodeSize=4>
+// CHECK-11-NEXT: <USR abbrevid=4 op0=20 op1=227 op2=181 op3=71 op4=2 op5=250 op6=191 op7=244 op8=3 op9=112 op10=37 op11=186 op12=25 op13=79 op14=194 op15=124 op16=71 op17=0 op18=99 op19=48 op20=181/>
+// CHECK-11-NEXT: <Name abbrevid=5 op0=1/> blob data = 'F'
+// CHECK-11-NEXT: <DefLocation abbrevid=6 op0=36 op1=4/> blob data = '{{.*}}'
+// CHECK-11-NEXT: <TagType abbrevid=8 op0=3/>
+// CHECK-11-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-11-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+// CHECK-11-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+// CHECK-11-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-11-NEXT: <Field abbrevid=7 op0=2/>
+// CHECK-11-NEXT: </ReferenceBlock>
+// CHECK-11-NEXT: <ReferenceBlock NumWords=10 BlockCodeSize=4>
+// CHECK-11-NEXT: <USR abbrevid=4 op0=20 op1=9 op2=33 op3=115 op4=117 op5=65 op6=32 op7=139 op8=143 op9=169 op10=187 op11=66 op12=182 op13=15 op14=120 op15=172 op16=29 op17=119 op18=154 op19=160 op20=84/>
+// CHECK-11-NEXT: <Name abbrevid=5 op0=1/> blob data = 'D'
+// CHECK-11-NEXT: <RefType abbrevid=6 op0=2/>
+// CHECK-11-NEXT: <Field abbrevid=7 op0=3/>
+// CHECK-11-NEXT: </ReferenceBlock>
+// CHECK-11-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/ACE81AFA6627B4CEF2B456FB6E1252925674AF7E.bc | FileCheck %s --check-prefix CHECK-12
+// CHECK-12: <BLOCKINFO_BLOCK/>
+// CHECK-12-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-12-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-12-NEXT: </VersionBlock>
+// CHECK-12-NEXT: <RecordBlock NumWords=33 BlockCodeSize=4>
+// CHECK-12-NEXT: <USR abbrevid=4 op0=20 op1=172 op2=232 op3=26 op4=250 op5=102 op6=39 op7=180 op8=206 op9=242 op10=180 op11=86 op12=251 op13=110 op14=18 op15=82 op16=146 op17=86 op18=116 op19=175 op20=126/>
+// CHECK-12-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK-12-NEXT: <DefLocation abbrevid=6 op0=15 op1=4/> blob data = '{{.*}}'
+// CHECK-12-NEXT: <TagType abbrevid=8 op0=2/>
+// CHECK-12-NEXT: <MemberTypeBlock NumWords=8 BlockCodeSize=4>
+// CHECK-12-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-12-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+// CHECK-12-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-12-NEXT: </ReferenceBlock>
+// CHECK-12-NEXT: <Name abbrevid=4 op0=1/> blob data = 'X'
+// CHECK-12-NEXT: </MemberTypeBlock>
+// CHECK-12-NEXT: <MemberTypeBlock NumWords=8 BlockCodeSize=4>
+// CHECK-12-NEXT: <ReferenceBlock NumWords=3 BlockCodeSize=4>
+// CHECK-12-NEXT: <Name abbrevid=5 op0=3/> blob data = 'int'
+// CHECK-12-NEXT: <Field abbrevid=7 op0=4/>
+// CHECK-12-NEXT: </ReferenceBlock>
+// CHECK-12-NEXT: <Name abbrevid=4 op0=1/> blob data = 'Y'
+// CHECK-12-NEXT: </MemberTypeBlock>
+// CHECK-12-NEXT: </RecordBlock>
+
+// RUN: llvm-bcanalyzer --dump %t/docs/bc/1E3438A08BA22025C0B46289FF0686F92C8924C5.bc | FileCheck %s --check-prefix CHECK-13
+// CHECK-13: <BLOCKINFO_BLOCK/>
+// CHECK-13-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+// CHECK-13-NEXT: <Version abbrevid=4 op0=2/>
+// CHECK-13-NEXT: </VersionBlock>
+// CHECK-13-NEXT: <EnumBlock NumWords=16 BlockCodeSize=4>
+// CHECK-13-NEXT: <USR abbrevid=4 op0=20 op1=30 op2=52 op3=56 op4=160 op5=139 op6=162 op7=32 op8=37 op9=192 op10=180 op11=98 op12=137 op13=255 op14=6 op15=134 op16=249 op17=44 op18=137 op19=36 op20=197/>
+// CHECK-13-NEXT: <Name abbrevid=5 op0=2/> blob data = 'Bc'
+// CHECK-13-NEXT: <DefLocation abbrevid=6 op0=19 op1=4/> blob data = '{{.*}}'
+// CHECK-13-NEXT: <Scoped abbrevid=9 op0=1/>
+// CHECK-13-NEXT: <Member abbrevid=8 op0=1/> blob data = 'A'
+// CHECK-13-NEXT: <Member abbrevid=8 op0=1/> blob data = 'B'
+// CHECK-13-NEXT: </EnumBlock>
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/module.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/module.cpp
new file mode 100644
index 0000000..a2b5945
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/module.cpp
@@ -0,0 +1,61 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --extra-arg=-fmodules-ts --doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: cat %t/docs/moduleFunction.yaml | FileCheck %s --check-prefix=CHECK-A
+// RUN: cat %t/docs/staticModuleFunction.yaml | FileCheck %s --check-prefix=CHECK-B
+// RUN: cat %t/docs/exportedModuleFunction.yaml | FileCheck %s --check-prefix=CHECK-C
+
+export module M;
+
+int moduleFunction(int x); //ModuleLinkage
+// CHECK-A: ---
+// CHECK-A-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-A-NEXT: Name: 'moduleFunction'
+// CHECK-A-NEXT: Location:
+// CHECK-A-NEXT: - LineNumber: 12
+// CHECK-A-NEXT: Filename: {{.*}}
+// CHECK-A-NEXT: Params:
+// CHECK-A-NEXT: - Type:
+// CHECK-A-NEXT: Name: 'int'
+// CHECK-A-NEXT: Name: 'x'
+// CHECK-A-NEXT: ReturnType:
+// CHECK-A-NEXT: Type:
+// CHECK-A-NEXT: Name: 'int'
+// CHECK-A-NEXT: ...
+
+static int staticModuleFunction(int x); //ModuleInternalLinkage
+// CHECK-B: ---
+// CHECK-B-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-B-NEXT: Name: 'staticModuleFunction'
+// CHECK-B-NEXT: Location:
+// CHECK-B-NEXT: - LineNumber: 28
+// CHECK-B-NEXT: Filename: {{.*}}
+// CHECK-B-NEXT: Params:
+// CHECK-B-NEXT: - Type:
+// CHECK-B-NEXT: Name: 'int'
+// CHECK-B-NEXT: Name: 'x'
+// CHECK-B-NEXT: ReturnType:
+// CHECK-B-NEXT: Type:
+// CHECK-B-NEXT: Name: 'int'
+// CHECK-B-NEXT: ...
+
+export double exportedModuleFunction(double y, int z); //ExternalLinkage
+// CHECK-C: ---
+// CHECK-C-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-C-NEXT: Name: 'exportedModuleFunction'
+// CHECK-C-NEXT: Location:
+// CHECK-C-NEXT: - LineNumber: 44
+// CHECK-C-NEXT: Filename: {{.*}}
+// CHECK-C-NEXT: Params:
+// CHECK-C-NEXT: - Type:
+// CHECK-C-NEXT: Name: 'double'
+// CHECK-C-NEXT: Name: 'y'
+// CHECK-C-NEXT: - Type:
+// CHECK-C-NEXT: Name: 'int'
+// CHECK-C-NEXT: Name: 'z'
+// CHECK-C-NEXT: ReturnType:
+// CHECK-C-NEXT: Type:
+// CHECK-C-NEXT: Name: 'double'
+// CHECK-C-NEXT: ...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/public-module.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/public-module.cpp
new file mode 100644
index 0000000..c7ebadd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/public-module.cpp
@@ -0,0 +1,53 @@
+// This test requires linux because it uses `diff` and compares filepaths
+// REQUIRES: system-linux
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --public --extra-arg=-fmodules-ts --doxygen -p %t %t/test.cpp -output=%t/docs-with-public-flag
+// RUN: clang-doc --extra-arg=-fmodules-ts --doxygen -p %t %t/test.cpp -output=%t/docs-without
+// RUN: cat %t/docs-with-public-flag/moduleFunction.yaml | FileCheck %s --check-prefix=CHECK-A
+// RUN: cat %t/docs-with-public-flag/exportedModuleFunction.yaml | FileCheck %s --check-prefix=CHECK-B
+// RUN: (diff -qry %t/docs-with-public-flag %t/docs-without | sed 's:.*/::' > %t/public.diff) || true
+// RUN: cat %t/public.diff | FileCheck %s --check-prefix=CHECK-C
+
+export module M;
+
+int moduleFunction(int x); //ModuleLinkage
+// CHECK-A: ---
+// CHECK-A-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-A-NEXT: Name: 'moduleFunction'
+// CHECK-A-NEXT: Location:
+// CHECK-A-NEXT: - LineNumber: 16
+// CHECK-A-NEXT: Filename: {{.*}}
+// CHECK-A-NEXT: Params:
+// CHECK-A-NEXT: - Type:
+// CHECK-A-NEXT: Name: 'int'
+// CHECK-A-NEXT: Name: 'x'
+// CHECK-A-NEXT: ReturnType:
+// CHECK-A-NEXT: Type:
+// CHECK-A-NEXT: Name: 'int'
+// CHECK-A-NEXT: ...
+
+static int staticModuleFunction(int x); //ModuleInternalLinkage
+
+export double exportedModuleFunction(double y, int z); //ExternalLinkage
+// CHECK-B: ---
+// CHECK-B-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-B-NEXT: Name: 'exportedModuleFunction'
+// CHECK-B-NEXT: Location:
+// CHECK-B-NEXT: - LineNumber: 34
+// CHECK-B-NEXT: Filename: {{.*}}
+// CHECK-B-NEXT: Params:
+// CHECK-B-NEXT: - Type:
+// CHECK-B-NEXT: Name: 'double'
+// CHECK-B-NEXT: Name: 'y'
+// CHECK-B-NEXT: - Type:
+// CHECK-B-NEXT: Name: 'int'
+// CHECK-B-NEXT: Name: 'z'
+// CHECK-B-NEXT: ReturnType:
+// CHECK-B-NEXT: Type:
+// CHECK-B-NEXT: Name: 'double'
+// CHECK-B-NEXT: ...
+
+// CHECK-C: docs-without: staticModuleFunction.yaml
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/public-records.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/public-records.cpp
new file mode 100644
index 0000000..a00a23b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/public-records.cpp
@@ -0,0 +1,341 @@
+// This test requires linux because it uses `diff` and compares filepaths
+// REQUIRES: system-linux
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --public --doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: clang-doc --doxygen -p %t %t/test.cpp -output=%t/docs-without-flag
+// RUN: cat %t/docs/function.yaml | FileCheck %s --check-prefix=CHECK-A
+// RUN: cat %t/docs/inlinedFunction.yaml | FileCheck %s --check-prefix=CHECK-B
+// RUN: cat %t/docs/functionWithInnerClass.yaml | FileCheck %s --check-prefix=CHECK-C
+// RUN: cat %t/docs/inlinedFunctionWithInnerClass.yaml | FileCheck %s --check-prefix=CHECK-D
+// RUN: cat %t/docs/Class/publicMethod.yaml| FileCheck %s --check-prefix=CHECK-E
+// RUN: cat %t/docs/Class.yaml| FileCheck %s --check-prefix=CHECK-F
+// RUN: cat %t/docs/Class/protectedMethod.yaml| FileCheck %s --check-prefix=CHECK-G
+// RUN: cat %t/docs/named.yaml| FileCheck %s --check-prefix=CHECK-H
+// RUN: cat %t/docs/named/NamedClass.yaml| FileCheck %s --check-prefix=CHECK-I
+// RUN: cat %t/docs/named/namedFunction.yaml| FileCheck %s --check-prefix=CHECK-J
+// RUN: cat %t/docs/named/namedInlineFunction.yaml| FileCheck %s --check-prefix=CHECK-K
+// RUN: cat %t/docs/named/NamedClass/namedPublicMethod.yaml| FileCheck %s --check-prefix=CHECK-L
+// RUN: cat %t/docs/named/NamedClass/namedProtectedMethod.yaml| FileCheck %s --check-prefix=CHECK-M
+// RUN: (diff -qry %t/docs-without-flag %t/docs | sed 's:.*/::' > %t/public.diff) || true
+// RUN: cat %t/public.diff | FileCheck %s --check-prefix=CHECK-N
+
+void function(int x);
+
+// CHECK-A: ---
+// CHECK-A-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-A-NEXT: Name: 'function'
+// CHECK-A-NEXT: Location:
+// CHECK-A-NEXT: - LineNumber: 25
+// CHECK-A-NEXT: Filename: {{.*}}
+// CHECK-A-NEXT: Params:
+// CHECK-A-NEXT: - Type:
+// CHECK-A-NEXT: Name: 'int'
+// CHECK-A-NEXT: Name: 'x'
+// CHECK-A-NEXT: ReturnType:
+// CHECK-A-NEXT: Type:
+// CHECK-A-NEXT: Name: 'void'
+// CHECK-A-NEXT: ...
+
+inline int inlinedFunction(int x);
+
+// CHECK-B: ---
+// CHECK-B-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-B-NEXT: Name: 'inlinedFunction'
+// CHECK-B-NEXT: Location:
+// CHECK-B-NEXT: - LineNumber: 42
+// CHECK-B-NEXT: Filename: {{.*}}
+// CHECK-B-NEXT: Params:
+// CHECK-B-NEXT: - Type:
+// CHECK-B-NEXT: Name: 'int'
+// CHECK-B-NEXT: Name: 'x'
+// CHECK-B-NEXT: ReturnType:
+// CHECK-B-NEXT: Type:
+// CHECK-B-NEXT: Name: 'int'
+// CHECK-B-NEXT: ...
+
+int functionWithInnerClass(int x){
+ class InnerClass { //NoLinkage
+ public:
+ int innerPublicMethod() { return 2; };
+ }; //end class
+ InnerClass temp;
+ return temp.innerPublicMethod();
+};
+
+// CHECK-C: ---
+// CHECK-C-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-C-NEXT: Name: 'functionWithInnerClass'
+// CHECK-C-NEXT: DefLocation:
+// CHECK-C-NEXT: LineNumber: 59
+// CHECK-C-NEXT: Filename: {{.*}}
+// CHECK-C-NEXT: Params:
+// CHECK-C-NEXT: - Type:
+// CHECK-C-NEXT: Name: 'int'
+// CHECK-C-NEXT: Name: 'x'
+// CHECK-C-NEXT: ReturnType:
+// CHECK-C-NEXT: Type:
+// CHECK-C-NEXT: Name: 'int'
+// CHECK-C-NEXT: ...
+
+inline int inlinedFunctionWithInnerClass(int x){
+ class InnerClass { //VisibleNoLinkage
+ public:
+ int innerPublicMethod() { return 2; };
+ }; //end class
+ InnerClass temp;
+ return temp.innerPublicMethod();
+};
+
+// CHECK-D: ---
+// CHECK-D-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-D-NEXT: Name: 'inlinedFunctionWithInnerClass'
+// CHECK-D-NEXT: DefLocation:
+// CHECK-D-NEXT: LineNumber: 83
+// CHECK-D-NEXT: Filename: {{.*}}
+// CHECK-D-NEXT: Params:
+// CHECK-D-NEXT: - Type:
+// CHECK-D-NEXT: Name: 'int'
+// CHECK-D-NEXT: Name: 'x'
+// CHECK-D-NEXT: ReturnType:
+// CHECK-D-NEXT: Type:
+// CHECK-D-NEXT: Name: 'int'
+// CHECK-D-NEXT: ...
+
+class Class {
+ public:
+ void publicMethod();
+ int publicField;
+ protected:
+ void protectedMethod();
+ int protectedField;
+ private:
+ void privateMethod();
+ int privateField;
+};
+
+// CHECK-E: ---
+// CHECK-E-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-E-NEXT: Name: 'publicMethod'
+// CHECK-E-NEXT: Namespace:
+// CHECK-E-NEXT: - Type: Record
+// CHECK-E-NEXT: Name: 'Class'
+// CHECK-E-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-E-NEXT: Location:
+// CHECK-E-NEXT: - LineNumber: 109
+// CHECK-E-NEXT: Filename: {{.*}}
+// CHECK-E-NEXT: IsMethod: true
+// CHECK-E-NEXT: Parent:
+// CHECK-E-NEXT: Type: Record
+// CHECK-E-NEXT: Name: 'Class'
+// CHECK-E-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-E-NEXT: ReturnType:
+// CHECK-E-NEXT: Type:
+// CHECK-E-NEXT: Name: 'void'
+// CHECK-E-NEXT: ...
+
+// CHECK-F: ---
+// CHECK-F-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-F-NEXT: Name: 'Class'
+// CHECK-F-NEXT: DefLocation:
+// CHECK-F-NEXT: LineNumber: 107
+// CHECK-F-NEXT: Filename: {{.*}}
+// CHECK-F-NEXT: TagType: Class
+// CHECK-F-NEXT: Members:
+// CHECK-F-NEXT: - Type:
+// CHECK-F-NEXT: Name: 'int'
+// CHECK-F-NEXT: Name: 'publicField'
+// CHECK-F-NEXT: - Type:
+// CHECK-F-NEXT: Name: 'int'
+// CHECK-F-NEXT: Name: 'protectedField'
+// CHECK-F-NEXT: Access: Protected
+// CHECK-F-NEXT: ...
+
+// CHECK-G: ---
+// CHECK-G-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-G-NEXT: Name: 'protectedMethod'
+// CHECK-G-NEXT: Namespace:
+// CHECK-G-NEXT: - Type: Record
+// CHECK-G-NEXT: Name: 'Class'
+// CHECK-G-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-G-NEXT: Location:
+// CHECK-G-NEXT: - LineNumber: 112
+// CHECK-G-NEXT: Filename: {{.*}}
+// CHECK-G-NEXT: IsMethod: true
+// CHECK-G-NEXT: Parent:
+// CHECK-G-NEXT: Type: Record
+// CHECK-G-NEXT: Name: 'Class'
+// CHECK-G-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-G-NEXT: ReturnType:
+// CHECK-G-NEXT: Type:
+// CHECK-G-NEXT: Name: 'void'
+// CHECK-G-NEXT: ...
+
+namespace named{
+ class NamedClass {
+ public:
+ void namedPublicMethod();
+ int namedPublicField;
+ protected:
+ void namedProtectedMethod();
+ int namedProtectedField;
+ private:
+ void namedPrivateMethod();
+ int namedPrivateField;
+ };
+
+ void namedFunction();
+ static void namedStaticFunction();
+ inline void namedInlineFunction();
+}
+
+// CHECK-H: ---
+// CHECK-H-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-H-NEXT: Name: 'named'
+// CHECK-H-NEXT: ...
+
+// CHECK-I: ---
+// CHECK-I-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-I-NEXT: Name: 'NamedClass'
+// CHECK-I-NEXT: Namespace:
+// CHECK-I-NEXT: - Type: Namespace
+// CHECK-I-NEXT: Name: 'named'
+// CHECK-I-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-I-NEXT: DefLocation:
+// CHECK-I-NEXT: LineNumber: 177
+// CHECK-I-NEXT: Filename: {{.*}}
+// CHECK-I-NEXT: TagType: Class
+// CHECK-I-NEXT: Members:
+// CHECK-I-NEXT: - Type:
+// CHECK-I-NEXT: Name: 'int'
+// CHECK-I-NEXT: Name: 'namedPublicField'
+// CHECK-I-NEXT: - Type:
+// CHECK-I-NEXT: Name: 'int'
+// CHECK-I-NEXT: Name: 'namedProtectedField'
+// CHECK-I-NEXT: Access: Protected
+// CHECK-I-NEXT: ...
+
+// CHECK-J: ---
+// CHECK-J-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-J-NEXT: Name: 'namedFunction'
+// CHECK-J-NEXT: Namespace:
+// CHECK-J-NEXT: - Type: Namespace
+// CHECK-J-NEXT: Name: 'named'
+// CHECK-J-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-J-NEXT: Location:
+// CHECK-J-NEXT: - LineNumber: 189
+// CHECK-J-NEXT: Filename: {{.*}}
+// CHECK-J-NEXT: ReturnType:
+// CHECK-J-NEXT: Type:
+// CHECK-J-NEXT: Name: 'void'
+// CHECK-J-NEXT: ...
+
+// CHECK-K: ---
+// CHECK-K-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-K-NEXT: Name: 'namedInlineFunction'
+// CHECK-K-NEXT: Namespace:
+// CHECK-K-NEXT: - Type: Namespace
+// CHECK-K-NEXT: Name: 'named'
+// CHECK-K-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-K-NEXT: Location:
+// CHECK-K-NEXT: - LineNumber: 191
+// CHECK-K-NEXT: Filename: {{.*}}
+// CHECK-K-NEXT: ReturnType:
+// CHECK-K-NEXT: Type:
+// CHECK-K-NEXT: Name: 'void'
+// CHECK-K-NEXT: ...
+
+// CHECK-L: ---
+// CHECK-L-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-L-NEXT: Name: 'namedPublicMethod'
+// CHECK-L-NEXT: Namespace:
+// CHECK-L-NEXT: - Type: Record
+// CHECK-L-NEXT: Name: 'NamedClass'
+// CHECK-L-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-L-NEXT: - Type: Namespace
+// CHECK-L-NEXT: Name: 'named'
+// CHECK-L-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-L-NEXT: Location:
+// CHECK-L-NEXT: - LineNumber: 179
+// CHECK-L-NEXT: Filename: {{.*}}
+// CHECK-L-NEXT: IsMethod: true
+// CHECK-L-NEXT: Parent:
+// CHECK-L-NEXT: Type: Record
+// CHECK-L-NEXT: Name: 'NamedClass'
+// CHECK-L-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-L-NEXT: ReturnType:
+// CHECK-L-NEXT: Type:
+// CHECK-L-NEXT: Name: 'void'
+// CHECK-L-NEXT: ...
+
+// CHECK-M: ---
+// CHECK-M-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-M-NEXT: Name: 'namedProtectedMethod'
+// CHECK-M-NEXT: Namespace:
+// CHECK-M-NEXT: - Type: Record
+// CHECK-M-NEXT: Name: 'NamedClass'
+// CHECK-M-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-M-NEXT: - Type: Namespace
+// CHECK-M-NEXT: Name: 'named'
+// CHECK-M-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-M-NEXT: Location:
+// CHECK-M-NEXT: - LineNumber: 182
+// CHECK-M-NEXT: Filename: {{.*}}
+// CHECK-M-NEXT: IsMethod: true
+// CHECK-M-NEXT: Parent:
+// CHECK-M-NEXT: Type: Record
+// CHECK-M-NEXT: Name: 'NamedClass'
+// CHECK-M-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-M-NEXT: ReturnType:
+// CHECK-M-NEXT: Type:
+// CHECK-M-NEXT: Name: 'void'
+// CHECK-M-NEXT: ...
+
+
+static void staticFunction(int x); //Internal Linkage
+
+static int staticFunctionWithInnerClass(int x){
+ class InnerClass { //NoLinkage
+ public:
+ int innerPublicMethod() { return 2; };
+ }; //end class
+ InnerClass temp;
+ return temp.innerPublicMethod();
+};
+
+namespace{
+ class AnonClass {
+ public:
+ void anonPublicMethod();
+ int anonPublicField;
+ protected:
+ void anonProtectedMethod();
+ int anonProtectedField;
+ private:
+ void anonPrivateMethod();
+ int anonPrivateField;
+ };
+
+ void anonFunction();
+ static void anonStaticFunction();
+ inline void anonInlineFunction();
+}
+
+// CHECK-N: docs-without-flag: .yaml
+// CHECK-N-NEXT: docs-without-flag: AnonClass
+// CHECK-N-NEXT: docs-without-flag: AnonClass.yaml
+// CHECK-N-NEXT: Class: privateMethod.yaml
+// CHECK-N-NEXT: Class.yaml differ
+// CHECK-N-NEXT: docs-without-flag: anonFunction.yaml
+// CHECK-N-NEXT: docs-without-flag: anonInlineFunction.yaml
+// CHECK-N-NEXT: docs-without-flag: anonStaticFunction.yaml
+// CHECK-N-NEXT: docs-without-flag: functionWithInnerClass
+// CHECK-N-NEXT: docs-without-flag: inlinedFunctionWithInnerClass
+// CHECK-N-NEXT: NamedClass: namedPrivateMethod.yaml
+// CHECK-N-NEXT: NamedClass.yaml differ
+// CHECK-N-NEXT: named: namedStaticFunction.yaml
+// CHECK-N-NEXT: docs-without-flag: staticFunction.yaml
+// CHECK-N-NEXT: docs-without-flag: staticFunctionWithInnerClass
+// CHECK-N-NEXT: docs-without-flag: staticFunctionWithInnerClass.yaml
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/test_cases/comment.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/test_cases/comment.cpp
new file mode 100644
index 0000000..9a4ae1b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/test_cases/comment.cpp
@@ -0,0 +1,28 @@
+// THIS IS A GENERATED TEST. DO NOT EDIT.
+// To regenerate, see clang-doc/gen_test.py docstring.
+//
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+
+/// \brief Brief description.
+///
+/// Extended description that
+/// continues onto the next line.
+///
+/// <ul class="test">
+/// <li> Testing.
+/// </ul>
+///
+/// \verbatim
+/// The description continues.
+/// \endverbatim
+/// --
+/// \param [out] I is a parameter.
+/// \param J is a parameter.
+/// \return void
+void F(int I, int J);
+
+/// Bonus comment on definition
+void F(int I, int J) {}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/test_cases/compile_flags.txt b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/test_cases/compile_flags.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/test_cases/compile_flags.txt
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/test_cases/namespace.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/test_cases/namespace.cpp
new file mode 100644
index 0000000..7fa6f8f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/test_cases/namespace.cpp
@@ -0,0 +1,26 @@
+// THIS IS A GENERATED TEST. DO NOT EDIT.
+// To regenerate, see clang-doc/gen_test.py docstring.
+//
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+
+namespace A {
+
+void f();
+
+} // namespace A
+
+namespace A {
+
+void f(){};
+
+namespace B {
+
+enum E { X };
+
+E func(int i) { return X; }
+
+} // namespace B
+} // namespace A
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/test_cases/record.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/test_cases/record.cpp
new file mode 100644
index 0000000..03419a9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/test_cases/record.cpp
@@ -0,0 +1,40 @@
+// THIS IS A GENERATED TEST. DO NOT EDIT.
+// To regenerate, see clang-doc/gen_test.py docstring.
+//
+// This test requires Linux due to system-dependent USR for the inner class.
+// REQUIRES: system-linux
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+
+void H() {
+ class I {};
+}
+
+union A { int X; int Y; };
+
+enum B { X, Y };
+
+enum class Bc { A, B };
+
+struct C { int i; };
+
+class D {};
+
+class E {
+public:
+ E() {}
+ ~E() {}
+
+protected:
+ void ProtectedMethod();
+};
+
+void E::ProtectedMethod() {}
+
+class F : virtual private D, public E {};
+
+class X {
+ class Y {};
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/yaml-comment.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/yaml-comment.cpp
new file mode 100644
index 0000000..445e2be
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/yaml-comment.cpp
@@ -0,0 +1,136 @@
+// THIS IS A GENERATED TEST. DO NOT EDIT.
+// To regenerate, see clang-doc/gen_test.py docstring.
+//
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+
+/// \brief Brief description.
+///
+/// Extended description that
+/// continues onto the next line.
+///
+/// <ul class="test">
+/// <li> Testing.
+/// </ul>
+///
+/// \verbatim
+/// The description continues.
+/// \endverbatim
+/// --
+/// \param [out] I is a parameter.
+/// \param J is a parameter.
+/// \return void
+void F(int I, int J);
+
+/// Bonus comment on definition
+void F(int I, int J) {}
+
+// RUN: clang-doc --format=yaml --doxygen -p %t %t/test.cpp -output=%t/docs
+
+
+// RUN: cat %t/docs/./F.yaml | FileCheck %s --check-prefix CHECK-0
+// CHECK-0: ---
+// CHECK-0-NEXT: USR: '7574630614A535710E5A6ABCFFF98BCA2D06A4CA'
+// CHECK-0-NEXT: Name: 'F'
+// CHECK-0-NEXT: Description:
+// CHECK-0-NEXT: - Kind: 'FullComment'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'ParagraphComment'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: - Kind: 'BlockCommandComment'
+// CHECK-0-NEXT: Name: 'brief'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'ParagraphComment'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: Text: ' Brief description.'
+// CHECK-0-NEXT: - Kind: 'ParagraphComment'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: Text: ' Extended description that'
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: Text: ' continues onto the next line.'
+// CHECK-0-NEXT: - Kind: 'ParagraphComment'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: - Kind: 'HTMLStartTagComment'
+// CHECK-0-NEXT: Name: 'ul'
+// CHECK-0-NEXT: AttrKeys:
+// CHECK-0-NEXT: - 'class'
+// CHECK-0-NEXT: AttrValues:
+// CHECK-0-NEXT: - 'test'
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: - Kind: 'HTMLStartTagComment'
+// CHECK-0-NEXT: Name: 'li'
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: Text: ' Testing.'
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: - Kind: 'HTMLEndTagComment'
+// CHECK-0-NEXT: Name: 'ul'
+// CHECK-0-NEXT: SelfClosing: true
+// CHECK-0-NEXT: - Kind: 'ParagraphComment'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: - Kind: 'VerbatimBlockComment'
+// CHECK-0-NEXT: Name: 'verbatim'
+// CHECK-0-NEXT: CloseName: 'endverbatim'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'VerbatimBlockLineComment'
+// CHECK-0-NEXT: Text: ' The description continues.'
+// CHECK-0-NEXT: - Kind: 'ParagraphComment'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: Text: ' --'
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: - Kind: 'ParamCommandComment'
+// CHECK-0-NEXT: Direction: '[out]'
+// CHECK-0-NEXT: ParamName: 'I'
+// CHECK-0-NEXT: Explicit: true
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'ParagraphComment'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: Text: ' is a parameter.'
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: - Kind: 'ParamCommandComment'
+// CHECK-0-NEXT: Direction: '[in]'
+// CHECK-0-NEXT: ParamName: 'J'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'ParagraphComment'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: Text: ' is a parameter.'
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: - Kind: 'BlockCommandComment'
+// CHECK-0-NEXT: Name: 'return'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'ParagraphComment'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: Text: ' void'
+// CHECK-0-NEXT: - Kind: 'FullComment'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'ParagraphComment'
+// CHECK-0-NEXT: Children:
+// CHECK-0-NEXT: - Kind: 'TextComment'
+// CHECK-0-NEXT: Text: ' Bonus comment on definition'
+// CHECK-0-NEXT: DefLocation:
+// CHECK-0-NEXT: LineNumber: 28
+// CHECK-0-NEXT: Filename: 'test'
+// CHECK-0-NEXT: Location:
+// CHECK-0-NEXT: - LineNumber: 25
+// CHECK-0-NEXT: Filename: 'test'
+// CHECK-0-NEXT: Params:
+// CHECK-0-NEXT: - Type:
+// CHECK-0-NEXT: Name: 'int'
+// CHECK-0-NEXT: Name: 'I'
+// CHECK-0-NEXT: - Type:
+// CHECK-0-NEXT: Name: 'int'
+// CHECK-0-NEXT: Name: 'J'
+// CHECK-0-NEXT: ReturnType:
+// CHECK-0-NEXT: Type:
+// CHECK-0-NEXT: Name: 'void'
+// CHECK-0-NEXT: ...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/yaml-namespace.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/yaml-namespace.cpp
new file mode 100644
index 0000000..c547c5c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/yaml-namespace.cpp
@@ -0,0 +1,105 @@
+// THIS IS A GENERATED TEST. DO NOT EDIT.
+// To regenerate, see clang-doc/gen_test.py docstring.
+//
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+
+namespace A {
+
+void f();
+
+} // namespace A
+
+namespace A {
+
+void f(){};
+
+namespace B {
+
+enum E { X };
+
+E func(int i) { return X; }
+
+} // namespace B
+} // namespace A
+
+// RUN: clang-doc --format=yaml --doxygen -p %t %t/test.cpp -output=%t/docs
+
+
+// RUN: cat %t/docs/./A.yaml | FileCheck %s --check-prefix CHECK-0
+// CHECK-0: ---
+// CHECK-0-NEXT: USR: '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-0-NEXT: Name: 'A'
+// CHECK-0-NEXT: ...
+
+// RUN: cat %t/docs/A/f.yaml | FileCheck %s --check-prefix CHECK-1
+// CHECK-1: ---
+// CHECK-1-NEXT: USR: '39D3C95A5F7CE2BA4937BD7B01BAE09EBC2AD8AC'
+// CHECK-1-NEXT: Name: 'f'
+// CHECK-1-NEXT: Namespace:
+// CHECK-1-NEXT: - Type: Namespace
+// CHECK-1-NEXT: Name: 'A'
+// CHECK-1-NEXT: USR: '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-1-NEXT: DefLocation:
+// CHECK-1-NEXT: LineNumber: 17
+// CHECK-1-NEXT: Filename: 'test'
+// CHECK-1-NEXT: Location:
+// CHECK-1-NEXT: - LineNumber: 11
+// CHECK-1-NEXT: Filename: 'test'
+// CHECK-1-NEXT: ReturnType:
+// CHECK-1-NEXT: Type:
+// CHECK-1-NEXT: Name: 'void'
+// CHECK-1-NEXT: ...
+
+// RUN: cat %t/docs/A/B.yaml | FileCheck %s --check-prefix CHECK-2
+// CHECK-2: ---
+// CHECK-2-NEXT: USR: 'E21AF79E2A9D02554BA090D10DF39FE273F5CDB5'
+// CHECK-2-NEXT: Name: 'B'
+// CHECK-2-NEXT: Namespace:
+// CHECK-2-NEXT: - Type: Namespace
+// CHECK-2-NEXT: Name: 'A'
+// CHECK-2-NEXT: USR: '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-2-NEXT: ...
+
+// RUN: cat %t/docs/A/B/E.yaml | FileCheck %s --check-prefix CHECK-3
+// CHECK-3: ---
+// CHECK-3-NEXT: USR: 'E9ABF7E7E2425B626723D41E76E4BC7E7A5BD775'
+// CHECK-3-NEXT: Name: 'E'
+// CHECK-3-NEXT: Namespace:
+// CHECK-3-NEXT: - Type: Namespace
+// CHECK-3-NEXT: Name: 'B'
+// CHECK-3-NEXT: USR: 'E21AF79E2A9D02554BA090D10DF39FE273F5CDB5'
+// CHECK-3-NEXT: - Type: Namespace
+// CHECK-3-NEXT: Name: 'A'
+// CHECK-3-NEXT: USR: '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-3-NEXT: DefLocation:
+// CHECK-3-NEXT: LineNumber: 21
+// CHECK-3-NEXT: Filename: 'test'
+// CHECK-3-NEXT: Members:
+// CHECK-3-NEXT: - 'X'
+// CHECK-3-NEXT: ...
+
+// RUN: cat %t/docs/A/B/func.yaml | FileCheck %s --check-prefix CHECK-4
+// CHECK-4: ---
+// CHECK-4-NEXT: USR: '9A82CB33ED0FDF81EE383D31CD0957D153C5E840'
+// CHECK-4-NEXT: Name: 'func'
+// CHECK-4-NEXT: Namespace:
+// CHECK-4-NEXT: - Type: Namespace
+// CHECK-4-NEXT: Name: 'B'
+// CHECK-4-NEXT: USR: 'E21AF79E2A9D02554BA090D10DF39FE273F5CDB5'
+// CHECK-4-NEXT: - Type: Namespace
+// CHECK-4-NEXT: Name: 'A'
+// CHECK-4-NEXT: USR: '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-4-NEXT: DefLocation:
+// CHECK-4-NEXT: LineNumber: 23
+// CHECK-4-NEXT: Filename: 'test'
+// CHECK-4-NEXT: Params:
+// CHECK-4-NEXT: - Type:
+// CHECK-4-NEXT: Name: 'int'
+// CHECK-4-NEXT: Name: 'i'
+// CHECK-4-NEXT: ReturnType:
+// CHECK-4-NEXT: Type:
+// CHECK-4-NEXT: Name: 'enum A::B::E'
+// CHECK-4-NEXT: ...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/yaml-record.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/yaml-record.cpp
new file mode 100644
index 0000000..1d5235f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-doc/yaml-record.cpp
@@ -0,0 +1,252 @@
+// THIS IS A GENERATED TEST. DO NOT EDIT.
+// To regenerate, see clang-doc/gen_test.py docstring.
+//
+// This test requires Linux due to system-dependent USR for the inner class.
+// REQUIRES: system-linux
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+
+void H() {
+ class I {};
+}
+
+union A { int X; int Y; };
+
+enum B { X, Y };
+
+enum class Bc { A, B };
+
+struct C { int i; };
+
+class D {};
+
+class E {
+public:
+ E() {}
+ ~E() {}
+
+protected:
+ void ProtectedMethod();
+};
+
+void E::ProtectedMethod() {}
+
+class F : virtual private D, public E {};
+
+class X {
+ class Y {};
+};
+
+// RUN: clang-doc --format=yaml --doxygen -p %t %t/test.cpp -output=%t/docs
+
+
+// RUN: cat %t/docs/./C.yaml | FileCheck %s --check-prefix CHECK-0
+// CHECK-0: ---
+// CHECK-0-NEXT: USR: '06B5F6A19BA9F6A832E127C9968282B94619B210'
+// CHECK-0-NEXT: Name: 'C'
+// CHECK-0-NEXT: DefLocation:
+// CHECK-0-NEXT: LineNumber: 21
+// CHECK-0-NEXT: Filename: 'test'
+// CHECK-0-NEXT: Members:
+// CHECK-0-NEXT: - Type:
+// CHECK-0-NEXT: Name: 'int'
+// CHECK-0-NEXT: Name: 'i'
+// CHECK-0-NEXT: ...
+
+// RUN: cat %t/docs/./A.yaml | FileCheck %s --check-prefix CHECK-1
+// CHECK-1: ---
+// CHECK-1-NEXT: USR: 'ACE81AFA6627B4CEF2B456FB6E1252925674AF7E'
+// CHECK-1-NEXT: Name: 'A'
+// CHECK-1-NEXT: DefLocation:
+// CHECK-1-NEXT: LineNumber: 15
+// CHECK-1-NEXT: Filename: 'test'
+// CHECK-1-NEXT: TagType: Union
+// CHECK-1-NEXT: Members:
+// CHECK-1-NEXT: - Type:
+// CHECK-1-NEXT: Name: 'int'
+// CHECK-1-NEXT: Name: 'X'
+// CHECK-1-NEXT: - Type:
+// CHECK-1-NEXT: Name: 'int'
+// CHECK-1-NEXT: Name: 'Y'
+// CHECK-1-NEXT: ...
+
+// RUN: cat %t/docs/./F.yaml | FileCheck %s --check-prefix CHECK-2
+// CHECK-2: ---
+// CHECK-2-NEXT: USR: 'E3B54702FABFF4037025BA194FC27C47006330B5'
+// CHECK-2-NEXT: Name: 'F'
+// CHECK-2-NEXT: DefLocation:
+// CHECK-2-NEXT: LineNumber: 36
+// CHECK-2-NEXT: Filename: 'test'
+// CHECK-2-NEXT: TagType: Class
+// CHECK-2-NEXT: Parents:
+// CHECK-2-NEXT: - Type: Record
+// CHECK-2-NEXT: Name: 'E'
+// CHECK-2-NEXT: USR: '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-2-NEXT: VirtualParents:
+// CHECK-2-NEXT: - Type: Record
+// CHECK-2-NEXT: Name: 'D'
+// CHECK-2-NEXT: USR: '0921737541208B8FA9BB42B60F78AC1D779AA054'
+// CHECK-2-NEXT: ...
+
+// RUN: cat %t/docs/./E.yaml | FileCheck %s --check-prefix CHECK-3
+// CHECK-3: ---
+// CHECK-3-NEXT: USR: '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-3-NEXT: Name: 'E'
+// CHECK-3-NEXT: DefLocation:
+// CHECK-3-NEXT: LineNumber: 25
+// CHECK-3-NEXT: Filename: 'test'
+// CHECK-3-NEXT: TagType: Class
+// CHECK-3-NEXT: ...
+
+// RUN: cat %t/docs/./D.yaml | FileCheck %s --check-prefix CHECK-4
+// CHECK-4: ---
+// CHECK-4-NEXT: USR: '0921737541208B8FA9BB42B60F78AC1D779AA054'
+// CHECK-4-NEXT: Name: 'D'
+// CHECK-4-NEXT: DefLocation:
+// CHECK-4-NEXT: LineNumber: 23
+// CHECK-4-NEXT: Filename: 'test'
+// CHECK-4-NEXT: TagType: Class
+// CHECK-4-NEXT: ...
+
+// RUN: cat %t/docs/./B.yaml | FileCheck %s --check-prefix CHECK-5
+// CHECK-5: ---
+// CHECK-5-NEXT: USR: 'FC07BD34D5E77782C263FA944447929EA8753740'
+// CHECK-5-NEXT: Name: 'B'
+// CHECK-5-NEXT: DefLocation:
+// CHECK-5-NEXT: LineNumber: 17
+// CHECK-5-NEXT: Filename: 'test'
+// CHECK-5-NEXT: Members:
+// CHECK-5-NEXT: - 'X'
+// CHECK-5-NEXT: - 'Y'
+// CHECK-5-NEXT: ...
+
+// RUN: cat %t/docs/./X.yaml | FileCheck %s --check-prefix CHECK-6
+// CHECK-6: ---
+// CHECK-6-NEXT: USR: 'CA7C7935730B5EACD25F080E9C83FA087CCDC75E'
+// CHECK-6-NEXT: Name: 'X'
+// CHECK-6-NEXT: DefLocation:
+// CHECK-6-NEXT: LineNumber: 38
+// CHECK-6-NEXT: Filename: 'test'
+// CHECK-6-NEXT: TagType: Class
+// CHECK-6-NEXT: ...
+
+// RUN: cat %t/docs/./H.yaml | FileCheck %s --check-prefix CHECK-7
+// CHECK-7: ---
+// CHECK-7-NEXT: USR: 'B6AC4C5C9F2EA3F2B3ECE1A33D349F4EE502B24E'
+// CHECK-7-NEXT: Name: 'H'
+// CHECK-7-NEXT: DefLocation:
+// CHECK-7-NEXT: LineNumber: 11
+// CHECK-7-NEXT: Filename: 'test'
+// CHECK-7-NEXT: ReturnType:
+// CHECK-7-NEXT: Type:
+// CHECK-7-NEXT: Name: 'void'
+// CHECK-7-NEXT: ...
+
+// RUN: cat %t/docs/./Bc.yaml | FileCheck %s --check-prefix CHECK-8
+// CHECK-8: ---
+// CHECK-8-NEXT: USR: '1E3438A08BA22025C0B46289FF0686F92C8924C5'
+// CHECK-8-NEXT: Name: 'Bc'
+// CHECK-8-NEXT: DefLocation:
+// CHECK-8-NEXT: LineNumber: 19
+// CHECK-8-NEXT: Filename: 'test'
+// CHECK-8-NEXT: Scoped: true
+// CHECK-8-NEXT: Members:
+// CHECK-8-NEXT: - 'A'
+// CHECK-8-NEXT: - 'B'
+// CHECK-8-NEXT: ...
+
+// RUN: cat %t/docs/H/I.yaml | FileCheck %s --check-prefix CHECK-9
+// CHECK-9: ---
+// CHECK-9-NEXT: USR: '3FB542274573CAEAD54CEBFFCAEE3D77FB9713D8'
+// CHECK-9-NEXT: Name: 'I'
+// CHECK-9-NEXT: Namespace:
+// CHECK-9-NEXT: - Type: Function
+// CHECK-9-NEXT: Name: 'H'
+// CHECK-9-NEXT: USR: 'B6AC4C5C9F2EA3F2B3ECE1A33D349F4EE502B24E'
+// CHECK-9-NEXT: DefLocation:
+// CHECK-9-NEXT: LineNumber: 12
+// CHECK-9-NEXT: Filename: 'test'
+// CHECK-9-NEXT: TagType: Class
+// CHECK-9-NEXT: ...
+
+// RUN: cat %t/docs/X/Y.yaml | FileCheck %s --check-prefix CHECK-10
+// CHECK-10: ---
+// CHECK-10-NEXT: USR: '641AB4A3D36399954ACDE29C7A8833032BF40472'
+// CHECK-10-NEXT: Name: 'Y'
+// CHECK-10-NEXT: Namespace:
+// CHECK-10-NEXT: - Type: Record
+// CHECK-10-NEXT: Name: 'X'
+// CHECK-10-NEXT: USR: 'CA7C7935730B5EACD25F080E9C83FA087CCDC75E'
+// CHECK-10-NEXT: DefLocation:
+// CHECK-10-NEXT: LineNumber: 39
+// CHECK-10-NEXT: Filename: 'test'
+// CHECK-10-NEXT: TagType: Class
+// CHECK-10-NEXT: ...
+
+// RUN: cat %t/docs/E/ProtectedMethod.yaml | FileCheck %s --check-prefix CHECK-11
+// CHECK-11: ---
+// CHECK-11-NEXT: USR: '5093D428CDC62096A67547BA52566E4FB9404EEE'
+// CHECK-11-NEXT: Name: 'ProtectedMethod'
+// CHECK-11-NEXT: Namespace:
+// CHECK-11-NEXT: - Type: Record
+// CHECK-11-NEXT: Name: 'E'
+// CHECK-11-NEXT: USR: '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-11-NEXT: DefLocation:
+// CHECK-11-NEXT: LineNumber: 34
+// CHECK-11-NEXT: Filename: 'test'
+// CHECK-11-NEXT: Location:
+// CHECK-11-NEXT: - LineNumber: 31
+// CHECK-11-NEXT: Filename: 'test'
+// CHECK-11-NEXT: IsMethod: true
+// CHECK-11-NEXT: Parent:
+// CHECK-11-NEXT: Type: Record
+// CHECK-11-NEXT: Name: 'E'
+// CHECK-11-NEXT: USR: '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-11-NEXT: ReturnType:
+// CHECK-11-NEXT: Type:
+// CHECK-11-NEXT: Name: 'void'
+// CHECK-11-NEXT: ...
+
+// RUN: cat %t/docs/E/E.yaml | FileCheck %s --check-prefix CHECK-12
+// CHECK-12: ---
+// CHECK-12-NEXT: USR: 'DEB4AC1CD9253CD9EF7FBE6BCAC506D77984ABD4'
+// CHECK-12-NEXT: Name: 'E'
+// CHECK-12-NEXT: Namespace:
+// CHECK-12-NEXT: - Type: Record
+// CHECK-12-NEXT: Name: 'E'
+// CHECK-12-NEXT: USR: '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-12-NEXT: DefLocation:
+// CHECK-12-NEXT: LineNumber: 27
+// CHECK-12-NEXT: Filename: 'test'
+// CHECK-12-NEXT: IsMethod: true
+// CHECK-12-NEXT: Parent:
+// CHECK-12-NEXT: Type: Record
+// CHECK-12-NEXT: Name: 'E'
+// CHECK-12-NEXT: USR: '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-12-NEXT: ReturnType:
+// CHECK-12-NEXT: Type:
+// CHECK-12-NEXT: Name: 'void'
+// CHECK-12-NEXT: ...
+
+// RUN: cat %t/docs/E/~E.yaml | FileCheck %s --check-prefix CHECK-13
+// CHECK-13: ---
+// CHECK-13-NEXT: USR: 'BD2BDEBD423F80BACCEA75DE6D6622D355FC2D17'
+// CHECK-13-NEXT: Name: '~E'
+// CHECK-13-NEXT: Namespace:
+// CHECK-13-NEXT: - Type: Record
+// CHECK-13-NEXT: Name: 'E'
+// CHECK-13-NEXT: USR: '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-13-NEXT: DefLocation:
+// CHECK-13-NEXT: LineNumber: 28
+// CHECK-13-NEXT: Filename: 'test'
+// CHECK-13-NEXT: IsMethod: true
+// CHECK-13-NEXT: Parent:
+// CHECK-13-NEXT: Type: Record
+// CHECK-13-NEXT: Name: 'E'
+// CHECK-13-NEXT: USR: '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-13-NEXT: ReturnType:
+// CHECK-13-NEXT: Type:
+// CHECK-13-NEXT: Name: 'void'
+// CHECK-13-NEXT: ...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/database_template.json b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/database_template.json
new file mode 100644
index 0000000..ceb499c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/database_template.json
@@ -0,0 +1,7 @@
+[
+{
+ "directory": "$test_dir/build",
+ "command": "clang++ -o test.o -I../include $test_dir/src/test.cpp",
+ "file": "$test_dir/src/test.cpp"
+}
+]
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/enum.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/enum.h
new file mode 100644
index 0000000..9ec3926
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/enum.h
@@ -0,0 +1,9 @@
+namespace a {
+enum E1 { Green, Red };
+
+enum class E2 { Yellow };
+
+class C {
+ enum E3 { Blue };
+};
+} // namespace a
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/function_test.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/function_test.cpp
new file mode 100644
index 0000000..5e86f59
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/function_test.cpp
@@ -0,0 +1,5 @@
+#include "function_test.h"
+
+void f() {}
+
+void A::f() {}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/function_test.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/function_test.h
new file mode 100644
index 0000000..810f803
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/function_test.h
@@ -0,0 +1,14 @@
+void f();
+
+inline int g() { return 0; }
+
+template<typename T>
+void h(T t) {}
+
+template<>
+void h(int t) {}
+
+class A {
+ public:
+ void f();
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/helper_decls_test.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/helper_decls_test.cpp
new file mode 100644
index 0000000..32d2a23
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/helper_decls_test.cpp
@@ -0,0 +1,97 @@
+#include "helper_decls_test.h"
+
+namespace {
+class HelperC1 {
+public:
+ static int I;
+};
+
+int HelperC1::I = 0;
+
+class HelperC2 {};
+
+class HelperC3 {
+ public:
+ static int I;
+};
+
+int HelperC3::I = 0;
+
+void HelperFun1() {}
+
+void HelperFun2() { HelperFun1(); }
+
+const int K1 = 1;
+} // namespace
+
+static const int K2 = 2;
+static void HelperFun3() { K2; }
+
+namespace a {
+
+static const int K3 = 3;
+static const int K4 = HelperC3::I;
+static const int K5 = 5;
+static const int K6 = 6;
+
+static void HelperFun4() {}
+static void HelperFun6() {}
+
+void Class1::f() { HelperFun2(); }
+
+void Class2::f() {
+ HelperFun1();
+ HelperFun3();
+}
+
+void Class3::f() { HelperC1::I; }
+
+void Class4::f() { HelperC2 c2; }
+
+void Class5::f() {
+ int Result = K1 + K2 + K3;
+ HelperFun4();
+}
+
+int Class6::f() {
+ int R = K4;
+ return R;
+}
+
+int Class7::f() {
+ int R = K6;
+ return R;
+}
+
+int Class7::g() {
+ HelperFun6();
+ return 1;
+}
+
+static int HelperFun5() {
+ int R = K5;
+ return R;
+}
+
+void Fun1() { HelperFun5(); }
+
+} // namespace a
+
+namespace b {
+namespace {
+void HelperFun7();
+
+class HelperC4;
+} // namespace
+
+void Fun3() {
+ HelperFun7();
+ HelperC4 *t;
+}
+
+namespace {
+void HelperFun7() {}
+
+class HelperC4 {};
+} // namespace
+} // namespace b
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/helper_decls_test.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/helper_decls_test.h
new file mode 100644
index 0000000..d8927c4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/helper_decls_test.h
@@ -0,0 +1,39 @@
+namespace a {
+class Class1 {
+ void f();
+};
+
+class Class2 {
+ void f();
+};
+
+class Class3 {
+ void f();
+};
+
+class Class4 {
+ void f();
+};
+
+class Class5 {
+ void f();
+};
+
+class Class6 {
+ int f();
+};
+
+class Class7 {
+ int f();
+ int g();
+};
+
+void Fun1();
+
+inline void Fun2() {}
+
+} // namespace a
+
+namespace b {
+void Fun3();
+} // namespace b
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/macro_helper_test.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/macro_helper_test.cpp
new file mode 100644
index 0000000..c2c1e1e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/macro_helper_test.cpp
@@ -0,0 +1,13 @@
+#include "macro_helper_test.h"
+
+#define DEFINE(name) \
+ namespace ns { \
+ static const bool t1 = false; \
+ bool t2_##name = t1; \
+ bool t3_##name = t1; \
+ } \
+ using ns::t2_##name;
+
+DEFINE(test)
+
+void f1() {}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/macro_helper_test.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/macro_helper_test.h
new file mode 100644
index 0000000..0ddfaae
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/macro_helper_test.h
@@ -0,0 +1,2 @@
+class A {};
+void f1();
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/multiple_class_test.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/multiple_class_test.cpp
new file mode 100644
index 0000000..5eb4bf3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/multiple_class_test.cpp
@@ -0,0 +1,52 @@
+#include "multiple_class_test.h"
+
+using a::Move1;
+using namespace a;
+using A = a::Move1;
+static int g = 0;
+
+namespace a {
+int Move1::f() {
+ return 0;
+}
+} // namespace a
+
+namespace {
+using a::Move1;
+using namespace a;
+static int k = 0;
+} // namespace
+
+namespace b {
+using a::Move1;
+using namespace a;
+using T = a::Move1;
+int Move2::f() {
+ return 0;
+}
+} // namespace b
+
+namespace c {
+int Move3::f() {
+ using a::Move1;
+ using namespace b;
+ return 0;
+}
+
+int Move4::f() {
+ return k;
+}
+
+int EnclosingMove5::a = 1;
+
+int EnclosingMove5::Nested::f() {
+ return g;
+}
+
+int EnclosingMove5::Nested::b = 1;
+
+int NoMove::f() {
+ static int F = 0;
+ return g;
+}
+} // namespace c
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/multiple_class_test.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/multiple_class_test.h
new file mode 100644
index 0000000..113a261
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/multiple_class_test.h
@@ -0,0 +1,39 @@
+namespace a {
+class Move1 {
+public:
+ int f();
+};
+} // namespace a
+
+namespace b {
+class Move2 {
+public:
+ int f();
+};
+} // namespace b
+
+namespace c {
+class Move3 {
+public:
+ int f();
+};
+
+class Move4 {
+public:
+ int f();
+};
+
+class EnclosingMove5 {
+public:
+ class Nested {
+ int f();
+ static int b;
+ };
+ static int a;
+};
+
+class NoMove {
+public:
+ int f();
+};
+} // namespace c
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/template_class_test.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/template_class_test.cpp
new file mode 100644
index 0000000..8ad2dcb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/template_class_test.cpp
@@ -0,0 +1,13 @@
+#include "template_class_test.h"
+
+template <typename T>
+void A<T>::g() {}
+
+template <typename T>
+template <typename U>
+void A<T>::k() {}
+
+template <typename T>
+int A<T>::c = 2;
+
+void B::f() {}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/template_class_test.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/template_class_test.h
new file mode 100644
index 0000000..d42a158
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/template_class_test.h
@@ -0,0 +1,30 @@
+#ifndef TEMPLATE_CLASS_TEST_H // comment 1
+#define TEMPLATE_CLASS_TEST_H
+
+template <typename T>
+class A {
+ public:
+ void f();
+ void g();
+ template <typename U> void h();
+ template <typename U> void k();
+ static int b;
+ static int c;
+};
+
+template <typename T>
+void A<T>::f() {}
+
+template <typename T>
+template <typename U>
+void A<T>::h() {}
+
+template <typename T>
+int A<T>::b = 2;
+
+class B {
+ public:
+ void f();
+};
+
+#endif // TEMPLATE_CLASS_TEST_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/test.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/test.cpp
new file mode 100644
index 0000000..fa777f0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/test.cpp
@@ -0,0 +1,11 @@
+#include "test.h"
+#include "test2.h"
+
+namespace a {
+int Foo::f() {
+ return 0;
+}
+int Foo::f2(int a, int b) {
+ return a + b;
+}
+} // namespace a
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/test.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/test.h
new file mode 100644
index 0000000..8006c34
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/test.h
@@ -0,0 +1,10 @@
+#ifndef TEST_H // comment 1
+#define TEST_H
+namespace a {
+class Foo {
+public:
+ int f();
+ int f2(int a, int b);
+};
+} // namespace a
+#endif // TEST_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/type_alias.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/type_alias.h
new file mode 100644
index 0000000..7a900f6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/type_alias.h
@@ -0,0 +1,11 @@
+typedef int Int1;
+using Int2 = int;
+
+template<class T>
+struct A {};
+
+template <class T> using B = A<T>;
+
+class C {
+ typedef int Int3;
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/var_test.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/var_test.cpp
new file mode 100644
index 0000000..9023abc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/var_test.cpp
@@ -0,0 +1,6 @@
+#include "var_test.h"
+
+namespace a{
+int kGlobalInt = 1;
+const char *const kGlobalStr = "Hello";
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/var_test.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/var_test.h
new file mode 100644
index 0000000..1bfd54c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/Inputs/var_test.h
@@ -0,0 +1,11 @@
+namespace a {
+extern int kGlobalInt;
+extern const char *const kGlobalStr;
+}
+
+int kEvilInt = 2;
+
+inline void f1() {
+ int kGlobalInt = 3;
+ const char *const kGlobalStr = "Hello2";
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-class.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-class.cpp
new file mode 100644
index 0000000..a30cb4d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-class.cpp
@@ -0,0 +1,43 @@
+// RUN: mkdir -p %T/clang-move/build
+// RUN: mkdir -p %T/clang-move/include
+// RUN: mkdir -p %T/clang-move/src
+// RUN: sed 's|$test_dir|%/T/clang-move|g' %S/Inputs/database_template.json > %T/clang-move/compile_commands.json
+// RUN: cp %S/Inputs/test.h %T/clang-move/include
+// RUN: cp %S/Inputs/test.cpp %T/clang-move/src
+// RUN: touch %T/clang-move/include/test2.h
+// RUN: cd %T/clang-move/build
+// RUN: clang-move -names="a::Foo" -new_cc=%T/clang-move/new_test.cpp -new_header=%T/clang-move/new_test.h -old_cc=../src/test.cpp -old_header=../include/test.h %T/clang-move/src/test.cpp
+// RUN: FileCheck -input-file=%T/clang-move/new_test.cpp -check-prefix=CHECK-NEW-TEST-CPP %s
+// RUN: FileCheck -input-file=%T/clang-move/new_test.h -check-prefix=CHECK-NEW-TEST-H %s
+// RUN: FileCheck -input-file=%T/clang-move/src/test.cpp -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s
+// RUN: FileCheck -input-file=%T/clang-move/include/test.h -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s
+//
+// RUN: cp %S/Inputs/test.h %T/clang-move/include
+// RUN: cp %S/Inputs/test.cpp %T/clang-move/src
+// RUN: cd %T/clang-move/build
+// RUN: clang-move -names="a::Foo" -new_cc=%T/clang-move/new_test.cpp -new_header=%T/clang-move/new_test.h -old_cc=%T/clang-move/src/test.cpp -old_header=%T/clang-move/include/test.h %T/clang-move/src/test.cpp
+// RUN: FileCheck -input-file=%T/clang-move/new_test.cpp -check-prefix=CHECK-NEW-TEST-CPP %s
+// RUN: FileCheck -input-file=%T/clang-move/new_test.h -check-prefix=CHECK-NEW-TEST-H %s
+// RUN: FileCheck -input-file=%T/clang-move/src/test.cpp -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s
+// RUN: FileCheck -input-file=%T/clang-move/include/test.h -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s
+//
+//
+// CHECK-NEW-TEST-H: #ifndef TEST_H // comment 1
+// CHECK-NEW-TEST-H: #define TEST_H
+// CHECK-NEW-TEST-H: namespace a {
+// CHECK-NEW-TEST-H: class Foo {
+// CHECK-NEW-TEST-H: public:
+// CHECK-NEW-TEST-H: int f();
+// CHECK-NEW-TEST-H: int f2(int a, int b);
+// CHECK-NEW-TEST-H: };
+// CHECK-NEW-TEST-H: } // namespace a
+// CHECK-NEW-TEST-H: #endif // TEST_H
+//
+// CHECK-NEW-TEST-CPP: #include "{{.*}}new_test.h"
+// CHECK-NEW-TEST-CPP: #include "test2.h"
+// CHECK-NEW-TEST-CPP: namespace a {
+// CHECK-NEW-TEST-CPP: int Foo::f() { return 0; }
+// CHECK-NEW-TEST-CPP: int Foo::f2(int a, int b) { return a + b; }
+// CHECK-NEW-TEST-CPP: } // namespace a
+//
+// CHECK-OLD-TEST-EMPTY: {{^}}{{$}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-enum-decl.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-enum-decl.cpp
new file mode 100644
index 0000000..42f6f99
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-enum-decl.cpp
@@ -0,0 +1,44 @@
+// RUN: mkdir -p %T/move-enum
+// RUN: cp %S/Inputs/enum.h %T/move-enum/enum.h
+// RUN: echo '#include "enum.h"' > %T/move-enum/enum.cpp
+// RUN: cd %T/move-enum
+//
+// -----------------------------------------------------------------------------
+// Test moving enum declarations.
+// -----------------------------------------------------------------------------
+// RUN: clang-move -names="a::E1" -new_cc=%T/move-enum/new_test.cpp -new_header=%T/move-enum/new_test.h -old_cc=%T/move-enum/enum.cpp -old_header=%T/move-enum/enum.h %T/move-enum/enum.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/move-enum/new_test.h -check-prefix=CHECK-NEW-TEST-H-CASE1 %s
+// RUN: FileCheck -input-file=%T/move-enum/enum.h -check-prefix=CHECK-OLD-TEST-H-CASE1 %s
+//
+// CHECK-NEW-TEST-H-CASE1: namespace a {
+// CHECK-NEW-TEST-H-CASE1-NEXT: enum E1 { Green, Red };
+// CHECK-NEW-TEST-H-CASE1-NEXT: }
+
+// CHECK-OLD-TEST-H-CASE1-NOT: enum E1 { Green, Red };
+
+
+// -----------------------------------------------------------------------------
+// Test moving scoped enum declarations.
+// -----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/enum.h %T/move-enum/enum.h
+// RUN: echo '#include "enum.h"' > %T/move-enum/enum.cpp
+// RUN: clang-move -names="a::E2" -new_cc=%T/move-enum/new_test.cpp -new_header=%T/move-enum/new_test.h -old_cc=%T/move-enum/enum.cpp -old_header=%T/move-enum/enum.h %T/move-enum/enum.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/move-enum/new_test.h -check-prefix=CHECK-NEW-TEST-H-CASE2 %s
+// RUN: FileCheck -input-file=%T/move-enum/enum.h -check-prefix=CHECK-OLD-TEST-H-CASE2 %s
+
+// CHECK-NEW-TEST-H-CASE2: namespace a {
+// CHECK-NEW-TEST-H-CASE2-NEXT: enum class E2 { Yellow };
+// CHECK-NEW-TEST-H-CASE2-NEXT: }
+
+// CHECK-OLD-TEST-H-CASE2-NOT: enum class E2 { Yellow };
+
+
+// -----------------------------------------------------------------------------
+// Test not moving class-insided enum declarations.
+// -----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/enum.h %T/move-enum/enum.h
+// RUN: echo '#include "enum.h"' > %T/move-enum/enum.cpp
+// RUN: clang-move -names="a::C::E3" -new_cc=%T/move-enum/new_test.cpp -new_header=%T/move-enum/new_test.h -old_cc=%T/move-enum/enum.cpp -old_header=%T/move-enum/enum.h %T/move-enum/enum.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/move-enum/new_test.h -allow-empty -check-prefix=CHECK-EMPTY %s
+
+// CHECK-EMPTY: {{^}}{{$}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-function.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-function.cpp
new file mode 100644
index 0000000..0324b80
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-function.cpp
@@ -0,0 +1,70 @@
+// RUN: mkdir -p %T/move-function
+// RUN: cat %S/Inputs/function_test.h > %T/move-function/function_test.h
+// RUN: cat %S/Inputs/function_test.cpp > %T/move-function/function_test.cpp
+// RUN: cd %T/move-function
+// RUN: clang-move -names="g" -new_header=%T/move-function/new_function_test.h -old_header=../move-function/function_test.h %T/move-function/function_test.cpp --
+// RUN: FileCheck -input-file=%T/move-function/new_function_test.h -check-prefix=CHECK-NEW-TEST-H-CASE1 %s
+//
+// CHECK-NEW-TEST-H-CASE1: #ifndef {{.*}}NEW_FUNCTION_TEST_H
+// CHECK-NEW-TEST-H-CASE1: #define {{.*}}NEW_FUNCTION_TEST_H
+// CHECK-NEW-TEST-H-CASE1: {{[[:space:]]+}}
+// CHECK-NEW-TEST-H-CASE1: inline int g() { return 0; }
+// CHECK-NEW-TEST-H-CASE1: {{[[:space:]]+}}
+// CHECK-NEW-TEST-H-CASE1: #endif // {{.*}}NEW_FUNCTION_TEST_H
+//
+// RUN: cp %S/Inputs/function_test* %T/move-function
+// RUN: clang-move -names="h" -new_header=%T/move-function/new_function_test.h -old_header=../move-function/function_test.h %T/move-function/function_test.cpp --
+// RUN: FileCheck -input-file=%T/move-function/new_function_test.h -check-prefix=CHECK-NEW-TEST-H-CASE2 %s
+//
+// CHECK-NEW-TEST-H-CASE2: #ifndef {{.*}}NEW_FUNCTION_TEST_H
+// CHECK-NEW-TEST-H-CASE2: #define {{.*}}NEW_FUNCTION_TEST_H
+// CHECK-NEW-TEST-H-CASE2: {{[[:space:]]+}}
+// CHECK-NEW-TEST-H-CASE2: template <typename T> void h(T t) {}
+// CHECK-NEW-TEST-H-CASE2: {{[[:space:]]+}}
+// CHECK-NEW-TEST-H-CASE2: template <> void h(int t) {}
+// CHECK-NEW-TEST-H-CASE2: {{[[:space:]]+}}
+// CHECK-NEW-TEST-H-CASE2: #endif // {{.*}}NEW_FUNCTION_TEST_H
+//
+// RUN: cp %S/Inputs/function_test* %T/move-function
+// RUN: clang-move -names="f" -new_header=%T/move-function/new_function_test.h -new_cc=%T/move-function/new_function_test.cpp -old_header=../move-function/function_test.h -old_cc=../move-function/function_test.cpp %T/move-function/function_test.cpp --
+// RUN: FileCheck -input-file=%T/move-function/new_function_test.h -check-prefix=CHECK-NEW-TEST-H-CASE3 %s
+// RUN: FileCheck -input-file=%T/move-function/new_function_test.cpp -check-prefix=CHECK-NEW-TEST-CPP-CASE3 %s
+//
+// CHECK-NEW-TEST-H-CASE3: #ifndef {{.*}}NEW_FUNCTION_TEST_H
+// CHECK-NEW-TEST-H-CASE3: #define {{.*}}NEW_FUNCTION_TEST_H
+// CHECK-NEW-TEST-H-CASE3: {{[[:space:]]+}}
+// CHECK-NEW-TEST-H-CASE3: void f();
+// CHECK-NEW-TEST-H-CASE3: {{[[:space:]]+}}
+// CHECK-NEW-TEST-H-CASE3: #endif // {{.*}}NEW_FUNCTION_TEST_H
+// CHECK-NEW-TEST-CPP-CASE3: #include "{{.*}}new_function_test.h"
+// CHECK-NEW-TEST-CPP-CASE3: {{[[:space:]]+}}
+// CHECK-NEW-TEST-CPP-CASE3: void f() {}
+//
+// RUN: cat %S/Inputs/function_test.h > %T/move-function/function_test.h
+// RUN: cat %S/Inputs/function_test.cpp > %T/move-function/function_test.cpp
+// RUN: clang-move -names="A::f" -new_header=%T/move-function/new_function_test.h -new_cc=%T/move-function/new_function_test.cpp -old_header=../move-function/function_test.h -old_cc=../move-function/function_test.cpp %T/move-function/function_test.cpp -dump_result -- | FileCheck %s -check-prefix=CHECK-EMPTY
+//
+// CHECK-EMPTY: [{{[[:space:]]*}}]
+//
+// RUN: cat %S/Inputs/function_test.h > %T/move-function/function_test.h
+// RUN: cat %S/Inputs/function_test.cpp > %T/move-function/function_test.cpp
+// RUN: clang-move -names="f,A" -new_header=%T/move-function/new_function_test.h -new_cc=%T/move-function/new_function_test.cpp -old_header=../move-function/function_test.h -old_cc=../move-function/function_test.cpp %T/move-function/function_test.cpp --
+// RUN: FileCheck -input-file=%T/move-function/new_function_test.h -check-prefix=CHECK-NEW-TEST-H-CASE4 %s
+// RUN: FileCheck -input-file=%T/move-function/new_function_test.cpp -check-prefix=CHECK-NEW-TEST-CPP-CASE4 %s
+
+// CHECK-NEW-TEST-H-CASE4: #ifndef {{.*}}NEW_FUNCTION_TEST_H
+// CHECK-NEW-TEST-H-CASE4: #define {{.*}}NEW_FUNCTION_TEST_H
+// CHECK-NEW-TEST-H-CASE4: {{[[:space:]]+}}
+// CHECK-NEW-TEST-H-CASE4: void f();
+// CHECK-NEW-TEST-H-CASE4: {{[[:space:]]+}}
+// CHECK-NEW-TEST-H-CASE4: class A {
+// CHECK-NEW-TEST-H-CASE4: public:
+// CHECK-NEW-TEST-H-CASE4: void f();
+// CHECK-NEW-TEST-H-CASE4: };
+// CHECK-NEW-TEST-H-CASE4: {{[[:space:]]+}}
+// CHECK-NEW-TEST-H-CASE4: #endif // {{.*}}NEW_FUNCTION_TEST_H
+// CHECK-NEW-TEST-CPP-CASE4: #include "{{.*}}new_function_test.h"
+// CHECK-NEW-TEST-CPP-CASE4: {{[[:space:]]+}}
+// CHECK-NEW-TEST-CPP-CASE4: void f() {}
+// CHECK-NEW-TEST-CPP-CASE4: {{[[:space:]]+}}
+// CHECK-NEW-TEST-CPP-CASE4: void A::f() {}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-multiple-classes.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-multiple-classes.cpp
new file mode 100644
index 0000000..821d567
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-multiple-classes.cpp
@@ -0,0 +1,104 @@
+// RUN: mkdir -p %T/move-multiple-classes
+// RUN: cp %S/Inputs/multiple_class_test* %T/move-multiple-classes/
+// RUN: cd %T/move-multiple-classes
+// RUN: clang-move -names="c::EnclosingMove5::Nested" -new_cc=%T/move-multiple-classes/new_multiple_class_test.cpp -new_header=%T/move-multiple-classes/new_multiple_class_test.h -old_cc=%T/move-multiple-classes/multiple_class_test.cpp -old_header=../move-multiple-classes/multiple_class_test.h -dump_result %T/move-multiple-classes/multiple_class_test.cpp -- -std=c++11| FileCheck %s -check-prefix=CHECK-EMPTY
+// RUN: clang-move -names="a::Move1, b::Move2,c::Move3,c::Move4,c::EnclosingMove5" -new_cc=%T/move-multiple-classes/new_multiple_class_test.cpp -new_header=%T/move-multiple-classes/new_multiple_class_test.h -old_cc=%T/move-multiple-classes/multiple_class_test.cpp -old_header=../move-multiple-classes/multiple_class_test.h %T/move-multiple-classes/multiple_class_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/move-multiple-classes/new_multiple_class_test.cpp -check-prefix=CHECK-NEW-TEST-CPP %s
+// RUN: FileCheck -input-file=%T/move-multiple-classes/new_multiple_class_test.h -check-prefix=CHECK-NEW-TEST-H %s
+// RUN: FileCheck -input-file=%T/move-multiple-classes/multiple_class_test.cpp -check-prefix=CHECK-OLD-TEST-CPP %s
+// RUN: FileCheck -input-file=%T/move-multiple-classes/multiple_class_test.h -check-prefix=CHECK-OLD-TEST-H %s
+//
+// CHECK-EMPTY: [{{[[:space:]]*}}]
+//
+// CHECK-OLD-TEST-H: namespace c {
+// CHECK-OLD-TEST-H: class NoMove {
+// CHECK-OLD-TEST-H: public:
+// CHECK-OLD-TEST-H: int f();
+// CHECK-OLD-TEST-H: };
+// CHECK-OLD-TEST-H: } // namespace c
+
+// CHECK-OLD-TEST-CPP: #include "{{.*}}multiple_class_test.h"
+// CHECK-OLD-TEST-CPP: using a::Move1;
+// CHECK-OLD-TEST-CPP: using namespace a;
+// CHECK-OLD-TEST-CPP: using A = a::Move1;
+// CHECK-OLD-TEST-CPP: static int g = 0;
+// CHECK-OLD-TEST-CPP: namespace {
+// CHECK-OLD-TEST-CPP: using a::Move1;
+// CHECK-OLD-TEST-CPP: using namespace a;
+// CHECK-OLD-TEST-CPP: } // namespace
+// CHECK-OLD-TEST-CPP: namespace b {
+// CHECK-OLD-TEST-CPP: using a::Move1;
+// CHECK-OLD-TEST-CPP: using namespace a;
+// CHECK-OLD-TEST-CPP: using T = a::Move1;
+// CHECK-OLD-TEST-CPP: } // namespace b
+// CHECK-OLD-TEST-CPP: namespace c {
+// CHECK-OLD-TEST-CPP: int NoMove::f() {
+// CHECK-OLD-TEST-CPP: static int F = 0;
+// CHECK-OLD-TEST-CPP: return g;
+// CHECK-OLD-TEST-CPP: }
+// CHECK-OLD-TEST-CPP: } // namespace c
+
+// CHECK-NEW-TEST-H: #ifndef {{.*}}NEW_MULTIPLE_CLASS_TEST_H
+// CHECK-NEW-TEST-H: #define {{.*}}NEW_MULTIPLE_CLASS_TEST_H
+// CHECK-NEW-TEST-H: namespace a {
+// CHECK-NEW-TEST-H: class Move1 {
+// CHECK-NEW-TEST-H: public:
+// CHECK-NEW-TEST-H: int f();
+// CHECK-NEW-TEST-H: };
+// CHECK-NEW-TEST-H: } // namespace a
+// CHECK-NEW-TEST-H: namespace b {
+// CHECK-NEW-TEST-H: class Move2 {
+// CHECK-NEW-TEST-H: public:
+// CHECK-NEW-TEST-H: int f();
+// CHECK-NEW-TEST-H: };
+// CHECK-NEW-TEST-H: } // namespace b
+// CHECK-NEW-TEST-H: namespace c {
+// CHECK-NEW-TEST-H: class Move3 {
+// CHECK-NEW-TEST-H: public:
+// CHECK-NEW-TEST-H: int f();
+// CHECK-NEW-TEST-H: };
+// CHECK-NEW-TEST-H: class Move4 {
+// CHECK-NEW-TEST-H: public:
+// CHECK-NEW-TEST-H: int f();
+// CHECK-NEW-TEST-H: };
+// CHECK-NEW-TEST-H: class EnclosingMove5 {
+// CHECK-NEW-TEST-H: public:
+// CHECK-NEW-TEST-H: class Nested {
+// CHECK-NEW-TEST-H: int f();
+// CHECK-NEW-TEST-H: static int b;
+// CHECK-NEW-TEST-H: };
+// CHECK-NEW-TEST-H: static int a;
+// CHECK-NEW-TEST-H: };
+// CHECK-NEW-TEST-H: } // namespace c
+// CHECK-NEW-TEST-H: #endif // {{.*}}NEW_MULTIPLE_CLASS_TEST_H
+
+// CHECK-NEW-TEST-CPP: #include "{{.*}}new_multiple_class_test.h"
+// CHECK-NEW-TEST-CPP: using a::Move1;
+// CHECK-NEW-TEST-CPP: using namespace a;
+// CHECK-NEW-TEST-CPP: using A = a::Move1;
+// CHECK-NEW-TEST-CPP: static int g = 0;
+// CHECK-NEW-TEST-CPP: namespace a {
+// CHECK-NEW-TEST-CPP: int Move1::f() { return 0; }
+// CHECK-NEW-TEST-CPP: } // namespace a
+// CHECK-NEW-TEST-CPP: namespace {
+// CHECK-NEW-TEST-CPP: using a::Move1;
+// CHECK-NEW-TEST-CPP: using namespace a;
+// CHECK-NEW-TEST-CPP: static int k = 0;
+// CHECK-NEW-TEST-CPP: } // namespace
+// CHECK-NEW-TEST-CPP: namespace b {
+// CHECK-NEW-TEST-CPP: using a::Move1;
+// CHECK-NEW-TEST-CPP: using namespace a;
+// CHECK-NEW-TEST-CPP: using T = a::Move1;
+// CHECK-NEW-TEST-CPP: int Move2::f() { return 0; }
+// CHECK-NEW-TEST-CPP: } // namespace b
+// CHECK-NEW-TEST-CPP: namespace c {
+// CHECK-NEW-TEST-CPP: int Move3::f() {
+// CHECK-NEW-TEST-CPP: using a::Move1;
+// CHECK-NEW-TEST-CPP: using namespace b;
+// CHECK-NEW-TEST-CPP: return 0;
+// CHECK-NEW-TEST-CPP: }
+// CHECK-NEW-TEST-CPP: int Move4::f() { return k; }
+// CHECK-NEW-TEST-CPP: int EnclosingMove5::a = 1;
+// CHECK-NEW-TEST-CPP: int EnclosingMove5::Nested::f() { return g; }
+// CHECK-NEW-TEST-CPP: int EnclosingMove5::Nested::b = 1;
+// CHECK-NEW-TEST-CPP: } // namespace c
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-template-class.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-template-class.cpp
new file mode 100644
index 0000000..1a6a60b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-template-class.cpp
@@ -0,0 +1,86 @@
+// RUN: mkdir -p %T/move-template-class
+// RUN: cp %S/Inputs/template_class_test* %T/move-template-class
+// RUN: cd %T/move-template-class
+// RUN: clang-move -names="A,B" -new_cc=%T/move-template-class/new_template_class_test.cpp -new_header=%T/move-template-class/new_template_class_test.h -old_cc=%T/move-template-class/template_class_test.cpp -old_header=../move-template-class/template_class_test.h %T/move-template-class/template_class_test.cpp --
+// RUN: FileCheck -input-file=%T/move-template-class/template_class_test.cpp -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s
+// RUN: FileCheck -input-file=%T/move-template-class/template_class_test.h -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s
+// RUN: FileCheck -input-file=%T/move-template-class/new_template_class_test.cpp -check-prefix=CHECK-NEW-TEST-CPP-CASE1 %s
+// RUN: FileCheck -input-file=%T/move-template-class/new_template_class_test.h -check-prefix=CHECK-NEW-TEST-H-CASE1 %s
+//
+// RUN: cp %S/Inputs/template_class_test* %T/move-template-class
+// RUN: clang-move -names="A" -new_cc=%T/move-template-class/new_template_class_test.cpp -new_header=%T/move-template-class/new_template_class_test.h -old_cc=%T/move-template-class/template_class_test.cpp -old_header=../move-template-class/template_class_test.h %T/move-template-class/template_class_test.cpp --
+// RUN: FileCheck -input-file=%T/move-template-class/template_class_test.h -check-prefix=CHECK-OLD-TEST-H-CASE2 %s
+// RUN: FileCheck -input-file=%T/move-template-class/template_class_test.cpp -check-prefix=CHECK-OLD-TEST-CPP-CASE2 %s
+// RUN: FileCheck -input-file=%T/move-template-class/new_template_class_test.h -check-prefix=CHECK-NEW-TEST-H-CASE2 %s
+// RUN: FileCheck -input-file=%T/move-template-class/new_template_class_test.cpp -check-prefix=CHECK-NEW-TEST-CPP-CASE2 %s
+//
+//
+// CHECK-OLD-TEST-EMPTY: {{^}}{{$}}
+//
+// CHECK-NEW-TEST-H-CASE1: #ifndef TEMPLATE_CLASS_TEST_H // comment 1
+// CHECK-NEW-TEST-H-CASE1: #define TEMPLATE_CLASS_TEST_H
+// CHECK-NEW-TEST-H-CASE1: template <typename T>
+// CHECK-NEW-TEST-H-CASE1: class A {
+// CHECK-NEW-TEST-H-CASE1: public:
+// CHECK-NEW-TEST-H-CASE1: void f();
+// CHECK-NEW-TEST-H-CASE1: void g();
+// CHECK-NEW-TEST-H-CASE1: template <typename U> void h();
+// CHECK-NEW-TEST-H-CASE1: template <typename U> void k();
+// CHECK-NEW-TEST-H-CASE1: static int b;
+// CHECK-NEW-TEST-H-CASE1: static int c;
+// CHECK-NEW-TEST-H-CASE1: };
+// CHECK-NEW-TEST-H-CASE1: template <typename T>
+// CHECK-NEW-TEST-H-CASE1: void A<T>::f() {}
+// CHECK-NEW-TEST-H-CASE1: template <typename T>
+// CHECK-NEW-TEST-H-CASE1: template <typename U>
+// CHECK-NEW-TEST-H-CASE1: void A<T>::h() {}
+// CHECK-NEW-TEST-H-CASE1: template <typename T>
+// CHECK-NEW-TEST-H-CASE1: int A<T>::b = 2;
+// CHECK-NEW-TEST-H-CASE1: class B {
+// CHECK-NEW-TEST-H-CASE1: public:
+// CHECK-NEW-TEST-H-CASE1: void f();
+// CHECK-NEW-TEST-H-CASE1: };
+// CHECK-NEW-TEST-H-CASE1: #endif // TEMPLATE_CLASS_TEST_H
+//
+// CHECK-NEW-TEST-CPP-CASE1: #include "{{.*}}new_template_class_test.h"
+// CHECK-NEW-TEST-CPP-CASE1: template <typename T>
+// CHECK-NEW-TEST-CPP-CASE1: void A<T>::g() {}
+// CHECK-NEW-TEST-CPP-CASE1: template <typename T>
+// CHECK-NEW-TEST-CPP-CASE1: template <typename U>
+// CHECK-NEW-TEST-CPP-CASE1: void A<T>::k() {}
+// CHECK-NEW-TEST-CPP-CASE1: template <typename T>
+// CHECK-NEW-TEST-CPP-CASE1: int A<T>::c = 2;
+// CHECK-NEW-TEST-CPP-CASE1: void B::f() {}
+//
+// CHECK-OLD-TEST-H-CASE2: #ifndef TEMPLATE_CLASS_TEST_H // comment 1
+// CHECK-OLD-TEST-H-CASE2: #define TEMPLATE_CLASS_TEST_H
+// CHECK-OLD-TEST-H-CASE2: class B {
+// CHECK-OLD-TEST-H-CASE2: public:
+// CHECK-OLD-TEST-H-CASE2: void f();
+// CHECK-OLD-TEST-H-CASE2: };
+// CHECK-OLD-TEST-H-CASE2: #endif // TEMPLATE_CLASS_TEST_H
+//
+// CHECK-OLD-TEST-CPP-CASE2: #include "template_class_test.h"
+// CHECK-OLD-TEST-CPP-CASE2: void B::f() {}
+//
+// CHECK-NEW-TEST-H-CASE2: #ifndef {{.*}}NEW_TEMPLATE_CLASS_TEST_H
+// CHECK-NEW-TEST-H-CASE2: #define {{.*}}NEW_TEMPLATE_CLASS_TEST_H
+// CHECK-NEW-TEST-H-CASE2: template <typename T>
+// CHECK-NEW-TEST-H-CASE2: class A {
+// CHECK-NEW-TEST-H-CASE2: public:
+// CHECK-NEW-TEST-H-CASE2: void f();
+// CHECK-NEW-TEST-H-CASE2: void g();
+// CHECK-NEW-TEST-H-CASE2: template <typename U> void h();
+// CHECK-NEW-TEST-H-CASE2: template <typename U> void k();
+// CHECK-NEW-TEST-H-CASE2: static int b;
+// CHECK-NEW-TEST-H-CASE2: static int c;
+// CHECK-NEW-TEST-H-CASE2: };
+// CHECK-NEW-TEST-H-CASE2: template <typename T> void A<T>::f() {}
+// CHECK-NEW-TEST-H-CASE2: template <typename T> template <typename U> void A<T>::h() {}
+// CHECK-NEW-TEST-H-CASE2: template <typename T> int A<T>::b = 2;
+// CHECK-NEW-TEST-H-CASE2: #endif // {{.*}}NEW_TEMPLATE_CLASS_TEST_H
+//
+// CHECK-NEW-TEST-CPP-CASE2: #include "{{.*}}new_template_class_test.h"
+// CHECK-NEW-TEST-CPP-CASE2: template <typename T> void A<T>::g() {}
+// CHECK-NEW-TEST-CPP-CASE2: template <typename T> template <typename U> void A<T>::k() {}
+// CHECK-NEW-TEST-CPP-CASE2: template <typename T> int A<T>::c = 2;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-type-alias.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-type-alias.cpp
new file mode 100644
index 0000000..ab70237
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-type-alias.cpp
@@ -0,0 +1,52 @@
+// RUN: mkdir -p %T/move-type-alias
+// RUN: cp %S/Inputs/type_alias.h %T/move-type-alias/type_alias.h
+// RUN: echo '#include "type_alias.h"' > %T/move-type-alias/type_alias.cpp
+// RUN: cd %T/move-type-alias
+//
+// -----------------------------------------------------------------------------
+// Test moving typedef declarations.
+// -----------------------------------------------------------------------------
+// RUN: clang-move -names="Int1" -new_cc=%T/move-type-alias/new_test.cpp -new_header=%T/move-type-alias/new_test.h -old_cc=%T/move-type-alias/type_alias.cpp -old_header=%T/move-type-alias/type_alias.h %T/move-type-alias/type_alias.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/move-type-alias/new_test.h -check-prefix=CHECK-NEW-TEST-H-CASE1 %s
+// RUN: FileCheck -input-file=%T/move-type-alias/type_alias.h -check-prefix=CHECK-OLD-TEST-H-CASE1 %s
+
+// CHECK-NEW-TEST-H-CASE1: typedef int Int1;
+
+// CHECK-OLD-TEST-H-CASE1-NOT: typedef int Int1;
+
+
+// -----------------------------------------------------------------------------
+// Test moving type alias declarations.
+// -----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/type_alias.h %T/move-type-alias/type_alias.h
+// RUN: echo '#include "type_alias.h"' > %T/move-type-alias/type_alias.cpp
+// RUN: clang-move -names="Int2" -new_cc=%T/move-type-alias/new_test.cpp -new_header=%T/move-type-alias/new_test.h -old_cc=%T/move-type-alias/type_alias.cpp -old_header=%T/move-type-alias/type_alias.h %T/move-type-alias/type_alias.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/move-type-alias/new_test.h -check-prefix=CHECK-NEW-TEST-H-CASE2 %s
+// RUN: FileCheck -input-file=%T/move-type-alias/type_alias.h -check-prefix=CHECK-OLD-TEST-H-CASE2 %s
+
+// CHECK-NEW-TEST-H-CASE2: using Int2 = int;
+
+// CHECK-OLD-TEST-H-CASE2-NOT: using Int2 = int;
+
+
+// -----------------------------------------------------------------------------
+// Test moving template type alias declarations.
+// -----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/type_alias.h %T/move-type-alias/type_alias.h
+// RUN: echo '#include "type_alias.h"' > %T/move-type-alias/type_alias.cpp
+// RUN: clang-move -names="B" -new_cc=%T/move-type-alias/new_test.cpp -new_header=%T/move-type-alias/new_test.h -old_cc=%T/move-type-alias/type_alias.cpp -old_header=%T/move-type-alias/type_alias.h %T/move-type-alias/type_alias.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/move-type-alias/new_test.h -check-prefix=CHECK-OLD-TEST-H-CASE3 %s
+
+// CHECK-NEW-TEST-H-CASE3: template<class T> using B = A<T>;
+// CHECK-OLD-TEST-H-CASE3-NOT: template<class T> using B = A<T>;
+
+
+// -----------------------------------------------------------------------------
+// Test not moving class-insided typedef declarations.
+// -----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/type_alias.h %T/move-type-alias/type_alias.h
+// RUN: echo '#include "type_alias.h"' > %T/move-type-alias/type_alias.cpp
+// RUN: clang-move -names="C::Int3" -new_cc=%T/move-type-alias/new_test.cpp -new_header=%T/move-type-alias/new_test.h -old_cc=%T/move-type-alias/type_alias.cpp -old_header=%T/move-type-alias/type_alias.h %T/move-type-alias/type_alias.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/move-type-alias/new_test.h -allow-empty -check-prefix=CHECK-EMPTY %s
+
+// CHECK-EMPTY: {{^}}{{$}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-used-helper-decls.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-used-helper-decls.cpp
new file mode 100644
index 0000000..45bd4be
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-used-helper-decls.cpp
@@ -0,0 +1,438 @@
+// RUN: mkdir -p %T/used-helper-decls
+// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
+// RUN: cd %T/used-helper-decls
+
+// ----------------------------------------------------------------------------
+// Test moving used helper function and its transively used functions.
+// ----------------------------------------------------------------------------
+// RUN: clang-move -names="a::Class1" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS1-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS1-CPP %s
+
+// CHECK-NEW-CLASS1-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-CLASS1-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS1-CPP-NEXT: namespace {
+// CHECK-NEW-CLASS1-CPP-NEXT: void HelperFun1() {}
+// CHECK-NEW-CLASS1-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS1-CPP-NEXT: void HelperFun2() { HelperFun1(); }
+// CHECK-NEW-CLASS1-CPP-NEXT: } // namespace
+// CHECK-NEW-CLASS1-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS1-CPP-NEXT: namespace a {
+// CHECK-NEW-CLASS1-CPP-NEXT: void Class1::f() { HelperFun2(); }
+// CHECK-NEW-CLASS1-CPP-NEXT: } // namespace a
+//
+// CHECK-OLD-CLASS1-CPP: void HelperFun1() {}
+// CHECK-OLD-CLASS1-CPP-NOT: void HelperFun2() { HelperFun1(); }
+// CHECK-OLD-CLASS1-CPP-NOT: void Class1::f() { HelperFun2(); }
+// CHECK-OLD-CLASS1-CPP: void Class2::f() {
+// CHECK-OLD-CLASS1-CPP: HelperFun1();
+
+
+// ----------------------------------------------------------------------------
+// Test moving used helper function and its transively used static variables.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
+// RUN: clang-move -names="a::Class2" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS2-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS2-CPP %s
+
+// CHECK-NEW-CLASS2-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-CLASS2-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS2-CPP-NEXT: namespace {
+// CHECK-NEW-CLASS2-CPP-NEXT: void HelperFun1() {}
+// CHECK-NEW-CLASS2-CPP-NEXT: } // namespace
+// CHECK-NEW-CLASS2-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS2-CPP-NEXT: static const int K2 = 2;
+// CHECK-NEW-CLASS2-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS2-CPP-NEXT: static void HelperFun3() { K2; }
+// CHECK-NEW-CLASS2-CPP-NEXT: namespace a {
+// CHECK-NEW-CLASS2-CPP-NEXT: void Class2::f() {
+// CHECK-NEW-CLASS2-CPP-NEXT: HelperFun1();
+// CHECK-NEW-CLASS2-CPP-NEXT: HelperFun3();
+// CHECK-NEW-CLASS2-CPP-NEXT: }
+// CHECK-NEW-CLASS2-CPP-NEXT: } // namespace a
+
+// CHECK-OLD-CLASS2-CPP: void HelperFun1() {}
+// CHECK-OLD-CLASS2-CPP: void HelperFun2() { HelperFun1(); }
+// CHECK-OLD-CLASS2-CPP: const int K1 = 1;
+// CHECK-OLD-CLASS2-CPP: static const int K2 = 2;
+// CHECK-OLD-CLASS2-CPP-NOT: static void HelperFun3() { K2; }
+// CHECK-OLD-CLASS2-CPP-NOT: void Class2::f() {
+// CHECK-OLD-CLASS2-CPP-NOT: HelperFun1();
+// CHECK-OLD-CLASS2-CPP-NOT: HelperFun3();
+// CHECK-OLD-CLASS2-CPP: void Class5::f() {
+// CHECK-OLD-CLASS2-CPP-NEXT: int Result = K1 + K2 + K3;
+
+
+// ----------------------------------------------------------------------------
+// Test using a static member variable of a helper class.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
+// RUN: clang-move -names="a::Class3" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS3-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS3-CPP %s
+
+// CHECK-NEW-CLASS3-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-CLASS3-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS3-CPP-NEXT: namespace {
+// CHECK-NEW-CLASS3-CPP-NEXT: class HelperC1 {
+// CHECK-NEW-CLASS3-CPP-NEXT: public:
+// CHECK-NEW-CLASS3-CPP-NEXT: static int I;
+// CHECK-NEW-CLASS3-CPP-NEXT: };
+// CHECK-NEW-CLASS3-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS3-CPP-NEXT: int HelperC1::I = 0;
+// CHECK-NEW-CLASS3-CPP-NEXT: } // namespace
+// CHECK-NEW-CLASS3-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS3-CPP-NEXT: namespace a {
+// CHECK-NEW-CLASS3-CPP-NEXT: void Class3::f() { HelperC1::I; }
+// CHECK-NEW-CLASS3-CPP-NEXT: } // namespace a
+
+// CHECK-OLD-CLASS3-CPP: namespace {
+// CHECK-OLD-CLASS3-CPP-NOT: class HelperC1 {
+// CHECK-OLD-CLASS3-CPP-NOT: public:
+// CHECK-OLD-CLASS3-CPP-NOT: static int I;
+// CHECK-OLD-CLASS3-CPP-NOT: };
+// CHECK-OLD-CLASS3-CPP-NOT: int HelperC1::I = 0;
+// CHECK-OLD-CLASS3-CPP: class HelperC2 {};
+
+
+// ----------------------------------------------------------------------------
+// Test moving helper classes.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
+// RUN: clang-move -names="a::Class4" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS4-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS4-CPP %s
+
+// CHECK-NEW-CLASS4-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-CLASS4-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS4-CPP-NEXT: namespace {
+// CHECK-NEW-CLASS4-CPP-NEXT: class HelperC2 {};
+// CHECK-NEW-CLASS4-CPP-NEXT: } // namespace
+// CHECK-NEW-CLASS4-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS4-CPP-NEXT: namespace a {
+// CHECK-NEW-CLASS4-CPP-NEXT: void Class4::f() { HelperC2 c2; }
+// CHECK-NEW-CLASS4-CPP-NEXT: } // namespace a
+
+// CHECK-OLD-CLASS4-CPP-NOT: class HelperC2 {};
+
+
+// ----------------------------------------------------------------------------
+// Test moving helper variables and helper functions together.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
+// RUN: clang-move -names="a::Class5" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS5-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS5-CPP %s
+
+// CHECK-NEW-CLASS5-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-CLASS5-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS5-CPP-NEXT: namespace {
+// CHECK-NEW-CLASS5-CPP-NEXT: const int K1 = 1;
+// CHECK-NEW-CLASS5-CPP-NEXT: } // namespace
+// CHECK-NEW-CLASS5-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS5-CPP-NEXT: static const int K2 = 2;
+// CHECK-NEW-CLASS5-CPP-NEXT: namespace a {
+// CHECK-NEW-CLASS5-CPP-NEXT: static const int K3 = 3;
+// CHECK-NEW-CLASS5-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS5-CPP-NEXT: static void HelperFun4() {}
+// CHECK-NEW-CLASS5-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS5-CPP-NEXT: void Class5::f() {
+// CHECK-NEW-CLASS5-CPP-NEXT: int Result = K1 + K2 + K3;
+// CHECK-NEW-CLASS5-CPP-NEXT: HelperFun4();
+// CHECK-NEW-CLASS5-CPP-NEXT: }
+// CHECK-NEW-CLASS5-CPP-NEXT: } // namespace a
+
+// CHECK-OLD-CLASS5-CPP-NOT: const int K1 = 1;
+// CHECK-OLD-CLASS5-CPP: static const int K2 = 2;
+// CHECK-OLD-CLASS5-CPP: static void HelperFun3() { K2; }
+// CHECK-OLD-CLASS5-CPP: static const int K4 = HelperC3::I;
+// CHECK-OLD-CLASS5-CPP-NOT: void Class5::f() {
+
+
+// ----------------------------------------------------------------------------
+// Test moving helper variables and their transively used helper classes.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
+// RUN: clang-move -names="a::Class6" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS6-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS6-CPP %s
+
+// CHECK-NEW-CLASS6-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-CLASS6-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS6-CPP-NEXT: namespace {
+// CHECK-NEW-CLASS6-CPP-NEXT: class HelperC3 {
+// CHECK-NEW-CLASS6-CPP-NEXT: public:
+// CHECK-NEW-CLASS6-CPP-NEXT: static int I;
+// CHECK-NEW-CLASS6-CPP-NEXT: };
+// CHECK-NEW-CLASS6-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS6-CPP-NEXT: int HelperC3::I = 0;
+// CHECK-NEW-CLASS6-CPP-NEXT: } // namespace
+// CHECK-NEW-CLASS6-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS6-CPP-NEXT: namespace a {
+// CHECK-NEW-CLASS6-CPP-NEXT: static const int K4 = HelperC3::I;
+// CHECK-NEW-CLASS6-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS6-CPP-NEXT: int Class6::f() {
+// CHECK-NEW-CLASS6-CPP-NEXT: int R = K4;
+// CHECK-NEW-CLASS6-CPP-NEXT: return R;
+// CHECK-NEW-CLASS6-CPP-NEXT: }
+// CHECK-NEW-CLASS6-CPP-NEXT: } // namespace a
+
+// CHECK-OLD-CLASS6-CPP-NOT: class HelperC3 {
+// CHECK-OLD-CLASS6-CPP-NOT: int HelperC3::I = 0;
+// CHECK-OLD-CLASS6-CPP-NOT: static const int K4 = HelperC3::I;
+
+
+// ----------------------------------------------------------------------------
+// Test moving classes where its methods use helpers.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
+// RUN: clang-move -names="a::Class7" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS7-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS7-CPP %s
+
+// CHECK-NEW-CLASS7-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-CLASS7-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS7-CPP-NEXT: namespace a {
+// CHECK-NEW-CLASS7-CPP-NEXT: static const int K6 = 6;
+// CHECK-NEW-CLASS7-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS7-CPP-NEXT: static void HelperFun6() {}
+// CHECK-NEW-CLASS7-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS7-CPP-NEXT: int Class7::f() {
+// CHECK-NEW-CLASS7-CPP-NEXT: int R = K6;
+// CHECK-NEW-CLASS7-CPP-NEXT: return R;
+// CHECK-NEW-CLASS7-CPP-NEXT: }
+// CHECK-NEW-CLASS7-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS7-CPP-NEXT: int Class7::g() {
+// CHECK-NEW-CLASS7-CPP-NEXT: HelperFun6();
+// CHECK-NEW-CLASS7-CPP-NEXT: return 1;
+// CHECK-NEW-CLASS7-CPP-NEXT: }
+// CHECK-NEW-CLASS7-CPP-NEXT: } // namespace a
+//
+// CHECK-OLD-CLASS7-CPP-NOT: static const int K6 = 6;
+// CHECK-OLD-CLASS7-CPP-NOT: static void HelperFun6() {}
+// CHECK-OLD-CLASS7-CPP-NOT: int Class7::f() {
+// CHECK-OLD-CLASS7-CPP-NOT: int Class7::g() {
+
+
+// ----------------------------------------------------------------------------
+// Test moving helper function and its transively used helper variables.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
+// RUN: clang-move -names="a::Fun1" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-FUN1-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-FUN1-CPP %s
+
+// CHECK-NEW-FUN1-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-FUN1-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-FUN1-CPP-NEXT: namespace a {
+// CHECK-NEW-FUN1-CPP-NEXT: static const int K5 = 5;
+// CHECK-NEW-FUN1-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-FUN1-CPP-NEXT: static int HelperFun5() {
+// CHECK-NEW-FUN1-CPP-NEXT: int R = K5;
+// CHECK-NEW-FUN1-CPP-NEXT: return R;
+// CHECK-NEW-FUN1-CPP-NEXT: }
+// CHECK-NEW-FUN1-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-FUN1-CPP-NEXT: void Fun1() { HelperFun5(); }
+// CHECK-NEW-FUN1-CPP-NEXT: } // namespace a
+
+// CHECK-OLD-FUN1-CPP-NOT: static const int K5 = 5;
+// CHECK-OLD-FUN1-CPP-NOT: static int HelperFun5() {
+// CHECK-OLD-FUN1-CPP-NOT: void Fun1() { HelperFun5(); }
+
+
+// ----------------------------------------------------------------------------
+// Test no moving helpers when moving inline functions in header.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
+// RUN: clang-move -names="a::Fun2" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-FUN2-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.h -check-prefix=CHECK-NEW-FUN2-H %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.h -check-prefix=CHECK-OLD-FUN2-H %s
+
+// CHECK-NEW-FUN2-H: namespace a {
+// CHECK-NEW-FUN2-H-NEXT: inline void Fun2() {}
+// CHECK-NEW-FUN2-H-NEXT: } // namespace a
+
+// CHECK-NEW-FUN2-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-FUN2-CPP-SAME: {{[[:space:]]}}
+
+// CHECK-OLD-FUN2-H-NOT: inline void Fun2() {}
+
+// ----------------------------------------------------------------------------
+// Test moving used helper function and its transively used functions.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
+// RUN: clang-move -names="b::Fun3" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-FUN3-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-FUN3-CPP %s
+
+// CHECK-NEW-FUN3-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-FUN3-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-FUN3-CPP-NEXT: namespace b {
+// CHECK-NEW-FUN3-CPP-NEXT: namespace {
+// CHECK-NEW-FUN3-CPP-NEXT: void HelperFun7();
+// CHECK-NEW-FUN3-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-FUN3-CPP-NEXT: class HelperC4;
+// CHECK-NEW-FUN3-CPP-NEXT: } // namespace
+// CHECK-NEW-FUN3-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-FUN3-CPP-NEXT: void Fun3() {
+// CHECK-NEW-FUN3-CPP-NEXT: HelperFun7();
+// CHECK-NEW-FUN3-CPP-NEXT: HelperC4 *t;
+// CHECK-NEW-FUN3-CPP-NEXT: }
+// CHECK-NEW-FUN3-CPP-NEXT: namespace {
+// CHECK-NEW-FUN3-CPP-NEXT: void HelperFun7() {}
+// CHECK-NEW-FUN3-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-FUN3-CPP-NEXT: class HelperC4 {};
+// CHECK-NEW-FUN3-CPP-NEXT: } // namespace
+// CHECK-NEW-FUN3-CPP-NEXT: } // namespace b
+//
+// CHECK-OLD-FUN3-CPP-NOT: void HelperFun7();
+// CHECK-OLD-FUN3-CPP-NOT: void HelperFun7() {}
+// CHECK-OLD-FUN3-CPP-NOT: void Fun3() { HelperFun7(); }
+
+// ----------------------------------------------------------------------------
+// Test moving all symbols in headers.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test* %T/used-helper-decls/
+// RUN: clang-move -names="a::Class1, a::Class2, a::Class3, a::Class4, a::Class5, a::Class5, a::Class6, a::Class7, a::Fun1, a::Fun2, b::Fun3" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.h -check-prefix=CHECK-NEW-H %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.h -allow-empty -check-prefix=CHECK-EMPTY %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -allow-empty -check-prefix=CHECK-EMPTY %s
+
+
+// CHECK-NEW-H: namespace a {
+// CHECK-NEW-H-NEXT: class Class1 {
+// CHECK-NEW-H-NEXT: void f();
+// CHECK-NEW-H-NEXT: };
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: class Class2 {
+// CHECK-NEW-H-NEXT: void f();
+// CHECK-NEW-H-NEXT: };
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: class Class3 {
+// CHECK-NEW-H-NEXT: void f();
+// CHECK-NEW-H-NEXT: };
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: class Class4 {
+// CHECK-NEW-H-NEXT: void f();
+// CHECK-NEW-H-NEXT: };
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: class Class5 {
+// CHECK-NEW-H-NEXT: void f();
+// CHECK-NEW-H-NEXT: };
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: class Class6 {
+// CHECK-NEW-H-NEXT: int f();
+// CHECK-NEW-H-NEXT: };
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: class Class7 {
+// CHECK-NEW-H-NEXT: int f();
+// CHECK-NEW-H-NEXT: int g();
+// CHECK-NEW-H-NEXT: };
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: void Fun1();
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: inline void Fun2() {}
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: } // namespace a
+
+
+// CHECK-NEW-CPP: namespace {
+// CHECK-NEW-CPP-NEXT: class HelperC1 {
+// CHECK-NEW-CPP-NEXT: public:
+// CHECK-NEW-CPP-NEXT: static int I;
+// CHECK-NEW-CPP-NEXT: };
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: int HelperC1::I = 0;
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: class HelperC2 {};
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: class HelperC3 {
+// CHECK-NEW-CPP-NEXT: public:
+// CHECK-NEW-CPP-NEXT: static int I;
+// CHECK-NEW-CPP-NEXT: };
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: int HelperC3::I = 0;
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void HelperFun1() {}
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void HelperFun2() { HelperFun1(); }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: const int K1 = 1;
+// CHECK-NEW-CPP-NEXT: } // namespace
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: static const int K2 = 2;
+// CHECK-NEW-CPP-NEXT: static void HelperFun3() { K2; }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: namespace a {
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: static const int K3 = 3;
+// CHECK-NEW-CPP-NEXT: static const int K4 = HelperC3::I;
+// CHECK-NEW-CPP-NEXT: static const int K5 = 5;
+// CHECK-NEW-CPP-NEXT: static const int K6 = 6;
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: static void HelperFun4() {}
+// CHECK-NEW-CPP-NEXT: static void HelperFun6() {}
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void Class1::f() { HelperFun2(); }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void Class2::f() {
+// CHECK-NEW-CPP-NEXT: HelperFun1();
+// CHECK-NEW-CPP-NEXT: HelperFun3();
+// CHECK-NEW-CPP-NEXT: }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void Class3::f() { HelperC1::I; }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void Class4::f() { HelperC2 c2; }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void Class5::f() {
+// CHECK-NEW-CPP-NEXT: int Result = K1 + K2 + K3;
+// CHECK-NEW-CPP-NEXT: HelperFun4();
+// CHECK-NEW-CPP-NEXT: }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: int Class6::f() {
+// CHECK-NEW-CPP-NEXT: int R = K4;
+// CHECK-NEW-CPP-NEXT: return R;
+// CHECK-NEW-CPP-NEXT: }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: int Class7::f() {
+// CHECK-NEW-CPP-NEXT: int R = K6;
+// CHECK-NEW-CPP-NEXT: return R;
+// CHECK-NEW-CPP-NEXT: }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: int Class7::g() {
+// CHECK-NEW-CPP-NEXT: HelperFun6();
+// CHECK-NEW-CPP-NEXT: return 1;
+// CHECK-NEW-CPP-NEXT: }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: static int HelperFun5() {
+// CHECK-NEW-CPP-NEXT: int R = K5;
+// CHECK-NEW-CPP-NEXT: return R;
+// CHECK-NEW-CPP-NEXT: }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void Fun1() { HelperFun5(); }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: } // namespace a
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: namespace b {
+// CHECK-NEW-CPP-NEXT: namespace {
+// CHECK-NEW-CPP-NEXT: void HelperFun7();
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: class HelperC4;
+// CHECK-NEW-CPP-NEXT: } // namespace
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void Fun3() {
+// CHECK-NEW-CPP-NEXT: HelperFun7();
+// CHECK-NEW-CPP-NEXT: HelperC4 *t;
+// CHECK-NEW-CPP-NEXT: }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: namespace {
+// CHECK-NEW-CPP-NEXT: void HelperFun7() {}
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: class HelperC4 {};
+// CHECK-NEW-CPP-NEXT: } // namespace
+// CHECK-NEW-CPP-NEXT: } // namespace b
+
+// CHECK-EMPTY: {{^}}{{$}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-var.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-var.cpp
new file mode 100644
index 0000000..4a3554c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/move-var.cpp
@@ -0,0 +1,46 @@
+// RUN: mkdir -p %T/move-var
+// RUN: cp %S/Inputs/var_test* %T/move-var
+// RUN: cd %T/move-var
+// RUN: clang-move -names="a::kGlobalInt" -new_header=%T/move-var/new_var_test.h -old_header=../move-var/var_test.h -old_cc=../move-var/var_test.cpp -new_cc=%T/move-var/new_var_test.cpp %T/move-var/var_test.cpp --
+// RUN: FileCheck -input-file=%T/move-var/var_test.h -check-prefix=CHECK-OLD-VAR-H-CASE1 %s
+// RUN: FileCheck -input-file=%T/move-var/var_test.cpp -check-prefix=CHECK-OLD-VAR-CPP-CASE1 %s
+// RUN: FileCheck -input-file=%T/move-var/new_var_test.h -check-prefix=CHECK-NEW-VAR-H-CASE1 %s
+// RUN: FileCheck -input-file=%T/move-var/new_var_test.cpp -check-prefix=CHECK-NEW-VAR-CPP-CASE1 %s
+
+// CHECK-OLD-VAR-H-CASE1-NOT: extern int kGlobalInt;
+// CHECK-OLD-VAR-H-CASE1: int kGlobalInt = 3;
+
+// CHECK-OLD-VAR-CPP-CASE1-NOT: int kGlobalInt = 1;
+
+// CHECK-NEW-VAR-H-CASE1: extern int kGlobalInt;
+// CHECK-NEW-VAR-H-CASE1-NOT: int kGlobalInt = 3;
+
+// CHECK-NEW-VAR-CPP-CASE1: int kGlobalInt = 1;
+
+
+// RUN: cp %S/Inputs/var_test* %T/move-var
+// RUN: clang-move -names="a::kGlobalStr" -new_header=%T/move-var/new_var_test.h -old_header=../move-var/var_test.h -old_cc=../move-var/var_test.cpp -new_cc=%T/move-var/new_var_test.cpp %T/move-var/var_test.cpp --
+// RUN: FileCheck -input-file=%T/move-var/var_test.h -check-prefix=CHECK-OLD-VAR-H-CASE2 %s
+// RUN: FileCheck -input-file=%T/move-var/var_test.cpp -check-prefix=CHECK-OLD-VAR-CPP-CASE2 %s
+// RUN: FileCheck -input-file=%T/move-var/new_var_test.h -check-prefix=CHECK-NEW-VAR-H-CASE2 %s
+// RUN: FileCheck -input-file=%T/move-var/new_var_test.cpp -check-prefix=CHECK-NEW-VAR-CPP-CASE2 %s
+
+// CHECK-OLD-VAR-H-CASE2-NOT: extern const char *const kGlobalStr;
+// CHECK-OLD-VAR-H-CASE2: const char *const kGlobalStr = "Hello2";
+
+// CHECK-OLD-VAR-CPP-CASE2-NOT: const char *const kGlobalStr = "Hello";
+
+// CHECK-NEW-VAR-H-CASE2: extern const char *const kGlobalStr;
+// CHECK-NEW-VAR-H-CASE2-NOT: const char *const kGlobalStr = "Hello2";
+
+// CHECK-NEW-VAR-CPP-CASE2: const char *const kGlobalStr = "Hello";
+
+
+// RUN: cp %S/Inputs/var_test* %T/move-var
+// RUN: clang-move -names="kEvilInt" -new_header=%T/move-var/new_var_test.h -old_header=../move-var/var_test.h -old_cc=../move-var/var_test.cpp -new_cc=%T/move-var/new_var_test.cpp %T/move-var/var_test.cpp --
+// RUN: FileCheck -input-file=%T/move-var/var_test.h -check-prefix=CHECK-OLD-VAR-H-CASE3 %s
+// RUN: FileCheck -input-file=%T/move-var/new_var_test.h -check-prefix=CHECK-NEW-VAR-H-CASE3 %s
+
+// CHECK-OLD-VAR-H-CASE3-NOT: int kEvilInt = 2;
+
+// CHECK-NEW-VAR-H-CASE3: int kEvilInt = 2;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-move/no-move-macro-helpers.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/no-move-macro-helpers.cpp
new file mode 100644
index 0000000..282eee0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-move/no-move-macro-helpers.cpp
@@ -0,0 +1,43 @@
+// RUN: mkdir -p %T/no-move-macro-helper
+// RUN: cat %S/Inputs/macro_helper_test.h > %T/no-move-macro-helper/macro_helper_test.h
+// RUN: cat %S/Inputs/macro_helper_test.cpp > %T/no-move-macro-helper/macro_helper_test.cpp
+// RUN: cd %T/no-move-macro-helper
+//
+// -----------------------------------------------------------------------------
+// Test no moving helpers in macro.
+// -----------------------------------------------------------------------------
+// RUN: clang-move -names="A" -new_cc=%T/no-move-macro-helper/new_test.cpp -new_header=%T/no-move-macro-helper/new_test.h -old_cc=%T/no-move-macro-helper/macro_helper_test.cpp -old_header=%T/no-move-macro-helper/macro_helper_test.h %T/no-move-macro-helper/macro_helper_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/no-move-macro-helper/new_test.h -check-prefix=CHECK-NEW-TEST-CASE1-H %s
+// RUN: FileCheck -input-file=%T/no-move-macro-helper/new_test.cpp -check-prefix=CHECK-NEW-TEST-CASE1-CPP %s
+// RUN: FileCheck -input-file=%T/no-move-macro-helper/macro_helper_test.h -check-prefix=CHECK-OLD-TEST-CASE1-H %s
+// RUN: FileCheck -input-file=%T/no-move-macro-helper/macro_helper_test.cpp -check-prefix=CHECK-OLD-TEST-CASE1-CPP %s
+
+// CHECK-NEW-TEST-CASE1-H: class A {};
+
+// CHECK-OLD-TEST-CASE1-H-NOT: class A {};
+
+// CHECK-OLD-TEST-CASE1-CPP: DEFINE(test)
+
+// CHECK-NEW-TEST-CASE1-CPP-NOT: DEFINE(test)
+
+
+// -----------------------------------------------------------------------------
+// Test moving all.
+// -----------------------------------------------------------------------------
+// RUN: cat %S/Inputs/macro_helper_test.h > %T/no-move-macro-helper/macro_helper_test.h
+// RUN: cat %S/Inputs/macro_helper_test.cpp > %T/no-move-macro-helper/macro_helper_test.cpp
+// RUN: clang-move -names="A, f1" -new_cc=%T/no-move-macro-helper/new_test.cpp -new_header=%T/no-move-macro-helper/new_test.h -old_cc=%T/no-move-macro-helper/macro_helper_test.cpp -old_header=%T/no-move-macro-helper/macro_helper_test.h %T/no-move-macro-helper/macro_helper_test.cpp -- -std=c++11
+//
+// RUN: FileCheck -input-file=%T/no-move-macro-helper/new_test.h -check-prefix=CHECK-NEW-TEST-CASE2-H %s
+// RUN: FileCheck -input-file=%T/no-move-macro-helper/new_test.cpp -check-prefix=CHECK-NEW-TEST-CASE2-CPP %s
+// RUN: FileCheck -input-file=%T/no-move-macro-helper/macro_helper_test.h -allow-empty -check-prefix=CHECK-EMPTY %s
+// RUN: FileCheck -input-file=%T/no-move-macro-helper/macro_helper_test.cpp -allow-empty -check-prefix=CHECK-EMPTY %s
+
+// CHECK-NEW-TEST-CASE2-H: class A {};
+// CHECK-NEW-TEST-CASE2-H-NEXT:void f1();
+
+
+// CHECK-NEW-TEST-CASE2-CPP: DEFINE(test)
+// CHECK-NEW-TEST-CASE2-CPP: void f1() {}
+
+// CHECK-EMPTY: {{^}}{{$}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-query/Inputs/foo.script b/src/third_party/llvm-project/clang-tools-extra/test/clang-query/Inputs/foo.script
new file mode 100644
index 0000000..3bd1f0e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-query/Inputs/foo.script
@@ -0,0 +1,2 @@
+foo
+bar
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-query/errors.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-query/errors.c
new file mode 100644
index 0000000..bbb7421
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-query/errors.c
@@ -0,0 +1,10 @@
+// RUN: not clang-query -c foo -c bar %s -- | FileCheck %s
+// RUN: not clang-query -f %S/Inputs/foo.script %s -- | FileCheck %s
+// RUN: not clang-query -f %S/Inputs/nonexistent.script %s -- 2>&1 | FileCheck --check-prefix=CHECK-NONEXISTENT %s
+// RUN: not clang-query -c foo -f foo %s -- 2>&1 | FileCheck --check-prefix=CHECK-BOTH %s
+
+// CHECK: unknown command: foo
+// CHECK-NOT: unknown command: bar
+
+// CHECK-NONEXISTENT: cannot open {{.*}}nonexistent.script
+// CHECK-BOTH: cannot specify both -c and -f
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-query/function-decl.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-query/function-decl.c
new file mode 100644
index 0000000..f35cba0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-query/function-decl.c
@@ -0,0 +1,4 @@
+// RUN: clang-query -c "match functionDecl()" %s -- | FileCheck %s
+
+// CHECK: function-decl.c:4:1: note: "root" binds here
+void foo(void) {}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.cpp
new file mode 100644
index 0000000..9d09c81
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.cpp
@@ -0,0 +1,14 @@
+// RUN: clang-reorder-fields -record-name Foo -fields-order z,y,x %s -- | FileCheck %s
+
+// The order of fields should not change.
+class Foo {
+public:
+ int x; // CHECK: {{^ int x;}}
+ int y; // CHECK-NEXT: {{^ int y;}}
+ int z; // CHECK-NEXT: {{^ int z;}}
+};
+
+int main() {
+ Foo foo = { 0, 1 }; // CHECK: {{^ Foo foo = { 0, 1 };}}
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/CStructAmbiguousName.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/CStructAmbiguousName.cpp
new file mode 100644
index 0000000..e1e6645
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/CStructAmbiguousName.cpp
@@ -0,0 +1,18 @@
+// RUN: clang-reorder-fields -record-name ::Foo -fields-order y,x %s -- | FileCheck %s
+
+struct Foo {
+ int x; // CHECK: {{^ double y;}}
+ double y; // CHECK-NEXT: {{^ int x;}}
+};
+
+namespace bar {
+struct Foo {
+ int x; // CHECK: {{^ int x;}}
+ double y; // CHECK-NEXT: {{^ double y;}}
+};
+} // end namespace bar
+
+int main() {
+ bar::Foo foo = { 1, 1.7 }; // CHECK: {{^ bar::Foo foo = { 1, 1.7 };}}
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/CStructFieldsOrder.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/CStructFieldsOrder.cpp
new file mode 100644
index 0000000..2ed3578
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/CStructFieldsOrder.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-reorder-fields -record-name ::bar::Foo -fields-order z,w,y,x %s -- | FileCheck %s
+
+namespace bar {
+struct Foo {
+ const int* x; // CHECK: {{^ double z;}}
+ int y; // CHECK-NEXT: {{^ int w;}}
+ double z; // CHECK-NEXT: {{^ int y;}}
+ int w; // CHECK-NEXT: {{^ const int\* x}}
+};
+} // end namespace bar
+
+int main() {
+ const int x = 13;
+ bar::Foo foo = { &x, 0, 1.29, 17 }; // CHECK: {{^ bar::Foo foo = { 1.29, 17, 0, &x };}}
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/ClassDerived.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/ClassDerived.cpp
new file mode 100644
index 0000000..e7e9ac1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/ClassDerived.cpp
@@ -0,0 +1,33 @@
+// RUN: clang-reorder-fields -record-name bar::Derived -fields-order z,y %s -- | FileCheck %s
+
+namespace bar {
+class Base {
+public:
+ Base(int nx, int np) : x(nx), p(np) {}
+ int x;
+ int p;
+};
+
+
+class Derived : public Base {
+public:
+ Derived(long ny);
+ Derived(char nz);
+private:
+ long y;
+ char z;
+};
+
+Derived::Derived(long ny) :
+ Base(ny, 0),
+ y(ny), // CHECK: {{^ z\(static_cast<char>\(ny\)\),}}
+ z(static_cast<char>(ny)) // CHECK-NEXT: {{^ y\(ny\)}}
+{}
+
+Derived::Derived(char nz) :
+ Base(1, 2),
+ y(nz), // CHECK: {{^ z\(x\),}}
+ z(x) // CHECK-NEXT: {{^ y\(nz\)}}
+{}
+
+} // namespace bar
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/ClassDifferentFieldsAccesses.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/ClassDifferentFieldsAccesses.cpp
new file mode 100644
index 0000000..dd0a555
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/ClassDifferentFieldsAccesses.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-reorder-fields -record-name Foo -fields-order z,y,x %s -- | FileCheck %s
+
+// The order of fields should not change.
+class Foo {
+public:
+ int x; // CHECK: {{^ int x;}}
+
+private:
+ int y; // CHECK: {{^ int y;}}
+ int z; // CHECK-NEXT: {{^ int z;}}
+};
+
+int main() {
+ Foo foo;
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/ClassMixedInitialization.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/ClassMixedInitialization.cpp
new file mode 100644
index 0000000..888649a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/ClassMixedInitialization.cpp
@@ -0,0 +1,24 @@
+// RUN: clang-reorder-fields -record-name Foo -fields-order e,x,pi,s2,s1 %s -- -std=c++11 | FileCheck %s
+
+class Foo {
+public:
+ Foo();
+
+private:
+ int x; // CHECK: {{^ double e = 2.71;}}
+ const char *s1; // CHECK-NEXT: {{^ int x;}}
+ const char *s2; // CHECK-NEXT: {{^ double pi = 3.14;}}
+ double pi = 3.14; // CHECK-NEXT: {{^ const char \*s2;}}
+ double e = 2.71; // CHECK-NEXT: {{^ const char \*s1;}}
+};
+
+Foo::Foo():
+ x(12), // CHECK: {{^ x\(12\)}},
+ s1("abc"), // CHECK-NEXT: {{^ s2\("def"\)}},
+ s2("def") // CHECK-NEXT: {{^ s1\("abc"\)}}
+{}
+
+int main() {
+ Foo foo;
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/ClassSimpleCtor.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/ClassSimpleCtor.cpp
new file mode 100644
index 0000000..6dc2722
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/ClassSimpleCtor.cpp
@@ -0,0 +1,24 @@
+// RUN: clang-reorder-fields -record-name Foo -fields-order s1,x,z,s2 %s -- | FileCheck %s
+
+class Foo {
+public:
+ Foo();
+
+private:
+ int x; // CHECK: {{^ const char \*s1;}}
+ const char *s1; // CHECK-NEXT: {{^ int x;}}
+ const char *s2; // CHECK-NEXT: {{^ double z;}}
+ double z; // CHECK-NEXT: {{^ const char \*s2;}}
+};
+
+Foo::Foo():
+ x(12), // CHECK: {{^ s1\("abc"\),}}
+ s1("abc"), // CHECK-NEXT: {{^ x\(12\),}}
+ s2("def"), // CHECK-NEXT: {{^ z\(3.14\),}}
+ z(3.14) // CHECK-NEXT: {{^ s2\("def"\)}}
+{}
+
+int main() {
+ Foo foo;
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/FieldDependencyWarning.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/FieldDependencyWarning.cpp
new file mode 100644
index 0000000..bbe0e7f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/FieldDependencyWarning.cpp
@@ -0,0 +1,54 @@
+// RUN: clang-reorder-fields -record-name bar::Foo -fields-order y,z,c,x %s -- 2>&1 | FileCheck --check-prefix=CHECK-MESSAGES %s
+// FIXME: clang-reorder-fields should provide -verify mode to make writing these checks
+// easier and more accurate, for now we follow clang-tidy's approach.
+
+namespace bar {
+
+struct Dummy {
+ Dummy(int x, char c) : x(x), c(c) {}
+ int x;
+ char c;
+};
+
+class Foo {
+public:
+ Foo(int x, double y, char cin);
+ Foo(int nx);
+ Foo();
+ int x;
+ double y;
+ char c;
+ Dummy z;
+};
+
+static char bar(char c) {
+ return c + 1;
+}
+
+Foo::Foo() : x(), y(), c(), z(0, 'a') {}
+
+Foo::Foo(int x, double y, char cin) :
+ x(x),
+ y(y),
+ c(cin),
+ z(this->x, bar(c))
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: reordering field x after z makes x uninitialized when used in init expression
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: reordering field c after z makes c uninitialized when used in init expression
+{}
+
+Foo::Foo(int nx) :
+ x(nx),
+ y(x),
+ c(0),
+ z(bar(bar(x)), c)
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: reordering field x after y makes x uninitialized when used in init expression
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: reordering field x after z makes x uninitialized when used in init expression
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: reordering field c after z makes c uninitialized when used in init expression
+{}
+
+} // namespace bar
+
+int main() {
+ bar::Foo F(5, 12.8, 'c');
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/FieldDependencyWarningDerived.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/FieldDependencyWarningDerived.cpp
new file mode 100644
index 0000000..bbc58ae
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/FieldDependencyWarningDerived.cpp
@@ -0,0 +1,36 @@
+// RUN: clang-reorder-fields -record-name bar::Derived -fields-order z,y %s -- 2>&1 | FileCheck --check-prefix=CHECK-MESSAGES %s
+// FIXME: clang-reorder-fields should provide -verify mode to make writing these checks
+// easier and more accurate, for now we follow clang-tidy's approach.
+
+namespace bar {
+struct Base {
+ int x;
+ int p;
+};
+
+class Derived : public Base {
+public:
+ Derived(long ny);
+ Derived(char nz);
+private:
+ long y;
+ char z;
+};
+
+Derived::Derived(long ny) :
+ Base(),
+ y(ny),
+ z(static_cast<char>(y))
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: reordering field y after z makes y uninitialized when used in init expression
+{}
+
+Derived::Derived(char nz) :
+ Base(),
+ y(nz),
+ // Check that base class fields are correctly ignored in reordering checks
+ // x has field index 1 and so would improperly warn if this wasn't the case since the command for this file swaps field indexes 1 and 2
+ z(x)
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: reordering field x after z makes x uninitialized when used in init expression
+{}
+
+} // namespace bar
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/PlainCStructFieldsOrder.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/PlainCStructFieldsOrder.c
new file mode 100644
index 0000000..5b4fe9e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-reorder-fields/PlainCStructFieldsOrder.c
@@ -0,0 +1,14 @@
+// RUN: clang-reorder-fields -record-name Foo -fields-order z,w,y,x %s -- | FileCheck %s
+
+struct Foo {
+ const int* x; // CHECK: {{^ double z;}}
+ int y; // CHECK-NEXT: {{^ int w;}}
+ double z; // CHECK-NEXT: {{^ int y;}}
+ int w; // CHECK-NEXT: {{^ const int\* x}}
+};
+
+int main() {
+ const int x = 13;
+ struct Foo foo = { &x, 0, 1.29, 17 }; // CHECK: {{^ struct Foo foo = { 1.29, 17, 0, &x };}}
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/a.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/a.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/a.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/b.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/b.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/b.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/clang-c/c.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/clang-c/c.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/clang-c/c.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/clang/b.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/clang/b.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/clang/b.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/cross-file-a.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/cross-file-a.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/cross-file-a.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/cross-file-b.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/cross-file-b.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/cross-file-b.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/cross-file-c.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/cross-file-c.h
new file mode 100644
index 0000000..342dd34
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/cross-file-c.h
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// The line number of the following include should match the location of the
+// corresponding comment in llvm-include-order.cpp
+#include "cross-file-b.h"
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/gtest/foo.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/gtest/foo.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/gtest/foo.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/i.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/i.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/i.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/j.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/j.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/j.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/llvm-c/d.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/llvm-c/d.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/llvm-c/d.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/llvm/a.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/llvm/a.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/llvm/a.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/s.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/s.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/s.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/system-header-simulation.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/system-header-simulation.h
new file mode 100644
index 0000000..0df5305
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/Headers/system-header-simulation.h
@@ -0,0 +1,24 @@
+#pragma clang system_header
+
+namespace std {
+
+template<class T, T v>
+struct integral_constant {
+ static constexpr T value = v;
+ typedef T value_type;
+ typedef integral_constant type;
+ constexpr operator value_type() const noexcept { return value; }
+};
+
+template <bool B>
+using bool_constant = integral_constant<bool, B>;
+using true_type = bool_constant<true>;
+using false_type = bool_constant<false>;
+
+template<class T>
+struct is_error_code_enum : false_type {};
+
+template<class T>
+void swap(T &a, T &b);
+}
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/compilation-database/template.json b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/compilation-database/template.json
new file mode 100644
index 0000000..74275d9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/compilation-database/template.json
@@ -0,0 +1,32 @@
+[
+{
+ "directory": "test_dir/a",
+ "command": "clang++ -o test.o test_dir/a/a.cpp",
+ "file": "test_dir/a/a.cpp"
+},
+{
+ "directory": "test_dir/a",
+ "command": "clang++ -o test.o test_dir/a/b.cpp",
+ "file": "test_dir/a/b.cpp"
+},
+{
+ "directory": "test_dir/",
+ "command": "clang++ -o test.o test_dir/b/b.cpp",
+ "file": "test_dir/b/b.cpp"
+},
+{
+ "directory": "test_dir/b",
+ "command": "clang++ -o test.o ../b/c.cpp",
+ "file": "test_dir/b/c.cpp"
+},
+{
+ "directory": "test_dir/b",
+ "command": "clang++ -I../include -o test.o ../b/d.cpp",
+ "file": "test_dir/b/d.cpp"
+},
+{
+ "directory": "test_dir/",
+ "command": "clang++ -o test.o test_dir/b/not-exist.cpp",
+ "file": "test_dir/b/not-exist.cpp"
+}
+]
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/config-files/.clang-tidy b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/config-files/.clang-tidy
new file mode 100644
index 0000000..942169f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/config-files/.clang-tidy
@@ -0,0 +1,2 @@
+Checks: 'from-parent'
+HeaderFilterRegex: 'parent'
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/config-files/1/.clang-tidy b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/config-files/1/.clang-tidy
new file mode 100644
index 0000000..800fd4e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/config-files/1/.clang-tidy
@@ -0,0 +1,2 @@
+Checks: 'from-child1'
+HeaderFilterRegex: 'child1'
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/explain-config/.clang-tidy b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/explain-config/.clang-tidy
new file mode 100644
index 0000000..4fbd09c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/explain-config/.clang-tidy
@@ -0,0 +1 @@
+Checks: '-*,modernize-use-nullptr'
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/file-filter/header1.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/file-filter/header1.h
new file mode 100644
index 0000000..ba9e3d1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/file-filter/header1.h
@@ -0,0 +1 @@
+class A1 { A1(int); };
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/file-filter/header2.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/file-filter/header2.h
new file mode 100644
index 0000000..09bfeab
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/file-filter/header2.h
@@ -0,0 +1 @@
+class A2 { A2(int); };
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/file-filter/system/system-header.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/file-filter/system/system-header.h
new file mode 100644
index 0000000..98482c4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/file-filter/system/system-header.h
@@ -0,0 +1 @@
+class A0 { A0(int); };
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/a.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/a.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/a.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/cstdarg.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/cstdarg.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/cstdarg.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/cstdlib.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/cstdlib.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/cstdlib.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/j.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/j.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/j.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/r.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/r.h
new file mode 100644
index 0000000..56757a7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/r.h
@@ -0,0 +1 @@
+void f() {}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/s.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/s.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/s.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/t.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/t.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/t.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/transitive.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/transitive.h
new file mode 100644
index 0000000..6dba769
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/system/transitive.h
@@ -0,0 +1,3 @@
+#include <r.h>
+#include <t.h>
+#include <s.h>
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/transitive2.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/transitive2.h
new file mode 100644
index 0000000..ea56788
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/fuchsia-restrict-system-includes/transitive2.h
@@ -0,0 +1,2 @@
+#include <s.h>
+#include <t.h>
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/google-namespaces.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/google-namespaces.h
new file mode 100644
index 0000000..f4d87f5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/google-namespaces.h
@@ -0,0 +1,7 @@
+namespace {
+int x;
+}
+
+namespace spaaaace {
+class core;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/line-filter/header1.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/line-filter/header1.h
new file mode 100644
index 0000000..35d59ce
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/line-filter/header1.h
@@ -0,0 +1,3 @@
+class A1 { A1(int); };
+class B1 { B1(int); };
+class C1 { C1(int); };
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/line-filter/header2.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/line-filter/header2.h
new file mode 100644
index 0000000..bb12598
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/line-filter/header2.h
@@ -0,0 +1,3 @@
+class A2 { A2(int); };
+class B2 { B2(int); };
+class C2 { C2(int); };
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/line-filter/header3.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/line-filter/header3.h
new file mode 100644
index 0000000..b5198ca
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/line-filter/header3.h
@@ -0,0 +1 @@
+class A3 { A3(int); };
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/assert.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/assert.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/assert.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/complex.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/complex.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/complex.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/ctype.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/ctype.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/ctype.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/errno.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/errno.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/errno.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/fenv.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/fenv.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/fenv.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/float.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/float.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/float.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/inttypes.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/inttypes.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/inttypes.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/iso646.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/iso646.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/iso646.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/limits.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/limits.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/limits.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/locale.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/locale.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/locale.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/math.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/math.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/math.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/setjmp.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/setjmp.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/setjmp.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/signal.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/signal.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/signal.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdalign.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdalign.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdalign.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdarg.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdarg.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdarg.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdbool.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdbool.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdbool.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stddef.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stddef.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stddef.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdint.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdint.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdint.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdio.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdio.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdio.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdlib.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdlib.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/stdlib.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/string.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/string.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/string.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/tgmath.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/tgmath.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/tgmath.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/time.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/time.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/time.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/uchar.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/uchar.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/uchar.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/wchar.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/wchar.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/wchar.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/wctype.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/wctype.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-deprecated-headers/wctype.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-loop-convert/structures.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-loop-convert/structures.h
new file mode 100644
index 0000000..02d440c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-loop-convert/structures.h
@@ -0,0 +1,206 @@
+#ifndef STRUCTURES_H
+#define STRUCTURES_H
+
+extern "C" {
+extern int printf(const char *restrict, ...);
+}
+
+struct Val {int X; void g(); };
+
+struct MutableVal {
+ void constFun(int) const;
+ void nonConstFun(int, int);
+ void constFun(MutableVal &) const;
+ void constParamFun(const MutableVal &) const;
+ void nonConstParamFun(const MutableVal &);
+ int X;
+};
+
+struct NonTriviallyCopyable {
+ NonTriviallyCopyable() = default;
+ // Define this constructor to make this class non-trivially copyable.
+ NonTriviallyCopyable(const NonTriviallyCopyable& Ntc);
+ int X;
+};
+
+struct TriviallyCopyableButBig {
+ int X;
+ char Array[16];
+};
+
+struct S {
+ typedef MutableVal *iterator;
+ typedef const MutableVal *const_iterator;
+ const_iterator begin() const;
+ const_iterator end() const;
+ const_iterator cbegin() const;
+ const_iterator cend() const;
+ iterator begin();
+ iterator end();
+};
+
+struct T {
+ struct iterator {
+ int& operator*();
+ const int& operator*()const;
+ iterator& operator ++();
+ bool operator!=(const iterator &other);
+ void insert(int);
+ int X;
+ };
+ iterator begin();
+ iterator end();
+};
+
+struct U {
+ struct iterator {
+ Val& operator*();
+ const Val& operator*()const;
+ iterator& operator ++();
+ bool operator!=(const iterator &other);
+ Val *operator->();
+ };
+ iterator begin();
+ iterator end();
+ int X;
+};
+
+struct X {
+ S Ss;
+ T Tt;
+ U Uu;
+ S getS();
+};
+
+template<typename ElemType>
+class dependent {
+ public:
+ dependent<ElemType>();
+ struct iterator_base {
+ const ElemType& operator*()const;
+ iterator_base& operator ++();
+ bool operator!=(const iterator_base &other) const;
+ const ElemType *operator->() const;
+ };
+
+ struct iterator : iterator_base {
+ ElemType& operator*();
+ iterator& operator ++();
+ ElemType *operator->();
+ };
+
+ typedef iterator_base const_iterator;
+ const_iterator begin() const;
+ const_iterator end() const;
+ iterator begin();
+ iterator end();
+ unsigned size() const;
+ ElemType & operator[](unsigned);
+ const ElemType & operator[](unsigned) const;
+ ElemType & at(unsigned);
+ ElemType & at(unsigned, unsigned);
+ const ElemType & at(unsigned) const;
+
+ // Intentionally evil.
+ dependent<ElemType> operator*();
+
+ void foo();
+ void constFoo() const;
+};
+
+template<typename First, typename Second>
+class doublyDependent{
+ public:
+ struct Value {
+ First first;
+ Second second;
+ };
+
+ struct iterator_base {
+ const Value& operator*()const;
+ iterator_base& operator ++();
+ bool operator!=(const iterator_base &other) const;
+ const Value *operator->() const;
+ };
+
+ struct iterator : iterator_base {
+ Value& operator*();
+ Value& operator ++();
+ Value *operator->();
+ };
+
+ typedef iterator_base const_iterator;
+ const_iterator begin() const;
+ const_iterator end() const;
+ iterator begin();
+ iterator end();
+};
+
+template<typename Contained>
+class transparent {
+ public:
+ Contained *at();
+ Contained *operator->();
+ Contained operator*();
+};
+
+template<typename IteratorType>
+struct Nested {
+ typedef IteratorType* iterator;
+ typedef const IteratorType* const_iterator;
+ IteratorType *operator->();
+ IteratorType operator*();
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+};
+
+// Like llvm::SmallPtrSet, the iterator has a dereference operator that returns
+// by value instead of by reference.
+template <typename T>
+struct PtrSet {
+ struct iterator {
+ bool operator!=(const iterator &other) const;
+ const T operator*();
+ iterator &operator++();
+ };
+ iterator begin() const;
+ iterator end() const;
+};
+
+template <typename T>
+struct TypedefDerefContainer {
+ struct iterator {
+ typedef T &deref_type;
+ bool operator!=(const iterator &other) const;
+ deref_type operator*();
+ iterator &operator++();
+ };
+ iterator begin() const;
+ iterator end() const;
+};
+
+template <typename T>
+struct RValueDerefContainer {
+ struct iterator {
+ typedef T &&deref_type;
+ bool operator!=(const iterator &other) const;
+ deref_type operator*();
+ iterator &operator++();
+ };
+ iterator begin() const;
+ iterator end() const;
+};
+
+namespace Macros {
+
+struct MacroStruct {
+ int Arr[10];
+};
+static MacroStruct *MacroSt;
+#define CONT MacroSt->
+
+} // namespace Macros
+
+#endif // STRUCTURES_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-pass-by-value/header-with-fix.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-pass-by-value/header-with-fix.h
new file mode 100644
index 0000000..62609e2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-pass-by-value/header-with-fix.h
@@ -0,0 +1,8 @@
+struct S {
+ S(S&&);
+ S(const S&);
+};
+struct Foo {
+ Foo(const S &s);
+ S s;
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-pass-by-value/header.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-pass-by-value/header.h
new file mode 100644
index 0000000..c2103cb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-pass-by-value/header.h
@@ -0,0 +1,10 @@
+class ThreadId {
+public:
+ ThreadId(const ThreadId &) {}
+ ThreadId(ThreadId &&) {}
+};
+
+struct A {
+ A(const ThreadId &tid) : threadid(tid) {}
+ ThreadId threadid;
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-replace-auto-ptr/memory.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-replace-auto-ptr/memory.h
new file mode 100644
index 0000000..bc476ce
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-replace-auto-ptr/memory.h
@@ -0,0 +1,45 @@
+#ifndef INPUTS_MEMORY_H
+#define INPUTS_MEMORY_H
+
+namespace std {
+
+inline namespace _1 {
+
+template <class Y> struct auto_ptr_ref {
+ Y *y_;
+};
+
+template <class X> class auto_ptr {
+public:
+ typedef X element_type;
+ explicit auto_ptr(X *p = 0) throw() {}
+ auto_ptr(auto_ptr &) throw() {}
+ template <class Y> auto_ptr(auto_ptr<Y> &) throw() {}
+ auto_ptr &operator=(auto_ptr &) throw() { return *this; }
+ template <class Y> auto_ptr &operator=(auto_ptr<Y> &) throw() {
+ return *this;
+ }
+ auto_ptr &operator=(auto_ptr_ref<X> r) throw() { return *this; }
+ ~auto_ptr() throw() {}
+ auto_ptr(auto_ptr_ref<X> r) throw() : x_(r.y_) {}
+ template <class Y> operator auto_ptr_ref<Y>() throw() {
+ auto_ptr_ref<Y> r;
+ r.y_ = x_;
+ return r;
+ }
+ template <class Y> operator auto_ptr<Y>() throw() { return auto_ptr<Y>(x_); }
+
+private:
+ X *x_;
+};
+
+template <> class auto_ptr<void> {
+public:
+ typedef void element_type;
+};
+
+} // namespace _1
+
+} // end namespace std
+
+#endif // INPUTS_MEMORY_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-smart-ptr/initializer_list.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-smart-ptr/initializer_list.h
new file mode 100644
index 0000000..28592cf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-smart-ptr/initializer_list.h
@@ -0,0 +1,32 @@
+namespace std {
+typedef decltype(sizeof(int)) size_t;
+
+template <class _E> class initializer_list {
+ const _E *__begin_;
+ size_t __size_;
+
+ initializer_list(const _E *__b, size_t __s) : __begin_(__b), __size_(__s) {}
+
+public:
+ typedef _E value_type;
+ typedef const _E &reference;
+ typedef const _E &const_reference;
+ typedef size_t size_type;
+
+ typedef const _E *iterator;
+ typedef const _E *const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const { return __size_; }
+ const _E *begin() const { return __begin_; }
+ const _E *end() const { return __begin_ + __size_; }
+};
+
+template <class _E>
+class vector {
+ public:
+ vector(initializer_list<_E> init);
+ ~vector();
+};
+} // namespace std
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-smart-ptr/shared_ptr.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-smart-ptr/shared_ptr.h
new file mode 100644
index 0000000..0f4f2a9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-smart-ptr/shared_ptr.h
@@ -0,0 +1,24 @@
+namespace std {
+
+template <typename type>
+class shared_ptr {
+public:
+ shared_ptr();
+ shared_ptr(type *ptr);
+ shared_ptr(const shared_ptr<type> &t) {}
+ shared_ptr(shared_ptr<type> &&t) {}
+ ~shared_ptr();
+ type &operator*() { return *ptr; }
+ type *operator->() { return ptr; }
+ type *release();
+ void reset();
+ void reset(type *pt);
+ shared_ptr &operator=(shared_ptr &&);
+ template <typename T>
+ shared_ptr &operator=(shared_ptr<T> &&);
+
+private:
+ type *ptr;
+};
+
+} // namespace std
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-smart-ptr/unique_ptr.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-smart-ptr/unique_ptr.h
new file mode 100644
index 0000000..5dc9e02
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-smart-ptr/unique_ptr.h
@@ -0,0 +1,28 @@
+namespace std {
+
+template <typename T>
+class default_delete {};
+
+template <typename type, typename Deleter = std::default_delete<type>>
+class unique_ptr {
+public:
+ unique_ptr() {}
+ unique_ptr(type *ptr) {}
+ unique_ptr(const unique_ptr<type> &t) = delete;
+ unique_ptr(unique_ptr<type> &&t) {}
+ ~unique_ptr() {}
+ type &operator*() { return *ptr; }
+ type *operator->() { return ptr; }
+ type *release() { return ptr; }
+ void reset() {}
+ void reset(type *pt) {}
+ void reset(type pt) {}
+ unique_ptr &operator=(unique_ptr &&) { return *this; }
+ template <typename T>
+ unique_ptr &operator=(unique_ptr<T> &&) { return *this; }
+
+private:
+ type *ptr;
+};
+
+} // namespace std
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-use-auto/containers.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-use-auto/containers.h
new file mode 100644
index 0000000..c99b7a4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/modernize-use-auto/containers.h
@@ -0,0 +1,253 @@
+#ifndef CONTAINERS_H
+#define CONTAINERS_H
+
+namespace std {
+
+template <typename T>
+class iterator {
+public:
+ iterator() {}
+ iterator(const iterator<T> &iter) : ptr(iter.ptr) {}
+
+ typedef T value_type;
+ typedef T *pointer;
+ typedef T &reference;
+
+ reference operator*() const { return *ptr; }
+ pointer operator->() const { return ptr; }
+ iterator &operator++() {
+ ++ptr;
+ return *this;
+ }
+ iterator &operator--() {
+ --ptr;
+ return *this;
+ }
+ iterator operator++(int) {
+ iterator res(*this);
+ ++ptr;
+ return res;
+ }
+ iterator operator--(int) {
+ iterator res(*this);
+ --ptr;
+ return res;
+ }
+ bool operator!=(const iterator<T> &iter) const {
+ return ptr != iter.operator->();
+ }
+
+private:
+ T *ptr;
+};
+
+template <class Iterator>
+class const_iterator {
+public:
+ const_iterator() {}
+ const_iterator(const Iterator &iter) : iter(iter) {}
+ const_iterator(const const_iterator<Iterator> &citer) : iter(citer.iter) {}
+
+ typedef const typename Iterator::value_type value_type;
+ typedef const typename Iterator::pointer pointer;
+ typedef const typename Iterator::reference reference;
+
+ reference operator*() const { return *iter; }
+ pointer operator->() const { return iter.operator->(); }
+
+ const_iterator &operator++() { return ++iter; }
+ const_iterator &operator--() { return --iter; }
+ const_iterator operator++(int) { return iter--; }
+ const_iterator operator--(int) { return iter--; }
+
+ bool operator!=(const Iterator &it) const {
+ return iter->operator->() != it.operator->();
+ }
+ bool operator!=(const const_iterator<Iterator> &it) const {
+ return iter.operator->() != it.operator->();
+ }
+
+private:
+ Iterator iter;
+};
+
+template <class Iterator>
+class forward_iterable {
+public:
+ forward_iterable() {}
+ typedef Iterator iterator;
+ typedef const_iterator<Iterator> const_iterator;
+
+ iterator begin() { return _begin; }
+ iterator end() { return _end; }
+
+ const_iterator begin() const { return _begin; }
+ const_iterator end() const { return _end; }
+
+ const_iterator cbegin() const { return _begin; }
+ const_iterator cend() const { return _end; }
+
+private:
+ iterator _begin, _end;
+};
+
+template <class Iterator>
+class reverse_iterator {
+public:
+ reverse_iterator() {}
+ reverse_iterator(const Iterator &iter) : iter(iter) {}
+ reverse_iterator(const reverse_iterator<Iterator> &rit) : iter(rit.iter) {}
+
+ typedef typename Iterator::value_type value_type;
+ typedef typename Iterator::pointer pointer;
+ typedef typename Iterator::reference reference;
+
+ reference operator*() { return *iter; }
+ pointer operator->() { return iter.operator->(); }
+
+ reverse_iterator &operator++() { return --iter; }
+ reverse_iterator &operator--() { return ++iter; }
+ reverse_iterator operator++(int) { return iter--; }
+ reverse_iterator operator--(int) { return iter++; }
+
+private:
+ Iterator iter;
+};
+
+template <class Iterator>
+class backward_iterable {
+public:
+ backward_iterable() {}
+
+ typedef reverse_iterator<Iterator> reverse_iterator;
+ typedef const_iterator<reverse_iterator> const_reverse_iterator;
+
+ reverse_iterator rbegin() { return _rbegin; }
+ reverse_iterator rend() { return _rend; }
+
+ const_reverse_iterator rbegin() const { return _rbegin; }
+ const_reverse_iterator rend() const { return _rend; }
+
+ const_reverse_iterator crbegin() const { return _rbegin; }
+ const_reverse_iterator crend() const { return _rend; }
+
+private:
+ reverse_iterator _rbegin, _rend;
+};
+
+template <class Iterator>
+class bidirectional_iterable : public forward_iterable<Iterator>,
+ public backward_iterable<Iterator> {};
+
+template <typename A, typename B>
+struct pair {
+ pair(A f, B s) : first(f), second(s) {}
+ A first;
+ B second;
+};
+
+class string {
+public:
+ string() {}
+ string(const char *) {}
+};
+
+template <typename T, int n>
+class array : public backward_iterable<iterator<T>> {
+public:
+ array() {}
+
+ typedef T *iterator;
+ typedef const T *const_iterator;
+
+ iterator begin() { return &v[0]; }
+ iterator end() { return &v[n - 1]; }
+
+ const_iterator begin() const { return &v[0]; }
+ const_iterator end() const { return &v[n - 1]; }
+
+ const_iterator cbegin() const { return &v[0]; }
+ const_iterator cend() const { return &v[n - 1]; }
+
+private:
+ T v[n];
+};
+
+template <typename T>
+class deque : public bidirectional_iterable<iterator<T>> {
+public:
+ deque() {}
+};
+
+template <typename T>
+class list : public bidirectional_iterable<iterator<T>> {
+public:
+ list() {}
+};
+
+template <typename T>
+class forward_list : public forward_iterable<iterator<T>> {
+public:
+ forward_list() {}
+};
+
+template <typename T>
+class vector : public bidirectional_iterable<iterator<T>> {
+public:
+ vector() {}
+};
+
+template <typename T>
+class set : public bidirectional_iterable<iterator<T>> {
+public:
+ set() {}
+};
+
+template <typename T>
+class multiset : public bidirectional_iterable<iterator<T>> {
+public:
+ multiset() {}
+};
+
+template <typename key, typename value>
+class map : public bidirectional_iterable<iterator<pair<key, value>>> {
+public:
+ map() {}
+
+ iterator<pair<key, value>> find(const key &) {}
+ const_iterator<iterator<pair<key, value>>> find(const key &) const {}
+};
+
+template <typename key, typename value>
+class multimap : public bidirectional_iterable<iterator<pair<key, value>>> {
+public:
+ multimap() {}
+};
+
+template <typename T>
+class unordered_set : public forward_iterable<iterator<T>> {
+public:
+ unordered_set() {}
+};
+
+template <typename T>
+class unordered_multiset : public forward_iterable<iterator<T>> {
+public:
+ unordered_multiset() {}
+};
+
+template <typename key, typename value>
+class unordered_map : public forward_iterable<iterator<pair<key, value>>> {
+public:
+ unordered_map() {}
+};
+
+template <typename key, typename value>
+class unordered_multimap : public forward_iterable<iterator<pair<key, value>>> {
+public:
+ unordered_multimap() {}
+};
+
+} // namespace std
+
+#endif // CONTAINERS_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/mpi-type-mismatch/mpimock.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/mpi-type-mismatch/mpimock.h
new file mode 100644
index 0000000..cb90028
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/mpi-type-mismatch/mpimock.h
@@ -0,0 +1,64 @@
+// This Message Passing Interface mock header is used, to mock typedefs,
+// constants and functions, required for integration tests being part of
+// clang-tidy MPI checks.
+
+#ifndef MPIMOCK_H
+#define MPIMOCK_H
+
+#define NULL 0
+
+// These typedefs are used to mock MPI types, fixed width integer types and the
+// templated C++ complex number type.
+typedef int MPI_Datatype;
+typedef int MPI_Comm;
+typedef int MPI_Request;
+typedef int MPI_Status;
+typedef int MPI_Op;
+typedef int int8_t;
+typedef int uint8_t;
+typedef int uint16_t;
+typedef int int64_t;
+namespace std { template<class T> struct complex { T real; T imag; }; }
+
+// These defines are used to mock MPI constants.
+#define MPI_DATATYPE_NULL 0
+#define MPI_CHAR 0
+#define MPI_BYTE 0
+#define MPI_SHORT 0
+#define MPI_INT 0
+#define MPI_LONG 0
+#define MPI_LONG_DOUBLE 0
+#define MPI_UNSIGNED 0
+#define MPI_INT8_T 0
+#define MPI_UINT8_T 0
+#define MPI_UINT16_T 0
+#define MPI_C_FLOAT_COMPLEX 0
+#define MPI_C_LONG_DOUBLE_COMPLEX 0
+#define MPI_FLOAT 0
+#define MPI_DOUBLE 0
+#define MPI_CXX_BOOL 0
+#define MPI_CXX_FLOAT_COMPLEX 0
+#define MPI_CXX_DOUBLE_COMPLEX 0
+#define MPI_CXX_LONG_DOUBLE_COMPLEX 0
+#define MPI_IN_PLACE 0
+#define MPI_COMM_WORLD 0
+#define MPI_STATUS_IGNORE 0
+#define MPI_STATUSES_IGNORE 0
+#define MPI_SUM 0
+
+// These declarations are used to mock MPI functions.
+int MPI_Comm_size(MPI_Comm, int *);
+int MPI_Comm_rank(MPI_Comm, int *);
+int MPI_Send(const void *, int, MPI_Datatype, int, int, MPI_Comm);
+int MPI_Recv(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Status *);
+int MPI_Isend(const void *, int, MPI_Datatype, int, int, MPI_Comm,
+ MPI_Request *);
+int MPI_Irecv(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Request *);
+int MPI_Wait(MPI_Request *, MPI_Status *);
+int MPI_Waitall(int, MPI_Request[], MPI_Status[]);
+int MPI_Reduce(const void *, void *, int, MPI_Datatype, MPI_Op, int, MPI_Comm);
+int MPI_Ireduce(const void *, void *, int, MPI_Datatype, MPI_Op, int, MPI_Comm,
+ MPI_Request *);
+int MPI_Bcast(void *, int count, MPI_Datatype, int, MPI_Comm);
+
+#endif // end of include guard: MPIMOCK_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/nolint/trigger_warning.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/nolint/trigger_warning.h
new file mode 100644
index 0000000..e8ebed2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/nolint/trigger_warning.h
@@ -0,0 +1,5 @@
+void A1(const int &In, int &Out) {
+ if (In > 123) // NOLINT
+ Out = 123;
+}
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/overlapping/o.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/overlapping/o.h
new file mode 100644
index 0000000..bfa7a0a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/overlapping/o.h
@@ -0,0 +1,9 @@
+// run: clang-tidy -checks=-*,llvm-include-order -header-filter=.* %s \
+// run: -- -isystem %S/Inputs/Headers -I %S/Inputs/overlapping | \
+// run: not grep "note: this fix will not be applied because it overlaps with another fix"
+
+#include "b.h"
+#include "a.h"
+
+// The comments above are there to match the offset of the #include with the
+// offset of the #includes in the .cpp file.
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/performance-unnecessary-value-param/header-fixed.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/performance-unnecessary-value-param/header-fixed.h
new file mode 100644
index 0000000..f3e9e72
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/performance-unnecessary-value-param/header-fixed.h
@@ -0,0 +1,15 @@
+// struct ABC is expensive to copy and should be
+// passed as a const referece.
+struct ABC {
+ ABC(const ABC&);
+ int get(int) const;
+};
+
+
+int f1(int n, const ABC& v1, const ABC& v2); // line 9
+
+int f1(int n, ABC v1); // line 11
+
+
+
+int f2( int n, const ABC& v2); // line 15
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/performance-unnecessary-value-param/header.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/performance-unnecessary-value-param/header.h
new file mode 100644
index 0000000..3f55c79
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/performance-unnecessary-value-param/header.h
@@ -0,0 +1,15 @@
+// struct ABC is expensive to copy and should be
+// passed as a const referece.
+struct ABC {
+ ABC(const ABC&);
+ int get(int) const;
+};
+
+
+int f1(int n, ABC v1, ABC v2); // line 9
+
+int f1(int n, ABC v1); // line 11
+
+
+
+int f2( int n, ABC v2); // line 15
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/readability-identifier-naming/system/system-header.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/readability-identifier-naming/system/system-header.h
new file mode 100644
index 0000000..8a394a9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/readability-identifier-naming/system/system-header.h
@@ -0,0 +1,17 @@
+#ifndef SYSTEM_HEADER_H
+#define SYSTEM_HEADER_H
+
+#define SYSTEM_MACRO(m) int m = 0
+
+namespace SYSTEM_NS {
+class structure {
+ int member;
+};
+
+float global;
+
+void function() {
+}
+}
+
+#endif // SYSTEM_HEADER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/readability-identifier-naming/user-header.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/readability-identifier-naming/user-header.h
new file mode 100644
index 0000000..f03982c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/readability-identifier-naming/user-header.h
@@ -0,0 +1,17 @@
+#ifndef USER_HEADER_H
+#define USER_HEADER_H
+
+#define USER_MACRO(m) int m = 0
+
+namespace USER_NS {
+class object {
+ int member;
+};
+
+float global;
+
+void function() {
+}
+}
+
+#endif // USER_HEADER_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/unused-using-decls.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/unused-using-decls.h
new file mode 100644
index 0000000..8245cb1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/unused-using-decls.h
@@ -0,0 +1,11 @@
+class MyClass {
+public:
+ template <template <typename> class S, typename T>
+ S<T> *func1(T *a) {
+ return new S<T>();
+ }
+ template <typename T, T (*S)()>
+ void func2(T a) {
+ S();
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/vfsoverlay/actual_header.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/vfsoverlay/actual_header.h
new file mode 100644
index 0000000..8e1b9ae
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/vfsoverlay/actual_header.h
@@ -0,0 +1 @@
+struct X {};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/vfsoverlay/vfsoverlay.yaml b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/vfsoverlay/vfsoverlay.yaml
new file mode 100644
index 0000000..80d8fba
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/Inputs/vfsoverlay/vfsoverlay.yaml
@@ -0,0 +1,12 @@
+{
+ 'version': 0,
+ 'roots': [
+ { 'name': 'OUT_DIR', 'type': 'directory',
+ 'contents': [
+ { 'name': 'not_real.h', 'type': 'file',
+ 'external-contents': 'INPUT_DIR/actual_header.h'
+ }
+ ]
+ }
+ ]
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/abseil-string-find-startswith.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/abseil-string-find-startswith.cpp
new file mode 100644
index 0000000..7d5fd73
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/abseil-string-find-startswith.cpp
@@ -0,0 +1,70 @@
+// RUN: %check_clang_tidy %s abseil-string-find-startswith %t -- \
+// RUN: -config="{CheckOptions: [{key: 'abseil-string-find-startswith.StringLikeClasses', value: '::std::basic_string;::basic_string'}]}" \
+// RUN: -- -std=c++11
+
+namespace std {
+template <typename T> class allocator {};
+template <typename T> class char_traits {};
+template <typename C, typename T = std::char_traits<C>,
+ typename A = std::allocator<C>>
+struct basic_string {
+ basic_string();
+ basic_string(const basic_string &);
+ basic_string(const C *, const A &a = A());
+ ~basic_string();
+ int find(basic_string<C> s, int pos = 0);
+ int find(const char *s, int pos = 0);
+};
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+
+struct cxx_string {
+ int find(const char *s, int pos = 0);
+};
+} // namespace std
+
+struct basic_string : public std::cxx_string {
+ basic_string();
+};
+typedef basic_string global_string;
+
+std::string foo(std::string);
+std::string bar();
+
+#define A_MACRO(x, y) ((x) == (y))
+
+void tests(std::string s, global_string s2) {
+ s.find("a") == 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith instead of find() == 0 [abseil-string-find-startswith]
+ // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(s, "a");{{$}}
+
+ s.find(s) == 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith
+ // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(s, s);{{$}}
+
+ s.find("aaa") != 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StartsWith
+ // CHECK-FIXES: {{^[[:space:]]*}}!absl::StartsWith(s, "aaa");{{$}}
+
+ s.find(foo(foo(bar()))) != 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StartsWith
+ // CHECK-FIXES: {{^[[:space:]]*}}!absl::StartsWith(s, foo(foo(bar())));{{$}}
+
+ if (s.find("....") == 0) { /* do something */ }
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use absl::StartsWith
+ // CHECK-FIXES: {{^[[:space:]]*}}if (absl::StartsWith(s, "....")) { /* do something */ }{{$}}
+
+ 0 != s.find("a");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StartsWith
+ // CHECK-FIXES: {{^[[:space:]]*}}!absl::StartsWith(s, "a");{{$}}
+
+ s2.find("a") == 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith
+ // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(s2, "a");{{$}}
+
+ // expressions that don't trigger the check are here.
+ A_MACRO(s.find("a"), 0);
+ s.find("a", 1) == 0;
+ s.find("a", 1) == 1;
+ s.find("a") == 1;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-accept.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-accept.cpp
new file mode 100644
index 0000000..9990594
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-accept.cpp
@@ -0,0 +1,28 @@
+// RUN: %check_clang_tidy %s android-cloexec-accept %t
+
+struct sockaddr {};
+typedef int socklen_t;
+#define NULL 0
+
+extern "C" int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+
+void f() {
+ accept(0, NULL, NULL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer accept4() to accept() because accept4() allows SOCK_CLOEXEC [android-cloexec-accept]
+ // CHECK-FIXES: accept4(0, NULL, NULL, SOCK_CLOEXEC);
+}
+
+namespace i {
+int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+void g() {
+ accept(0, NULL, NULL);
+}
+} // namespace i
+
+class C {
+public:
+ int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+ void h() {
+ accept(0, NULL, NULL);
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-accept4.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-accept4.cpp
new file mode 100644
index 0000000..448d4a9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-accept4.cpp
@@ -0,0 +1,66 @@
+// RUN: %check_clang_tidy %s android-cloexec-accept4 %t
+
+typedef int socklen_t;
+struct sockaddr {};
+
+#define SOCK_NONBLOCK 1
+#define __O_CLOEXEC 3
+#define SOCK_CLOEXEC __O_CLOEXEC
+#define TEMP_FAILURE_RETRY(exp) \
+ ({ \
+ int _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1); \
+ })
+#define NULL 0
+
+extern "C" int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
+
+void a() {
+ accept4(0, NULL, NULL, SOCK_NONBLOCK);
+ // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: 'accept4' should use SOCK_CLOEXEC where possible [android-cloexec-accept4]
+ // CHECK-FIXES: accept4(0, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
+ TEMP_FAILURE_RETRY(accept4(0, NULL, NULL, SOCK_NONBLOCK));
+ // CHECK-MESSAGES: :[[@LINE-1]]:58: warning: 'accept4'
+ // CHECK-FIXES: TEMP_FAILURE_RETRY(accept4(0, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC));
+}
+
+void f() {
+ accept4(0, NULL, NULL, 3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: 'accept4'
+ // CHECK-FIXES: accept4(0, NULL, NULL, 3 | SOCK_CLOEXEC);
+ TEMP_FAILURE_RETRY(accept4(0, NULL, NULL, 3));
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning: 'accept4'
+ // CHECK-FIXES: TEMP_FAILURE_RETRY(accept4(0, NULL, NULL, 3 | SOCK_CLOEXEC));
+
+ int flag = SOCK_NONBLOCK;
+ accept4(0, NULL, NULL, flag);
+ TEMP_FAILURE_RETRY(accept4(0, NULL, NULL, flag));
+}
+
+namespace i {
+int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
+
+void d() {
+ accept4(0, NULL, NULL, SOCK_NONBLOCK);
+ TEMP_FAILURE_RETRY(accept4(0, NULL, NULL, SOCK_NONBLOCK));
+}
+
+} // namespace i
+
+void e() {
+ accept4(0, NULL, NULL, SOCK_CLOEXEC);
+ TEMP_FAILURE_RETRY(accept4(0, NULL, NULL, SOCK_CLOEXEC));
+ accept4(0, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
+ TEMP_FAILURE_RETRY(accept4(0, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC));
+}
+
+class G {
+public:
+ int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
+ void d() {
+ accept4(0, NULL, NULL, SOCK_NONBLOCK);
+ TEMP_FAILURE_RETRY(accept4(0, NULL, NULL, SOCK_NONBLOCK));
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-creat.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-creat.cpp
new file mode 100644
index 0000000..df57b10
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-creat.cpp
@@ -0,0 +1,35 @@
+// RUN: %check_clang_tidy %s android-cloexec-creat %t
+
+typedef int mode_t;
+
+extern "C" int creat(const char *path, mode_t, ...);
+extern "C" int create(const char *path, mode_t, ...);
+
+void f() {
+ creat("filename", 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer open() to creat() because open() allows O_CLOEXEC [android-cloexec-creat]
+ // CHECK-FIXES: open ("filename", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0);
+ create("filename", 0);
+ // CHECK-MESSAGES-NOT: warning:
+ mode_t mode = 0755;
+ creat("filename", mode);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning:
+ // CHECK-FIXES: open ("filename", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
+}
+
+namespace i {
+int creat(const char *path, mode_t, ...);
+void g() {
+ creat("filename", 0);
+ // CHECK-MESSAGES-NOT: warning:
+}
+} // namespace i
+
+class C {
+public:
+ int creat(const char *path, mode_t, ...);
+ void h() {
+ creat("filename", 0);
+ // CHECK-MESSAGES-NOT: warning:
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-dup.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-dup.cpp
new file mode 100644
index 0000000..f7011b8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-dup.cpp
@@ -0,0 +1,31 @@
+// RUN: %check_clang_tidy %s android-cloexec-dup %t
+
+extern "C" int dup(int oldfd);
+void f() {
+ dup(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer fcntl() to dup() because fcntl() allows F_DUPFD_CLOEXEC [android-cloexec-dup]
+ // CHECK-FIXES: fcntl(1, F_DUPFD_CLOEXEC);
+ int oldfd = 0;
+ dup(oldfd);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer
+ // CHECK-FIXES: fcntl(oldfd, F_DUPFD_CLOEXEC);
+}
+
+namespace i {
+int dup(int oldfd);
+void g() {
+ dup(0);
+ int oldfd = 1;
+ dup(oldfd);
+}
+} // namespace i
+
+class C {
+public:
+ int dup(int oldfd);
+ void h() {
+ dup(0);
+ int oldfd = 1;
+ dup(oldfd);
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-epoll-create.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-epoll-create.cpp
new file mode 100644
index 0000000..d58e493
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-epoll-create.cpp
@@ -0,0 +1,24 @@
+// RUN: %check_clang_tidy %s android-cloexec-epoll-create %t
+
+extern "C" int epoll_create(int size);
+
+void f() {
+ epoll_create(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer epoll_create() to epoll_create1() because epoll_create1() allows EPOLL_CLOEXEC [android-cloexec-epoll-create]
+ // CHECK-FIXES: epoll_create1(EPOLL_CLOEXEC);
+}
+
+namespace i {
+int epoll_create(int size);
+void g() {
+ epoll_create(0);
+}
+} // namespace i
+
+class C {
+public:
+ int epoll_create(int size);
+ void h() {
+ epoll_create(0);
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-epoll-create1.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-epoll-create1.cpp
new file mode 100644
index 0000000..696a20c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-epoll-create1.cpp
@@ -0,0 +1,59 @@
+// RUN: %check_clang_tidy %s android-cloexec-epoll-create1 %t
+
+#define __O_CLOEXEC 3
+#define EPOLL_CLOEXEC __O_CLOEXEC
+#define TEMP_FAILURE_RETRY(exp) \
+ ({ \
+ int _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1); \
+ })
+
+extern "C" int epoll_create1(int flags);
+
+void a() {
+ epoll_create1(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'epoll_create1' should use EPOLL_CLOEXEC where possible [android-cloexec-epoll-create1]
+ // CHECK-FIXES: epoll_create1(EPOLL_CLOEXEC);
+ TEMP_FAILURE_RETRY(epoll_create1(0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: 'epoll_create1'
+ // CHECK-FIXES: TEMP_FAILURE_RETRY(epoll_create1(EPOLL_CLOEXEC));
+}
+
+void f() {
+ epoll_create1(3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'epoll_create1'
+ // CHECK-FIXES: epoll_create1(EPOLL_CLOEXEC);
+ TEMP_FAILURE_RETRY(epoll_create1(3));
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: 'epoll_create1'
+ // CHECK-FIXES: TEMP_FAILURE_RETRY(epoll_create1(EPOLL_CLOEXEC));
+
+ int flag = 0;
+ epoll_create1(EPOLL_CLOEXEC);
+ TEMP_FAILURE_RETRY(epoll_create1(EPOLL_CLOEXEC));
+}
+
+namespace i {
+int epoll_create1(int flags);
+
+void d() {
+ epoll_create1(0);
+ TEMP_FAILURE_RETRY(epoll_create1(0));
+}
+
+} // namespace i
+
+void e() {
+ epoll_create1(EPOLL_CLOEXEC);
+ TEMP_FAILURE_RETRY(epoll_create1(EPOLL_CLOEXEC));
+}
+
+class G {
+public:
+ int epoll_create1(int flags);
+ void d() {
+ epoll_create1(EPOLL_CLOEXEC);
+ TEMP_FAILURE_RETRY(epoll_create1(EPOLL_CLOEXEC));
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-fopen.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-fopen.cpp
new file mode 100644
index 0000000..6b6c655
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-fopen.cpp
@@ -0,0 +1,57 @@
+// RUN: %check_clang_tidy %s android-cloexec-fopen %t
+
+#define FILE_OPEN_RO "r"
+
+typedef int FILE;
+
+extern "C" FILE *fopen(const char *filename, const char *mode, ...);
+extern "C" FILE *open(const char *filename, const char *mode, ...);
+
+void f() {
+ fopen("filename", "r");
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use 'fopen' mode 'e' to set O_CLOEXEC [android-cloexec-fopen]
+ // CHECK-FIXES: fopen("filename", "re");
+
+ fopen("filename", FILE_OPEN_RO);
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use 'fopen' mode 'e'
+ // CHECK-FIXES: fopen("filename", FILE_OPEN_RO "e");
+
+ fopen("filename", "er");
+ // CHECK-MESSAGES-NOT: warning:
+ fopen("filename", "re");
+ // CHECK-MESSAGES-NOT: warning:
+ fopen("filename", "e");
+ // CHECK-MESSAGES-NOT: warning:
+ open("filename", "e");
+ // CHECK-MESSAGES-NOT: warning:
+
+ char *str = "r";
+ fopen("filename", str);
+ // CHECK-MESSAGES-NOT: warning:
+ str = "re";
+ fopen("filename", str);
+ // CHECK-MESSAGES-NOT: warning:
+ char arr[2] = "r";
+ fopen("filename", arr);
+ // CHECK-MESSAGES-NOT: warning:
+ char arr2[3] = "re";
+ fopen("filename", arr2);
+ // CHECK-MESSAGES-NOT: warning:
+}
+
+namespace i {
+int *fopen(const char *filename, const char *mode, ...);
+void g() {
+ fopen("filename", "e");
+ // CHECK-MESSAGES-NOT: warning:
+}
+} // namespace i
+
+class C {
+public:
+ int *fopen(const char *filename, const char *mode, ...);
+ void h() {
+ fopen("filename", "e");
+ // CHECK-MESSAGES-NOT: warning:
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-inotify-init.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-inotify-init.cpp
new file mode 100644
index 0000000..01eb51e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-inotify-init.cpp
@@ -0,0 +1,24 @@
+// RUN: %check_clang_tidy %s android-cloexec-inotify-init %t
+
+extern "C" int inotify_init();
+
+void f() {
+ inotify_init();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer inotify_init() to inotify_init1() because inotify_init1() allows IN_CLOEXEC [android-cloexec-inotify-init]
+ // CHECK-FIXES: inotify_init1(IN_CLOEXEC);
+}
+
+namespace i {
+int inotify_init();
+void g() {
+ inotify_init();
+}
+} // namespace i
+
+class C {
+public:
+ int inotify_init();
+ void h() {
+ inotify_init();
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-inotify-init1.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-inotify-init1.cpp
new file mode 100644
index 0000000..2b74fad
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-inotify-init1.cpp
@@ -0,0 +1,64 @@
+// RUN: %check_clang_tidy %s android-cloexec-inotify-init1 %t
+
+#define IN_NONBLOCK 1
+#define __O_CLOEXEC 3
+#define IN_CLOEXEC __O_CLOEXEC
+#define TEMP_FAILURE_RETRY(exp) \
+ ({ \
+ int _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1); \
+ })
+
+extern "C" int inotify_init1(int flags);
+
+void a() {
+ inotify_init1(IN_NONBLOCK);
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: 'inotify_init1' should use IN_CLOEXEC where possible [android-cloexec-inotify-init1]
+ // CHECK-FIXES: inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+ TEMP_FAILURE_RETRY(inotify_init1(IN_NONBLOCK));
+ // CHECK-MESSAGES: :[[@LINE-1]]:47: warning: 'inotify_init1'
+ // CHECK-FIXES: TEMP_FAILURE_RETRY(inotify_init1(IN_NONBLOCK | IN_CLOEXEC));
+}
+
+void f() {
+ inotify_init1(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'inotify_init1'
+ // CHECK-FIXES: inotify_init1(IN_CLOEXEC);
+ TEMP_FAILURE_RETRY(inotify_init1(0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: 'inotify_init1'
+ // CHECK-FIXES: TEMP_FAILURE_RETRY(inotify_init1(IN_CLOEXEC));
+
+ int flag = 1;
+ inotify_init1(flag);
+ TEMP_FAILURE_RETRY(inotify_init1(flag));
+}
+
+namespace i {
+int inotify_init1(int flags);
+
+void d() {
+ inotify_init1(IN_NONBLOCK);
+ TEMP_FAILURE_RETRY(inotify_init1(IN_NONBLOCK));
+}
+
+} // namespace i
+
+void e() {
+ inotify_init1(IN_CLOEXEC);
+ TEMP_FAILURE_RETRY(inotify_init1(IN_CLOEXEC));
+ inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+ TEMP_FAILURE_RETRY(inotify_init1(IN_NONBLOCK | IN_CLOEXEC));
+}
+
+class G {
+public:
+ int inotify_init1(int flags);
+ void d() {
+ inotify_init1(IN_CLOEXEC);
+ TEMP_FAILURE_RETRY(inotify_init1(IN_CLOEXEC));
+ inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+ TEMP_FAILURE_RETRY(inotify_init1(IN_NONBLOCK | IN_CLOEXEC));
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-memfd-create.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-memfd-create.cpp
new file mode 100644
index 0000000..a8dafd5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-memfd-create.cpp
@@ -0,0 +1,63 @@
+// RUN: %check_clang_tidy %s android-cloexec-memfd-create %t
+
+#define MFD_ALLOW_SEALING 1
+#define __O_CLOEXEC 3
+#define MFD_CLOEXEC __O_CLOEXEC
+#define TEMP_FAILURE_RETRY(exp) \
+ ({ \
+ int _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1); \
+ })
+#define NULL 0
+
+extern "C" int memfd_create(const char *name, unsigned int flags);
+
+void a() {
+ memfd_create(NULL, MFD_ALLOW_SEALING);
+ // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: 'memfd_create' should use MFD_CLOEXEC where possible [android-cloexec-memfd-create]
+ // CHECK-FIXES: memfd_create(NULL, MFD_ALLOW_SEALING | MFD_CLOEXEC)
+ TEMP_FAILURE_RETRY(memfd_create(NULL, MFD_ALLOW_SEALING));
+ // CHECK-MESSAGES: :[[@LINE-1]]:58: warning: 'memfd_create'
+ // CHECK-FIXES: TEMP_FAILURE_RETRY(memfd_create(NULL, MFD_ALLOW_SEALING | MFD_CLOEXEC))
+}
+
+void f() {
+ memfd_create(NULL, 3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: 'memfd_create'
+ // CHECK-FIXES: memfd_create(NULL, 3 | MFD_CLOEXEC)
+ TEMP_FAILURE_RETRY(memfd_create(NULL, 3));
+ // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: 'memfd_create'
+ // CHECK-FIXES: TEMP_FAILURE_RETRY(memfd_create(NULL, 3 | MFD_CLOEXEC))
+
+ int flag = 3;
+ memfd_create(NULL, flag);
+ TEMP_FAILURE_RETRY(memfd_create(NULL, flag));
+}
+
+namespace i {
+int memfd_create(const char *name, unsigned int flags);
+
+void d() {
+ memfd_create(NULL, MFD_ALLOW_SEALING);
+ TEMP_FAILURE_RETRY(memfd_create(NULL, MFD_ALLOW_SEALING));
+}
+
+} // namespace i
+
+void e() {
+ memfd_create(NULL, MFD_CLOEXEC);
+ TEMP_FAILURE_RETRY(memfd_create(NULL, MFD_CLOEXEC));
+ memfd_create(NULL, MFD_ALLOW_SEALING | MFD_CLOEXEC);
+ TEMP_FAILURE_RETRY(memfd_create(NULL, MFD_ALLOW_SEALING | MFD_CLOEXEC));
+}
+
+class G {
+public:
+ int memfd_create(const char *name, unsigned int flags);
+ void d() {
+ memfd_create(NULL, MFD_ALLOW_SEALING);
+ TEMP_FAILURE_RETRY(memfd_create(NULL, MFD_ALLOW_SEALING));
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-open.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-open.cpp
new file mode 100644
index 0000000..4ef1f40
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-open.cpp
@@ -0,0 +1,180 @@
+// RUN: %check_clang_tidy %s android-cloexec-open %t
+
+#define O_RDWR 1
+#define O_EXCL 2
+#define __O_CLOEXEC 3
+#define O_CLOEXEC __O_CLOEXEC
+#define TEMP_FAILURE_RETRY(exp) \
+ ({ \
+ int _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1); \
+ })
+
+extern "C" int open(const char *fn, int flags, ...);
+extern "C" int open64(const char *fn, int flags, ...);
+extern "C" int openat(int dirfd, const char *pathname, int flags, ...);
+
+void a() {
+ open("filename", O_RDWR);
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: 'open' should use O_CLOEXEC where possible [android-cloexec-open]
+ // CHECK-FIXES: O_RDWR | O_CLOEXEC
+ TEMP_FAILURE_RETRY(open("filename", O_RDWR));
+ // CHECK-MESSAGES: :[[@LINE-1]]:45: warning: 'open' should use O_CLOEXEC where
+ // CHECK-FIXES: O_RDWR | O_CLOEXEC
+ open("filename", O_RDWR | O_EXCL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: 'open' should use O_CLOEXEC where
+ // CHECK-FIXES: O_RDWR | O_EXCL | O_CLOEXEC
+ TEMP_FAILURE_RETRY(open("filename", O_RDWR | O_EXCL));
+ // CHECK-MESSAGES: :[[@LINE-1]]:54: warning: 'open' should use O_CLOEXEC where
+ // CHECK-FIXES: O_RDWR | O_EXCL | O_CLOEXEC
+}
+
+void b() {
+ open64("filename", O_RDWR);
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: 'open64' should use O_CLOEXEC where possible [android-cloexec-open]
+ // CHECK-FIXES: O_RDWR | O_CLOEXEC
+ TEMP_FAILURE_RETRY(open64("filename", O_RDWR));
+ // CHECK-MESSAGES: :[[@LINE-1]]:47: warning: 'open64' should use O_CLOEXEC where
+ // CHECK-FIXES: O_RDWR | O_CLOEXEC
+ open64("filename", O_RDWR | O_EXCL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: 'open64' should use O_CLOEXEC where
+ // CHECK-FIXES: O_RDWR | O_EXCL | O_CLOEXEC
+ TEMP_FAILURE_RETRY(open64("filename", O_RDWR | O_EXCL));
+ // CHECK-MESSAGES: :[[@LINE-1]]:56: warning: 'open64' should use O_CLOEXEC where
+ // CHECK-FIXES: O_RDWR | O_EXCL | O_CLOEXEC
+}
+
+void c() {
+ openat(0, "filename", O_RDWR);
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: 'openat' should use O_CLOEXEC where possible [android-cloexec-open]
+ // CHECK-FIXES: O_RDWR | O_CLOEXEC
+ TEMP_FAILURE_RETRY(openat(0, "filename", O_RDWR));
+ // CHECK-MESSAGES: :[[@LINE-1]]:50: warning: 'openat' should use O_CLOEXEC where
+ // CHECK-FIXES: O_RDWR | O_CLOEXEC
+ openat(0, "filename", O_RDWR | O_EXCL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: 'openat' should use O_CLOEXEC where
+ // CHECK-FIXES: O_RDWR | O_EXCL | O_CLOEXEC
+ TEMP_FAILURE_RETRY(openat(0, "filename", O_RDWR | O_EXCL));
+ // CHECK-MESSAGES: :[[@LINE-1]]:59: warning: 'openat' should use O_CLOEXEC where
+ // CHECK-FIXES: O_RDWR | O_EXCL | O_CLOEXEC
+}
+
+void f() {
+ open("filename", 3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: 'open' should use O_CLOEXEC where possible [android-cloexec-open]
+ // CHECK-FIXES: 3 | O_CLOEXEC
+ TEMP_FAILURE_RETRY(open("filename", 3));
+ // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: 'open' should use O_CLOEXEC where
+ // CHECK-FIXES: 3 | O_CLOEXEC
+ open64("filename", 3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: 'open64' should use O_CLOEXEC where possible [android-cloexec-open]
+ // CHECK-FIXES: 3 | O_CLOEXEC
+ TEMP_FAILURE_RETRY(open64("filename", 3));
+ // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: 'open64' should use O_CLOEXEC where
+ // CHECK-FIXES: 3 | O_CLOEXEC
+ openat(0, "filename", 3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: 'openat' should use O_CLOEXEC where possible [android-cloexec-open]
+ // CHECK-FIXES: 3 | O_CLOEXEC
+ TEMP_FAILURE_RETRY(openat(0, "filename", 3));
+ // CHECK-MESSAGES: :[[@LINE-1]]:45: warning: 'openat' should use O_CLOEXEC where
+ // CHECK-FIXES: 3 | O_CLOEXEC
+
+ int flag = 3;
+ open("filename", flag);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(open("filename", flag));
+ // CHECK-MESSAGES-NOT: warning:
+ open64("filename", flag);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(open64("filename", flag));
+ // CHECK-MESSAGES-NOT: warning:
+ openat(0, "filename", flag);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(openat(0, "filename", flag));
+ // CHECK-MESSAGES-NOT: warning:
+}
+
+namespace i {
+int open(const char *pathname, int flags, ...);
+int open64(const char *pathname, int flags, ...);
+int openat(int dirfd, const char *pathname, int flags, ...);
+
+void d() {
+ open("filename", O_RDWR);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(open("filename", O_RDWR));
+ // CHECK-MESSAGES-NOT: warning:
+ open64("filename", O_RDWR);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(open64("filename", O_RDWR));
+ // CHECK-MESSAGES-NOT: warning:
+ openat(0, "filename", O_RDWR);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(openat(0, "filename", O_RDWR));
+ // CHECK-MESSAGES-NOT: warning:
+}
+
+} // namespace i
+
+void e() {
+ open("filename", O_CLOEXEC);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(open("filename", O_CLOEXEC));
+ // CHECK-MESSAGES-NOT: warning:
+ open("filename", O_RDWR | O_CLOEXEC);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(open("filename", O_RDWR | O_CLOEXEC));
+ // CHECK-MESSAGES-NOT: warning:
+ open("filename", O_RDWR | O_CLOEXEC | O_EXCL);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(open("filename", O_RDWR | O_CLOEXEC | O_EXCL));
+ // CHECK-MESSAGES-NOT: warning:
+ open64("filename", O_CLOEXEC);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(open64("filename", O_CLOEXEC));
+ // CHECK-MESSAGES-NOT: warning:
+ open64("filename", O_RDWR | O_CLOEXEC);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(open64("filename", O_RDWR | O_CLOEXEC));
+ // CHECK-MESSAGES-NOT: warning:
+ open64("filename", O_RDWR | O_CLOEXEC | O_EXCL);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(open64("filename", O_RDWR | O_CLOEXEC | O_EXCL));
+ // CHECK-MESSAGES-NOT: warning:
+ openat(0, "filename", O_CLOEXEC);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(openat(0, "filename", O_CLOEXEC));
+ // CHECK-MESSAGES-NOT: warning:
+ openat(0, "filename", O_RDWR | O_CLOEXEC);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(openat(0, "filename", O_RDWR | O_CLOEXEC));
+ // CHECK-MESSAGES-NOT: warning:
+ openat(0, "filename", O_RDWR | O_CLOEXEC | O_EXCL);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(openat(0, "filename", O_RDWR | O_CLOEXEC | O_EXCL));
+ // CHECK-MESSAGES-NOT: warning:
+}
+
+class G {
+public:
+ int open(const char *pathname, int flags, ...);
+ int open64(const char *pathname, int flags, ...);
+ int openat(int dirfd, const char *pathname, int flags, ...);
+
+ void h() {
+ open("filename", O_RDWR);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(open("filename", O_RDWR));
+ // CHECK-MESSAGES-NOT: warning:
+ open64("filename", O_RDWR);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(open64("filename", O_RDWR));
+ // CHECK-MESSAGES-NOT: warning:
+ openat(0, "filename", O_RDWR);
+ // CHECK-MESSAGES-NOT: warning:
+ TEMP_FAILURE_RETRY(openat(0, "filename", O_RDWR));
+ // CHECK-MESSAGES-NOT: warning:
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-socket.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-socket.cpp
new file mode 100644
index 0000000..25f332d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-cloexec-socket.cpp
@@ -0,0 +1,75 @@
+// RUN: %check_clang_tidy %s android-cloexec-socket %t
+
+#define SOCK_STREAM 1
+#define SOCK_DGRAM 2
+#define __O_CLOEXEC 3
+#define SOCK_CLOEXEC __O_CLOEXEC
+#define TEMP_FAILURE_RETRY(exp) \
+ ({ \
+ int _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1); \
+ })
+
+extern "C" int socket(int domain, int type, int protocol);
+
+void a() {
+ socket(0, SOCK_STREAM, 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: 'socket' should use SOCK_CLOEXEC where possible [android-cloexec-socket]
+ // CHECK-FIXES: socket(0, SOCK_STREAM | SOCK_CLOEXEC, 0)
+ TEMP_FAILURE_RETRY(socket(0, SOCK_STREAM, 0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: 'socket'
+ // CHECK-FIXES: TEMP_FAILURE_RETRY(socket(0, SOCK_STREAM | SOCK_CLOEXEC, 0))
+ socket(0, SOCK_STREAM | SOCK_DGRAM, 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: 'socket'
+ // CHECK-FIXES: socket(0, SOCK_STREAM | SOCK_DGRAM | SOCK_CLOEXEC, 0)
+ TEMP_FAILURE_RETRY(socket(0, SOCK_STREAM | SOCK_DGRAM, 0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:56: warning: 'socket'
+ // CHECK-FIXES: TEMP_FAILURE_RETRY(socket(0, SOCK_STREAM | SOCK_DGRAM | SOCK_CLOEXEC, 0))
+}
+
+void f() {
+ socket(0, 3, 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 'socket'
+ // CHECK-FIXES: socket(0, 3 | SOCK_CLOEXEC, 0)
+ TEMP_FAILURE_RETRY(socket(0, 3, 0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: 'socket'
+ // CHECK-FIXES: TEMP_FAILURE_RETRY(socket(0, 3 | SOCK_CLOEXEC, 0))
+
+ int flag = 3;
+ socket(0, flag, 0);
+ TEMP_FAILURE_RETRY(socket(0, flag, 0));
+}
+
+namespace i {
+int socket(int domain, int type, int protocol);
+
+void d() {
+ socket(0, SOCK_STREAM, 0);
+ TEMP_FAILURE_RETRY(socket(0, SOCK_STREAM, 0));
+ socket(0, SOCK_STREAM | SOCK_DGRAM, 0);
+ TEMP_FAILURE_RETRY(socket(0, SOCK_STREAM | SOCK_DGRAM, 0));
+}
+
+} // namespace i
+
+void e() {
+ socket(0, SOCK_CLOEXEC, 0);
+ TEMP_FAILURE_RETRY(socket(0, SOCK_CLOEXEC, 0));
+ socket(0, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ TEMP_FAILURE_RETRY(socket(0, SOCK_STREAM | SOCK_CLOEXEC, 0));
+ socket(0, SOCK_STREAM | SOCK_CLOEXEC | SOCK_DGRAM, 0);
+ TEMP_FAILURE_RETRY(socket(0, SOCK_STREAM | SOCK_CLOEXEC | SOCK_DGRAM, 0));
+}
+
+class G {
+public:
+ int socket(int domain, int type, int protocol);
+ void d() {
+ socket(0, SOCK_STREAM, 0);
+ TEMP_FAILURE_RETRY(socket(0, SOCK_STREAM, 0));
+ socket(0, SOCK_STREAM | SOCK_DGRAM, 0);
+ TEMP_FAILURE_RETRY(socket(0, SOCK_STREAM | SOCK_DGRAM, 0));
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-comparison-in-temp-failure-retry.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-comparison-in-temp-failure-retry.c
new file mode 100644
index 0000000..3be3eec
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/android-comparison-in-temp-failure-retry.c
@@ -0,0 +1,148 @@
+// RUN: %check_clang_tidy %s android-comparison-in-temp-failure-retry %t
+
+#define TEMP_FAILURE_RETRY(x) \
+ ({ \
+ typeof(x) __z; \
+ do \
+ __z = (x); \
+ while (__z == -1); \
+ __z; \
+ })
+
+int foo();
+int bar(int a);
+
+void test() {
+ int i;
+ TEMP_FAILURE_RETRY((i = foo()));
+ TEMP_FAILURE_RETRY(foo());
+ TEMP_FAILURE_RETRY((foo()));
+
+ TEMP_FAILURE_RETRY(foo() == 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: top-level comparison in TEMP_FAILURE_RETRY [android-comparison-in-temp-failure-retry]
+ TEMP_FAILURE_RETRY((foo() == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: top-level comparison in TEMP_FAILURE_RETRY
+ TEMP_FAILURE_RETRY((int)(foo() == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: top-level comparison in TEMP_FAILURE_RETRY
+
+ TEMP_FAILURE_RETRY(bar(foo() == 1));
+ TEMP_FAILURE_RETRY((bar(foo() == 1)));
+ TEMP_FAILURE_RETRY((bar(foo() == 1)) == 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: top-level comparison in TEMP_FAILURE_RETRY
+ TEMP_FAILURE_RETRY(((bar(foo() == 1)) == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: top-level comparison in TEMP_FAILURE_RETRY
+ TEMP_FAILURE_RETRY((int)((bar(foo() == 1)) == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning: top-level comparison in TEMP_FAILURE_RETRY
+
+#define INDIRECT TEMP_FAILURE_RETRY
+ INDIRECT(foo());
+ INDIRECT((foo() == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: top-level comparison in TEMP_FAILURE_RETRY
+ INDIRECT(bar(foo() == 1));
+ INDIRECT((int)((bar(foo() == 1)) == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: top-level comparison in TEMP_FAILURE_RETRY
+
+#define TFR(x) TEMP_FAILURE_RETRY(x)
+ TFR(foo());
+ TFR((foo() == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: top-level comparison in TEMP_FAILURE_RETRY
+ TFR(bar(foo() == 1));
+ TFR((int)((bar(foo() == 1)) == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: top-level comparison in TEMP_FAILURE_RETRY
+
+#define ADD_TFR(x) (1 + TEMP_FAILURE_RETRY(x) + 1)
+ ADD_TFR(foo());
+ ADD_TFR(foo() == 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: top-level comparison in TEMP_FAILURE_RETRY
+
+ ADD_TFR(bar(foo() == 1));
+ ADD_TFR((int)((bar(foo() == 1)) == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: top-level comparison in TEMP_FAILURE_RETRY
+
+#define ADDP_TFR(x) (1 + TEMP_FAILURE_RETRY((x)) + 1)
+ ADDP_TFR(foo());
+ ADDP_TFR((foo() == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: top-level comparison in TEMP_FAILURE_RETRY
+
+ ADDP_TFR(bar(foo() == 1));
+ ADDP_TFR((int)((bar(foo() == 1)) == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: top-level comparison in TEMP_FAILURE_RETRY
+
+#define MACRO TEMP_FAILURE_RETRY(foo() == 1)
+ MACRO;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: top-level comparison in TEMP_FAILURE_RETRY
+
+ // Be sure that being a macro arg doesn't mess with this.
+#define ID(x) (x)
+ ID(ADDP_TFR(bar(foo() == 1)));
+ ID(ADDP_TFR(bar(foo() == 1) == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: top-level comparison in TEMP_FAILURE_RETRY
+ ID(MACRO);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: top-level comparison in TEMP_FAILURE_RETRY
+
+#define CMP(x) x == 1
+ TEMP_FAILURE_RETRY(CMP(foo()));
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: top-level comparison in TEMP_FAILURE_RETRY
+}
+
+// Be sure that it works inside of things like loops, if statements, etc.
+void control_flow() {
+ do {
+ if (TEMP_FAILURE_RETRY(foo())) {
+ }
+
+ if (TEMP_FAILURE_RETRY(foo() == 1)) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: top-level comparison in TEMP_FAILURE_RETRY
+ }
+
+ if (TEMP_FAILURE_RETRY(bar(foo() == 1))) {
+ }
+
+ if (TEMP_FAILURE_RETRY(bar(foo() == 1) == 1)) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: top-level comparison in TEMP_FAILURE_RETRY
+ }
+ } while (TEMP_FAILURE_RETRY(foo() == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: top-level comparison in TEMP_FAILURE_RETRY
+}
+
+void with_nondependent_variable_type() {
+#undef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(x) \
+ ({ \
+ long int __z; \
+ do \
+ __z = (x); \
+ while (__z == -1); \
+ __z; \
+ })
+
+ TEMP_FAILURE_RETRY((foo()));
+ TEMP_FAILURE_RETRY((int)(foo() == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: top-level comparison in TEMP_FAILURE_RETRY
+ TEMP_FAILURE_RETRY((bar(foo() == 1)));
+ TEMP_FAILURE_RETRY((int)((bar(foo() == 1)) == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning: top-level comparison in TEMP_FAILURE_RETRY
+}
+
+// I can't find a case where TEMP_FAILURE_RETRY is implemented like this, but if
+// we can cheaply support it, I don't see why not.
+void obscured_temp_failure_retry() {
+#undef TEMP_FAILURE_RETRY
+#define IMPL(x) \
+ ({ \
+ typeof(x) __z; \
+ do \
+ __z = (x); \
+ while (__z == -1); \
+ __z; \
+ })
+
+#define IMPL2(x) IMPL(x)
+#define TEMP_FAILURE_RETRY(x) IMPL2(x)
+ TEMP_FAILURE_RETRY((foo()));
+ TEMP_FAILURE_RETRY((int)(foo() == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: top-level comparison in TEMP_FAILURE_RETRY
+ TEMP_FAILURE_RETRY((bar(foo() == 1)));
+ TEMP_FAILURE_RETRY((int)((bar(foo() == 1)) == 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:46: warning: top-level comparison in TEMP_FAILURE_RETRY
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/basic.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/basic.cpp
new file mode 100644
index 0000000..12eb6fe
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/basic.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-tidy %s -checks='-*,llvm-namespace-comment' -- | FileCheck %s
+// RUN: c-index-test -test-load-source-reparse 2 all %s -Xclang -add-plugin -Xclang clang-tidy -Xclang -plugin-arg-clang-tidy -Xclang -checks='-*,llvm-namespace-comment' 2>&1 | FileCheck %s
+
+namespace i {
+}
+// CHECK: warning: namespace 'i' not terminated with a closing comment [llvm-namespace-comment]
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/boost-use-to-string.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/boost-use-to-string.cpp
new file mode 100644
index 0000000..44ba172
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/boost-use-to-string.cpp
@@ -0,0 +1,169 @@
+// RUN: %check_clang_tidy %s boost-use-to-string %t
+
+namespace std {
+
+template <typename T>
+class basic_string {};
+
+using string = basic_string<char>;
+using wstring = basic_string<wchar_t>;
+}
+
+namespace boost {
+template <typename T, typename V>
+T lexical_cast(const V &) {
+ return T();
+};
+}
+
+struct my_weird_type {};
+
+std::string fun(const std::string &) {}
+
+void test_to_string1() {
+
+ auto xa = boost::lexical_cast<std::string>(5);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::to_string instead of boost::lexical_cast<std::string> [boost-use-to-string]
+ // CHECK-FIXES: auto xa = std::to_string(5);
+
+ auto z = boost::lexical_cast<std::string>(42LL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use std::to_string
+ // CHECK-FIXES: auto z = std::to_string(42LL);
+
+ // this should not trigger
+ fun(boost::lexical_cast<std::string>(42.0));
+ auto non = boost::lexical_cast<my_weird_type>(42);
+ boost::lexical_cast<int>("12");
+}
+
+void test_to_string2() {
+ int a;
+ long b;
+ long long c;
+ unsigned d;
+ unsigned long e;
+ unsigned long long f;
+ float g;
+ double h;
+ long double i;
+ bool j;
+
+ fun(boost::lexical_cast<std::string>(a));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string
+ // CHECK-FIXES: fun(std::to_string(a));
+ fun(boost::lexical_cast<std::string>(b));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string
+ // CHECK-FIXES: fun(std::to_string(b));
+ fun(boost::lexical_cast<std::string>(c));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string
+ // CHECK-FIXES: fun(std::to_string(c));
+ fun(boost::lexical_cast<std::string>(d));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string
+ // CHECK-FIXES: fun(std::to_string(d));
+ fun(boost::lexical_cast<std::string>(e));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string
+ // CHECK-FIXES: fun(std::to_string(e));
+ fun(boost::lexical_cast<std::string>(f));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_string
+ // CHECK-FIXES: fun(std::to_string(f));
+
+ // No change for floating numbers.
+ fun(boost::lexical_cast<std::string>(g));
+ fun(boost::lexical_cast<std::string>(h));
+ fun(boost::lexical_cast<std::string>(i));
+ // And bool.
+ fun(boost::lexical_cast<std::string>(j));
+}
+
+std::string fun(const std::wstring &) {}
+
+void test_to_wstring() {
+ int a;
+ long b;
+ long long c;
+ unsigned d;
+ unsigned long e;
+ unsigned long long f;
+ float g;
+ double h;
+ long double i;
+ bool j;
+
+ fun(boost::lexical_cast<std::wstring>(a));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring instead of boost::lexical_cast<std::wstring> [boost-use-to-string]
+ // CHECK-FIXES: fun(std::to_wstring(a));
+ fun(boost::lexical_cast<std::wstring>(b));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring
+ // CHECK-FIXES: fun(std::to_wstring(b));
+ fun(boost::lexical_cast<std::wstring>(c));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring
+ // CHECK-FIXES: fun(std::to_wstring(c));
+ fun(boost::lexical_cast<std::wstring>(d));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring
+ // CHECK-FIXES: fun(std::to_wstring(d));
+ fun(boost::lexical_cast<std::wstring>(e));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring
+ // CHECK-FIXES: fun(std::to_wstring(e));
+ fun(boost::lexical_cast<std::wstring>(f));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::to_wstring
+ // CHECK-FIXES: fun(std::to_wstring(f));
+
+ // No change for floating numbers
+ fun(boost::lexical_cast<std::wstring>(g));
+ fun(boost::lexical_cast<std::wstring>(h));
+ fun(boost::lexical_cast<std::wstring>(i));
+ // and bool.
+ fun(boost::lexical_cast<std::wstring>(j));
+}
+
+const auto glob = boost::lexical_cast<std::string>(42);
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use std::to_string
+// CHECK-FIXES: const auto glob = std::to_string(42);
+
+template <typename T>
+void string_as_T(T t = T()) {
+ boost::lexical_cast<std::string>(42);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use std::to_string
+ // CHECK-FIXES: std::to_string(42);
+
+ boost::lexical_cast<T>(42);
+ string_as_T(boost::lexical_cast<T>(42));
+ auto p = boost::lexical_cast<T>(42);
+ auto p2 = (T)boost::lexical_cast<T>(42);
+ auto p3 = static_cast<T>(boost::lexical_cast<T>(42));
+}
+
+#define my_to_string boost::lexical_cast<std::string>
+
+void no_fixup_inside_macro() {
+ my_to_string(12);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use std::to_string
+}
+
+void no_warnings() {
+ fun(boost::lexical_cast<std::string>("abc"));
+ fun(boost::lexical_cast<std::wstring>("abc"));
+ fun(boost::lexical_cast<std::string>(my_weird_type{}));
+ string_as_T<int>();
+ string_as_T<std::string>();
+}
+
+struct Fields {
+ int integer;
+ float floating;
+ Fields* wierd;
+ const int &getConstInteger() const {return integer;}
+};
+
+void testFields() {
+ Fields fields;
+ auto s1 = boost::lexical_cast<std::string>(fields.integer);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::to_string
+ // CHECK-FIXES: auto s1 = std::to_string(fields.integer);
+
+ auto s2 = boost::lexical_cast<std::string>(fields.floating);
+ auto s3 = boost::lexical_cast<std::string>(fields.wierd);
+ auto s4 = boost::lexical_cast<std::string>(fields.getConstInteger());
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::to_string
+ // CHECK-FIXES: auto s4 = std::to_string(fields.getConstInteger());
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-argument-comment-gmock.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-argument-comment-gmock.cpp
new file mode 100644
index 0000000..e79395e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-argument-comment-gmock.cpp
@@ -0,0 +1,108 @@
+// RUN: %check_clang_tidy %s bugprone-argument-comment %t
+
+namespace testing {
+namespace internal {
+
+template <typename F>
+struct Function;
+
+template <typename R>
+struct Function<R()> {
+ typedef R Result;
+};
+
+template <typename R, typename A1>
+struct Function<R(A1)>
+ : Function<R()> {
+ typedef A1 Argument1;
+};
+
+template <typename R, typename A1, typename A2>
+struct Function<R(A1, A2)>
+ : Function<R(A1)> {
+ typedef A2 Argument2;
+};
+
+} // namespace internal
+
+template <typename F>
+class MockSpec {
+ public:
+ void f();
+};
+
+template <typename T>
+class Matcher {
+ public:
+ explicit Matcher();
+ Matcher(T value);
+};
+
+} // namespace testing
+
+#define GMOCK_RESULT_(tn, ...) \
+ tn ::testing::internal::Function<__VA_ARGS__>::Result
+#define GMOCK_ARG_(tn, N, ...) \
+ tn ::testing::internal::Function<__VA_ARGS__>::Argument##N
+#define GMOCK_MATCHER_(tn, N, ...) \
+ const ::testing::Matcher<GMOCK_ARG_(tn, N, __VA_ARGS__)>&
+#define GMOCK_METHOD2_(tn, constness, ct, Method, ...) \
+ GMOCK_RESULT_(tn, __VA_ARGS__) \
+ ct Method( \
+ GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_ARG_(tn, 2, __VA_ARGS__) gmock_a2) constness; \
+ ::testing::MockSpec<__VA_ARGS__> \
+ gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
+ GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2) constness
+#define MOCK_METHOD2(m, ...) GMOCK_METHOD2_(, , , m, __VA_ARGS__)
+#define MOCK_CONST_METHOD2(m, ...) GMOCK_METHOD2_(, const, , m, __VA_ARGS__)
+#define GMOCK_EXPECT_CALL_IMPL_(obj, call) \
+ ((obj).gmock_##call).f()
+#define EXPECT_CALL(obj, call) GMOCK_EXPECT_CALL_IMPL_(obj, call)
+
+class Base {
+ public:
+ virtual void Method(int param_one_base, int param_two_base);
+};
+class Derived : public Base {
+ public:
+ virtual void Method(int param_one, int param_two);
+ virtual void Method2(int p_one, int p_two) const;
+};
+class MockDerived : public Derived {
+ public:
+ MOCK_METHOD2(Method, void(int a, int b));
+ MOCK_CONST_METHOD2(Method2, void(int c, int d));
+};
+
+class MockStandalone {
+ public:
+ MOCK_METHOD2(Method, void(int aaa, int bbb));
+};
+
+void test_gmock_expectations() {
+ MockDerived m;
+ EXPECT_CALL(m, Method(/*param_one=*/1, /*param_tw=*/2));
+// CHECK-MESSAGES: [[@LINE-1]]:42: warning: argument name 'param_tw' in comment does not match parameter name 'param_two'
+// CHECK-FIXES: EXPECT_CALL(m, Method(/*param_one=*/1, /*param_two=*/2));
+ EXPECT_CALL(m, Method2(/*p_on=*/3, /*p_two=*/4));
+// CHECK-MESSAGES: [[@LINE-1]]:26: warning: argument name 'p_on' in comment does not match parameter name 'p_one'
+// CHECK-FIXES: EXPECT_CALL(m, Method2(/*p_one=*/3, /*p_two=*/4));
+
+ #define PARAM1 11
+ #define PARAM2 22
+ EXPECT_CALL(m, Method2(/*p_on1=*/PARAM1, /*p_tw2=*/PARAM2));
+// CHECK-MESSAGES: [[@LINE-1]]:26: warning: argument name 'p_on1' in comment does not match parameter name 'p_one'
+// CHECK-MESSAGES: [[@LINE-2]]:44: warning: argument name 'p_tw2' in comment does not match parameter name 'p_two'
+// CHECK-FIXES: EXPECT_CALL(m, Method2(/*p_one=*/PARAM1, /*p_two=*/PARAM2));
+
+ MockStandalone m2;
+ EXPECT_CALL(m2, Method(/*aaa=*/5, /*bbc=*/6));
+}
+
+void test_gmock_direct_calls() {
+ MockDerived m;
+ m.Method(/*param_one=*/1, /*param_tw=*/2);
+// CHECK-MESSAGES: [[@LINE-1]]:29: warning: argument name 'param_tw' in comment does not match parameter name 'param_two'
+// CHECK-FIXES: m.Method(/*param_one=*/1, /*param_two=*/2);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-argument-comment-strict.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-argument-comment-strict.cpp
new file mode 100644
index 0000000..0e06a4c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-argument-comment-strict.cpp
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy %s bugprone-argument-comment %t -- \
+// RUN: -config="{CheckOptions: [{key: StrictMode, value: 1}]}" --
+
+void f(int _with_underscores_);
+void g(int x_);
+void ignores_underscores() {
+ f(/*With_Underscores=*/0);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: argument name 'With_Underscores' in comment does not match parameter name '_with_underscores_'
+// CHECK-FIXES: f(/*_with_underscores_=*/0);
+ f(/*with_underscores=*/1);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: argument name 'with_underscores' in comment does not match parameter name '_with_underscores_'
+// CHECK-FIXES: f(/*_with_underscores_=*/1);
+ f(/*_With_Underscores_=*/2);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: argument name '_With_Underscores_' in comment does not match parameter name '_with_underscores_'
+// CHECK-FIXES: f(/*_with_underscores_=*/2);
+ g(/*X=*/3);
+// CHECK-MESSAGES: [[@LINE-1]]:5: warning: argument name 'X' in comment does not match parameter name 'x_'
+// CHECK-FIXES: g(/*x_=*/3);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-argument-comment.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-argument-comment.cpp
new file mode 100644
index 0000000..6452791
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-argument-comment.cpp
@@ -0,0 +1,89 @@
+// RUN: %check_clang_tidy %s bugprone-argument-comment %t
+
+// FIXME: clang-tidy should provide a -verify mode to make writing these checks
+// easier and more accurate.
+
+void ffff(int xxxx, int yyyy);
+
+void f(int x, int y);
+void g() {
+ // CHECK-MESSAGES: [[@LINE+4]]:5: warning: argument name 'y' in comment does not match parameter name 'x'
+ // CHECK-MESSAGES: :[[@LINE-3]]:12: note: 'x' declared here
+ // CHECK-MESSAGES: [[@LINE+2]]:14: warning: argument name 'z' in comment does not match parameter name 'y'
+ // CHECK-MESSAGES: :[[@LINE-5]]:19: note: 'y' declared here
+ f(/*y=*/0, /*z=*/0);
+ // CHECK-FIXES: {{^}} f(/*y=*/0, /*z=*/0);
+
+ f(/*x=*/1, /*y=*/1);
+
+ ffff(0 /*aaaa=*/, /*bbbb*/ 0); // Unsupported formats.
+}
+
+struct C {
+ C(int x, int y);
+};
+C c(/*x=*/0, /*y=*/0);
+
+struct Closure {};
+
+template <typename T1, typename T2>
+Closure *NewCallback(void (*f)(T1, T2), T1 arg1, T2 arg2) { return nullptr; }
+
+template <typename T1, typename T2>
+Closure *NewPermanentCallback(void (*f)(T1, T2), T1 arg1, T2 arg2) { return nullptr; }
+
+void h() {
+ (void)NewCallback(&ffff, /*xxxx=*/11, /*yyyy=*/22);
+ (void)NewPermanentCallback(&ffff, /*xxxx=*/11, /*yyyy=*/22);
+}
+
+template<typename... Args>
+void variadic(Args&&... args);
+
+template<typename... Args>
+void variadic2(int zzz, Args&&... args);
+
+void templates() {
+ variadic(/*xxx=*/0, /*yyy=*/1);
+ variadic2(/*zzU=*/0, /*xxx=*/1, /*yyy=*/2);
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: argument name 'zzU' in comment does not match parameter name 'zzz'
+ // CHECK-FIXES: variadic2(/*zzz=*/0, /*xxx=*/1, /*yyy=*/2);
+}
+
+#define FALSE 0
+void qqq(bool aaa);
+void f2() { qqq(/*bbb=*/FALSE); }
+// CHECK-MESSAGES: [[@LINE-1]]:17: warning: argument name 'bbb' in comment does not match parameter name 'aaa'
+// CHECK-FIXES: void f2() { qqq(/*bbb=*/FALSE); }
+
+void f3(bool _with_underscores_);
+void ignores_underscores() {
+ f3(/*With_Underscores=*/false);
+}
+
+namespace ThisEditDistanceAboveThreshold {
+void f4(int xxx);
+void g() { f4(/*xyz=*/0); }
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: argument name 'xyz' in comment does not match parameter name 'xxx'
+// CHECK-FIXES: void g() { f4(/*xyz=*/0); }
+}
+
+namespace OtherEditDistanceAboveThreshold {
+void f5(int xxx, int yyy);
+void g() { f5(/*Zxx=*/0, 0); }
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: argument name 'Zxx' in comment does not match parameter name 'xxx'
+// CHECK-FIXES: void g() { f5(/*xxx=*/0, 0); }
+struct C2 {
+ C2(int xxx, int yyy);
+};
+C2 c2(/*Zxx=*/0, 0);
+// CHECK-MESSAGES: [[@LINE-1]]:7: warning: argument name 'Zxx' in comment does not match parameter name 'xxx'
+// CHECK-FIXES: C2 c2(/*xxx=*/0, 0);
+}
+
+namespace OtherEditDistanceBelowThreshold {
+void f6(int xxx, int yyy);
+void g() { f6(/*xxy=*/0, 0); }
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: argument name 'xxy' in comment does not match parameter name 'xxx'
+// CHECK-FIXES: void g() { f6(/*xxy=*/0, 0); }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-assert-side-effect.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-assert-side-effect.cpp
new file mode 100644
index 0000000..0933402
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-assert-side-effect.cpp
@@ -0,0 +1,114 @@
+// RUN: %check_clang_tidy %s bugprone-assert-side-effect %t -- -config="{CheckOptions: [{key: bugprone-assert-side-effect.CheckFunctionCalls, value: 1}, {key: bugprone-assert-side-effect.AssertMacros, value: 'assert,assert2,my_assert,convoluted_assert,msvc_assert'}]}" -- -fexceptions
+
+//===--- assert definition block ------------------------------------------===//
+int abort() { return 0; }
+
+#ifdef NDEBUG
+#define assert(x) 1
+#else
+#define assert(x) \
+ if (!(x)) \
+ (void)abort()
+#endif
+
+void print(...);
+#define assert2(e) (__builtin_expect(!(e), 0) ? \
+ print (#e, __FILE__, __LINE__) : (void)0)
+
+#ifdef NDEBUG
+#define my_assert(x) 1
+#else
+#define my_assert(x) \
+ ((void)((x) ? 1 : abort()))
+#endif
+
+#ifdef NDEBUG
+#define not_my_assert(x) 1
+#else
+#define not_my_assert(x) \
+ if (!(x)) \
+ (void)abort()
+#endif
+
+#define real_assert(x) ((void)((x) ? 1 : abort()))
+#define wrap1(x) real_assert(x)
+#define wrap2(x) wrap1(x)
+#define convoluted_assert(x) wrap2(x)
+
+#define msvc_assert(expression) (void)( \
+ (!!(expression)) || \
+ (abort(), 0) \
+ )
+
+
+//===----------------------------------------------------------------------===//
+
+class MyClass {
+public:
+ bool badFunc(int a, int b) { return a * b > 0; }
+ bool goodFunc(int a, int b) const { return a * b > 0; }
+
+ MyClass &operator=(const MyClass &rhs) { return *this; }
+
+ int operator-() { return 1; }
+
+ operator bool() const { return true; }
+
+ void operator delete(void *p) {}
+};
+
+bool freeFunction() {
+ return true;
+}
+
+int main() {
+
+ int X = 0;
+ bool B = false;
+ assert(X == 1);
+
+ assert(X = 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() with side effect [bugprone-assert-side-effect]
+ my_assert(X = 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found my_assert() with side effect
+ convoluted_assert(X = 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found convoluted_assert() with side effect
+ not_my_assert(X = 1);
+
+ assert(++X);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() with side effect
+ assert(!B);
+
+ assert(B || true);
+
+ assert(freeFunction());
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() with side effect
+
+ MyClass mc;
+ assert(mc.badFunc(0, 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() with side effect
+ assert(mc.goodFunc(0, 1));
+
+ MyClass mc2;
+ assert(mc2 = mc);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() with side effect
+
+ assert(-mc > 0);
+
+ MyClass *mcp;
+ assert(mcp = new MyClass);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() with side effect
+
+ assert((delete mcp, false));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() with side effect
+
+ assert((throw 1, false));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() with side effect
+
+ assert2(1 == 2 - 1);
+
+ msvc_assert(mc2 = mc);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found msvc_assert() with side effect
+
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-bool-pointer-implicit-conversion.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-bool-pointer-implicit-conversion.cpp
new file mode 100644
index 0000000..37c6939
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-bool-pointer-implicit-conversion.cpp
@@ -0,0 +1,82 @@
+// RUN: %check_clang_tidy %s bugprone-bool-pointer-implicit-conversion %t
+
+bool *SomeFunction();
+void SomeOtherFunction(bool*);
+bool F();
+void G(bool);
+
+
+template <typename T>
+void t(T b) {
+ if (b) {
+ }
+}
+
+void foo() {
+ bool *b = SomeFunction();
+ if (b) {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: dubious check of 'bool *' against 'nullptr'
+// CHECK-FIXES: if (*b) {
+ }
+
+ if (F() && b) {
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: dubious check of 'bool *' against 'nullptr'
+// CHECK-FIXES: if (F() && *b) {
+ }
+
+ // TODO: warn here.
+ if (b) {
+ G(b);
+ }
+
+#define TESTMACRO if (b || F())
+
+ TESTMACRO {
+ }
+
+ t(b);
+
+ if (!b) {
+ // no-warning
+ }
+
+ if (SomeFunction()) {
+ // no-warning
+ }
+
+ bool *c = SomeFunction();
+ if (c) {
+ (void)c;
+ (void)*c; // no-warning
+ }
+
+ if (c) {
+ *c = true; // no-warning
+ }
+
+ if (c) {
+ c[0] = false; // no-warning
+ }
+
+ if (c) {
+ SomeOtherFunction(c); // no-warning
+ }
+
+ if (c) {
+ delete[] c; // no-warning
+ }
+
+ if (c) {
+ *(c) = false; // no-warning
+ }
+
+ struct {
+ bool *b;
+ } d = { SomeFunction() };
+
+ if (d.b)
+ (void)*d.b; // no-warning
+
+#define CHECK(b) if (b) {}
+ CHECK(c)
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-copy-constructor-init.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-copy-constructor-init.cpp
new file mode 100644
index 0000000..981d0b5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-copy-constructor-init.cpp
@@ -0,0 +1,188 @@
+// RUN: %check_clang_tidy %s bugprone-copy-constructor-init %t
+
+class NonCopyable {
+public:
+ NonCopyable() = default;
+ NonCopyable(const NonCopyable &) = delete;
+
+private:
+ int a;
+};
+
+class NonCopyable2 {
+public:
+ NonCopyable2() = default;
+
+private:
+ NonCopyable2(const NonCopyable2 &);
+ int a;
+};
+
+class Copyable {
+public:
+ Copyable() = default;
+ Copyable(const Copyable &) = default;
+
+private:
+ int a;
+};
+
+class Copyable2 {
+public:
+ Copyable2() = default;
+ Copyable2(const Copyable2 &) = default;
+
+private:
+ int a;
+};
+
+class Copyable3 : public Copyable {
+public:
+ Copyable3() = default;
+ Copyable3(const Copyable3 &) = default;
+};
+
+template <class C>
+class Copyable4 {
+public:
+ Copyable4() = default;
+ Copyable4(const Copyable4 &) = default;
+
+private:
+ int a;
+};
+
+template <class T, class S>
+class Copyable5 {
+public:
+ Copyable5() = default;
+ Copyable5(const Copyable5 &) = default;
+
+private:
+ int a;
+};
+
+class EmptyCopyable {
+public:
+ EmptyCopyable() = default;
+ EmptyCopyable(const EmptyCopyable &) = default;
+};
+
+template <typename T>
+using CopyableAlias = Copyable5<T, int>;
+
+typedef Copyable5<int, int> CopyableAlias2;
+
+class X : public Copyable, public EmptyCopyable {
+ X(const X &other) : Copyable(other) {}
+};
+
+class X2 : public Copyable2 {
+ X2(const X2 &other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor other than the copy constructor [bugprone-copy-constructor-init]
+ // CHECK-FIXES: X2(const X2 &other) : Copyable2(other) {}
+};
+
+class X2_A : public Copyable2 {
+ X2_A(const X2_A &) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor
+ // CHECK-FIXES: X2_A(const X2_A &) {}
+};
+
+class X3 : public Copyable, public Copyable2 {
+ X3(const X3 &other) : Copyable(other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor
+ // CHECK-FIXES: X3(const X3 &other) : Copyable(other) {}
+};
+
+class X4 : public Copyable {
+ X4(const X4 &other) : Copyable() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor
+ // CHECK-FIXES: X4(const X4 &other) : Copyable(other) {}
+};
+
+class X5 : public Copyable3 {
+ X5(const X5 &other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor
+ // CHECK-FIXES: X5(const X5 &other) : Copyable3(other) {}
+};
+
+class X6 : public Copyable2, public Copyable3 {
+ X6(const X6 &other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor
+ // CHECK-FIXES: X6(const X6 &other) : Copyable2(other), Copyable3(other) {}
+};
+
+class X7 : public Copyable, public Copyable2 {
+ X7(const X7 &other) : Copyable() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor
+ // CHECK-FIXES: X7(const X7 &other) : Copyable(other) {}
+};
+
+class X8 : public Copyable4<int> {
+ X8(const X8 &other) : Copyable4(other) {}
+};
+
+class X9 : public Copyable4<int> {
+ X9(const X9 &other) : Copyable4() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor
+ // CHECK-FIXES: X9(const X9 &other) : Copyable4(other) {}
+};
+
+class X10 : public Copyable4<int> {
+ X10(const X10 &other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor
+ // CHECK-FIXES: X10(const X10 &other) : Copyable4(other) {}
+};
+
+class X11 : public Copyable5<int, float> {
+ X11(const X11 &other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor
+ // CHECK-FIXES: X11(const X11 &other) : Copyable5(other) {}
+};
+
+class X12 : public CopyableAlias<float> {
+ X12(const X12 &other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor
+ // CHECK-FIXES: X12(const X12 &other) {}
+};
+
+template <typename T>
+class X13 : T {
+ X13(const X13 &other) {}
+};
+
+template class X13<EmptyCopyable>;
+template class X13<Copyable>;
+
+#define FROMMACRO \
+ class X14 : public Copyable2 { \
+ X14(const X14 &other) {} \
+ };
+
+FROMMACRO
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: calling a base constructor
+
+class X15 : public CopyableAlias2 {
+ X15(const X15 &other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor
+ // CHECK-FIXES: X15(const X15 &other) {}
+};
+
+class X16 : public NonCopyable {
+ X16(const X16 &other) {}
+};
+
+class X17 : public NonCopyable2 {
+ X17(const X17 &other) {}
+};
+
+class X18 : private Copyable {
+ X18(const X18 &other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor
+ // CHECK-FIXES: X18(const X18 &other) : Copyable(other) {}
+};
+
+class X19 : private Copyable {
+ X19(const X19 &other) : Copyable(other) {}
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-dangling-handle.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-dangling-handle.cpp
new file mode 100644
index 0000000..d11a2f2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-dangling-handle.cpp
@@ -0,0 +1,195 @@
+// RUN: %check_clang_tidy %s bugprone-dangling-handle %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: bugprone-dangling-handle.HandleClasses, \
+// RUN: value: 'std::basic_string_view; ::llvm::StringRef;'}]}" \
+// RUN: -- -std=c++11
+
+namespace std {
+
+template <typename T>
+class vector {
+ public:
+ using const_iterator = const T*;
+ using iterator = T*;
+ using size_type = int;
+
+ void assign(size_type count, const T& value);
+ iterator insert(const_iterator pos, const T& value);
+ iterator insert(const_iterator pos, T&& value);
+ iterator insert(const_iterator pos, size_type count, const T& value);
+ void push_back(const T&);
+ void push_back(T&&);
+ void resize(size_type count, const T& value);
+};
+
+template <typename, typename>
+class pair {};
+
+template <typename T>
+class set {
+ public:
+ using const_iterator = const T*;
+ using iterator = T*;
+
+ std::pair<iterator, bool> insert(const T& value);
+ std::pair<iterator, bool> insert(T&& value);
+ iterator insert(const_iterator hint, const T& value);
+ iterator insert(const_iterator hint, T&& value);
+};
+
+template <typename Key, typename Value>
+class map {
+ public:
+ using value_type = pair<Key, Value>;
+ value_type& operator[](const Key& key);
+ value_type& operator[](Key&& key);
+};
+
+class basic_string_view;
+
+class basic_string {
+ public:
+ basic_string();
+ basic_string(const char*);
+
+ operator basic_string_view() const noexcept;
+
+ ~basic_string();
+};
+
+typedef basic_string string;
+
+class basic_string_view {
+ public:
+ basic_string_view(const char*);
+};
+
+typedef basic_string_view string_view;
+
+} // namespace std
+
+namespace llvm {
+
+class StringRef {
+ public:
+ StringRef();
+ StringRef(const char*);
+ StringRef(const std::string&);
+};
+
+} // namespace llvm
+
+std::string ReturnsAString();
+
+void Positives() {
+ std::string_view view1 = std::string();
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives its value [bugprone-dangling-handle]
+
+ std::string_view view_2 = ReturnsAString();
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives
+
+ view1 = std::string();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
+
+ const std::string& str_ref = "";
+ std::string_view view3 = true ? "A" : str_ref;
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives
+ view3 = true ? "A" : str_ref;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
+
+ std::string_view view4(ReturnsAString());
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: std::basic_string_view outlives
+}
+
+void OtherTypes() {
+ llvm::StringRef ref = std::string();
+ // CHECK-MESSAGES: [[@LINE-1]]:19: warning: llvm::StringRef outlives its value
+}
+
+const char static_array[] = "A";
+std::string_view ReturnStatements(int i, std::string value_arg,
+ const std::string &ref_arg) {
+ const char array[] = "A";
+ const char* ptr = "A";
+ std::string s;
+ static std::string ss;
+ switch (i) {
+ // Bad cases
+ case 0:
+ return array; // refers to local
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
+ case 1:
+ return s; // refers to local
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
+ case 2:
+ return std::string(); // refers to temporary
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
+ case 3:
+ return value_arg; // refers to by-value arg
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: std::basic_string_view outliv
+
+ // Ok cases
+ case 100:
+ return ss; // refers to static
+ case 101:
+ return static_array; // refers to static
+ case 102:
+ return ptr; // pointer is ok
+ case 103:
+ return ref_arg; // refers to by-ref arg
+ }
+
+ struct S {
+ std::string_view view() { return value; }
+ std::string value;
+ };
+
+ (void)[&]()->std::string_view {
+ // This should not warn. The string is bound by reference.
+ return s;
+ };
+ (void)[=]() -> std::string_view {
+ // This should not warn. The reference is valid as long as the lambda.
+ return s;
+ };
+ (void)[=]() -> std::string_view {
+ // FIXME: This one should warn. We are returning a reference to a local
+ // lambda variable.
+ std::string local;
+ return local;
+ };
+ return "";
+}
+
+void Containers() {
+ std::vector<std::string_view> v;
+ v.assign(3, std::string());
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
+ v.insert(nullptr, std::string());
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
+ v.insert(nullptr, 3, std::string());
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
+ v.push_back(std::string());
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
+ v.resize(3, std::string());
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
+
+ std::set<std::string_view> s;
+ s.insert(std::string());
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
+ s.insert(nullptr, std::string());
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
+
+ std::map<std::string_view, int> m;
+ m[std::string()];
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: std::basic_string_view outlives
+}
+
+void TakesAStringView(std::string_view);
+
+void Negatives(std::string_view default_arg = ReturnsAString()) {
+ std::string str;
+ std::string_view view = str;
+
+ TakesAStringView(std::string());
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-exception-escape.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-exception-escape.cpp
new file mode 100644
index 0000000..eba14bf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-exception-escape.cpp
@@ -0,0 +1,290 @@
+// RUN: %check_clang_tidy %s bugprone-exception-escape %t -- -extra-arg=-std=c++11 -extra-arg=-fexceptions -config="{CheckOptions: [{key: bugprone-exception-escape.IgnoredExceptions, value: 'ignored1,ignored2'}, {key: bugprone-exception-escape.FunctionsThatShouldNotThrow, value: 'enabled1,enabled2,enabled3'}]}" --
+
+struct throwing_destructor {
+ ~throwing_destructor() {
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function '~throwing_destructor' which should not throw exceptions
+ throw 1;
+ }
+};
+
+struct throwing_move_constructor {
+ throwing_move_constructor(throwing_move_constructor&&) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'throwing_move_constructor' which should not throw exceptions
+ throw 1;
+ }
+};
+
+struct throwing_move_assignment {
+ throwing_move_assignment& operator=(throwing_move_assignment&&) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: an exception may be thrown in function 'operator=' which should not throw exceptions
+ throw 1;
+ }
+};
+
+void throwing_noexcept() noexcept {
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throwing_noexcept' which should not throw exceptions
+ throw 1;
+}
+
+void throwing_throw_nothing() throw() {
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throwing_throw_nothing' which should not throw exceptions
+ throw 1;
+}
+
+void throw_and_catch() noexcept {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_and_catch' which should not throw exceptions
+ try {
+ throw 1;
+ } catch(int &) {
+ }
+}
+
+void throw_and_catch_some(int n) noexcept {
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_and_catch_some' which should not throw exceptions
+ try {
+ if (n) throw 1;
+ throw 1.1;
+ } catch(int &) {
+ }
+}
+
+void throw_and_catch_each(int n) noexcept {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_and_catch_each' which should not throw exceptions
+ try {
+ if (n) throw 1;
+ throw 1.1;
+ } catch(int &) {
+ } catch(double &) {
+ }
+}
+
+void throw_and_catch_all(int n) noexcept {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_and_catch_all' which should not throw exceptions
+ try {
+ if (n) throw 1;
+ throw 1.1;
+ } catch(...) {
+ }
+}
+
+void throw_and_rethrow() noexcept {
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_and_rethrow' which should not throw exceptions
+ try {
+ throw 1;
+ } catch(int &) {
+ throw;
+ }
+}
+
+void throw_catch_throw() noexcept {
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_catch_throw' which should not throw exceptions
+ try {
+ throw 1;
+ } catch(int &) {
+ throw 2;
+ }
+}
+
+void throw_catch_rethrow_the_rest(int n) noexcept {
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_catch_rethrow_the_rest' which should not throw exceptions
+ try {
+ if (n) throw 1;
+ throw 1.1;
+ } catch(int &) {
+ } catch(...) {
+ throw;
+ }
+}
+
+class base {};
+class derived: public base {};
+
+void throw_derived_catch_base() noexcept {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_derived_catch_base' which should not throw exceptions
+ try {
+ throw derived();
+ } catch(base &) {
+ }
+}
+
+void try_nested_try(int n) noexcept {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'try_nested_try' which should not throw exceptions
+ try {
+ try {
+ if (n) throw 1;
+ throw 1.1;
+ } catch(int &) {
+ }
+ } catch(double &) {
+ }
+}
+
+void bad_try_nested_try(int n) noexcept {
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'bad_try_nested_try' which should not throw exceptions
+ try {
+ if (n) throw 1;
+ try {
+ throw 1.1;
+ } catch(int &) {
+ }
+ } catch(double &) {
+ }
+}
+
+void try_nested_catch() noexcept {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'try_nested_catch' which should not throw exceptions
+ try {
+ try {
+ throw 1;
+ } catch(int &) {
+ throw 1.1;
+ }
+ } catch(double &) {
+ }
+}
+
+void catch_nested_try() noexcept {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'catch_nested_try' which should not throw exceptions
+ try {
+ throw 1;
+ } catch(int &) {
+ try {
+ throw 1;
+ } catch(int &) {
+ }
+ }
+}
+
+void bad_catch_nested_try() noexcept {
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'bad_catch_nested_try' which should not throw exceptions
+ try {
+ throw 1;
+ } catch(int &) {
+ try {
+ throw 1.1;
+ } catch(int &) {
+ }
+ } catch(double &) {
+ }
+}
+
+void implicit_int_thrower() {
+ throw 1;
+}
+
+void explicit_int_thrower() throw(int);
+
+void indirect_implicit() noexcept {
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'indirect_implicit' which should not throw exceptions
+ implicit_int_thrower();
+}
+
+void indirect_explicit() noexcept {
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'indirect_explicit' which should not throw exceptions
+ explicit_int_thrower();
+}
+
+void indirect_catch() noexcept {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'indirect_catch' which should not throw exceptions
+ try {
+ implicit_int_thrower();
+ } catch(int&) {
+ }
+}
+
+template<typename T>
+void dependent_throw() noexcept(sizeof(T)<4) {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'dependent_throw' which should not throw exceptions
+ if (sizeof(T) > 4)
+ throw 1;
+}
+
+void swap(int&, int&) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'swap' which should not throw exceptions
+ throw 1;
+}
+
+namespace std {
+class bad_alloc {};
+}
+
+void alloc() {
+ throw std::bad_alloc();
+}
+
+void allocator() noexcept {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'allocator' which should not throw exceptions
+ alloc();
+}
+
+void enabled1() {
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'enabled1' which should not throw exceptions
+ throw 1;
+}
+
+void enabled2() {
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'enabled2' which should not throw exceptions
+ enabled1();
+}
+
+void enabled3() {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'enabled3' which should not throw exceptions
+ try {
+ enabled1();
+ } catch(...) {
+ }
+}
+
+class ignored1 {};
+class ignored2 {};
+
+void this_does_not_count() noexcept {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'this_does_not_count' which should not throw exceptions
+ throw ignored1();
+}
+
+void this_does_not_count_either(int n) noexcept {
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'this_does_not_count_either' which should not throw exceptions
+ try {
+ throw 1;
+ if (n) throw ignored2();
+ } catch(int &) {
+ }
+}
+
+void this_counts(int n) noexcept {
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'this_counts' which should not throw exceptions
+ if (n) throw 1;
+ throw ignored1();
+}
+
+void thrower(int n) {
+ throw n;
+}
+
+int directly_recursive(int n) noexcept {
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'directly_recursive' which should not throw exceptions
+ if (n == 0)
+ thrower(n);
+ return directly_recursive(n);
+}
+
+int indirectly_recursive(int n) noexcept;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'indirectly_recursive' which should not throw exceptions
+
+int recursion_helper(int n) {
+ indirectly_recursive(n);
+}
+
+int indirectly_recursive(int n) noexcept {
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'indirectly_recursive' which should not throw exceptions
+ if (n == 0)
+ thrower(n);
+ return recursion_helper(n);
+}
+
+int main() {
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'main' which should not throw exceptions
+ throw 1;
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-fold-init-type.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-fold-init-type.cpp
new file mode 100644
index 0000000..e7fdf39
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-fold-init-type.cpp
@@ -0,0 +1,158 @@
+// RUN: %check_clang_tidy %s bugprone-fold-init-type %t
+
+namespace std {
+template <class InputIt, class T>
+T accumulate(InputIt first, InputIt last, T init);
+
+template <class InputIt, class T>
+T reduce(InputIt first, InputIt last, T init);
+template <class ExecutionPolicy, class InputIt, class T>
+T reduce(ExecutionPolicy &&policy,
+ InputIt first, InputIt last, T init);
+
+struct parallel_execution_policy {};
+constexpr parallel_execution_policy par{};
+
+template <class InputIt1, class InputIt2, class T>
+T inner_product(InputIt1 first1, InputIt1 last1,
+ InputIt2 first2, T value);
+
+template <class ExecutionPolicy, class InputIt1, class InputIt2, class T>
+T inner_product(ExecutionPolicy &&policy, InputIt1 first1, InputIt1 last1,
+ InputIt2 first2, T value);
+
+} // namespace std
+
+struct FloatIterator {
+ typedef float value_type;
+};
+template <typename ValueType>
+struct TypedefTemplateIterator { typedef ValueType value_type; };
+template <typename ValueType>
+struct UsingTemplateIterator { using value_type = ValueType; };
+template <typename ValueType>
+struct DependentTypedefTemplateIterator { typedef typename ValueType::value_type value_type; };
+template <typename ValueType>
+struct DependentUsingTemplateIterator : public TypedefTemplateIterator<ValueType> { using typename TypedefTemplateIterator<ValueType>::value_type; };
+using TypedeffedIterator = FloatIterator;
+
+// Positives.
+
+int accumulatePositive1() {
+ float a[1] = {0.5f};
+ return std::accumulate(a, a + 1, 0);
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
+}
+
+int accumulatePositive2() {
+ FloatIterator it;
+ return std::accumulate(it, it, 0);
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
+}
+
+int accumulatePositive3() {
+ double a[1] = {0.0};
+ return std::accumulate(a, a + 1, 0.0f);
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'double' into type 'float'
+}
+
+int accumulatePositive4() {
+ TypedefTemplateIterator<unsigned> it;
+ return std::accumulate(it, it, 0);
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int'
+}
+
+int accumulatePositive5() {
+ UsingTemplateIterator<unsigned> it;
+ return std::accumulate(it, it, 0);
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int'
+}
+
+int accumulatePositive6() {
+ DependentTypedefTemplateIterator<UsingTemplateIterator<unsigned>> it;
+ return std::accumulate(it, it, 0);
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'unsigned int' into type 'int'
+}
+
+int accumulatePositive7() {
+ TypedeffedIterator it;
+ return std::accumulate(it, it, 0);
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
+}
+
+int accumulatePositive8() {
+ DependentUsingTemplateIterator<unsigned> it;
+ return std::accumulate(it, it, 0);
+ // FIXME: this one should trigger too.
+}
+
+int reducePositive1() {
+ float a[1] = {0.5f};
+ return std::reduce(a, a + 1, 0);
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
+}
+
+int reducePositive2() {
+ float a[1] = {0.5f};
+ return std::reduce(std::par, a, a + 1, 0);
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
+}
+
+int innerProductPositive1() {
+ float a[1] = {0.5f};
+ int b[1] = {1};
+ return std::inner_product(std::par, a, a + 1, b, 0);
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
+}
+
+int innerProductPositive2() {
+ float a[1] = {0.5f};
+ int b[1] = {1};
+ return std::inner_product(std::par, a, a + 1, b, 0);
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: folding type 'float' into type 'int'
+}
+
+// Negatives.
+
+int negative1() {
+ float a[1] = {0.5f};
+ // This is OK because types match.
+ return std::accumulate(a, a + 1, 0.0);
+}
+
+int negative2() {
+ float a[1] = {0.5f};
+ // This is OK because double is bigger than float.
+ return std::accumulate(a, a + 1, 0.0);
+}
+
+int negative3() {
+ float a[1] = {0.5f};
+ // This is OK because the user explicitly specified T.
+ return std::accumulate<float *, float>(a, a + 1, 0);
+}
+
+int negative4() {
+ TypedefTemplateIterator<unsigned> it;
+ // For now this is OK.
+ return std::accumulate(it, it, 0.0);
+}
+
+int negative5() {
+ float a[1] = {0.5f};
+ float b[1] = {1.0f};
+ return std::inner_product(std::par, a, a + 1, b, 0.0f);
+}
+
+namespace blah {
+namespace std {
+template <class InputIt, class T>
+T accumulate(InputIt, InputIt, T); // We should not care about this one.
+}
+
+int negative5() {
+ float a[1] = {0.5f};
+ // Note that this is using blah::std::accumulate.
+ return std::accumulate(a, a + 1, 0);
+}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-forward-declaration-namespace.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-forward-declaration-namespace.cpp
new file mode 100644
index 0000000..d938148
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-forward-declaration-namespace.cpp
@@ -0,0 +1,163 @@
+// RUN: %check_clang_tidy %s bugprone-forward-declaration-namespace %t
+
+namespace {
+// This is a declaration in a wrong namespace.
+class T_A;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration 'T_A' is never referenced, but a declaration with the same name found in another namespace 'na' [bugprone-forward-declaration-namespace]
+// CHECK-MESSAGES: note: a declaration of 'T_A' is found here
+// CHECK-MESSAGES: :[[@LINE-3]]:7: warning: no definition found for 'T_A', but a definition with the same name 'T_A' found in another namespace '(global)' [bugprone-forward-declaration-namespace]
+// CHECK-MESSAGES: note: a definition of 'T_A' is found here
+}
+
+namespace na {
+// This is a declaration in a wrong namespace.
+class T_A;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration 'T_A' is never referenced, but a declaration with the same name found in another namespace '(anonymous)'
+// CHECK-MESSAGES: note: a declaration of 'T_A' is found here
+// CHECK-MESSAGES: :[[@LINE-3]]:7: warning: no definition found for 'T_A', but a definition with the same name 'T_A' found in another namespace '(global)'
+// CHECK-MESSAGES: note: a definition of 'T_A' is found here
+}
+
+class T_A;
+
+class T_A {
+ int x;
+};
+
+class NESTED;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: no definition found for 'NESTED', but a definition with the same name 'NESTED' found in another namespace '(anonymous namespace)::nq::(anonymous)'
+// CHECK-MESSAGES: note: a definition of 'NESTED' is found here
+
+namespace {
+namespace nq {
+namespace {
+class NESTED {};
+}
+}
+}
+
+namespace na {
+class T_B;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration 'T_B' is never referenced, but a declaration with the same name found in another namespace 'nb'
+// CHECK-MESSAGES: note: a declaration of 'T_B' is found here
+// CHECK-MESSAGES: :[[@LINE-3]]:7: warning: no definition found for 'T_B', but a definition with the same name 'T_B' found in another namespace 'nb'
+// CHECK-MESSAGES: note: a definition of 'T_B' is found here
+}
+
+namespace nb {
+class T_B;
+}
+
+namespace nb {
+class T_B {
+ int x;
+};
+}
+
+namespace na {
+class T_B;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration 'T_B' is never referenced, but a declaration with the same name found in another namespace 'nb'
+// CHECK-MESSAGES: note: a declaration of 'T_B' is found here
+// CHECK-MESSAGES: :[[@LINE-3]]:7: warning: no definition found for 'T_B', but a definition with the same name 'T_B' found in another namespace 'nb'
+// CHECK-MESSAGES: note: a definition of 'T_B' is found here
+}
+
+// A simple forward declaration. Although it is never used, but no declaration
+// with the same name is found in other namespace.
+class OUTSIDER;
+
+namespace na {
+// This class is referenced declaration, we don't generate warning.
+class OUTSIDER_1;
+}
+
+void f(na::OUTSIDER_1);
+
+namespace nc {
+// This class is referenced as friend in OOP.
+class OUTSIDER_1;
+
+class OOP {
+ friend struct OUTSIDER_1;
+};
+}
+
+namespace nd {
+class OUTSIDER_1;
+void f(OUTSIDER_1 *);
+}
+
+namespace nb {
+class OUTSIDER_1;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration 'OUTSIDER_1' is never referenced, but a declaration with the same name found in another namespace 'na'
+// CHECK-MESSAGES: note: a declaration of 'OUTSIDER_1' is found here
+}
+
+
+namespace na {
+template<typename T>
+class T_C;
+}
+
+namespace nb {
+// FIXME: this is an error, but we don't consider template class declaration
+// now.
+template<typename T>
+class T_C;
+}
+
+namespace na {
+template<typename T>
+class T_C {
+ int x;
+};
+}
+
+namespace na {
+
+template <typename T>
+class T_TEMP {
+ template <typename _Tp1>
+ struct rebind { typedef T_TEMP<_Tp1> other; };
+};
+
+// We ignore class template specialization.
+template class T_TEMP<char>;
+}
+
+namespace nb {
+
+template <typename T>
+class T_TEMP_1 {
+ template <typename _Tp1>
+ struct rebind { typedef T_TEMP_1<_Tp1> other; };
+};
+
+// We ignore class template specialization.
+extern template class T_TEMP_1<char>;
+}
+
+namespace nd {
+class D;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: declaration 'D' is never referenced, but a declaration with the same name found in another namespace 'nd::ne'
+// CHECK-MESSAGES: note: a declaration of 'D' is found here
+}
+
+namespace nd {
+namespace ne {
+class D;
+}
+}
+
+int f(nd::ne::D &d);
+
+
+// This should be ignored by the check.
+template <typename... Args>
+class Observer {
+ class Impl;
+};
+
+template <typename... Args>
+class Observer<Args...>::Impl {
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-forwarding-reference-overload.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-forwarding-reference-overload.cpp
new file mode 100644
index 0000000..3510685
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-forwarding-reference-overload.cpp
@@ -0,0 +1,145 @@
+// RUN: %check_clang_tidy %s bugprone-forwarding-reference-overload %t -- -- -std=c++14
+
+namespace std {
+template <bool B, class T = void> struct enable_if { typedef T type; };
+
+template <class T> struct enable_if<true, T> { typedef T type; };
+
+template <bool B, class T = void>
+using enable_if_t = typename enable_if<B, T>::type;
+
+template <class T> struct enable_if_nice { typedef T type; };
+} // namespace std
+
+namespace foo {
+template <class T> struct enable_if { typedef T type; };
+} // namespace foo
+
+template <typename T> constexpr bool just_true = true;
+
+class Test1 {
+public:
+ template <typename T> Test1(T &&n);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: constructor accepting a forwarding reference can hide the copy and move constructors [bugprone-forwarding-reference-overload]
+
+ template <typename T> Test1(T &&n, int i = 5, ...);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: constructor accepting a forwarding reference can hide the copy and move constructors
+
+ template <typename T, typename U = typename std::enable_if_nice<T>::type>
+ Test1(T &&n);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor accepting a forwarding reference can hide the copy and move constructors
+
+ template <typename T>
+ Test1(T &&n, typename foo::enable_if<long>::type i = 5, ...);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor accepting a forwarding reference can hide the copy and move constructors
+
+ Test1(const Test1 &other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: note: copy constructor declared here
+
+ Test1(Test1 &other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: note: copy constructor declared here
+
+ Test1(Test1 &&other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: note: move constructor declared here
+};
+
+template <typename U> class Test2 {
+public:
+ // Two parameters without default value, can't act as copy / move constructor.
+ template <typename T, class V> Test2(T &&n, V &&m, int i = 5, ...);
+
+ // Guarded with enable_if.
+ template <typename T>
+ Test2(T &&n, int i = 5,
+ std::enable_if_t<sizeof(int) < sizeof(long), int> a = 5, ...);
+
+ // Guarded with enable_if.
+ template <typename T, typename X = typename std::enable_if<
+ sizeof(int) < sizeof(long), double>::type &>
+ Test2(T &&n);
+
+ // Guarded with enable_if.
+ template <typename T>
+ Test2(T &&n, typename std::enable_if<just_true<T>>::type **a = nullptr);
+
+ // Guarded with enable_if.
+ template <typename T, typename X = std::enable_if_t<just_true<T>> *&&>
+ Test2(T &&n, double d = 0.0);
+
+ // Not a forwarding reference parameter.
+ template <typename T> Test2(const T &&n);
+
+ // Not a forwarding reference parameter.
+ Test2(int &&x);
+
+ // Two parameters without default value, can't act as copy / move constructor.
+ template <typename T> Test2(T &&n, int x);
+
+ // Not a forwarding reference parameter.
+ template <typename T> Test2(U &&n);
+};
+
+// The copy and move constructors are both disabled.
+class Test3 {
+public:
+ template <typename T> Test3(T &&n);
+
+ template <typename T> Test3(T &&n, int I = 5, ...);
+
+ Test3(const Test3 &rhs) = delete;
+
+private:
+ Test3(Test3 &&rhs);
+};
+
+// Both the copy and the (compiler generated) move constructors can be hidden.
+class Test4 {
+public:
+ template <typename T> Test4(T &&n);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: constructor accepting a forwarding reference can hide the copy and move constructors
+
+ Test4(const Test4 &rhs);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: note: copy constructor declared here
+};
+
+// Nothing can be hidden, the copy constructor is implicitly deleted.
+class Test5 {
+public:
+ template <typename T> Test5(T &&n);
+
+ Test5(Test5 &&rhs) = delete;
+};
+
+// Only the move constructor can be hidden.
+class Test6 {
+public:
+ template <typename T> Test6(T &&n);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: constructor accepting a forwarding reference can hide the move constructor
+
+ Test6(Test6 &&rhs);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: note: move constructor declared here
+private:
+ Test6(const Test6 &rhs);
+};
+
+// Do not dereference a null BaseType.
+template <class _Callable> class result_of;
+template <class _Fp, class ..._Args> class result_of<_Fp(_Args...)> { };
+template <class _Tp> using result_of_t = typename result_of<_Tp>::type;
+
+template <class... _Types> struct __overload;
+template <class _Tp, class... _Types>
+struct __overload<_Tp, _Types...> : __overload<_Types...> {
+ using __overload<_Types...>::operator();
+};
+
+template <class _Tp, class... _Types>
+using __best_match_t = typename result_of_t<__overload<_Types...>(_Tp&&)>::type;
+
+template <class... _Types>
+class variant {
+public:
+ template <class _Arg, class _Tp = __best_match_t<_Arg, _Types...> >
+ constexpr variant(_Arg&& __arg) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: constructor accepting a forwarding reference can hide the copy and move constructors
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-inaccurate-erase.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-inaccurate-erase.cpp
new file mode 100644
index 0000000..d29fa9c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-inaccurate-erase.cpp
@@ -0,0 +1,100 @@
+// RUN: %check_clang_tidy %s bugprone-inaccurate-erase %t
+
+namespace std {
+template <typename T> struct vec_iterator {
+ T ptr;
+ vec_iterator operator++(int);
+
+ template <typename X>
+ vec_iterator(const vec_iterator<X> &); // Omit enable_if<...>.
+};
+
+template <typename T> struct vector {
+ typedef vec_iterator<T*> iterator;
+
+ iterator begin();
+ iterator end();
+
+ void erase(iterator);
+ void erase(iterator, iterator);
+};
+
+template <typename T> struct vector_with_const_iterator {
+ typedef vec_iterator<T*> iterator;
+ typedef vec_iterator<const T*> const_iterator;
+
+ iterator begin();
+ iterator end();
+
+ void erase(const_iterator);
+ void erase(const_iterator, const_iterator);
+};
+
+template <typename FwIt, typename T>
+FwIt remove(FwIt begin, FwIt end, const T &val);
+
+template <typename FwIt, typename Func>
+FwIt remove_if(FwIt begin, FwIt end, Func f);
+
+template <typename FwIt> FwIt unique(FwIt begin, FwIt end);
+
+template <typename T> struct unique_ptr {};
+} // namespace std
+
+struct custom_iter {};
+struct custom_container {
+ void erase(...);
+ custom_iter begin();
+ custom_iter end();
+};
+
+template <typename T> void g() {
+ T t;
+ t.erase(std::remove(t.begin(), t.end(), 10));
+ // CHECK-FIXES: {{^ }}t.erase(std::remove(t.begin(), t.end(), 10));{{$}}
+
+ std::vector<int> v;
+ v.erase(remove(v.begin(), v.end(), 10));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this call will remove at most one
+ // CHECK-FIXES: {{^ }}v.erase(remove(v.begin(), v.end(), 10), v.end());{{$}}
+}
+
+#define ERASE(x, y) x.erase(remove(x.begin(), x.end(), y))
+// CHECK-FIXES: #define ERASE(x, y) x.erase(remove(x.begin(), x.end(), y))
+
+int main() {
+ std::vector<int> v;
+
+ v.erase(remove(v.begin(), v.end(), 10));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this call will remove at most one item even when multiple items should be removed [bugprone-inaccurate-erase]
+ // CHECK-FIXES: {{^ }}v.erase(remove(v.begin(), v.end(), 10), v.end());{{$}}
+ v.erase(remove(v.begin(), v.end(), 20), v.end());
+
+ auto *p = &v;
+ p->erase(remove(p->begin(), p->end(), 11));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this call will remove at most one
+ // CHECK-FIXES: {{^ }}p->erase(remove(p->begin(), p->end(), 11), p->end());{{$}}
+
+ std::vector_with_const_iterator<int> v2;
+ v2.erase(remove(v2.begin(), v2.end(), 12));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this call will remove at most one
+ // CHECK-FIXES: {{^ }}v2.erase(remove(v2.begin(), v2.end(), 12), v2.end());{{$}}
+
+ // Fix is not trivial.
+ auto it = v.end();
+ v.erase(remove(v.begin(), it, 10));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this call will remove at most one
+ // CHECK-FIXES: {{^ }}v.erase(remove(v.begin(), it, 10));{{$}}
+
+ g<std::vector<int>>();
+ g<custom_container>();
+
+ ERASE(v, 15);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: this call will remove at most one
+ // CHECK-FIXES: {{^ }}ERASE(v, 15);{{$}}
+
+ std::vector<std::unique_ptr<int>> vupi;
+ auto iter = vupi.begin();
+ vupi.erase(iter++);
+ // CHECK-FIXES: {{^ }}vupi.erase(iter++);{{$}}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-incorrect-roundings.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-incorrect-roundings.cpp
new file mode 100644
index 0000000..7ada061
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-incorrect-roundings.cpp
@@ -0,0 +1,86 @@
+// RUN: %check_clang_tidy %s bugprone-incorrect-roundings %t
+
+void b(int x) {}
+
+void f1() {
+ float f;
+ double d;
+ long double ld;
+ int x;
+
+ x = (d + 0.5);
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: casting (double + 0.5) to integer leads to incorrect rounding; consider using lround (#include <cmath>) instead [bugprone-incorrect-roundings]
+ x = (d + 0.5f);
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: casting (double + 0.5)
+ x = (f + 0.5);
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: casting (double + 0.5)
+ x = (f + 0.5f);
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: casting (double + 0.5)
+ x = (0.5 + d);
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: casting (double + 0.5)
+ x = (0.5f + d);
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: casting (double + 0.5)
+ x = (0.5 + ld);
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: casting (double + 0.5)
+ x = (0.5f + ld);
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: casting (double + 0.5)
+ x = (0.5 + f);
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: casting (double + 0.5)
+ x = (0.5f + f);
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: casting (double + 0.5)
+ x = (int)(d + 0.5);
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: casting (double + 0.5)
+ x = (int)(d + 0.5f);
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: casting (double + 0.5)
+ x = (int)(ld + 0.5);
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: casting (double + 0.5)
+ x = (int)(ld + 0.5f);
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: casting (double + 0.5)
+ x = (int)(f + 0.5);
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: casting (double + 0.5)
+ x = (int)(f + 0.5f);
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: casting (double + 0.5)
+ x = (int)(0.5 + d);
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: casting (double + 0.5)
+ x = (int)(0.5f + d);
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: casting (double + 0.5)
+ x = (int)(0.5 + ld);
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: casting (double + 0.5)
+ x = (int)(0.5f + ld);
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: casting (double + 0.5)
+ x = (int)(0.5 + f);
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: casting (double + 0.5)
+ x = (int)(0.5f + f);
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: casting (double + 0.5)
+ x = static_cast<int>(d + 0.5);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: casting (double + 0.5)
+ x = static_cast<int>(d + 0.5f);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: casting (double + 0.5)
+ x = static_cast<int>(ld + 0.5);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: casting (double + 0.5)
+ x = static_cast<int>(ld + 0.5f);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: casting (double + 0.5)
+ x = static_cast<int>(f + 0.5);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: casting (double + 0.5)
+ x = static_cast<int>(f + 0.5f);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: casting (double + 0.5)
+ x = static_cast<int>(0.5 + d);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: casting (double + 0.5)
+ x = static_cast<int>(0.5f + d);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: casting (double + 0.5)
+ x = static_cast<int>(0.5 + ld);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: casting (double + 0.5)
+ x = static_cast<int>(0.5f + ld);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: casting (double + 0.5)
+ x = static_cast<int>(0.5 + f);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: casting (double + 0.5)
+ x = static_cast<int>(0.5f + f);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: casting (double + 0.5)
+
+ // Don't warn if constant is not 0.5.
+ x = (int)(d + 0.6);
+ x = (int)(0.6 + d);
+
+ // Don't warn if binary operator is not directly beneath cast.
+ x = (int)(1 + (0.5 + f));
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-integer-division.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-integer-division.cpp
new file mode 100644
index 0000000..243ad46
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-integer-division.cpp
@@ -0,0 +1,130 @@
+// RUN: %check_clang_tidy %s bugprone-integer-division %t
+
+// Functions expecting a floating-point parameter.
+void floatArg(float x) {}
+void doubleArg(double x) {}
+void longDoubleArg(long double x) {}
+
+// Functions expected to return a floating-point value.
+float singleDiv() {
+ int x = -5;
+ int y = 2;
+ return x/y;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: result of integer division used in
+}
+
+double wrongOrder(int x, int y) {
+ return x/y/0.1;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: result of integer division used in
+}
+
+long double rightOrder(int x, int y) {
+ return 0.1/x/y; // OK
+}
+
+// Typical mathematical functions.
+float sin(float);
+double acos(double);
+long double tanh(long double);
+
+namespace std {
+ using ::sin;
+}
+
+template <typename T>
+void intDivSin(T x) {
+ sin(x);
+}
+
+int intFunc(int);
+
+struct X {
+ int n;
+ void m() {
+ sin(n / 3);
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: result of integer division used in
+ }
+};
+
+void integerDivision() {
+ char a = 2;
+ short b = -5;
+ int c = 9784;
+ enum third { x, y, z=2 };
+ third d = z;
+ char e[] = {'a', 'b', 'c'};
+ char f = *(e + 1 / a);
+ bool g = 1;
+
+ sin(1 + c / (2 + 2));
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: result of integer division used in
+ sin(c / (1 + .5));
+ sin((c + .5) / 3);
+
+ sin(intFunc(3) / 5);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: result of integer division used in
+ acos(2 / intFunc(7));
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: result of integer division used in
+
+ floatArg(1 + 2 / 3);
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: result of integer division used in
+ sin(1 + 2 / 3);
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: result of integer division used in
+ intFunc(sin(1 + 2 / 3));
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: result of integer division used in
+
+ floatArg(1 + intFunc(1 + 2 / 3));
+ floatArg(1 + 3 * intFunc(a / b));
+
+ 1 << (2 / 3);
+ 1 << intFunc(2 / 3);
+
+#define M_SIN sin(a / b);
+ M_SIN
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result of integer division used in
+
+ intDivSin<float>(a / b);
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: result of integer division used in
+ intDivSin<double>(c / d);
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: result of integer division used in
+ intDivSin<long double>(f / g);
+// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: result of integer division used in
+
+ floatArg(1 / 3);
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: result of integer division used in
+ doubleArg(a / b);
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: result of integer division used in
+ longDoubleArg(3 / d);
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: result of integer division used in
+ floatArg(a / b / 0.1);
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: result of integer division used in
+ doubleArg(1 / 3 / 0.1);
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: result of integer division used in
+ longDoubleArg(2 / 3 / 5);
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: result of integer division used in
+
+ std::sin(2 / 3);
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: result of integer division used in
+ ::acos(7 / d);
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: result of integer division used in
+ tanh(f / g);
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: result of integer division used in
+
+ floatArg(0.1 / a / b);
+ doubleArg(0.1 / 3 / 1);
+
+ singleDiv();
+ wrongOrder(a,b);
+ rightOrder(a,b);
+
+ sin(a / b);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: result of integer division used in
+ acos(f / d);
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: result of integer division used in
+ tanh(c / g);
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: result of integer division used in
+
+ sin(3.0 / a);
+ acos(b / 3.14);
+ tanh(3.14 / f / g);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-lambda-function-name.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-lambda-function-name.cpp
new file mode 100644
index 0000000..145928b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-lambda-function-name.cpp
@@ -0,0 +1,41 @@
+// RUN: %check_clang_tidy %s bugprone-lambda-function-name %t
+
+void Foo(const char* a, const char* b, int c) {}
+
+#define FUNC_MACRO Foo(__func__, "", 0)
+#define FUNCTION_MACRO Foo(__FUNCTION__, "", 0)
+#define EMBED_IN_ANOTHER_MACRO1 FUNC_MACRO
+
+void Positives() {
+ [] { __func__; }();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: inside a lambda, '__func__' expands to the name of the function call operator; consider capturing the name of the enclosing function explicitly [bugprone-lambda-function-name]
+ [] { __FUNCTION__; }();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: inside a lambda, '__FUNCTION__' expands to the name of the function call operator; consider capturing the name of the enclosing function explicitly [bugprone-lambda-function-name]
+ [] { FUNC_MACRO; }();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: inside a lambda, '__func__' expands to the name of the function call operator; consider capturing the name of the enclosing function explicitly [bugprone-lambda-function-name]
+ [] { FUNCTION_MACRO; }();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: inside a lambda, '__FUNCTION__' expands to the name of the function call operator; consider capturing the name of the enclosing function explicitly [bugprone-lambda-function-name]
+ [] { EMBED_IN_ANOTHER_MACRO1; }();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: inside a lambda, '__func__' expands to the name of the function call operator; consider capturing the name of the enclosing function explicitly [bugprone-lambda-function-name]
+}
+
+#define FUNC_MACRO_WITH_FILE_AND_LINE Foo(__func__, __FILE__, __LINE__)
+#define FUNCTION_MACRO_WITH_FILE_AND_LINE Foo(__FUNCTION__, __FILE__, __LINE__)
+#define EMBED_IN_ANOTHER_MACRO2 FUNC_MACRO_WITH_FILE_AND_LINE
+
+void Negatives() {
+ __func__;
+ __FUNCTION__;
+
+ // __PRETTY_FUNCTION__ should not trigger a warning because its value is
+ // actually potentially useful.
+ __PRETTY_FUNCTION__;
+ [] { __PRETTY_FUNCTION__; }();
+
+ // Don't warn if __func__/__FUNCTION is used inside a macro that also uses
+ // __FILE__ and __LINE__, on the assumption that __FILE__ and __LINE__ will
+ // be useful even if __func__/__FUNCTION__ is not.
+ [] { FUNC_MACRO_WITH_FILE_AND_LINE; }();
+ [] { FUNCTION_MACRO_WITH_FILE_AND_LINE; }();
+ [] { EMBED_IN_ANOTHER_MACRO2; }();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-macro-parentheses-cmdline.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-macro-parentheses-cmdline.cpp
new file mode 100644
index 0000000..9ff757d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-macro-parentheses-cmdline.cpp
@@ -0,0 +1,10 @@
+// RUN: %check_clang_tidy %s bugprone-macro-parentheses %t -- -- -DVAL=0+0
+
+// The previous command-line is producing warnings and fixes with the source
+// locations from a virtual buffer. VAL is replaced by '0+0'.
+// Fixes could not be applied and should not be reported.
+int foo() { return VAL; }
+
+#define V 0+0
+int bar() { return V; }
+// CHECK-FIXES: #define V (0+0)
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-macro-parentheses.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-macro-parentheses.cpp
new file mode 100644
index 0000000..2cc45e8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-macro-parentheses.cpp
@@ -0,0 +1,49 @@
+// RUN: %check_clang_tidy %s bugprone-macro-parentheses %t
+
+#define BAD1 -1
+// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: macro replacement list should be enclosed in parentheses [bugprone-macro-parentheses]
+#define BAD2 1+2
+// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: macro replacement list should be enclosed in parentheses [bugprone-macro-parentheses]
+#define BAD3(A) (A+1)
+// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: macro argument should be enclosed in parentheses [bugprone-macro-parentheses]
+#define BAD4(x) ((unsigned char)(x & 0xff))
+// CHECK-MESSAGES: :[[@LINE-1]]:44: warning: macro argument should be enclosed in parentheses [bugprone-macro-parentheses]
+#define BAD5(X) A*B=(C*)X+2
+// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: macro argument should be enclosed in parentheses [bugprone-macro-parentheses]
+
+#define GOOD1 1
+#define GOOD2 (1+2)
+#define GOOD3(A) #A
+#define GOOD4(A,B) A ## B
+#define GOOD5(T) ((T*)0)
+#define GOOD6(B) "A" B "C"
+#define GOOD7(b) A b
+#define GOOD8(a) a B
+#define GOOD9(type) (type(123))
+#define GOOD10(car, ...) car
+#define GOOD11 a[b+c]
+#define GOOD12(x) a[x]
+#define GOOD13(x) a.x
+#define GOOD14(x) a->x
+#define GOOD15(x) ({ int a = x; a+4; })
+#define GOOD16(x) a_ ## x, b_ ## x = c_ ## x - 1,
+#define GOOD17 case 123: x=4+5; break;
+#define GOOD18(x) ;x;
+#define GOOD19 ;-2;
+#define GOOD20 void*
+#define GOOD21(a) case Fred::a:
+#define GOOD22(a) if (verbose) return a;
+#define GOOD23(type) (type::Field)
+#define GOOD24(t) std::set<t> s
+#define GOOD25(t) std::set<t,t,t> s
+#define GOOD26(x) (a->*x)
+#define GOOD27(x) (a.*x)
+#define GOOD28(x) namespace x {int b;}
+#define GOOD29(...) std::cout << __VA_ARGS__;
+#define GOOD30(args...) std::cout << args;
+#define GOOD31(X) A*X=2
+#define GOOD32(X) std::vector<X>
+
+// These are allowed for now..
+#define MAYBE1 *12.34
+#define MAYBE2 <<3
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-macro-repeated-side-effects.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-macro-repeated-side-effects.c
new file mode 100644
index 0000000..bcea47a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-macro-repeated-side-effects.c
@@ -0,0 +1,106 @@
+// RUN: %check_clang_tidy %s bugprone-macro-repeated-side-effects %t
+
+#define badA(x,y) ((x)+((x)+(y))+(y))
+void bad(int ret, int a, int b) {
+ ret = badA(a++, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: side effects in the 1st macro argument 'x' are repeated in macro expansion [bugprone-macro-repeated-side-effects]
+ ret = badA(++a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: side effects in the 1st macro argument 'x'
+ ret = badA(a--, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: side effects in the 1st macro argument 'x'
+ ret = badA(--a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: side effects in the 1st macro argument 'x'
+ ret = badA(a, b++);
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: side effects in the 2nd macro argument 'y'
+ ret = badA(a, ++b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: side effects in the 2nd macro argument 'y'
+ ret = badA(a, b--);
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: side effects in the 2nd macro argument 'y'
+ ret = badA(a, --b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: side effects in the 2nd macro argument 'y'
+}
+
+
+#define MIN(A,B) ((A) < (B) ? (A) : (B)) // single ?:
+#define LIMIT(X,A,B) ((X) < (A) ? (A) : ((X) > (B) ? (B) : (X))) // two ?:
+void question(int x) {
+ MIN(x++, 12);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: side effects in the 1st macro argument 'A'
+ MIN(34, x++);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: side effects in the 2nd macro argument 'B'
+ LIMIT(x++, 0, 100);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: side effects in the 1st macro argument 'X'
+ LIMIT(20, x++, 100);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: side effects in the 2nd macro argument 'A'
+ LIMIT(20, 0, x++);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: side effects in the 3rd macro argument 'B'
+}
+
+// False positive: Repeated side effects is intentional.
+// It is hard to know when it's done by intention so right now we warn.
+#define UNROLL(A) {A A}
+void fp1(int i) {
+ UNROLL({ i++; });
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: side effects in the 1st macro argument 'A'
+}
+
+// Do not produce a false positive on a strchr() macro. Explanation; Currently the '?'
+// triggers the test to bail out, because it cannot evaluate __builtin_constant_p(c).
+# define strchrs(s, c) \
+ (__extension__ (__builtin_constant_p (c) && !__builtin_constant_p (s) \
+ && (c) == '\0' \
+ ? (char *) __rawmemchr (s, c) \
+ : __builtin_strchr (s, c)))
+char* __rawmemchr(char* a, char b) {
+ return a;
+}
+void pass(char* pstr, char ch) {
+ strchrs(pstr, ch++); // No error.
+}
+
+// Check large arguments (t=20, u=21).
+#define largeA(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, x, y, z) \
+ ((a) + (a) + (b) + (b) + (c) + (c) + (d) + (d) + (e) + (e) + (f) + (f) + (g) + (g) + \
+ (h) + (h) + (i) + (i) + (j) + (j) + (k) + (k) + (l) + (l) + (m) + (m) + (n) + (n) + \
+ (o) + (o) + (p) + (p) + (q) + (q) + (r) + (r) + (s) + (s) + (t) + (t) + (u) + (u) + \
+ (v) + (v) + (x) + (x) + (y) + (y) + (z) + (z))
+void large(int a) {
+ largeA(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a++, 0, 0, 0, 0, 0, 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:64: warning: side effects in the 19th macro argument 's'
+ largeA(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a++, 0, 0, 0, 0, 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:67: warning: side effects in the 20th macro argument 't'
+ largeA(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a++, 0, 0, 0, 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:70: warning: side effects in the 21st macro argument 'u'
+}
+
+// Passing macro argument as argument to __builtin_constant_p and macros.
+#define builtinbad(x) (__builtin_constant_p(x) + (x) + (x))
+#define builtingood1(x) (__builtin_constant_p(x) + (x))
+#define builtingood2(x) ((__builtin_constant_p(x) && (x)) || (x))
+#define macrobad(x) (builtingood1(x) + (x) + (x))
+#define macrogood(x) (builtingood1(x) + (x))
+void builtins(int ret, int a) {
+ ret += builtinbad(a++);
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: side effects in the 1st macro argument 'x'
+
+ ret += builtingood1(a++);
+ ret += builtingood2(a++);
+
+ ret += macrobad(a++);
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: side effects in the 1st macro argument 'x'
+
+ ret += macrogood(a++);
+}
+
+// Bail out for conditionals.
+#define condB(x,y) if(x) {x=y;} else {x=y + 1;}
+void conditionals(int a, int b)
+{
+ condB(a, b++);
+}
+
+void log(const char *s, int v);
+#define LOG(val) log(#val, (val))
+void test_log(int a) {
+ LOG(a++);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-misplaced-operator-in-strlen-in-alloc.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-misplaced-operator-in-strlen-in-alloc.c
new file mode 100644
index 0000000..c5deb25
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-misplaced-operator-in-strlen-in-alloc.c
@@ -0,0 +1,85 @@
+// RUN: %check_clang_tidy %s bugprone-misplaced-operator-in-strlen-in-alloc %t
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void *alloca(size_t);
+void *calloc(size_t, size_t);
+void *realloc(void *, size_t);
+
+size_t strlen(const char *);
+size_t strnlen(const char *, size_t);
+size_t strnlen_s(const char *, size_t);
+
+typedef unsigned wchar_t;
+
+size_t wcslen(const wchar_t *);
+size_t wcsnlen(const wchar_t *, size_t);
+size_t wcsnlen_s(const wchar_t *, size_t);
+
+void bad_malloc(char *name) {
+ char *new_name = (char *)malloc(strlen(name + 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: addition operator is applied to the argument of strlen
+ // CHECK-FIXES: {{^ char \*new_name = \(char \*\)malloc\(}}strlen(name) + 1{{\);$}}
+ new_name = (char *)malloc(strnlen(name + 1, 10));
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: addition operator is applied to the argument of strnlen
+ // CHECK-FIXES: {{^ new_name = \(char \*\)malloc\(}}strnlen(name, 10) + 1{{\);$}}
+ new_name = (char *)malloc(strnlen_s(name + 1, 10));
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: addition operator is applied to the argument of strnlen_s
+ // CHECK-FIXES: {{^ new_name = \(char \*\)malloc\(}}strnlen_s(name, 10) + 1{{\);$}}
+}
+
+void bad_malloc_wide(wchar_t *name) {
+ wchar_t *new_name = (wchar_t *)malloc(wcslen(name + 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: addition operator is applied to the argument of wcslen
+ // CHECK-FIXES: {{^ wchar_t \*new_name = \(wchar_t \*\)malloc\(}}wcslen(name) + 1{{\);$}}
+ new_name = (wchar_t *)malloc(wcsnlen(name + 1, 10));
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: addition operator is applied to the argument of wcsnlen
+ // CHECK-FIXES: {{^ new_name = \(wchar_t \*\)malloc\(}}wcsnlen(name, 10) + 1{{\);$}}
+ new_name = (wchar_t *)malloc(wcsnlen_s(name + 1, 10));
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: addition operator is applied to the argument of wcsnlen_s
+ // CHECK-FIXES: {{^ new_name = \(wchar_t \*\)malloc\(}}wcsnlen_s(name, 10) + 1{{\);$}}
+}
+
+void bad_alloca(char *name) {
+ char *new_name = (char *)alloca(strlen(name + 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: addition operator is applied to the argument of strlen
+ // CHECK-FIXES: {{^ char \*new_name = \(char \*\)alloca\(}}strlen(name) + 1{{\);$}}
+}
+
+void bad_calloc(char *name) {
+ char *new_names = (char *)calloc(2, strlen(name + 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: addition operator is applied to the argument of strlen
+ // CHECK-FIXES: {{^ char \*new_names = \(char \*\)calloc\(2, }}strlen(name) + 1{{\);$}}
+}
+
+void bad_realloc(char *old_name, char *name) {
+ char *new_name = (char *)realloc(old_name, strlen(name + 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: addition operator is applied to the argument of strlen
+ // CHECK-FIXES: {{^ char \*new_name = \(char \*\)realloc\(old_name, }}strlen(name) + 1{{\);$}}
+}
+
+void intentional1(char *name) {
+ char *new_name = (char *)malloc(strlen(name + 1) + 1);
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:28: warning: addition operator is applied to the argument of strlen
+ // We have + 1 outside as well so we assume this is intentional
+}
+
+void intentional2(char *name) {
+ char *new_name = (char *)malloc(strlen(name + 2));
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:28: warning: addition operator is applied to the argument of strlen
+ // Only give warning for + 1, not + 2
+}
+
+void intentional3(char *name) {
+ char *new_name = (char *)malloc(strlen((name + 1)));
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:28: warning: addition operator is applied to the argument of strlen
+ // If expression is in extra parentheses, consider it as intentional
+}
+
+void (*(*const alloc_ptr)(size_t)) = malloc;
+
+void bad_indirect_alloc(char *name) {
+ char *new_name = (char *)alloc_ptr(strlen(name + 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: addition operator is applied to the argument of strlen
+ // CHECK-FIXES: {{^ char \*new_name = \(char \*\)alloc_ptr\(}}strlen(name) + 1{{\);$}}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-misplaced-operator-in-strlen-in-alloc.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-misplaced-operator-in-strlen-in-alloc.cpp
new file mode 100644
index 0000000..58d63fa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-misplaced-operator-in-strlen-in-alloc.cpp
@@ -0,0 +1,58 @@
+// RUN: %check_clang_tidy %s bugprone-misplaced-operator-in-strlen-in-alloc %t
+
+namespace std {
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+
+size_t strlen(const char *);
+} // namespace std
+
+namespace non_std {
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+
+size_t strlen(const char *);
+} // namespace non_std
+
+void bad_std_malloc_std_strlen(char *name) {
+ char *new_name = (char *)std::malloc(std::strlen(name + 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: addition operator is applied to the argument of strlen
+ // CHECK-FIXES: {{^ char \*new_name = \(char \*\)std::malloc\(}}std::strlen(name) + 1{{\);$}}
+}
+
+void ignore_non_std_malloc_std_strlen(char *name) {
+ char *new_name = (char *)non_std::malloc(std::strlen(name + 1));
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:28: warning: addition operator is applied to the argument of strlen
+ // Ignore functions of the malloc family in custom namespaces
+}
+
+void ignore_std_malloc_non_std_strlen(char *name) {
+ char *new_name = (char *)std::malloc(non_std::strlen(name + 1));
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:28: warning: addition operator is applied to the argument of strlen
+ // Ignore functions of the strlen family in custom namespaces
+}
+
+void bad_new_strlen(char *name) {
+ char *new_name = new char[std::strlen(name + 1)];
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: addition operator is applied to the argument of strlen
+ // CHECK-FIXES: {{^ char \*new_name = new char\[}}std::strlen(name) + 1{{\];$}}
+}
+
+void good_new_strlen(char *name) {
+ char *new_name = new char[std::strlen(name) + 1];
+ // CHECK-MESSAGES-NOT: :[[@LINE-1]]:20: warning: addition operator is applied to the argument of strlen
+}
+
+class C {
+ char c;
+public:
+ static void *operator new[](std::size_t count) {
+ return ::operator new(count);
+ }
+};
+
+void bad_custom_new_strlen(char *name) {
+ C *new_name = new C[std::strlen(name + 1)];
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: addition operator is applied to the argument of strlen
+ // CHECK-FIXES: {{^ C \*new_name = new C\[}}std::strlen(name) + 1{{\];$}}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-misplaced-widening-cast-explicit-only.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-misplaced-widening-cast-explicit-only.cpp
new file mode 100644
index 0000000..be12614
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-misplaced-widening-cast-explicit-only.cpp
@@ -0,0 +1,64 @@
+// RUN: %check_clang_tidy %s bugprone-misplaced-widening-cast %t -- -config="{CheckOptions: [{key: bugprone-misplaced-widening-cast.CheckImplicitCasts, value: 0}]}" --
+
+void func(long arg) {}
+
+void assign(int a, int b) {
+ long l;
+
+ l = a * b;
+ l = (long)(a * b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: either cast from 'int' to 'long' is ineffective, or there is loss of precision before the conversion [bugprone-misplaced-widening-cast]
+ l = (long)a * b;
+
+ l = a << 8;
+ l = (long)(a << 8);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: either cast from 'int' to 'long'
+ l = (long)b << 8;
+
+ l = static_cast<long>(a * b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: either cast from 'int' to 'long'
+}
+
+void compare(int a, int b, long c) {
+ bool l;
+
+ l = a * b == c;
+ l = c == a * b;
+ l = (long)(a * b) == c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: either cast from 'int' to 'long'
+ l = c == (long)(a * b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: either cast from 'int' to 'long'
+ l = (long)a * b == c;
+ l = c == (long)a * b;
+}
+
+void init(unsigned int n) {
+ long l1 = n << 8;
+ long l2 = (long)(n << 8);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: either cast from 'unsigned int' to 'long'
+ long l3 = (long)n << 8;
+}
+
+void call(unsigned int n) {
+ func(n << 8);
+ func((long)(n << 8));
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: either cast from 'unsigned int' to 'long'
+ func((long)n << 8);
+}
+
+long ret(int a) {
+ if (a < 0) {
+ return a * 1000;
+ } else if (a > 0) {
+ return (long)(a * 1000);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: either cast from 'int' to 'long'
+ } else {
+ return (long)a * 1000;
+ }
+}
+
+// Shall not generate an assert. https://bugs.llvm.org/show_bug.cgi?id=33660
+template <class> class A {
+ enum Type {};
+ static char *m_fn1() { char p = (Type)(&p - m_fn1()); }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-misplaced-widening-cast-implicit-enabled.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-misplaced-widening-cast-implicit-enabled.cpp
new file mode 100644
index 0000000..5487b33
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-misplaced-widening-cast-implicit-enabled.cpp
@@ -0,0 +1,101 @@
+// RUN: %check_clang_tidy %s bugprone-misplaced-widening-cast %t -- -config="{CheckOptions: [{key: bugprone-misplaced-widening-cast.CheckImplicitCasts, value: 1}]}" --
+
+void func(long arg) {}
+
+void assign(int a, int b) {
+ long l;
+
+ l = a * b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: either cast from 'int' to 'long' is ineffective, or there is loss of precision before the conversion [bugprone-misplaced-widening-cast]
+ l = (long)(a * b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: either cast from 'int' to 'long'
+ l = (long)a * b;
+
+ l = a << 8;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: either cast from 'int' to 'long'
+ l = (long)(a << 8);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: either cast from 'int' to 'long'
+ l = (long)b << 8;
+
+ l = static_cast<long>(a * b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: either cast from 'int' to 'long'
+}
+
+void compare(int a, int b, long c) {
+ bool l;
+
+ l = a * b == c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: either cast from 'int' to 'long'
+ l = c == a * b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: either cast from 'int' to 'long'
+ l = (long)(a * b) == c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: either cast from 'int' to 'long'
+ l = c == (long)(a * b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: either cast from 'int' to 'long'
+ l = (long)a * b == c;
+ l = c == (long)a * b;
+}
+
+void init(unsigned int n) {
+ long l1 = n << 8;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: either cast from 'unsigned int' to 'long'
+ long l2 = (long)(n << 8);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: either cast from 'unsigned int' to 'long'
+ long l3 = (long)n << 8;
+}
+
+void call(unsigned int n) {
+ func(n << 8);
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: either cast from 'unsigned int' to 'long'
+ func((long)(n << 8));
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: either cast from 'unsigned int' to 'long'
+ func((long)n << 8);
+}
+
+long ret(int a) {
+ if (a < 0) {
+ return a * 1000;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: either cast from 'int' to 'long'
+ } else if (a > 0) {
+ return (long)(a * 1000);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: either cast from 'int' to 'long'
+ } else {
+ return (long)a * 1000;
+ }
+}
+
+void dontwarn1(unsigned char a, int i, unsigned char *p) {
+ long l;
+ // The result is a 9 bit value, there is no truncation in the implicit cast.
+ l = (long)(a + 15);
+ // The result is a 12 bit value, there is no truncation in the implicit cast.
+ l = (long)(a << 4);
+ // The result is a 3 bit value, there is no truncation in the implicit cast.
+ l = (long)((i % 5) + 1);
+ // The result is a 16 bit value, there is no truncation in the implicit cast.
+ l = (long)(((*p) << 8) + *(p + 1));
+}
+
+template <class T> struct DontWarn2 {
+ void assign(T a, T b) {
+ long l;
+ l = (long)(a * b);
+ }
+};
+DontWarn2<int> DW2;
+
+// Cast is not suspicious when casting macro.
+#define A (X<<2)
+long macro1(int X) {
+ return (long)A;
+}
+
+// Don't warn about cast in macro.
+#define B(X,Y) (long)(X*Y)
+long macro2(int x, int y) {
+ return B(x,y);
+}
+
+void floatingpoint(float a, float b) {
+ double d = (double)(a * b); // Currently we don't warn for this.
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-move-forwarding-reference.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-move-forwarding-reference.cpp
new file mode 100644
index 0000000..befca29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-move-forwarding-reference.cpp
@@ -0,0 +1,125 @@
+// RUN: %check_clang_tidy %s bugprone-move-forwarding-reference %t -- -- -std=c++14 -fno-delayed-template-parsing
+
+namespace std {
+template <typename> struct remove_reference;
+
+template <typename _Tp> struct remove_reference { typedef _Tp type; };
+
+template <typename _Tp> struct remove_reference<_Tp &> { typedef _Tp type; };
+
+template <typename _Tp> struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template <typename _Tp>
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t);
+
+} // namespace std
+
+// Standard case.
+template <typename T, typename U> void f1(U &&SomeU) {
+ T SomeT(std::move(SomeU));
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+ // CHECK-FIXES: T SomeT(std::forward<U>(SomeU));
+}
+
+// Ignore parentheses around the argument to std::move().
+template <typename T, typename U> void f2(U &&SomeU) {
+ T SomeT(std::move((SomeU)));
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+ // CHECK-FIXES: T SomeT(std::forward<U>((SomeU)));
+}
+
+// Handle the case correctly where std::move() is being used through a using
+// declaration.
+template <typename T, typename U> void f3(U &&SomeU) {
+ using std::move;
+ T SomeT(move(SomeU));
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+ // CHECK-FIXES: T SomeT(std::forward<U>(SomeU));
+}
+
+// Handle the case correctly where a global specifier is prepended to
+// std::move().
+template <typename T, typename U> void f4(U &&SomeU) {
+ T SomeT(::std::move(SomeU));
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+ // CHECK-FIXES: T SomeT(::std::forward<U>(SomeU));
+}
+
+// Create a correct fix if there are spaces around the scope resolution
+// operator.
+template <typename T, typename U> void f5(U &&SomeU) {
+ {
+ T SomeT(:: std :: move(SomeU));
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+ // CHECK-FIXES: T SomeT(::std::forward<U>(SomeU));
+ }
+ {
+ T SomeT(std :: move(SomeU));
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: forwarding reference passed to
+ // CHECK-FIXES: T SomeT(std::forward<U>(SomeU));
+ }
+}
+
+// Ignore const rvalue reference parameters.
+template <typename T, typename U> void f6(const U &&SomeU) {
+ T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the argument to std::move() is a lambda parameter (and
+// thus not actually a parameter of the function template).
+template <typename T, typename U> void f7() {
+ [](U &&SomeU) { T SomeT(std::move(SomeU)); };
+}
+
+// Ignore the case where the argument is a lvalue reference.
+template <typename T, typename U> void f8(U &SomeU) {
+ T SomeT(std::move(SomeU));
+}
+
+// Ignore the case where the template parameter is a class template parameter
+// (i.e. no template argument deduction is taking place).
+template <typename T, typename U> class SomeClass {
+ void f(U &&SomeU) { T SomeT(std::move(SomeU)); }
+};
+
+// Ignore the case where the function parameter in the template isn't an rvalue
+// reference but the template argument is explicitly set to be an rvalue
+// reference.
+class A {};
+template <typename T> void foo(T);
+void f8() {
+ A a;
+ foo<A &&>(std::move(a));
+}
+
+// A warning is output, but no fix is suggested, if a macro is used to rename
+// std::move.
+#define MOVE(x) std::move((x))
+template <typename T, typename U> void f9(U &&SomeU) {
+ T SomeT(MOVE(SomeU));
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the argument is passed outside of the macro.
+#undef MOVE
+#define MOVE std::move
+template <typename T, typename U> void f10(U &&SomeU) {
+ T SomeT(MOVE(SomeU));
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Same result if the macro does not include the "std" namespace.
+#undef MOVE
+#define MOVE move
+template <typename T, typename U> void f11(U &&SomeU) {
+ T SomeT(std::MOVE(SomeU));
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: forwarding reference passed to
+}
+
+// Handle the case correctly where the forwarding reference is a parameter of a
+// generic lambda.
+template <typename T> void f12() {
+ [] (auto&& x) { T SomeT(std::move(x)); };
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: forwarding reference passed to
+ // CHECK-FIXES: [] (auto&& x) { T SomeT(std::forward<decltype(x)>(x)); }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-multiple-statement-macro.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-multiple-statement-macro.cpp
new file mode 100644
index 0000000..5b88d8d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-multiple-statement-macro.cpp
@@ -0,0 +1,85 @@
+// RUN: %check_clang_tidy %s bugprone-multiple-statement-macro %t
+
+void F();
+
+#define BAD_MACRO(x) \
+ F(); \
+ F()
+
+#define GOOD_MACRO(x) \
+ do { \
+ F(); \
+ F(); \
+ } while (0)
+
+#define GOOD_MACRO2(x) F()
+
+#define GOOD_MACRO3(x) F();
+
+#define MACRO_ARG_MACRO(X) \
+ if (54) \
+ X(2)
+
+#define ALL_IN_MACRO(X) \
+ if (43) \
+ F(); \
+ F()
+
+#define GOOD_NESTED(x) \
+ if (x) \
+ GOOD_MACRO3(x); \
+ F();
+
+#define IF(x) if(x)
+
+void positives() {
+ if (1)
+ BAD_MACRO(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: multiple statement macro used without braces; some statements will be unconditionally executed [bugprone-multiple-statement-macro]
+ if (1) {
+ } else
+ BAD_MACRO(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: multiple statement macro used
+ while (1)
+ BAD_MACRO(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: multiple statement macro used
+ for (;;)
+ BAD_MACRO(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: multiple statement macro used
+
+ MACRO_ARG_MACRO(BAD_MACRO);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: multiple statement macro used
+ MACRO_ARG_MACRO(F(); int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: multiple statement macro used
+ IF(1) BAD_MACRO(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: multiple statement macro used
+}
+
+void negatives() {
+ if (1) {
+ BAD_MACRO(1);
+ } else {
+ BAD_MACRO(1);
+ }
+ while (1) {
+ BAD_MACRO(1);
+ }
+ for (;;) {
+ BAD_MACRO(1);
+ }
+
+ if (1)
+ GOOD_MACRO(1);
+ if (1) {
+ GOOD_MACRO(1);
+ }
+ if (1)
+ GOOD_MACRO2(1);
+ if (1)
+ GOOD_MACRO3(1);
+
+ MACRO_ARG_MACRO(GOOD_MACRO);
+ ALL_IN_MACRO(1);
+
+ IF(1) GOOD_MACRO(1);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-parent-virtual-call.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-parent-virtual-call.cpp
new file mode 100755
index 0000000..ad84588
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-parent-virtual-call.cpp
@@ -0,0 +1,179 @@
+// RUN: %check_clang_tidy %s bugprone-parent-virtual-call %t
+
+extern int foo();
+
+class A {
+public:
+ A() = default;
+ virtual ~A() = default;
+
+ virtual int virt_1() { return foo() + 1; }
+ virtual int virt_2() { return foo() + 2; }
+
+ int non_virt() { return foo() + 3; }
+ static int stat() { return foo() + 4; }
+};
+
+class B : public A {
+public:
+ B() = default;
+
+ // Nothing to fix: calls to direct parent.
+ int virt_1() override { return A::virt_1() + 3; }
+ int virt_2() override { return A::virt_2() + 4; }
+};
+
+class C : public B {
+public:
+ int virt_1() override { return A::virt_1() + B::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' refers to a member overridden in subclass; did you mean 'B'? [bugprone-parent-virtual-call]
+ // CHECK-FIXES: int virt_1() override { return B::virt_1() + B::virt_1(); }
+ int virt_2() override { return A::virt_1() + B::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'B'? {{.*}}
+ // CHECK-FIXES: int virt_2() override { return B::virt_1() + B::virt_1(); }
+
+ // Test that non-virtual and static methods are not affected by this cherker.
+ int method_c() { return A::stat() + A::non_virt(); }
+};
+
+// Check aliased type names
+using A1 = A;
+typedef A A2;
+#define A3 A
+
+class C2 : public B {
+public:
+ int virt_1() override { return A1::virt_1() + A2::virt_1() + A3::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A1::virt_1' {{.*}}; did you mean 'B'? {{.*}}
+ // CHECK-MESSAGES: :[[@LINE-2]]:49: warning: qualified name 'A2::virt_1' {{.*}}; did you mean 'B'? {{.*}}
+ // CHECK-MESSAGES: :[[@LINE-3]]:64: warning: qualified name 'A3::virt_1' {{.*}}; did you mean 'B'? {{.*}}
+ // CHECK-FIXES: int virt_1() override { return B::virt_1() + B::virt_1() + B::virt_1(); }
+};
+
+// Test that the check affects grand-grand..-parent calls too.
+class D : public C {
+public:
+ int virt_1() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'C'? {{.*}}
+ // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: qualified name 'B::virt_1' {{.*}}; did you mean 'C'? {{.*}}
+ // CHECK-FIXES: int virt_1() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+ int virt_2() override { return A::virt_1() + B::virt_1() + D::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'C'? {{.*}}
+ // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: qualified name 'B::virt_1' {{.*}}; did you mean 'C'? {{.*}}
+ // CHECK-FIXES: int virt_2() override { return C::virt_1() + C::virt_1() + D::virt_1(); }
+};
+
+// Test classes in namespaces.
+namespace {
+class BN : public A {
+public:
+ int virt_1() override { return A::virt_1() + 3; }
+ int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace
+
+namespace N1 {
+class A {
+public:
+ A() = default;
+ virtual int virt_1() { return foo() + 1; }
+ virtual int virt_2() { return foo() + 2; }
+};
+} // namespace N1
+
+namespace N2 {
+class BN : public N1::A {
+public:
+ int virt_1() override { return A::virt_1() + 3; }
+ int virt_2() override { return A::virt_2() + 4; }
+};
+} // namespace N2
+
+class CN : public BN {
+public:
+ int virt_1() override { return A::virt_1() + BN::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'BN'? {{.*}}
+ // CHECK-FIXES: int virt_1() override { return BN::virt_1() + BN::virt_1(); }
+ int virt_2() override { return A::virt_1() + BN::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'BN'? {{.*}}
+ // CHECK-FIXES: int virt_2() override { return BN::virt_1() + BN::virt_1(); }
+};
+
+class CNN : public N2::BN {
+public:
+ int virt_1() override { return N1::A::virt_1() + N2::BN::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'N1::A::virt_1' {{.*}}; did you mean 'N2::BN'? {{.*}}
+ // CHECK-FIXES: int virt_1() override { return N2::BN::virt_1() + N2::BN::virt_1(); }
+ int virt_2() override { return N1::A::virt_1() + N2::BN::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'N1::A::virt_1' {{.*}}; did you mean 'N2::BN'? {{.*}}
+ // CHECK-FIXES: int virt_2() override { return N2::BN::virt_1() + N2::BN::virt_1(); }
+};
+
+// Test multiple inheritance fixes
+class AA {
+public:
+ AA() = default;
+ virtual ~AA() = default;
+
+ virtual int virt_1() { return foo() + 1; }
+ virtual int virt_2() { return foo() + 2; }
+
+ int non_virt() { return foo() + 3; }
+ static int stat() { return foo() + 4; }
+};
+
+class BB_1 : virtual public AA {
+public:
+ BB_1() = default;
+
+ // Nothing to fix: calls to parent.
+ int virt_1() override { return AA::virt_1() + 3; }
+ int virt_2() override { return AA::virt_2() + 4; }
+};
+
+class BB_2 : virtual public AA {
+public:
+ BB_2() = default;
+ int virt_1() override { return AA::virt_1() + 3; }
+};
+
+class CC : public BB_1, public BB_2 {
+public:
+ int virt_1() override { return AA::virt_1() + 3; }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'AA::virt_1' refers to a member overridden in subclasses; did you mean 'BB_1' or 'BB_2'? {{.*}}
+ // No fix available due to multiple choice of parent class.
+};
+
+// Test that virtual method is not diagnosed as not overridden in parent.
+class BI : public A {
+public:
+ BI() = default;
+};
+
+class CI : BI {
+ int virt_1() override { return A::virt_1(); }
+};
+
+// Test templated classes.
+template <class F> class BF : public A {
+public:
+ int virt_1() override { return A::virt_1() + 3; }
+};
+
+// Test templated parent class.
+class CF : public BF<int> {
+public:
+ int virt_1() override { return A::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'BF'? {{.*}}
+};
+
+// Test both templated class and its parent class.
+template <class F> class DF : public BF<F> {
+public:
+ DF() = default;
+ int virt_1() override { return A::virt_1(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: qualified name 'A::virt_1' {{.*}}; did you mean 'BF'? {{.*}}
+};
+
+// Just to instantiate DF<F>.
+int bar() { return (new DF<int>())->virt_1(); }
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-sizeof-container.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-sizeof-container.cpp
new file mode 100644
index 0000000..27798d6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-sizeof-container.cpp
@@ -0,0 +1,103 @@
+// RUN: %check_clang_tidy %s bugprone-sizeof-container %t -- -- -std=c++11 -target x86_64-unknown-unknown
+
+namespace std {
+
+typedef unsigned int size_t;
+
+template <typename T>
+struct basic_string {
+ size_t size() const;
+};
+
+template <typename T>
+basic_string<T> operator+(const basic_string<T> &, const T *);
+
+typedef basic_string<char> string;
+
+template <typename T>
+struct vector {
+ size_t size() const;
+};
+
+// std::bitset<> is not a container. sizeof() is reasonable for it.
+template <size_t N>
+struct bitset {
+ size_t size() const;
+};
+
+// std::array<> is, well, an array. sizeof() is reasonable for it.
+template <typename T, size_t N>
+struct array {
+ size_t size() const;
+};
+
+class fake_container1 {
+ size_t size() const; // non-public
+};
+
+struct fake_container2 {
+ size_t size(); // non-const
+};
+
+}
+
+using std::size_t;
+
+#define ARRAYSIZE(a) \
+ ((sizeof(a) / sizeof(*(a))) / static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+
+#define ARRAYSIZE2(a) \
+ (((sizeof(a)) / (sizeof(*(a)))) / static_cast<size_t>(!((sizeof(a)) % (sizeof(*(a))))))
+
+struct string {
+ std::size_t size() const;
+};
+
+template<typename T>
+void g(T t) {
+ (void)sizeof(t);
+}
+
+void f() {
+ string s1;
+ std::string s2;
+ std::vector<int> v;
+
+ int a = 42 + sizeof(s1);
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: sizeof() doesn't return the size of the container; did you mean .size()? [bugprone-sizeof-container]
+ a = 123 * sizeof(s2);
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: sizeof() doesn't return the size
+ a = 45 + sizeof(s2 + "asdf");
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: sizeof() doesn't return the size
+ a = sizeof(v);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: sizeof() doesn't return the size
+ a = sizeof(std::vector<int>{});
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: sizeof() doesn't return the size
+
+ a = sizeof(a);
+ a = sizeof(int);
+ a = sizeof(std::string);
+ a = sizeof(std::vector<int>);
+
+ g(s1);
+ g(s2);
+ g(v);
+
+ std::fake_container1 fake1;
+ std::fake_container2 fake2;
+ std::bitset<7> std_bitset;
+ std::array<int, 3> std_array;
+
+ a = sizeof(fake1);
+ a = sizeof(fake2);
+ a = sizeof(std_bitset);
+ a = sizeof(std_array);
+
+
+ std::string arr[3];
+ a = ARRAYSIZE(arr);
+ a = ARRAYSIZE2(arr);
+ a = sizeof(arr) / sizeof(arr[0]);
+
+ (void)a;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-sizeof-expression.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-sizeof-expression.cpp
new file mode 100644
index 0000000..683ad08
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-sizeof-expression.cpp
@@ -0,0 +1,256 @@
+// RUN: %check_clang_tidy %s bugprone-sizeof-expression %t -- -config="{CheckOptions: [{key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression, value: 1}]}" --
+
+class C {
+ int size() { return sizeof(this); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: suspicious usage of 'sizeof(this)'
+};
+
+#define LEN 8
+
+int X;
+extern int A[10];
+extern short B[10];
+
+#pragma pack(1)
+struct S { char a, b, c; };
+
+enum E { E_VALUE = 0 };
+enum class EC { VALUE = 0 };
+
+bool AsBool() { return false; }
+int AsInt() { return 0; }
+E AsEnum() { return E_VALUE; }
+EC AsEnumClass() { return EC::VALUE; }
+S AsStruct() { return {}; }
+
+struct M {
+ int AsInt() { return 0; }
+ E AsEnum() { return E_VALUE; }
+ S AsStruct() { return {}; }
+};
+
+int ReturnOverload(int) { return {}; }
+S ReturnOverload(S) { return {}; }
+
+template <class T>
+T ReturnTemplate(T) { return {}; }
+
+template <class T>
+bool TestTrait1() {
+ return sizeof(ReturnOverload(T{})) == sizeof(A);
+}
+
+template <class T>
+bool TestTrait2() {
+ return sizeof(ReturnTemplate(T{})) == sizeof(A);
+}
+
+template <class T>
+bool TestTrait3() {
+ return sizeof(ReturnOverload(0)) == sizeof(T{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+}
+
+template <class T>
+bool TestTrait4() {
+ return sizeof(ReturnTemplate(0)) == sizeof(T{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+}
+
+bool TestTemplates() {
+ bool b = true;
+ b &= TestTrait1<int>();
+ b &= TestTrait1<S>();
+ b &= TestTrait2<int>();
+ b &= TestTrait2<S>();
+ b &= TestTrait3<int>();
+ b &= TestTrait3<S>();
+ b &= TestTrait4<int>();
+ b &= TestTrait4<S>();
+ return b;
+}
+
+int Test1(const char* ptr) {
+ int sum = 0;
+ sum += sizeof(LEN);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(K)'
+ sum += sizeof(LEN + 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(K)'
+ sum += sizeof(sum, LEN);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(..., ...)'
+ sum += sizeof(AsBool());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+ sum += sizeof(AsInt());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+ sum += sizeof(AsEnum());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+ sum += sizeof(AsEnumClass());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+ sum += sizeof(M{}.AsInt());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+ sum += sizeof(M{}.AsEnum());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof()' on an expression that results in an integer
+ sum += sizeof(sizeof(X));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
+ sum += sizeof(LEN + sizeof(X));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
+ sum += sizeof(LEN + LEN + sizeof(X));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
+ sum += sizeof(LEN + (LEN + sizeof(X)));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
+ sum += sizeof(LEN + -sizeof(X));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
+ sum += sizeof(LEN + - + -sizeof(X));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(sizeof(...))'
+ sum += sizeof(char) / sizeof(char);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T)/sizeof(T)'
+ sum += sizeof(A) / sizeof(S);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
+ sum += sizeof(char) / sizeof(int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
+ sum += sizeof(char) / sizeof(A);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
+ sum += sizeof(B[0]) / sizeof(A);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(...)/sizeof(...)'; numerator is not a multiple of denominator
+ sum += sizeof(ptr) / sizeof(char);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T*)/sizeof(T)'
+ sum += sizeof(ptr) / sizeof(ptr[0]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T*)/sizeof(T)'
+ sum += sizeof(ptr) / sizeof(char*);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(P*)/sizeof(Q*)'
+ sum += sizeof(ptr) / sizeof(void*);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(P*)/sizeof(Q*)'
+ sum += sizeof(ptr) / sizeof(const void volatile*);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(P*)/sizeof(Q*)'
+ sum += sizeof(ptr) / sizeof(char);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T*)/sizeof(T)'
+ sum += sizeof(ptr) / sizeof(ptr[0]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T*)/sizeof(T)'
+ sum += sizeof(int) * sizeof(char);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious 'sizeof' by 'sizeof' multiplication
+ sum += sizeof(ptr) * sizeof(ptr[0]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious 'sizeof' by 'sizeof' multiplication
+ sum += sizeof(int) * (2 * sizeof(char));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious 'sizeof' by 'sizeof' multiplication
+ sum += (2 * sizeof(char)) * sizeof(int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious 'sizeof' by 'sizeof' multiplication
+ if (sizeof(A) < 0x100000) sum += 42;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: suspicious comparison of 'sizeof(expr)' to a constant
+ if (sizeof(A) <= 0xFFFFFFFEU) sum += 42;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: suspicious comparison of 'sizeof(expr)' to a constant
+ return sum;
+}
+
+typedef char MyChar;
+typedef const MyChar MyConstChar;
+
+int CE0 = sizeof sizeof(char);
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
+int CE1 = sizeof +sizeof(char);
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
+int CE2 = sizeof sizeof(const char*);
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
+int CE3 = sizeof sizeof(const volatile char* const*);
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
+int CE4 = sizeof sizeof(MyConstChar);
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(sizeof(...))'
+
+int Test2(MyConstChar* A) {
+ int sum = 0;
+ sum += sizeof(MyConstChar) / sizeof(char);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T)/sizeof(T)'
+ sum += sizeof(MyConstChar) / sizeof(MyChar);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T)/sizeof(T)'
+ sum += sizeof(A[0]) / sizeof(char);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of sizeof pointer 'sizeof(T)/sizeof(T)'
+ return sum;
+}
+
+template <int T>
+int Foo() { int A[T]; return sizeof(T); }
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: suspicious usage of 'sizeof(K)'
+template <typename T>
+int Bar() { T A[5]; return sizeof(A[0]) / sizeof(T); }
+// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: suspicious usage of sizeof pointer 'sizeof(T)/sizeof(T)'
+int Test3() { return Foo<42>() + Bar<char>(); }
+
+static const char* kABC = "abc";
+static const wchar_t* kDEF = L"def";
+int Test4(const char A[10]) {
+ int sum = 0;
+ sum += sizeof(kABC);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(char*)'
+ sum += sizeof(kDEF);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(char*)'
+ return sum;
+}
+
+int Test5() {
+ typedef int Array10[10];
+
+ struct MyStruct {
+ Array10 arr;
+ Array10* ptr;
+ };
+ typedef const MyStruct TMyStruct;
+
+ static TMyStruct kGlocalMyStruct = {};
+ static TMyStruct volatile * kGlocalMyStructPtr = &kGlocalMyStruct;
+
+ MyStruct S;
+ Array10 A10;
+
+ int sum = 0;
+ sum += sizeof(&S.arr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(&kGlocalMyStruct.arr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(&kGlocalMyStructPtr->arr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(S.arr + 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(+ S.arr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof((int*)S.arr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+
+ sum += sizeof(S.ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(kGlocalMyStruct.ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(kGlocalMyStructPtr->ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+
+ sum += sizeof(&kGlocalMyStruct);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(&S);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+ sum += sizeof(&A10);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: suspicious usage of 'sizeof(A*)'; pointer to aggregate
+
+ return sum;
+}
+
+int ValidExpressions() {
+ int A[] = {1, 2, 3, 4};
+ static const char str[] = "hello";
+ static const char* ptr[] { "aaa", "bbb", "ccc" };
+ int sum = 0;
+ if (sizeof(A) < 10)
+ sum += sizeof(A);
+ sum += sizeof(int);
+ sum += sizeof(AsStruct());
+ sum += sizeof(M{}.AsStruct());
+ sum += sizeof(A[sizeof(A) / sizeof(int)]);
+ sum += sizeof(&A[sizeof(A) / sizeof(int)]);
+ sum += sizeof(sizeof(0)); // Special case: sizeof size_t.
+ sum += sizeof(void*);
+ sum += sizeof(void const *);
+ sum += sizeof(void const *) / 4;
+ sum += sizeof(str);
+ sum += sizeof(str) / sizeof(char);
+ sum += sizeof(str) / sizeof(str[0]);
+ sum += sizeof(ptr) / sizeof(ptr[0]);
+ sum += sizeof(ptr) / sizeof(*(ptr));
+ return sum;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-string-constructor.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-string-constructor.cpp
new file mode 100644
index 0000000..51d9130
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-string-constructor.cpp
@@ -0,0 +1,56 @@
+// RUN: %check_clang_tidy %s bugprone-string-constructor %t
+
+namespace std {
+template <typename T>
+class allocator {};
+template <typename T>
+class char_traits {};
+template <typename C, typename T = std::char_traits<C>, typename A = std::allocator<C> >
+struct basic_string {
+ basic_string();
+ basic_string(const C*, unsigned int size);
+ basic_string(unsigned int size, C c);
+};
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+}
+
+const char* kText = "";
+const char kText2[] = "";
+extern const char kText3[];
+
+void Test() {
+ std::string str('x', 4);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: string constructor parameters are probably swapped; expecting string(count, character) [bugprone-string-constructor]
+ // CHECK-FIXES: std::string str(4, 'x');
+ std::wstring wstr(L'x', 4);
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: string constructor parameters are probably swapped
+ // CHECK-FIXES: std::wstring wstr(4, L'x');
+ std::string s0(0, 'x');
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructor creating an empty string
+ std::string s1(-4, 'x');
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: negative value used as length parameter
+ std::string s2(0x1000000, 'x');
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+
+ std::string q0("test", 0);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructor creating an empty string
+ std::string q1(kText, -4);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: negative value used as length parameter
+ std::string q2("test", 200);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string literal size
+ std::string q3(kText, 200);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string literal size
+ std::string q4(kText2, 200);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string literal size
+ std::string q5(kText3, 0x1000000);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+}
+
+void Valid() {
+ std::string empty();
+ std::string str(4, 'x');
+ std::wstring wstr(4, L'x');
+ std::string s1("test", 4);
+ std::string s2("test", 3);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp
new file mode 100644
index 0000000..c4e13fc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -0,0 +1,53 @@
+// RUN: %check_clang_tidy %s bugprone-string-integer-assignment %t
+
+namespace std {
+template<typename T>
+struct basic_string {
+ basic_string& operator=(T);
+ basic_string& operator=(basic_string);
+ basic_string& operator+=(T);
+ basic_string& operator+=(basic_string);
+};
+
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+}
+
+typedef int MyArcaneChar;
+
+int main() {
+ std::string s;
+ std::wstring ws;
+ int x = 5;
+
+ s = 6;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a character code when assigning {{.*}} [bugprone-string-integer-assignment]
+// CHECK-FIXES: {{^}} s = '6';{{$}}
+ s = 66;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} s = "66";{{$}}
+ s = x;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} s = std::to_string(x);{{$}}
+ s = 'c';
+ s = static_cast<char>(6);
+
+// +=
+ ws += 6;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} ws += L'6';{{$}}
+ ws += 66;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} ws += L"66";{{$}}
+ ws += x;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} ws += std::to_wstring(x);{{$}}
+ ws += L'c';
+ ws += (wchar_t)6;
+
+ std::basic_string<MyArcaneChar> as;
+ as = 6;
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+// CHECK-FIXES: {{^}} as = 6;{{$}}
+
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-string-literal-with-embedded-nul.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-string-literal-with-embedded-nul.cpp
new file mode 100644
index 0000000..f939f52
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-string-literal-with-embedded-nul.cpp
@@ -0,0 +1,85 @@
+// RUN: %check_clang_tidy %s bugprone-string-literal-with-embedded-nul %t
+
+namespace std {
+template <typename T>
+class allocator {};
+template <typename T>
+class char_traits {};
+template <typename C, typename T, typename A>
+struct basic_string {
+ typedef basic_string<C, T, A> _Type;
+ basic_string();
+ basic_string(const C *p, const A &a = A());
+
+ _Type& operator+=(const C* s);
+ _Type& operator=(const C* s);
+};
+
+typedef basic_string<char, std::char_traits<char>, std::allocator<char>> string;
+typedef basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>> wstring;
+}
+
+bool operator==(const std::string&, const char*);
+bool operator==(const char*, const std::string&);
+
+
+const char Valid[] = "This is valid \x12.";
+const char Strange[] = "This is strange \0x12 and must be fixed";
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: suspicious embedded NUL character [bugprone-string-literal-with-embedded-nul]
+
+const char textA[] = "\0x01\0x02\0x03\0x04";
+// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: suspicious embedded NUL character
+const wchar_t textW[] = L"\0x01\0x02\0x03\0x04";
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: suspicious embedded NUL character
+
+const char A[] = "\0";
+const char B[] = "\0x";
+const char C[] = "\0x1";
+const char D[] = "\0x11";
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: suspicious embedded NUL character
+
+const wchar_t E[] = L"\0";
+const wchar_t F[] = L"\0x";
+const wchar_t G[] = L"\0x1";
+const wchar_t H[] = L"\0x11";
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: suspicious embedded NUL character
+
+const char I[] = "\000\000\000\000";
+const char J[] = "\0\0\0\0\0\0";
+const char K[] = "";
+
+const char L[] = "\0x12" "\0x12" "\0x12" "\0x12";
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: suspicious embedded NUL character
+
+void TestA() {
+ std::string str1 = "abc\0def";
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: truncated string literal
+ std::string str2 = "\0";
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: truncated string literal
+ std::string str3("\0");
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: truncated string literal
+ std::string str4{"\x00\x01\x02\x03"};
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: truncated string literal
+
+ std::string str;
+ str += "abc\0def";
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: truncated string literal
+ str = "abc\0def";
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: truncated string literal
+
+ if (str == "abc\0def") return;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: truncated string literal
+ if ("abc\0def" == str) return;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: truncated string literal
+}
+
+void TestW() {
+ std::wstring str1 = L"abc\0def";
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: truncated string literal
+ std::wstring str2 = L"\0";
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: truncated string literal
+ std::wstring str3(L"\0");
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: truncated string literal
+ std::wstring str4{L"\x00\x01\x02\x03"};
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: truncated string literal
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-enum-usage-strict.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-enum-usage-strict.cpp
new file mode 100644
index 0000000..d9ed8ce
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-enum-usage-strict.cpp
@@ -0,0 +1,98 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-enum-usage %t -- -config="{CheckOptions: [{key: bugprone-suspicious-enum-usage.StrictMode, value: 1}]}" --
+
+enum A {
+ A = 1,
+ B = 2,
+ C = 4,
+ D = 8,
+ E = 16,
+ F = 32,
+ G = 63
+};
+
+// CHECK-MESSAGES: :[[@LINE+2]]:1: warning: enum type seems like a bitmask (contains mostly power-of-2 literals) but a literal is not power-of-2
+// CHECK-MESSAGES: :76:7: note: used here as a bitmask
+enum X {
+ X = 8,
+ Y = 16,
+ Z = 4,
+ ZZ = 3
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: enum type seems like a bitmask (contains mostly power-of-2 literals), but this literal is not a power-of-2 [bugprone-suspicious-enum-usage]
+// CHECK-MESSAGES: :70:13: note: used here as a bitmask
+};
+// CHECK-MESSAGES: :[[@LINE+2]]:1: warning: enum type seems like a bitmask (contains mostly power-of-2 literals) but some literals are not power-of-2
+// CHECK-MESSAGES: :73:8: note: used here as a bitmask
+enum PP {
+ P = 2,
+ Q = 3,
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: enum type seems like a bitmask (contains mostly power-of-2 literals), but this literal is not a power-of-2
+ // CHECK-MESSAGES: :65:11: note: used here as a bitmask
+ R = 4,
+ S = 8,
+ T = 16,
+ U = 31
+};
+
+enum {
+ H,
+ I,
+ J,
+ K,
+ L
+};
+
+enum Days {
+ Monday,
+ Tuesday,
+ Wednesday,
+ Thursday,
+ Friday,
+ Saturday,
+ Sunday
+};
+
+Days bestDay() {
+ return Friday;
+}
+
+int trigger() {
+ if (bestDay() | A)
+ return 1;
+ // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different enum types
+ if (I | Y)
+ return 1;
+ // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different enum types
+ if (P + Q == R)
+ return 1;
+ else if ((S | R) == T)
+ return 1;
+ else
+ int k = ZZ | Z;
+ unsigned p = R;
+ PP pp = Q;
+ p |= pp;
+
+ enum X x = Z;
+ p = x | Z;
+ return 0;
+}
+
+int dont_trigger() {
+ int a = 1, b = 5;
+ int c = a + b;
+ int d = c | H, e = b * a;
+ a = B | C;
+ b = X | Z;
+
+ unsigned bitflag;
+ enum A aa = B;
+ bitflag = aa | C;
+
+ if (Tuesday != Monday + 1 ||
+ Friday - Thursday != 1 ||
+ Sunday + Wednesday == (Sunday | Wednesday))
+ return 1;
+ if (H + I + L == 42)
+ return 1;
+ return 42;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-enum-usage.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-enum-usage.cpp
new file mode 100644
index 0000000..e1a54d4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-enum-usage.cpp
@@ -0,0 +1,96 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-enum-usage %t -- -config="{CheckOptions: [{key: bugprone-suspicious-enum-usage.StrictMode, value: 0}]}" --
+
+enum Empty {
+};
+
+enum A {
+ A = 1,
+ B = 2,
+ C = 4,
+ D = 8,
+ E = 16,
+ F = 32,
+ G = 63
+};
+
+enum X {
+ X = 8,
+ Y = 16,
+ Z = 4
+};
+
+enum {
+ P = 2,
+ Q = 3,
+ R = 4,
+ S = 8,
+ T = 16
+};
+
+enum {
+ H,
+ I,
+ J,
+ K,
+ L
+};
+
+enum Days {
+ Monday,
+ Tuesday,
+ Wednesday,
+ Thursday,
+ Friday,
+ Saturday,
+ Sunday
+};
+
+Days bestDay() {
+ return Friday;
+}
+
+int trigger() {
+ Empty EmptyVal;
+ int emptytest = EmptyVal | B;
+ if (bestDay() | A)
+ return 1;
+ // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: enum values are from different enum types
+ if (I | Y)
+ return 1;
+ // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: enum values are from different enum types
+}
+
+int dont_trigger() {
+ unsigned p;
+ p = Q | P;
+
+ if (A + G == E)
+ return 1;
+ else if ((Q | R) == T)
+ return 1;
+ else
+ int k = T | Q;
+
+ Empty EmptyVal;
+ int emptytest = EmptyVal | B;
+
+ int a = 1, b = 5;
+ int c = a + b;
+ int d = c | H, e = b * a;
+ a = B | C;
+ b = X | Z;
+
+ if (Tuesday != Monday + 1 ||
+ Friday - Thursday != 1 ||
+ Sunday + Wednesday == (Sunday | Wednesday))
+ return 1;
+ if (H + I + L == 42)
+ return 1;
+ return 42;
+}
+
+namespace PR34400 {
+enum { E1 = 0 };
+enum { E2 = -1 };
+enum { l = E1 | E2 };
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-memset-usage.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-memset-usage.cpp
new file mode 100644
index 0000000..f33ae5a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-memset-usage.cpp
@@ -0,0 +1,77 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-memset-usage %t
+
+void *memset(void *, int, __SIZE_TYPE__);
+
+namespace std {
+ using ::memset;
+}
+
+template <typename T>
+void mtempl(int *ptr) {
+ memset(ptr, '0', sizeof(T));
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: memset fill value is char '0', potentially mistaken for int 0 [bugprone-suspicious-memset-usage]
+// CHECK-FIXES: memset(ptr, 0, sizeof(T));
+ memset(ptr, 256, sizeof(T));
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: memset fill value is out of unsigned character range, gets truncated [bugprone-suspicious-memset-usage]
+ memset(0, sizeof(T), 0);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: memset of size zero, potentially swapped arguments [bugprone-suspicious-memset-usage]
+// CHECK-FIXES: memset(0, 0, sizeof(T));
+ memset(0, sizeof(int), 0);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: memset of size zero, potentially swapped arguments [bugprone-suspicious-memset-usage]
+// CHECK-FIXES: memset(0, 0, sizeof(int));
+}
+
+void foo(int xsize, int ysize) {
+ int i[5] = {1, 2, 3, 4, 5};
+ char ca[3] = {'a', 'b', 'c'};
+ int *p = i;
+ int l = 5;
+ char z = '1';
+ char *c = &z;
+ int v = 0;
+
+ memset(p, '0', l);
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: memset fill value is char '0', potentially mistaken for int 0 [bugprone-suspicious-memset-usage]
+// CHECK-FIXES: memset(p, 0, l);
+
+ memset(p, 0xabcd, l);
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: memset fill value is out of unsigned character range, gets truncated [bugprone-suspicious-memset-usage]
+
+ memset(p, sizeof(int), 0);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: memset of size zero, potentially swapped arguments [bugprone-suspicious-memset-usage]
+// CHECK-FIXES: memset(p, 0, sizeof(int));
+ std::memset(p, sizeof(int), 0x00);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: memset of size zero, potentially swapped arguments [bugprone-suspicious-memset-usage]
+// CHECK-FIXES: std::memset(p, 0x00, sizeof(int));
+
+#define M_CHAR_ZERO memset(p, '0', l);
+ M_CHAR_ZERO
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: memset fill value is char '0', potentially mistaken for int 0 [bugprone-suspicious-memset-usage]
+
+#define M_OUTSIDE_RANGE memset(p, 0xabcd, l);
+ M_OUTSIDE_RANGE
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: memset fill value is out of unsigned character range, gets truncated [bugprone-suspicious-memset-usage]
+
+#define M_ZERO_LENGTH memset(p, sizeof(int), 0);
+ M_ZERO_LENGTH
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: memset of size zero, potentially swapped arguments [bugprone-suspicious-memset-usage]
+
+ memset(p, '2', l);
+ memset(p, 0, l);
+ memset(c, '0', 1);
+ memset(ca, '0', sizeof(ca));
+
+ memset(p, 0x00, l);
+ mtempl<int>(p);
+
+ memset(p, sizeof(int), v + 1);
+ memset(p, 0xcd, 1);
+
+ // Don't warn when the fill char and the length are both known to be
+ // zero. No bug is possible.
+ memset(p, 0, v);
+
+ // -1 is clearly not a length by virtue of being negative, so no warning
+ // despite v == 0.
+ memset(p, -1, v);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-missing-comma.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-missing-comma.cpp
new file mode 100644
index 0000000..f039310
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-missing-comma.cpp
@@ -0,0 +1,82 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-missing-comma %t
+
+const char* Cartoons[] = {
+ "Bugs Bunny",
+ "Homer Simpson",
+ "Mickey Mouse",
+ "Bart Simpson",
+ "Charlie Brown" // There is a missing comma here.
+ "Fred Flintstone",
+ "Popeye",
+};
+// CHECK-MESSAGES: :[[@LINE-4]]:3: warning: suspicious string literal, probably missing a comma [bugprone-suspicious-missing-comma]
+
+const wchar_t* Colors[] = {
+ L"Red", L"Yellow", L"Blue", L"Green", L"Purple", L"Rose", L"White", L"Black"
+};
+
+// The following array should not trigger any warnings. There is more than 5
+// elements, but they are all concatenated string literals.
+const char* HttpCommands[] = {
+ "GET / HTTP/1.0\r\n"
+ "\r\n",
+
+ "GET /index.html HTTP/1.0\r\n"
+ "\r\n",
+
+ "GET /favicon.ico HTTP/1.0\r\n"
+ "header: dummy"
+ "\r\n",
+
+ "GET /index.html-en HTTP/1.0\r\n"
+ "\r\n",
+
+ "GET /index.html-fr HTTP/1.0\r\n"
+ "\r\n",
+
+ "GET /index.html-es HTTP/1.0\r\n"
+ "\r\n",
+};
+
+// This array is too small to trigger a warning.
+const char* SmallArray[] = {
+ "a" "b", "c"
+};
+
+// Parentheses should be enough to avoid warnings.
+const char* ParentheseArray[] = {
+ ("a" "b"), "c",
+ ("d"
+ "e"
+ "f"),
+ "g", "h", "i", "j", "k", "l"
+};
+
+// Indentation should be enough to avoid warnings.
+const char* CorrectlyIndentedArray[] = {
+ "This is a long message "
+ "which is spanning over multiple lines."
+ "And this should be fine.",
+ "a", "b", "c", "d", "e", "f",
+ "g", "h", "i", "j", "k", "l"
+};
+
+const char* IncorrectlyIndentedArray[] = {
+ "This is a long message "
+ "which is spanning over multiple lines."
+ "And this should be fine.",
+ "a", "b", "c", "d", "e", "f",
+ "g", "h", "i", "j", "k", "l"
+};
+// CHECK-MESSAGES: :[[@LINE-6]]:3: warning: suspicious string literal, probably missing a comma [bugprone-suspicious-missing-comma]
+
+const char* TooManyConcatenatedTokensArray[] = {
+ "Dummy line",
+ "Dummy line",
+ "a" "b" "c" "d" "e" "f",
+ "g" "h" "i" "j" "k" "l",
+ "Dummy line",
+ "Dummy line",
+ "Dummy line",
+ "Dummy line",
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-semicolon-fail.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-semicolon-fail.cpp
new file mode 100644
index 0000000..45fa226
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-semicolon-fail.cpp
@@ -0,0 +1,28 @@
+// RUN: not clang-tidy %s \
+// RUN: -checks="-*,bugprone-suspicious-semicolon" -- -DERROR 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-ERROR \
+// RUN: -implicit-check-not="{{warning|error}}:"
+// RUN: not clang-tidy %s \
+// RUN: -checks="-*,bugprone-suspicious-semicolon,clang-diagnostic*" \
+// RUN: -- -DWERROR -Wno-everything -Werror=unused-variable 2>&1 \
+// RUN: | FileCheck %s -check-prefix=CHECK-WERROR \
+// RUN: -implicit-check-not="{{warning|error}}:"
+
+// Note: This test verifies that, the checker does not emit any warning for
+// files that do not compile.
+
+bool g();
+
+void f() {
+ if (g());
+ // CHECK-WERROR: :[[@LINE-1]]:11: warning: potentially unintended semicolon [bugprone-suspicious-semicolon]
+#if ERROR
+ int a
+ // CHECK-ERROR: :[[@LINE-1]]:8: error: expected ';' at end of declaration [clang-diagnostic-error]
+#elif WERROR
+ int a;
+ // CHECK-WERROR: :[[@LINE-1]]:7: error: unused variable 'a' [clang-diagnostic-unused-variable]
+#else
+#error "One of ERROR or WERROR should be defined.
+#endif
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-semicolon.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-semicolon.cpp
new file mode 100644
index 0000000..4f9f4c5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-semicolon.cpp
@@ -0,0 +1,117 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-semicolon %t
+
+int x = 5;
+
+void nop();
+
+void correct1()
+{
+ if(x < 5) nop();
+}
+
+void correct2()
+{
+ if(x == 5)
+ nop();
+}
+
+void correct3()
+{
+ if(x > 5)
+ {
+ nop();
+ }
+}
+
+void fail1()
+{
+ if(x > 5); nop();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: potentially unintended semicolon [bugprone-suspicious-semicolon]
+ // CHECK-FIXES: if(x > 5) nop();
+}
+
+void fail2()
+{
+ if(x == 5);
+ nop();
+ // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: potentially unintended semicolon [bugprone-suspicious-semicolon]
+ // CHECK-FIXES: if(x == 5){{$}}
+}
+
+void fail3()
+{
+ if(x < 5);
+ {
+ nop();
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:11: warning: potentially unintended semicolon
+ // CHECK-FIXES: if(x < 5){{$}}
+}
+
+void correct4()
+{
+ while(x % 5 == 1);
+ nop();
+}
+
+void correct5()
+{
+ for(int i = 0; i < x; ++i)
+ ;
+}
+
+void fail4()
+{
+ for(int i = 0; i < x; ++i);
+ nop();
+ // CHECK-MESSAGES: :[[@LINE-2]]:28: warning: potentially unintended semicolon
+ // CHECK-FIXES: for(int i = 0; i < x; ++i){{$}}
+}
+
+void fail5()
+{
+ if(x % 5 == 1);
+ nop();
+ // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: potentially unintended semicolon
+ // CHECK-FIXES: if(x % 5 == 1){{$}}
+}
+
+void fail6() {
+ int a = 0;
+ if (a != 0) {
+ } else if (a != 1);
+ a = 2;
+ // CHECK-MESSAGES: :[[@LINE-2]]:21: warning: potentially unintended semicolon
+ // CHECK-FIXES: } else if (a != 1){{$}}
+}
+
+void fail7() {
+ if (true)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: potentially unintended semicolon
+}
+
+void correct6()
+{
+ do; while(false);
+}
+
+int correct7()
+{
+ int t_num = 0;
+ char c = 'b';
+ char *s = "a";
+ if (s == "(" || s != "'" || c == '"') {
+ t_num += 3;
+ return (c == ')' && c == '\'');
+ }
+
+ return 0;
+}
+
+void correct8() {
+ if (true)
+ ;
+ else {
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-string-compare.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-string-compare.c
new file mode 100644
index 0000000..3b3175a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-string-compare.c
@@ -0,0 +1,79 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-string-compare %t -- \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: bugprone-suspicious-string-compare.WarnOnImplicitComparison, value: 1}, \
+// RUN: {key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison, value: 1}]}' \
+// RUN: -- -std=c99
+
+static const char A[] = "abc";
+
+int strcmp(const char *, const char *);
+
+int test_warning_patterns() {
+ if (strcmp(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result [bugprone-suspicious-string-compare]
+ // CHECK-FIXES: if (strcmp(A, "a") != 0)
+
+ if (strcmp(A, "a") != 0 ||
+ strcmp(A, "b"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result
+ // CHECK-FIXES: strcmp(A, "b") != 0)
+
+ if (strcmp(A, "a") == 1)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (strcmp(A, "a") == -1)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (strcmp(A, "a") < '0')
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (strcmp(A, "a") < 0.)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast
+
+ if (!strcmp(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:8: warning: function 'strcmp' is compared using logical not operator
+ // CHECK-FIXES: if (strcmp(A, "a") == 0)
+}
+
+void test_structure_patterns() {
+ if (strcmp(A, "a")) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: function 'strcmp' is called without explicitly comparing result
+ // CHECK-FIXES: if (strcmp(A, "a") != 0) {}
+
+ while (strcmp(A, "a")) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: function 'strcmp' is called without explicitly comparing result
+ // CHECK-FIXES: while (strcmp(A, "a") != 0) {}
+
+ for (;strcmp(A, "a");) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: function 'strcmp' is called without explicitly comparing result
+ // CHECK-FIXES: for (;strcmp(A, "a") != 0;) {}
+}
+
+int test_valid_patterns() {
+ // The following cases are valid.
+ if (strcmp(A, "a") < 0) return 0;
+ if (strcmp(A, "a") == 0) return 0;
+ if (strcmp(A, "a") <= 0) return 0;
+ if (strcmp(A, "a") == strcmp(A, "b")) return 0;
+ return 1;
+}
+
+int wrapper(const char* a, const char* b) {
+ return strcmp(a, b);
+}
+
+int assignment_wrapper(const char* a, const char* b) {
+ int cmp = strcmp(a, b);
+ return cmp;
+}
+
+int condexpr_wrapper(const char* a, const char* b) {
+ return (a < b) ? strcmp(a, b) : strcmp(b, a);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-string-compare.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-string-compare.cpp
new file mode 100644
index 0000000..c1c24ff
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-suspicious-string-compare.cpp
@@ -0,0 +1,337 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-string-compare %t -- \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: bugprone-suspicious-string-compare.WarnOnImplicitComparison, value: 1}, \
+// RUN: {key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison, value: 1}]}' \
+// RUN: --
+
+typedef __SIZE_TYPE__ size;
+
+struct locale_t {
+ void* dummy;
+} locale;
+
+static const char A[] = "abc";
+static const unsigned char U[] = "abc";
+static const unsigned char V[] = "xyz";
+static const wchar_t W[] = L"abc";
+
+int strlen(const char *);
+
+int memcmp(const void *, const void *, size);
+int wmemcmp(const wchar_t *, const wchar_t *, size);
+int memicmp(const void *, const void *, size);
+int _memicmp(const void *, const void *, size);
+int _memicmp_l(const void *, const void *, size, locale_t);
+
+int strcmp(const char *, const char *);
+int strncmp(const char *, const char *, size);
+int strcasecmp(const char *, const char *);
+int strncasecmp(const char *, const char *, size);
+int stricmp(const char *, const char *);
+int strcmpi(const char *, const char *);
+int strnicmp(const char *, const char *, size);
+int _stricmp(const char *, const char * );
+int _strnicmp(const char *, const char *, size);
+int _stricmp_l(const char *, const char *, locale_t);
+int _strnicmp_l(const char *, const char *, size, locale_t);
+
+int wcscmp(const wchar_t *, const wchar_t *);
+int wcsncmp(const wchar_t *, const wchar_t *, size);
+int wcscasecmp(const wchar_t *, const wchar_t *);
+int wcsicmp(const wchar_t *, const wchar_t *);
+int wcsnicmp(const wchar_t *, const wchar_t *, size);
+int _wcsicmp(const wchar_t *, const wchar_t *);
+int _wcsnicmp(const wchar_t *, const wchar_t *, size);
+int _wcsicmp_l(const wchar_t *, const wchar_t *, locale_t);
+int _wcsnicmp_l(const wchar_t *, const wchar_t *, size, locale_t);
+
+int _mbscmp(const unsigned char *, const unsigned char *);
+int _mbsncmp(const unsigned char *, const unsigned char *, size);
+int _mbsnbcmp(const unsigned char *, const unsigned char *, size);
+int _mbsnbicmp(const unsigned char *, const unsigned char *, size);
+int _mbsicmp(const unsigned char *, const unsigned char *);
+int _mbsnicmp(const unsigned char *, const unsigned char *, size);
+int _mbscmp_l(const unsigned char *, const unsigned char *, locale_t);
+int _mbsncmp_l(const unsigned char *, const unsigned char *, size, locale_t);
+int _mbsicmp_l(const unsigned char *, const unsigned char *, locale_t);
+int _mbsnicmp_l(const unsigned char *, const unsigned char *, size, locale_t);
+int _mbsnbcmp_l(const unsigned char *, const unsigned char *, size, locale_t);
+int _mbsnbicmp_l(const unsigned char *, const unsigned char *, size, locale_t);
+
+int test_warning_patterns() {
+ if (strcmp(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result [bugprone-suspicious-string-compare]
+ // CHECK-FIXES: if (strcmp(A, "a") != 0)
+
+ if (strcmp(A, "a") == 0 ||
+ strcmp(A, "b"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result
+ // CHECK-FIXES: strcmp(A, "b") != 0)
+
+ if (strcmp(A, "a") == 1)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (strcmp(A, "a") == -1)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (strcmp(A, "a") == true)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (strcmp(A, "a") < '0')
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (strcmp(A, "a") < 0.)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast
+}
+
+int test_valid_patterns() {
+ // The following cases are valid.
+ if (strcmp(A, "a") < 0)
+ return 0;
+ if (strcmp(A, "a") == 0)
+ return 0;
+ if (strcmp(A, "a") <= 0)
+ return 0;
+
+ if (wcscmp(W, L"a") < 0)
+ return 0;
+ if (wcscmp(W, L"a") == 0)
+ return 0;
+ if (wcscmp(W, L"a") <= 0)
+ return 0;
+
+ return 1;
+}
+
+int test_implicit_compare_with_functions() {
+
+ if (memcmp(A, "a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'memcmp' is called without explicitly comparing result
+ // CHECK-FIXES: memcmp(A, "a", 1) != 0)
+
+ if (wmemcmp(W, L"a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wmemcmp' is called without explicitly comparing result
+ // CHECK-FIXES: wmemcmp(W, L"a", 1) != 0)
+
+ if (memicmp(A, "a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'memicmp' is called without explicitly comparing result
+ // CHECK-FIXES: memicmp(A, "a", 1) != 0)
+
+ if (_memicmp(A, "a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_memicmp' is called without explicitly comparing result
+ // CHECK-FIXES: _memicmp(A, "a", 1) != 0)
+
+ if (_memicmp_l(A, "a", 1, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_memicmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _memicmp_l(A, "a", 1, locale) != 0)
+
+ if (strcmp(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result
+ // CHECK-FIXES: strcmp(A, "a") != 0)
+
+ if (strncmp(A, "a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strncmp' is called without explicitly comparing result
+ // CHECK-FIXES: strncmp(A, "a", 1) != 0)
+
+ if (strcasecmp(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcasecmp' is called without explicitly comparing result
+ // CHECK-FIXES: strcasecmp(A, "a") != 0)
+
+ if (strncasecmp(A, "a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strncasecmp' is called without explicitly comparing result
+ // CHECK-FIXES: strncasecmp(A, "a", 1) != 0)
+
+ if (stricmp(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'stricmp' is called without explicitly comparing result
+ // CHECK-FIXES: stricmp(A, "a") != 0)
+
+ if (strcmpi(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmpi' is called without explicitly comparing result
+ // CHECK-FIXES: strcmpi(A, "a") != 0)
+
+ if (_stricmp(A, "a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_stricmp' is called without explicitly comparing result
+ // CHECK-FIXES: _stricmp(A, "a") != 0)
+
+ if (strnicmp(A, "a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strnicmp' is called without explicitly comparing result
+ // CHECK-FIXES: strnicmp(A, "a", 1) != 0)
+
+ if (_strnicmp(A, "a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_strnicmp' is called without explicitly comparing result
+ // CHECK-FIXES: _strnicmp(A, "a", 1) != 0)
+
+ if (_stricmp_l(A, "a", locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_stricmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _stricmp_l(A, "a", locale) != 0)
+
+ if (_strnicmp_l(A, "a", 1, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_strnicmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _strnicmp_l(A, "a", 1, locale) != 0)
+
+ if (wcscmp(W, L"a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcscmp' is called without explicitly comparing result
+ // CHECK-FIXES: wcscmp(W, L"a") != 0)
+
+ if (wcsncmp(W, L"a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsncmp' is called without explicitly comparing result
+ // CHECK-FIXES: wcsncmp(W, L"a", 1) != 0)
+
+ if (wcscasecmp(W, L"a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcscasecmp' is called without explicitly comparing result
+ // CHECK-FIXES: wcscasecmp(W, L"a") != 0)
+
+ if (wcsicmp(W, L"a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsicmp' is called without explicitly comparing result
+ // CHECK-FIXES: wcsicmp(W, L"a") != 0)
+
+ if (_wcsicmp(W, L"a"))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsicmp' is called without explicitly comparing result
+ // CHECK-FIXES: _wcsicmp(W, L"a") != 0)
+
+ if (_wcsicmp_l(W, L"a", locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsicmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _wcsicmp_l(W, L"a", locale) != 0)
+
+ if (wcsnicmp(W, L"a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsnicmp' is called without explicitly comparing result
+ // CHECK-FIXES: wcsnicmp(W, L"a", 1) != 0)
+
+ if (_wcsnicmp(W, L"a", 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsnicmp' is called without explicitly comparing result
+ // CHECK-FIXES: _wcsnicmp(W, L"a", 1) != 0)
+
+ if (_wcsnicmp_l(W, L"a", 1, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsnicmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _wcsnicmp_l(W, L"a", 1, locale) != 0)
+
+ if (_mbscmp(U, V))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbscmp' is called without explicitly comparing result
+ // CHECK-FIXES: _mbscmp(U, V) != 0)
+
+ if (_mbsncmp(U, V, 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsncmp' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsncmp(U, V, 1) != 0)
+
+ if (_mbsnbcmp(U, V, 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbcmp' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsnbcmp(U, V, 1) != 0)
+
+ if (_mbsnbicmp(U, V, 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbicmp' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsnbicmp(U, V, 1) != 0)
+
+ if (_mbsicmp(U, V))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsicmp' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsicmp(U, V) != 0)
+
+ if (_mbsnicmp(U, V, 1))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnicmp' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsnicmp(U, V, 1) != 0)
+
+ if (_mbscmp_l(U, V, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbscmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _mbscmp_l(U, V, locale) != 0)
+
+ if (_mbsncmp_l(U, V, 1, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsncmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsncmp_l(U, V, 1, locale) != 0)
+
+ if (_mbsicmp_l(U, V, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsicmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsicmp_l(U, V, locale) != 0)
+
+ if (_mbsnicmp_l(U, V, 1, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnicmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsnicmp_l(U, V, 1, locale) != 0)
+
+ if (_mbsnbcmp_l(U, V, 1, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbcmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsnbcmp_l(U, V, 1, locale) != 0)
+
+ if (_mbsnbicmp_l(U, V, 1, locale))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbicmp_l' is called without explicitly comparing result
+ // CHECK-FIXES: _mbsnbicmp_l(U, V, 1, locale) != 0)
+
+ return 1;
+}
+
+int strcmp_wrapper1(const char* a, const char* b) {
+ return strcmp(a, b);
+}
+
+int strcmp_wrapper2(const char* a, const char* b) {
+ return (a && b) ? strcmp(a, b) : 0;
+}
+
+#define macro_strncmp(s1, s2, n) \
+ (__extension__ (__builtin_constant_p (n) \
+ && ((__builtin_constant_p (s1) \
+ && strlen (s1) < ((size) (n))) \
+ || (__builtin_constant_p (s2) \
+ && strlen (s2) < ((size) (n)))) \
+ ? strcmp (s1, s2) : strncmp (s1, s2, n)))
+
+int strncmp_macro(const char* a, const char* b) {
+ if (macro_strncmp(a, b, 4))
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result
+
+ if (macro_strncmp(a, b, 4) == 2)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+ if (macro_strncmp(a, b, 4) <= .0)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast
+
+ if (macro_strncmp(a, b, 4) + 0)
+ return 0;
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: results of function 'strcmp' used by operator '+'
+
+ return 1;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-swapped-arguments.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-swapped-arguments.cpp
new file mode 100644
index 0000000..06fb2d8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-swapped-arguments.cpp
@@ -0,0 +1,53 @@
+// RUN: %check_clang_tidy %s bugprone-swapped-arguments %t
+
+void F(int, double);
+
+int SomeFunction();
+
+template <typename T, typename U>
+void G(T a, U b) {
+ F(a, b); // no-warning
+ F(2.0, 4);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments.
+// CHECK-FIXES: F(4, 2.0)
+}
+
+void foo() {
+ F(1.0, 3);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments.
+// CHECK-FIXES: F(3, 1.0)
+
+#define M(x, y) x##y()
+
+ double b = 1.0;
+ F(b, M(Some, Function));
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments.
+// CHECK-FIXES: F(M(Some, Function), b);
+
+#define N F(b, SomeFunction())
+
+ N;
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments.
+// In macro, don't emit fixits.
+// CHECK-FIXES: #define N F(b, SomeFunction())
+
+ G(b, 3);
+ G(3, 1.0);
+ G(0, 0);
+
+ F(1.0, 1.0); // no-warning
+ F(3, 1.0); // no-warning
+ F(true, false); // no-warning
+ F(0, 'c'); // no-warning
+
+#define APPLY(f, x, y) f(x, y)
+ APPLY(F, 1.0, 3);
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments.
+// CHECK-FIXES: APPLY(F, 3, 1.0);
+
+#define PARAMS 1.0, 3
+#define CALL(P) F(P)
+ CALL(PARAMS);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: argument with implicit conversion from 'int' to 'double' followed by argument converted from 'double' to 'int', potentially swapped arguments.
+// In macro, don't emit fixits.
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-terminating-continue.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-terminating-continue.cpp
new file mode 100644
index 0000000..4bdcbc4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-terminating-continue.cpp
@@ -0,0 +1,65 @@
+// RUN: %check_clang_tidy %s bugprone-terminating-continue %t
+
+void f() {
+ do {
+ continue;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'continue' in loop with false condition is equivalent to 'break' [bugprone-terminating-continue]
+ // CHECK-FIXES: break;
+ } while(false);
+
+ do {
+ continue;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'continue' in loop with false condition is equivalent to 'break' [bugprone-terminating-continue]
+ // CHECK-FIXES: break;
+ } while(0);
+
+ do {
+ continue;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'continue' in loop with false condition is equivalent to 'break' [bugprone-terminating-continue]
+ // CHECK-FIXES: break;
+ } while(nullptr);
+
+ do {
+ continue;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'continue' in loop with false condition is equivalent to 'break' [bugprone-terminating-continue]
+ // CHECK-FIXES: break;
+ } while(__null);
+
+
+ do {
+ int x = 1;
+ if (x > 0) continue;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'continue' in loop with false condition is equivalent to 'break' [bugprone-terminating-continue]
+ // CHECK-FIXES: if (x > 0) break;
+ } while (false);
+}
+
+void g() {
+ do {
+ do {
+ continue;
+ int x = 1;
+ } while (1 == 1);
+ } while (false);
+
+ do {
+ for (int i = 0; i < 1; ++i) {
+ continue;
+ int x = 1;
+ }
+ } while (false);
+
+ do {
+ while (true) {
+ continue;
+ int x = 1;
+ }
+ } while (false);
+
+ int v[] = {1,2,3,34};
+ do {
+ for (int n : v) {
+ if (n>2) continue;
+ }
+ } while (false);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-throw-keyword-missing.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-throw-keyword-missing.cpp
new file mode 100644
index 0000000..93ecf06
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-throw-keyword-missing.cpp
@@ -0,0 +1,167 @@
+// RUN: %check_clang_tidy %s bugprone-throw-keyword-missing %t -- -- -fexceptions
+
+namespace std {
+
+// std::string declaration (taken from test/clang-tidy/readability-redundant-string-cstr-msvc.cpp).
+template <typename T>
+class allocator {};
+template <typename T>
+class char_traits {};
+template <typename C, typename T = std::char_traits<C>, typename A = std::allocator<C>>
+struct basic_string {
+ basic_string();
+ basic_string(const basic_string &);
+ // MSVC headers define two constructors instead of using optional arguments.
+ basic_string(const C *);
+ basic_string(const C *, const A &);
+ ~basic_string();
+};
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+
+// std::exception and std::runtime_error declaration.
+struct exception {
+ exception();
+ exception(const exception &other);
+ virtual ~exception();
+};
+
+struct runtime_error : public exception {
+ explicit runtime_error(const std::string &what_arg);
+};
+
+} // namespace std
+
+// The usage of this class should never emit a warning.
+struct RegularClass {};
+
+// Class name contains the substring "exception", in certain cases using this class should emit a warning.
+struct RegularException {
+ RegularException() {}
+
+ // Constructors with a single argument are treated differently (cxxFunctionalCastExpr).
+ RegularException(int) {}
+};
+
+// --------------
+
+void stdExceptionNotTrownTest(int i) {
+ if (i < 0)
+ // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: suspicious exception object created but not thrown; did you mean 'throw {{.*}}'? [bugprone-throw-keyword-missing]
+ std::exception();
+
+ if (i > 0)
+ // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: suspicious exception
+ std::runtime_error("Unexpected argument");
+}
+
+void stdExceptionThrownTest(int i) {
+ if (i < 0)
+ throw std::exception();
+
+ if (i > 0)
+ throw std::runtime_error("Unexpected argument");
+}
+
+void regularClassNotThrownTest(int i) {
+ if (i < 0)
+ RegularClass();
+}
+
+void regularClassThrownTest(int i) {
+ if (i < 0)
+ throw RegularClass();
+}
+
+void nameContainsExceptionNotThrownTest(int i) {
+ if (i < 0)
+ // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: suspicious exception
+ RegularException();
+
+ if (i > 0)
+ // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: suspicious exception
+ RegularException(5);
+}
+
+void nameContainsExceptionThrownTest(int i) {
+ if (i < 0)
+ throw RegularException();
+
+ if (i > 0)
+ throw RegularException(5);
+}
+
+template <class Exception>
+void f(int i, Exception excToBeThrown) {}
+
+void funcCallWithTempExcTest() {
+ f(5, RegularException());
+}
+
+// Global variable initilization test.
+RegularException exc = RegularException();
+RegularException *excptr = new RegularException();
+
+void localVariableInitTest() {
+ RegularException exc = RegularException();
+ RegularException *excptr = new RegularException();
+}
+
+class CtorInitializerListTest {
+ RegularException exc;
+
+ CtorInitializerListTest() : exc(RegularException()) {}
+
+ CtorInitializerListTest(int) try : exc(RegularException()) {
+ // Constructor body
+ } catch (...) {
+ // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: suspicious exception
+ RegularException();
+ }
+
+ CtorInitializerListTest(float);
+};
+
+CtorInitializerListTest::CtorInitializerListTest(float) try : exc(RegularException()) {
+ // Constructor body
+} catch (...) {
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: suspicious exception
+ RegularException();
+}
+
+RegularException funcReturningExceptionTest(int i) {
+ return RegularException();
+}
+
+void returnedValueTest() {
+ funcReturningExceptionTest(3);
+}
+
+struct ClassBracedInitListTest {
+ ClassBracedInitListTest(RegularException exc) {}
+};
+
+void foo(RegularException, ClassBracedInitListTest) {}
+
+void bracedInitListTest() {
+ RegularException exc{};
+ ClassBracedInitListTest test = {RegularException()};
+ foo({}, {RegularException()});
+}
+
+typedef std::exception ERROR_BASE;
+class RegularError : public ERROR_BASE {};
+
+void typedefTest() {
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: suspicious exception
+ RegularError();
+}
+
+struct ExceptionRAII {
+ ExceptionRAII() {}
+ ~ExceptionRAII() {}
+};
+
+void exceptionRAIITest() {
+ ExceptionRAII E;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-undefined-memory-manipulation.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-undefined-memory-manipulation.cpp
new file mode 100644
index 0000000..8055010
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-undefined-memory-manipulation.cpp
@@ -0,0 +1,213 @@
+// RUN: %check_clang_tidy %s bugprone-undefined-memory-manipulation %t
+
+void *memset(void *, int, __SIZE_TYPE__);
+void *memcpy(void *, const void *, __SIZE_TYPE__);
+void *memmove(void *, const void *, __SIZE_TYPE__);
+
+namespace std {
+using ::memcpy;
+using ::memmove;
+using ::memset;
+}
+
+namespace types {
+// TriviallyCopyable types:
+struct Plain {
+ int n;
+};
+
+enum E {
+ X,
+ Y,
+ Z
+};
+
+struct Base {
+ float b;
+};
+
+struct Derived : Base {
+ bool d;
+};
+
+// not TriviallyCopyable types:
+struct Destruct {
+ ~Destruct() {}
+};
+
+struct Copy {
+ Copy() {}
+ Copy(const Copy &) {}
+};
+
+struct Move {
+ Move() {}
+ Move(Move &&) {}
+};
+
+struct VirtualFunc {
+ virtual void f() {}
+};
+
+struct VirtualBase : virtual Base {
+ int vb;
+};
+
+// Incomplete type, assume it is TriviallyCopyable.
+struct NoDef;
+
+} // end namespace types
+
+void f(types::NoDef *s) {
+ memset(s, 0, 5);
+}
+
+template <typename T>
+void memset_temp(T *b) {
+ memset(b, 0, sizeof(T));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc' is not TriviallyCopyable [bugprone-undefined-memory-manipulation]
+}
+
+template <typename S, typename T>
+void memcpy_temp(S *a, T *b) {
+ memcpy(a, b, sizeof(T));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc'
+}
+
+template <typename S, typename T>
+void memmove_temp(S *a, T *b) {
+ memmove(a, b, sizeof(T));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc'
+}
+
+namespace aliases {
+using Copy2 = types::Copy;
+typedef types::Move Move2;
+}
+
+void notTriviallyCopyable() {
+ types::Plain p; // TriviallyCopyable for variety
+ types::Destruct d;
+ types::Copy c;
+ types::Move m;
+ types::VirtualFunc vf;
+ types::VirtualBase vb;
+
+ memset(&vf, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc'
+ memset(&d, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct'
+ memset(&c, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy'
+ std::memset(&m, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Move'
+ ::memset(&vb, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualBase'
+
+ memcpy(&p, &vf, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualFunc'
+ memcpy(&p, &d, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Destruct'
+ memcpy(&c, &p, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Copy'
+ std::memcpy(&m, &p, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Move'
+ ::memcpy(&vb, &p, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualBase'
+
+ memmove(&vf, &p, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc'
+ memmove(&d, &p, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct'
+ memmove(&p, &c, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Copy'
+ std::memmove(&p, &m, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Move'
+ ::memmove(&p, &vb, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::VirtualBase'
+
+#define MEMSET memset(&vf, 0, sizeof(int));
+ MEMSET
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::VirtualFunc'
+#define MEMCPY memcpy(&d, &p, sizeof(int));
+ MEMCPY
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'types::Destruct'
+#define MEMMOVE memmove(&p, &c, sizeof(int));
+ MEMMOVE
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, source object type 'types::Copy'
+
+ memset_temp<types::VirtualFunc>(&vf);
+ memcpy_temp<types::Plain, types::VirtualFunc>(&p, &vf);
+ memmove_temp<types::Plain, types::VirtualFunc>(&p, &vf);
+
+ aliases::Copy2 c2;
+ aliases::Move2 m2;
+ memset(&c2, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Copy2'
+ memset(&m2, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Move2'
+
+ typedef aliases::Copy2 Copy3;
+ typedef aliases::Copy2 *PCopy2;
+ typedef Copy3 *PCopy3;
+ Copy3 c3;
+ PCopy2 pc2;
+ PCopy3 pc3;
+ memset(&c3, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3'
+ memset(pc2, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'aliases::Copy2'
+ memset(pc3, 0, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: undefined behavior, destination object type 'Copy3'
+}
+
+void triviallyCopyable() {
+ types::Plain p;
+ types::Base base;
+ types::Derived derived;
+
+ int i = 5;
+ int ia[3] = {1, 2, 3};
+ float f = 3.14;
+ float fa[3] = {1.1, 2.2, 3.3};
+ bool b = false;
+ bool ba[2] = {true, false};
+ types::E e = types::X;
+ p.n = 2;
+
+ memset(&p, 0, sizeof(int));
+ memset(&base, 0, sizeof(float));
+ memset(&derived, 0, sizeof(bool));
+ memset(&i, 0, sizeof(int));
+ memset(ia, 0, sizeof(int));
+ memset(&f, 0, sizeof(float));
+ memset(fa, 0, sizeof(float));
+ memset(&b, 0, sizeof(bool));
+ memset(ba, 0, sizeof(bool));
+ memset(&e, 0, sizeof(int));
+ memset(&p.n, 0, sizeof(int));
+
+ memcpy(&p, &p, sizeof(int));
+ memcpy(&base, &base, sizeof(float));
+ memcpy(&derived, &derived, sizeof(bool));
+ memcpy(&i, &i, sizeof(int));
+ memcpy(ia, ia, sizeof(int));
+ memcpy(&f, &f, sizeof(float));
+ memcpy(fa, fa, sizeof(float));
+ memcpy(&b, &b, sizeof(bool));
+ memcpy(ba, ba, sizeof(bool));
+ memcpy(&e, &e, sizeof(int));
+ memcpy(&p.n, &p.n, sizeof(int));
+
+ memmove(&p, &p, sizeof(int));
+ memmove(&base, &base, sizeof(float));
+ memmove(&derived, &derived, sizeof(bool));
+ memmove(&i, &i, sizeof(int));
+ memmove(ia, ia, sizeof(int));
+ memmove(&f, &f, sizeof(float));
+ memmove(fa, fa, sizeof(float));
+ memmove(&b, &b, sizeof(bool));
+ memmove(ba, ba, sizeof(bool));
+ memmove(&e, &e, sizeof(int));
+ memmove(&p.n, &p.n, sizeof(int));
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-undelegated-constructor-cxx98.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-undelegated-constructor-cxx98.cpp
new file mode 100644
index 0000000..f859f24
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-undelegated-constructor-cxx98.cpp
@@ -0,0 +1,23 @@
+// RUN: clang-tidy %s -checks=-*,bugprone-undelegated-constructor -- -std=c++98 | count 0
+
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+
+struct Ctor;
+Ctor foo();
+
+struct Ctor {
+ Ctor();
+ Ctor(int);
+ Ctor(int, int);
+ Ctor(Ctor *i) {
+ Ctor();
+ Ctor(0);
+ Ctor(1, 2);
+ foo();
+ }
+};
+
+Ctor::Ctor() {
+ Ctor(1);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-undelegated-constructor.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-undelegated-constructor.cpp
new file mode 100644
index 0000000..09b20ac
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-undelegated-constructor.cpp
@@ -0,0 +1,54 @@
+// RUN: %check_clang_tidy %s bugprone-undelegated-constructor %t
+
+struct Ctor;
+Ctor foo();
+
+struct Ctor {
+ Ctor();
+ Ctor(int);
+ Ctor(int, int);
+ Ctor(Ctor *i) {
+ Ctor();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor? A temporary object is created here instead [bugprone-undelegated-constructor]
+ Ctor(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor?
+ Ctor(1, 2);
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor?
+ foo();
+ }
+};
+
+Ctor::Ctor() {
+ Ctor(1);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: did you intend to call a delegated constructor?
+}
+
+Ctor::Ctor(int i) : Ctor(i, 1) {} // properly delegated.
+
+struct Dtor {
+ Dtor();
+ Dtor(int);
+ Dtor(int, int);
+ Dtor(Ctor *i) {
+ Dtor();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor?
+ Dtor(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor?
+ Dtor(1, 2);
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: did you intend to call a delegated constructor?
+ }
+ ~Dtor();
+};
+
+struct Base {};
+struct Derived : public Base {
+ Derived() { Base(); }
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: did you intend to call a delegated constructor?
+};
+
+template <typename T>
+struct TDerived : public Base {
+ TDerived() { Base(); }
+};
+
+TDerived<int> t;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-unused-raii.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-unused-raii.cpp
new file mode 100644
index 0000000..91ade52
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-unused-raii.cpp
@@ -0,0 +1,68 @@
+// RUN: %check_clang_tidy %s bugprone-unused-raii %t
+
+struct Foo {
+ Foo();
+ Foo(int);
+ Foo(int, int);
+ ~Foo();
+};
+
+struct Bar {
+ Bar();
+};
+
+struct FooBar {
+ FooBar();
+ Foo f;
+};
+
+template <typename T>
+void qux() {
+ T(42);
+}
+
+template <typename T>
+struct TFoo {
+ TFoo(T);
+ ~TFoo();
+};
+
+Foo f();
+
+struct Ctor {
+ Ctor(int);
+ Ctor() {
+ Ctor(0); // TODO: warn here.
+ }
+};
+
+void test() {
+ Foo(42);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+// CHECK-FIXES: Foo give_me_a_name(42);
+ Foo(23, 42);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+// CHECK-FIXES: Foo give_me_a_name(23, 42);
+ Foo();
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+// CHECK-FIXES: Foo give_me_a_name;
+ TFoo<int>(23);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+// CHECK-FIXES: TFoo<int> give_me_a_name(23);
+
+ FooBar();
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: object destroyed immediately after creation; did you mean to name the object?
+// CHECK-FIXES: FooBar give_me_a_name;
+
+ Bar();
+ f();
+ qux<Foo>();
+
+#define M Foo();
+ M
+
+ {
+ Foo();
+ }
+ Foo();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-unused-return-value-custom.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-unused-return-value-custom.cpp
new file mode 100644
index 0000000..efe3705
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-unused-return-value-custom.cpp
@@ -0,0 +1,100 @@
+// RUN: %check_clang_tidy %s bugprone-unused-return-value %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: bugprone-unused-return-value.CheckedFunctions, \
+// RUN: value: "::fun;::ns::Outer::Inner::memFun;::ns::Type::staticFun;::ns::ClassTemplate::memFun;::ns::ClassTemplate::staticFun"}]}' \
+// RUN: --
+
+namespace std {
+
+template <typename T>
+T *launder(T *);
+
+} // namespace std
+
+namespace ns {
+
+struct Outer {
+ struct Inner {
+ bool memFun();
+ };
+};
+
+using AliasName = Outer;
+
+struct Derived : public Outer::Inner {};
+
+struct Retval {
+ int *P;
+ Retval() { P = new int; }
+ ~Retval() { delete P; }
+};
+
+struct Type {
+ Retval memFun();
+ static Retval staticFun();
+};
+
+template <typename T>
+struct ClassTemplate {
+ Retval memFun();
+ static Retval staticFun();
+};
+
+} // namespace ns
+
+int fun();
+void fun(int);
+
+void warning() {
+ fun();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ (fun());
+ // CHECK-MESSAGES: [[@LINE-1]]:4: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ ns::Outer::Inner ObjA1;
+ ObjA1.memFun();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ ns::AliasName::Inner ObjA2;
+ ObjA2.memFun();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ ns::Derived ObjA3;
+ ObjA3.memFun();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ ns::Type::staticFun();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ ns::ClassTemplate<int> ObjA4;
+ ObjA4.memFun();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ ns::ClassTemplate<int>::staticFun();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+}
+
+void noWarning() {
+ auto R1 = fun();
+
+ ns::Outer::Inner ObjB1;
+ auto R2 = ObjB1.memFun();
+
+ auto R3 = ns::Type::staticFun();
+
+ ns::ClassTemplate<int> ObjB2;
+ auto R4 = ObjB2.memFun();
+
+ auto R5 = ns::ClassTemplate<int>::staticFun();
+
+ // test calling a void overload of a checked function
+ fun(5);
+
+ // test discarding return value of functions that are not configured to be checked
+ int I = 1;
+ std::launder(&I);
+
+ ns::Type ObjB3;
+ ObjB3.memFun();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-unused-return-value.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-unused-return-value.cpp
new file mode 100644
index 0000000..b4f280e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-unused-return-value.cpp
@@ -0,0 +1,215 @@
+// RUN: %check_clang_tidy %s bugprone-unused-return-value %t -- -- -fexceptions
+
+namespace std {
+
+struct future {};
+
+enum class launch {
+ async,
+ deferred
+};
+
+template <typename Function, typename... Args>
+future async(Function &&, Args &&...);
+
+template <typename Function, typename... Args>
+future async(launch, Function &&, Args &&...);
+
+template <typename ForwardIt, typename T>
+ForwardIt remove(ForwardIt, ForwardIt, const T &);
+
+template <typename ForwardIt, typename UnaryPredicate>
+ForwardIt remove_if(ForwardIt, ForwardIt, UnaryPredicate);
+
+template <typename ForwardIt>
+ForwardIt unique(ForwardIt, ForwardIt);
+
+template <typename T>
+struct default_delete;
+
+template <typename T, typename Deleter = std::default_delete<T>>
+struct unique_ptr {
+ T *release() noexcept;
+};
+
+template <typename T>
+struct char_traits;
+
+template <typename T>
+struct allocator;
+
+template <typename CharT,
+ typename Traits = char_traits<CharT>,
+ typename Allocator = allocator<CharT>>
+struct basic_string {
+ bool empty() const;
+};
+
+typedef basic_string<char> string;
+
+template <typename T, typename Allocator = std::allocator<T>>
+struct vector {
+ bool empty() const noexcept;
+};
+
+// the check should be able to match std lib calls even if the functions are
+// declared inside inline namespaces
+inline namespace v1 {
+
+template <typename T>
+T *launder(T *);
+
+} // namespace v1
+} // namespace std
+
+struct Foo {
+ void f();
+};
+
+int increment(int i) {
+ return i + 1;
+}
+
+void useFuture(const std::future &fut);
+
+void warning() {
+ std::async(increment, 42);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ std::async(std::launch::async, increment, 42);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ Foo F;
+ std::launder(&F);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ std::remove_if(nullptr, nullptr, nullptr);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ std::unique(nullptr, nullptr);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ std::unique_ptr<Foo> UPtr;
+ UPtr.release();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ std::string Str;
+ Str.empty();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ std::vector<Foo> Vec;
+ Vec.empty();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ // test discarding return values inside different kinds of statements
+
+ auto Lambda = [] { std::remove(nullptr, nullptr, 1); };
+ // CHECK-MESSAGES: [[@LINE-1]]:22: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ if (true)
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+ else if (true)
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+ else
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ while (true)
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ do
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+ while (true);
+
+ for (;;)
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ for (std::remove(nullptr, nullptr, 1);;)
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the value returned by this function should be used [bugprone-unused-return-value]
+ ;
+
+ for (;; std::remove(nullptr, nullptr, 1))
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: the value returned by this function should be used [bugprone-unused-return-value]
+ ;
+
+ for (auto C : "foo")
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+ switch (1) {
+ case 1:
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+ break;
+ default:
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+ break;
+ }
+
+ try {
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+ } catch (...) {
+ std::remove(nullptr, nullptr, 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+ }
+}
+
+void noWarning() {
+ auto AsyncRetval1 = std::async(increment, 42);
+ auto AsyncRetval2 = std::async(std::launch::async, increment, 42);
+
+ Foo FNoWarning;
+ auto LaunderRetval = std::launder(&FNoWarning);
+
+ auto RemoveRetval = std::remove(nullptr, nullptr, 1);
+
+ auto RemoveIfRetval = std::remove_if(nullptr, nullptr, nullptr);
+
+ auto UniqueRetval = std::unique(nullptr, nullptr);
+
+ std::unique_ptr<Foo> UPtrNoWarning;
+ auto ReleaseRetval = UPtrNoWarning.release();
+
+ std::string StrNoWarning;
+ auto StrEmptyRetval = StrNoWarning.empty();
+
+ std::vector<Foo> VecNoWarning;
+ auto VecEmptyRetval = VecNoWarning.empty();
+
+ // test using the return value in different kinds of expressions
+ useFuture(std::async(increment, 42));
+ std::launder(&FNoWarning)->f();
+ delete std::launder(&FNoWarning);
+
+ if (std::launder(&FNoWarning))
+ ;
+ for (; std::launder(&FNoWarning);)
+ ;
+ while (std::launder(&FNoWarning))
+ ;
+ do
+ ;
+ while (std::launder(&FNoWarning));
+ switch (std::unique(1, 1))
+ ;
+
+ // cast to void should allow ignoring the return value
+ (void)std::async(increment, 42);
+
+ // test discarding return value of functions that are not configured to be checked
+ increment(1);
+
+ // test that the check is disabled inside GNU statement expressions
+ ({ std::async(increment, 42); });
+ auto StmtExprRetval = ({ std::async(increment, 42); });
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-use-after-move.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-use-after-move.cpp
new file mode 100644
index 0000000..43e6322
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-use-after-move.cpp
@@ -0,0 +1,1164 @@
+// RUN: %check_clang_tidy %s bugprone-use-after-move %t -- -- -std=c++11 -fno-delayed-template-parsing
+
+typedef decltype(nullptr) nullptr_t;
+
+namespace std {
+typedef unsigned size_t;
+
+template <typename T>
+struct unique_ptr {
+ unique_ptr();
+ T *get() const;
+ explicit operator bool() const;
+ void reset(T *ptr);
+ T &operator*() const;
+ T *operator->() const;
+ T& operator[](size_t i) const;
+};
+
+template <typename T>
+struct shared_ptr {
+ shared_ptr();
+ T *get() const;
+ explicit operator bool() const;
+ void reset(T *ptr);
+ T &operator*() const;
+ T *operator->() const;
+};
+
+template <typename T>
+struct weak_ptr {
+ weak_ptr();
+ bool expired() const;
+};
+
+#define DECLARE_STANDARD_CONTAINER(name) \
+ template <typename T> \
+ struct name { \
+ name(); \
+ void clear(); \
+ bool empty(); \
+ }
+
+#define DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(name) \
+ template <typename T> \
+ struct name { \
+ name(); \
+ void clear(); \
+ bool empty(); \
+ void assign(size_t, const T &); \
+ }
+
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(basic_string);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(vector);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(deque);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(forward_list);
+DECLARE_STANDARD_CONTAINER_WITH_ASSIGN(list);
+DECLARE_STANDARD_CONTAINER(set);
+DECLARE_STANDARD_CONTAINER(map);
+DECLARE_STANDARD_CONTAINER(multiset);
+DECLARE_STANDARD_CONTAINER(multimap);
+DECLARE_STANDARD_CONTAINER(unordered_set);
+DECLARE_STANDARD_CONTAINER(unordered_map);
+DECLARE_STANDARD_CONTAINER(unordered_multiset);
+DECLARE_STANDARD_CONTAINER(unordered_multimap);
+
+typedef basic_string<char> string;
+
+template <typename>
+struct remove_reference;
+
+template <typename _Tp>
+struct remove_reference {
+ typedef _Tp type;
+};
+
+template <typename _Tp>
+struct remove_reference<_Tp &> {
+ typedef _Tp type;
+};
+
+template <typename _Tp>
+struct remove_reference<_Tp &&> {
+ typedef _Tp type;
+};
+
+template <typename _Tp>
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) noexcept {
+ return static_cast<typename remove_reference<_Tp>::type &&>(__t);
+}
+
+} // namespace std
+
+class A {
+public:
+ A();
+ A(const A &);
+ A(A &&);
+
+ A &operator=(const A &);
+ A &operator=(A &&);
+
+ void foo() const;
+ int getInt() const;
+
+ operator bool() const;
+
+ int i;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// General tests.
+
+// Simple case.
+void simple() {
+ A a;
+ a.foo();
+ A other_a = std::move(a);
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:15: note: move occurred here
+}
+
+// A warning should only be emitted for one use-after-move.
+void onlyFlagOneUseAfterMove() {
+ A a;
+ a.foo();
+ A other_a = std::move(a);
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:15: note: move occurred here
+ a.foo();
+}
+
+void moveAfterMove() {
+ // Move-after-move also counts as a use.
+ {
+ A a;
+ std::move(a);
+ std::move(a);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+ // This is also true if the move itself turns into the use on the second loop
+ // iteration.
+ {
+ A a;
+ for (int i = 0; i < 10; ++i) {
+ std::move(a);
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-2]]:7: note: move occurred here
+ // CHECK-MESSAGES: [[@LINE-3]]:17: note: the use happens in a later loop
+ }
+ }
+}
+
+// Checks also works on function parameters that have a use-after move.
+void parameters(A a) {
+ std::move(a);
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:3: note: move occurred here
+}
+
+void standardSmartPtr() {
+ // std::unique_ptr<>, std::shared_ptr<> and std::weak_ptr<> are guaranteed to
+ // be null after a std::move. So the check only flags accesses that would
+ // dereference the pointer.
+ {
+ std::unique_ptr<A> ptr;
+ std::move(ptr);
+ ptr.get();
+ static_cast<bool>(ptr);
+ *ptr;
+ // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'ptr' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-5]]:5: note: move occurred here
+ }
+ {
+ std::unique_ptr<A> ptr;
+ std::move(ptr);
+ ptr->foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+ {
+ std::unique_ptr<A> ptr;
+ std::move(ptr);
+ ptr[0];
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+ {
+ std::shared_ptr<A> ptr;
+ std::move(ptr);
+ ptr.get();
+ static_cast<bool>(ptr);
+ *ptr;
+ // CHECK-MESSAGES: [[@LINE-1]]:6: warning: 'ptr' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-5]]:5: note: move occurred here
+ }
+ {
+ std::shared_ptr<A> ptr;
+ std::move(ptr);
+ ptr->foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+ {
+ // std::weak_ptr<> cannot be dereferenced directly, so we only check that
+ // member functions may be called on it after a move.
+ std::weak_ptr<A> ptr;
+ std::move(ptr);
+ ptr.expired();
+ }
+ // Make sure we recognize std::unique_ptr<> or std::shared_ptr<> if they're
+ // wrapped in a typedef.
+ {
+ typedef std::unique_ptr<A> PtrToA;
+ PtrToA ptr;
+ std::move(ptr);
+ ptr.get();
+ }
+ {
+ typedef std::shared_ptr<A> PtrToA;
+ PtrToA ptr;
+ std::move(ptr);
+ ptr.get();
+ }
+ // And we don't get confused if the template argument is a little more
+ // involved.
+ {
+ struct B {
+ typedef A AnotherNameForA;
+ };
+ std::unique_ptr<B::AnotherNameForA> ptr;
+ std::move(ptr);
+ ptr.get();
+ }
+ // We don't give any special treatment to types that are called "unique_ptr"
+ // or "shared_ptr" but are not in the "::std" namespace.
+ {
+ struct unique_ptr {
+ void get();
+ } ptr;
+ std::move(ptr);
+ ptr.get();
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'ptr' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+}
+
+// The check also works in member functions.
+class Container {
+ void useAfterMoveInMemberFunction() {
+ A a;
+ std::move(a);
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+};
+
+// We see the std::move() if it's inside a declaration.
+void moveInDeclaration() {
+ A a;
+ A another_a(std::move(a));
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+}
+
+// We see the std::move if it's inside an initializer list. Initializer lists
+// are a special case because they cause ASTContext::getParents() to return
+// multiple parents for certain nodes in their subtree. This is because
+// RecursiveASTVisitor visits both the syntactic and semantic forms of
+// InitListExpr, and the parent-child relationships are different between the
+// two forms.
+void moveInInitList() {
+ struct S {
+ A a;
+ };
+ A a;
+ S s{std::move(a)};
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:7: note: move occurred here
+}
+
+void lambdas() {
+ // Use-after-moves inside a lambda should be detected.
+ {
+ A a;
+ auto lambda = [a] {
+ std::move(a);
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:7: note: move occurred here
+ };
+ }
+ // This is just as true if the variable was declared inside the lambda.
+ {
+ auto lambda = [] {
+ A a;
+ std::move(a);
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:7: note: move occurred here
+ };
+ }
+ // But don't warn if the move happened inside the lambda but the use happened
+ // outside -- because
+ // - the 'a' inside the lambda is a copy, and
+ // - we don't know when the lambda will get called anyway
+ {
+ A a;
+ auto lambda = [a] {
+ std::move(a);
+ };
+ a.foo();
+ }
+ // Warn if the use consists of a capture that happens after a move.
+ {
+ A a;
+ std::move(a);
+ auto lambda = [a]() { a.foo(); };
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+ // ...even if the capture was implicit.
+ {
+ A a;
+ std::move(a);
+ auto lambda = [=]() { a.foo(); };
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+ // Same tests but for capture by reference.
+ {
+ A a;
+ std::move(a);
+ auto lambda = [&a]() { a.foo(); };
+ // CHECK-MESSAGES: [[@LINE-1]]:21: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+ {
+ A a;
+ std::move(a);
+ auto lambda = [&]() { a.foo(); };
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+ // But don't warn if the move happened after the capture.
+ {
+ A a;
+ auto lambda = [a]() { a.foo(); };
+ std::move(a);
+ }
+ // ...and again, same thing with an implicit move.
+ {
+ A a;
+ auto lambda = [=]() { a.foo(); };
+ std::move(a);
+ }
+ // Same tests but for capture by reference.
+ {
+ A a;
+ auto lambda = [&a]() { a.foo(); };
+ std::move(a);
+ }
+ {
+ A a;
+ auto lambda = [&]() { a.foo(); };
+ std::move(a);
+ }
+}
+
+// Use-after-moves are detected in uninstantiated templates if the moved type
+// is not a dependent type.
+template <class T>
+void movedTypeIsNotDependentType() {
+ T t;
+ A a;
+ std::move(a);
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:3: note: move occurred here
+}
+
+// And if the moved type is a dependent type, the use-after-move is detected if
+// the template is instantiated.
+template <class T>
+void movedTypeIsDependentType() {
+ T t;
+ std::move(t);
+ t.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 't' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:3: note: move occurred here
+}
+template void movedTypeIsDependentType<A>();
+
+// We handle the case correctly where the move consists of an implicit call
+// to a conversion operator.
+void implicitConversionOperator() {
+ struct Convertible {
+ operator A() && { return A(); }
+ };
+ void takeA(A a);
+
+ Convertible convertible;
+ takeA(std::move(convertible));
+ convertible;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'convertible' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:9: note: move occurred here
+}
+
+// Using decltype on an expression is not a use.
+void decltypeIsNotUse() {
+ A a;
+ std::move(a);
+ decltype(a) other_a;
+}
+
+// Ignore moves or uses that occur as part of template arguments.
+template <int>
+class ClassTemplate {
+public:
+ void foo(A a);
+};
+template <int>
+void functionTemplate(A a);
+void templateArgIsNotUse() {
+ {
+ // A pattern like this occurs in the EXPECT_EQ and ASSERT_EQ macros in
+ // Google Test.
+ A a;
+ ClassTemplate<sizeof(A(std::move(a)))>().foo(std::move(a));
+ }
+ {
+ A a;
+ functionTemplate<sizeof(A(std::move(a)))>(std::move(a));
+ }
+}
+
+// Ignore moves of global variables.
+A global_a;
+void ignoreGlobalVariables() {
+ std::move(global_a);
+ global_a.foo();
+}
+
+// Ignore moves of member variables.
+class IgnoreMemberVariables {
+ A a;
+ static A static_a;
+
+ void f() {
+ std::move(a);
+ a.foo();
+
+ std::move(static_a);
+ static_a.foo();
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Tests involving control flow.
+
+void useAndMoveInLoop() {
+ // Warn about use-after-moves if they happen in a later loop iteration than
+ // the std::move().
+ {
+ A a;
+ for (int i = 0; i < 10; ++i) {
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE+2]]:7: note: move occurred here
+ // CHECK-MESSAGES: [[@LINE-3]]:7: note: the use happens in a later loop
+ std::move(a);
+ }
+ }
+ // However, this case shouldn't be flagged -- the scope of the declaration of
+ // 'a' is important.
+ {
+ for (int i = 0; i < 10; ++i) {
+ A a;
+ a.foo();
+ std::move(a);
+ }
+ }
+ // Same as above, except that we have an unrelated variable being declared in
+ // the same declaration as 'a'. This case is interesting because it tests that
+ // the synthetic DeclStmts generated by the CFG are sequenced correctly
+ // relative to the other statements.
+ {
+ for (int i = 0; i < 10; ++i) {
+ A a, other;
+ a.foo();
+ std::move(a);
+ }
+ }
+ // Don't warn if we return after the move.
+ {
+ A a;
+ for (int i = 0; i < 10; ++i) {
+ a.foo();
+ if (a.getInt() > 0) {
+ std::move(a);
+ return;
+ }
+ }
+ }
+}
+
+void differentBranches(int i) {
+ // Don't warn if the use is in a different branch from the move.
+ {
+ A a;
+ if (i > 0) {
+ std::move(a);
+ } else {
+ a.foo();
+ }
+ }
+ // Same thing, but with a ternary operator.
+ {
+ A a;
+ i > 0 ? (void)std::move(a) : a.foo();
+ }
+ // A variation on the theme above.
+ {
+ A a;
+ a.getInt() > 0 ? a.getInt() : A(std::move(a)).getInt();
+ }
+ // Same thing, but with a switch statement.
+ {
+ A a;
+ switch (i) {
+ case 1:
+ std::move(a);
+ break;
+ case 2:
+ a.foo();
+ break;
+ }
+ }
+ // However, if there's a fallthrough, we do warn.
+ {
+ A a;
+ switch (i) {
+ case 1:
+ std::move(a);
+ case 2:
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-4]]:7: note: move occurred here
+ break;
+ }
+ }
+}
+
+// False positive: A use-after-move is flagged even though the "if (b)" and
+// "if (!b)" are mutually exclusive.
+void mutuallyExclusiveBranchesFalsePositive(bool b) {
+ A a;
+ if (b) {
+ std::move(a);
+ }
+ if (!b) {
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-5]]:5: note: move occurred here
+ }
+}
+
+// Destructors marked [[noreturn]] are handled correctly in the control flow
+// analysis. (These are used in some styles of assertion macros.)
+class FailureLogger {
+public:
+ FailureLogger();
+ [[noreturn]] ~FailureLogger();
+ void log(const char *);
+};
+#define ASSERT(x) \
+ while (x) \
+ FailureLogger().log(#x)
+bool operationOnA(A);
+void noreturnDestructor() {
+ A a;
+ // The while loop in the ASSERT() would ordinarily have the potential to cause
+ // a use-after-move because the second iteration of the loop would be using a
+ // variable that had been moved from in the first iteration. Check that the
+ // CFG knows that the second iteration of the loop is never reached because
+ // the FailureLogger destructor is marked [[noreturn]].
+ ASSERT(operationOnA(std::move(a)));
+}
+#undef ASSERT
+
+////////////////////////////////////////////////////////////////////////////////
+// Tests for reinitializations
+
+template <class T>
+void swap(T &a, T &b) {
+ T tmp = std::move(a);
+ a = std::move(b);
+ b = std::move(tmp);
+}
+void assignments(int i) {
+ // Don't report a use-after-move if the variable was assigned to in the
+ // meantime.
+ {
+ A a;
+ std::move(a);
+ a = A();
+ a.foo();
+ }
+ // The assignment should also be recognized if move, assignment and use don't
+ // all happen in the same block (but the assignment is still guaranteed to
+ // prevent a use-after-move).
+ {
+ A a;
+ if (i == 1) {
+ std::move(a);
+ a = A();
+ }
+ if (i == 2) {
+ a.foo();
+ }
+ }
+ {
+ A a;
+ if (i == 1) {
+ std::move(a);
+ }
+ if (i == 2) {
+ a = A();
+ a.foo();
+ }
+ }
+ // The built-in assignment operator should also be recognized as a
+ // reinitialization. (std::move() may be called on built-in types in template
+ // code.)
+ {
+ int a1 = 1, a2 = 2;
+ swap(a1, a2);
+ }
+ // A std::move() after the assignment makes the variable invalid again.
+ {
+ A a;
+ std::move(a);
+ a = A();
+ std::move(a);
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+ // Report a use-after-move if we can't be sure that the variable was assigned
+ // to.
+ {
+ A a;
+ std::move(a);
+ if (i < 10) {
+ a = A();
+ }
+ if (i > 5) {
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-7]]:5: note: move occurred here
+ }
+ }
+}
+
+// Passing the object to a function through a non-const pointer or reference
+// counts as a re-initialization.
+void passByNonConstPointer(A *);
+void passByNonConstReference(A &);
+void passByNonConstPointerIsReinit() {
+ {
+ A a;
+ std::move(a);
+ passByNonConstPointer(&a);
+ a.foo();
+ }
+ {
+ A a;
+ std::move(a);
+ passByNonConstReference(a);
+ a.foo();
+ }
+}
+
+// Passing the object through a const pointer or reference counts as a use --
+// since the called function cannot reinitialize the object.
+void passByConstPointer(const A *);
+void passByConstReference(const A &);
+void passByConstPointerIsUse() {
+ {
+ // Declaring 'a' as const so that no ImplicitCastExpr is inserted into the
+ // AST -- we wouldn't want the check to rely solely on that to detect a
+ // const pointer argument.
+ const A a;
+ std::move(a);
+ passByConstPointer(&a);
+ // CHECK-MESSAGES: [[@LINE-1]]:25: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+ const A a;
+ std::move(a);
+ passByConstReference(a);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:3: note: move occurred here
+}
+
+// Clearing a standard container using clear() is treated as a
+// re-initialization.
+void standardContainerClearIsReinit() {
+ {
+ std::string container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::vector<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+
+ auto container2 = container;
+ std::move(container2);
+ container2.clear();
+ container2.empty();
+ }
+ {
+ std::deque<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::forward_list<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::list<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::set<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::map<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::multiset<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::multimap<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::unordered_set<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::unordered_map<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::unordered_multiset<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ {
+ std::unordered_multimap<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ // This should also work for typedefs of standard containers.
+ {
+ typedef std::vector<int> IntVector;
+ IntVector container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ // But it shouldn't work for non-standard containers.
+ {
+ // This might be called "vector", but it's not in namespace "std".
+ struct vector {
+ void clear() {}
+ } container;
+ std::move(container);
+ container.clear();
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'container' used after it was
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+ // An intervening clear() on a different container does not reinitialize.
+ {
+ std::vector<int> container1, container2;
+ std::move(container1);
+ container2.clear();
+ container1.empty();
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'container1' used after it was
+ // CHECK-MESSAGES: [[@LINE-4]]:5: note: move occurred here
+ }
+}
+
+// Clearing a standard container using assign() is treated as a
+// re-initialization.
+void standardContainerAssignIsReinit() {
+ {
+ std::string container;
+ std::move(container);
+ container.assign(0, ' ');
+ container.empty();
+ }
+ {
+ std::vector<int> container;
+ std::move(container);
+ container.assign(0, 0);
+ container.empty();
+ }
+ {
+ std::deque<int> container;
+ std::move(container);
+ container.assign(0, 0);
+ container.empty();
+ }
+ {
+ std::forward_list<int> container;
+ std::move(container);
+ container.assign(0, 0);
+ container.empty();
+ }
+ {
+ std::list<int> container;
+ std::move(container);
+ container.clear();
+ container.empty();
+ }
+ // But it doesn't work for non-standard containers.
+ {
+ // This might be called "vector", but it's not in namespace "std".
+ struct vector {
+ void assign(std::size_t, int) {}
+ } container;
+ std::move(container);
+ container.assign(0, 0);
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'container' used after it was
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+ // An intervening assign() on a different container does not reinitialize.
+ {
+ std::vector<int> container1, container2;
+ std::move(container1);
+ container2.assign(0, 0);
+ container1.empty();
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'container1' used after it was
+ // CHECK-MESSAGES: [[@LINE-4]]:5: note: move occurred here
+ }
+}
+
+// Resetting the standard smart pointer types using reset() is treated as a
+// re-initialization. (We don't test std::weak_ptr<> because it can't be
+// dereferenced directly.)
+void standardSmartPointerResetIsReinit() {
+ {
+ std::unique_ptr<A> ptr;
+ std::move(ptr);
+ ptr.reset(new A);
+ *ptr;
+ }
+ {
+ std::shared_ptr<A> ptr;
+ std::move(ptr);
+ ptr.reset(new A);
+ *ptr;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Tests related to order of evaluation within expressions
+
+// Relative sequencing of move and use.
+void passByRvalueReference(int i, A &&a);
+void passByValue(int i, A a);
+void passByValue(A a, int i);
+A g(A, A &&);
+int intFromA(A &&);
+int intFromInt(int);
+void sequencingOfMoveAndUse() {
+ // This case is fine because the move only happens inside
+ // passByRvalueReference(). At this point, a.getInt() is guaranteed to have
+ // been evaluated.
+ {
+ A a;
+ passByRvalueReference(a.getInt(), std::move(a));
+ }
+ // However, if we pass by value, the move happens when the move constructor is
+ // called to create a temporary, and this happens before the call to
+ // passByValue(). Because the order in which arguments are evaluated isn't
+ // defined, the move may happen before the call to a.getInt().
+ //
+ // Check that we warn about a potential use-after move for both orderings of
+ // a.getInt() and std::move(a), independent of the order in which the
+ // arguments happen to get evaluated by the compiler.
+ {
+ A a;
+ passByValue(a.getInt(), std::move(a));
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-2]]:29: note: move occurred here
+ // CHECK-MESSAGES: [[@LINE-3]]:17: note: the use and move are unsequenced
+ }
+ {
+ A a;
+ passByValue(std::move(a), a.getInt());
+ // CHECK-MESSAGES: [[@LINE-1]]:31: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-2]]:17: note: move occurred here
+ // CHECK-MESSAGES: [[@LINE-3]]:31: note: the use and move are unsequenced
+ }
+ // An even more convoluted example.
+ {
+ A a;
+ g(g(a, std::move(a)), g(a, std::move(a)));
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-2]]:27: note: move occurred here
+ // CHECK-MESSAGES: [[@LINE-3]]:9: note: the use and move are unsequenced
+ // CHECK-MESSAGES: [[@LINE-4]]:29: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-5]]:7: note: move occurred here
+ // CHECK-MESSAGES: [[@LINE-6]]:29: note: the use and move are unsequenced
+ }
+ // This case is fine because the actual move only happens inside the call to
+ // operator=(). a.getInt(), by necessity, is evaluated before that call.
+ {
+ A a;
+ A vec[1];
+ vec[a.getInt()] = std::move(a);
+ }
+ // However, in the following case, the move happens before the assignment, and
+ // so the order of evaluation is not guaranteed.
+ {
+ A a;
+ int v[3];
+ v[a.getInt()] = intFromA(std::move(a));
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-2]]:21: note: move occurred here
+ // CHECK-MESSAGES: [[@LINE-3]]:7: note: the use and move are unsequenced
+ }
+ {
+ A a;
+ int v[3];
+ v[intFromA(std::move(a))] = intFromInt(a.i);
+ // CHECK-MESSAGES: [[@LINE-1]]:44: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-2]]:7: note: move occurred here
+ // CHECK-MESSAGES: [[@LINE-3]]:44: note: the use and move are unsequenced
+ }
+}
+
+// Relative sequencing of move and reinitialization. If the two are unsequenced,
+// we conservatively assume that the move happens after the reinitialization,
+// i.e. the that object does not get reinitialized after the move.
+A MutateA(A a);
+void passByValue(A a1, A a2);
+void sequencingOfMoveAndReinit() {
+ // Move and reinitialization as function arguments (which are indeterminately
+ // sequenced). Again, check that we warn for both orderings.
+ {
+ A a;
+ passByValue(std::move(a), (a = A()));
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:17: note: move occurred here
+ }
+ {
+ A a;
+ passByValue((a = A()), std::move(a));
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:28: note: move occurred here
+ }
+ // Common usage pattern: Move the object to a function that mutates it in some
+ // way, then reassign the result to the object. This pattern is fine.
+ {
+ A a;
+ a = MutateA(std::move(a));
+ a.foo();
+ }
+}
+
+// Relative sequencing of reinitialization and use. If the two are unsequenced,
+// we conservatively assume that the reinitialization happens after the use,
+// i.e. that the object is not reinitialized at the point in time when it is
+// used.
+void sequencingOfReinitAndUse() {
+ // Reinitialization and use in function arguments. Again, check both possible
+ // orderings.
+ {
+ A a;
+ std::move(a);
+ passByValue(a.getInt(), (a = A()));
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+ {
+ A a;
+ std::move(a);
+ passByValue((a = A()), a.getInt());
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:5: note: move occurred here
+ }
+}
+
+// The comma operator sequences its operands.
+void commaOperatorSequences() {
+ {
+ A a;
+ A(std::move(a))
+ , (a = A());
+ a.foo();
+ }
+ {
+ A a;
+ (a = A()), A(std::move(a));
+ a.foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-3]]:16: note: move occurred here
+ }
+}
+
+// An initializer list sequences its initialization clauses.
+void initializerListSequences() {
+ {
+ struct S1 {
+ int i;
+ A a;
+ };
+ A a;
+ S1 s1{a.getInt(), std::move(a)};
+ }
+ {
+ struct S2 {
+ A a;
+ int i;
+ };
+ A a;
+ S2 s2{std::move(a), a.getInt()};
+ // CHECK-MESSAGES: [[@LINE-1]]:25: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-2]]:11: note: move occurred here
+ }
+}
+
+// A declaration statement containing multiple declarations sequences the
+// initializer expressions.
+void declarationSequences() {
+ {
+ A a;
+ A a1 = a, a2 = std::move(a);
+ }
+ {
+ A a;
+ A a1 = std::move(a), a2 = a;
+ // CHECK-MESSAGES: [[@LINE-1]]:31: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-2]]:12: note: move occurred here
+ }
+}
+
+// The logical operators && and || sequence their operands.
+void logicalOperatorsSequence() {
+ {
+ A a;
+ if (a.getInt() > 0 && A(std::move(a)).getInt() > 0) {
+ A().foo();
+ }
+ }
+ // A variation: Negate the result of the && (which pushes the && further down
+ // into the AST).
+ {
+ A a;
+ if (!(a.getInt() > 0 && A(std::move(a)).getInt() > 0)) {
+ A().foo();
+ }
+ }
+ {
+ A a;
+ if (A(std::move(a)).getInt() > 0 && a.getInt() > 0) {
+ // CHECK-MESSAGES: [[@LINE-1]]:41: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-2]]:9: note: move occurred here
+ A().foo();
+ }
+ }
+ {
+ A a;
+ if (a.getInt() > 0 || A(std::move(a)).getInt() > 0) {
+ A().foo();
+ }
+ }
+ {
+ A a;
+ if (A(std::move(a)).getInt() > 0 || a.getInt() > 0) {
+ // CHECK-MESSAGES: [[@LINE-1]]:41: warning: 'a' used after it was moved
+ // CHECK-MESSAGES: [[@LINE-2]]:9: note: move occurred here
+ A().foo();
+ }
+ }
+}
+
+// A range-based for sequences the loop variable declaration before the body.
+void forRangeSequences() {
+ A v[2] = {A(), A()};
+ for (A &a : v) {
+ std::move(a);
+ }
+}
+
+// If a variable is declared in an if statement, the declaration of the variable
+// (which is treated like a reinitialization by the check) is sequenced before
+// the evaluation of the condition (which constitutes a use).
+void ifStmtSequencesDeclAndCondition() {
+ for (int i = 0; i < 10; ++i) {
+ if (A a = A()) {
+ std::move(a);
+ }
+ }
+}
+
+namespace PR33020 {
+class D {
+ ~D();
+};
+struct A {
+ D d;
+};
+class B {
+ A a;
+};
+template <typename T>
+class C : T, B {
+ void m_fn1() {
+ int a;
+ std::move(a);
+ C c;
+ }
+};
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-virtual-near-miss.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-virtual-near-miss.cpp
new file mode 100644
index 0000000..553d2f4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/bugprone-virtual-near-miss.cpp
@@ -0,0 +1,133 @@
+// RUN: %check_clang_tidy %s bugprone-virtual-near-miss %t
+
+class NoDefinedClass1;
+class NoDefinedClass2;
+
+struct Base {
+ virtual void func();
+ virtual void gunk();
+ virtual ~Base();
+ virtual Base &operator=(const Base &);
+ virtual NoDefinedClass1 *f();
+};
+
+struct Derived : Base {
+ // Should not warn "do you want to override 'gunk'?", because gunk is already
+ // overriden by this class.
+ virtual void funk();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Derived::funk' has a similar name and the same signature as virtual method 'Base::func'; did you mean to override it? [bugprone-virtual-near-miss]
+ // CHECK-FIXES: virtual void func();
+
+ void func2();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Derived::func2' has {{.*}} 'Base::func'
+ // CHECK-FIXES: void func();
+
+ void func22(); // Should not warn.
+
+ void gunk(); // Should not warn: gunk is override.
+
+ void fun();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Derived::fun' has {{.*}} 'Base::func'
+ // CHECK-FIXES: void func();
+
+ Derived &operator==(const Base &); // Should not warn: operators are ignored.
+
+ virtual NoDefinedClass2 *f1(); // Should not crash: non-defined class return type is ignored.
+};
+
+template <typename T>
+struct TBase {
+ virtual void tfunc(T t);
+};
+
+template <typename T>
+struct TDerived : TBase<T> {
+ virtual void tfunk(T t);
+ // Should not apply fix for template.
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: method 'TDerived<double>::tfunk' has {{.*}} 'TBase<double>::tfunc'
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: method 'TDerived<int>::tfunk' has {{.*}} 'TBase<int>::tfunc'
+ // CHECK-FIXES: virtual void tfunk(T t);
+};
+
+TDerived<int> T1;
+TDerived<double> T2;
+
+// Should not fix macro definition
+#define MACRO1 void funcM()
+// CHECK-FIXES: #define MACRO1 void funcM()
+#define MACRO2(m) void m()
+// CHECK-FIXES: #define MACRO2(m) void m()
+
+struct DerivedMacro : Base {
+ MACRO1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'DerivedMacro::funcM' has {{.*}} 'Base::func'
+ // CHECK-FIXES: MACRO1;
+
+ MACRO2(func3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'DerivedMacro::func3' has {{.*}} 'Base::func'
+ // CHECK-FIXES: MACRO2(func);
+};
+
+typedef Derived derived_type;
+
+class Father {
+public:
+ Father();
+ virtual void func();
+ virtual Father *create(int i);
+ virtual Base &&generate();
+ virtual Base *canonical(Derived D);
+};
+
+class Mother {
+public:
+ Mother();
+ static void method();
+ virtual int method(int argc, const char **argv);
+ virtual int method(int argc) const;
+ virtual int decay(const char *str);
+};
+
+class Child : private Father, private Mother {
+public:
+ Child();
+
+ virtual void func2();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::func2' has {{.*}} 'Father::func'
+ // CHECK-FIXES: virtual void func();
+
+ int methoe(int x, char **strs); // Should not warn: parameter types don't match.
+
+ int methoe(int x);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::methoe' has {{.*}} 'Mother::method'
+ // CHECK-FIXES: int method(int x);
+
+ void methof(int x, const char **strs); // Should not warn: return types don't match.
+
+ int methoh(int x, const char **strs);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::methoh' has {{.*}} 'Mother::method'
+ // CHECK-FIXES: int method(int x, const char **strs);
+
+ virtual Child *creat(int i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::creat' has {{.*}} 'Father::create'
+ // CHECK-FIXES: virtual Child *create(int i);
+
+ virtual Derived &&generat();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::generat' has {{.*}} 'Father::generate'
+ // CHECK-FIXES: virtual Derived &&generate();
+
+ int decaz(const char str[]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::decaz' has {{.*}} 'Mother::decay'
+ // CHECK-FIXES: int decay(const char str[]);
+
+ operator bool();
+
+ derived_type *canonica(derived_type D);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::canonica' has {{.*}} 'Father::canonical'
+ // CHECK-FIXES: derived_type *canonical(derived_type D);
+
+private:
+ void funk();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: method 'Child::funk' has {{.*}} 'Father::func'
+ // CHECK-FIXES: void func();
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-dcl21-cpp.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-dcl21-cpp.cpp
new file mode 100644
index 0000000..c975f70
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-dcl21-cpp.cpp
@@ -0,0 +1,134 @@
+// RUN: %check_clang_tidy %s cert-dcl21-cpp %t
+
+class A {};
+
+A operator++(A &, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator++' returns a non-constant object instead of a constant object type [cert-dcl21-cpp]
+// CHECK-FIXES: {{^}}const A operator++(A &, int);
+
+A operator--(A &, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator--' returns a no
+// CHECK-FIXES: {{^}}const A operator--(A &, int);
+
+class B {};
+
+B &operator++(B &);
+const B operator++(B &, int);
+
+B &operator--(B &);
+const B operator--(B &, int);
+
+
+class D {
+D &operator++();
+const D operator++(int);
+
+D &operator--();
+const D operator--(int);
+};
+
+class C {
+C operator++(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator++' returns a no
+// CHECK-FIXES: {{^}}const C operator++(int);
+
+C operator--(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator--' returns a no
+// CHECK-FIXES: {{^}}const C operator--(int);
+};
+
+class E {};
+
+E &operator++(E &, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator++' returns a reference instead of a constant object type [cert-dcl21-cpp]
+// CHECK-FIXES: {{^}}const E operator++(E &, int);
+
+E &operator--(E &, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator--' returns a re
+// CHECK-FIXES: {{^}}const E operator--(E &, int);
+
+class G {
+G &operator++(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}}const G operator++(int);
+
+G &operator--(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator--' returns a re
+// CHECK-FIXES: {{^}}const G operator--(int);
+};
+
+class F {};
+
+const F &operator++(F &, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}}const F operator++(F &, int);
+
+const F &operator--(F &, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: overloaded 'operator--' returns a re
+// CHECK-FIXES: {{^}}const F operator--(F &, int);
+
+class H {
+const H &operator++(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}}const H operator++(int);
+
+const H &operator--(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: overloaded 'operator--' returns a re
+// CHECK-FIXES: {{^}}const H operator--(int);
+};
+
+
+#define FROM_MACRO P&
+class P {
+const FROM_MACRO operator++(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}}const FROM_MACRO operator++(int);
+};
+
+
+template<typename T>
+class Q {
+const Q &operator++(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}}const Q<T> operator++(int);
+
+const Q &operator--(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: overloaded 'operator--' returns a re
+// CHECK-FIXES: {{^}}const Q<T> operator--(int);
+};
+
+void foobar() {
+ Q<int> a;
+ Q<float> b;
+ (void)a;
+ (void)b;
+}
+
+struct S {};
+typedef S& SRef;
+
+SRef operator++(SRef, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}}SRef operator++(SRef, int);
+
+struct T {
+ typedef T& TRef;
+
+ TRef operator++(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}} TRef operator++(int);
+};
+
+struct U {
+ typedef const U& ConstURef;
+
+ ConstURef& operator++(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: overloaded 'operator++' returns a re
+// CHECK-FIXES: {{^}} ConstURef& operator++(int);
+};
+
+struct V {
+ V *operator++(int);
+ V *const operator--(int);
+};
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-dcl58-cpp.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-dcl58-cpp.cpp
new file mode 100644
index 0000000..34ee368
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-dcl58-cpp.cpp
@@ -0,0 +1,67 @@
+// RUN: %check_clang_tidy %s cert-dcl58-cpp %t -- -- -std=c++1z -I %S/Inputs/Headers
+
+#include "system-header-simulation.h"
+
+namespace A {
+ namespace B {
+ int b;
+ }
+}
+
+namespace A {
+ namespace B {
+ int c;
+ }
+}
+
+namespace posix {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: modification of 'posix' namespace can result in undefined behavior [cert-dcl58-cpp]
+ namespace vmi {
+ }
+}
+
+namespace std {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: modification of 'std' namespace can
+ int stdInt;
+}
+
+namespace foobar {
+ namespace std {
+ int bar;
+ }
+}
+
+namespace posix::a {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: modification of 'posix' namespace
+}
+
+enum class MyError {
+ ErrorA,
+ ErrorB
+};
+
+namespace std {
+template <>
+struct is_error_code_enum<MyError> : std::true_type {};
+
+template<>
+void swap<MyError>(MyError &a, MyError &b);
+}
+
+enum class MyError2 {
+ Error2A,
+ Error2B
+};
+
+namespace std {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: modification of 'std' namespace
+template <>
+struct is_error_code_enum<MyError2> : std::true_type {};
+
+int foobar;
+}
+
+using namespace std;
+
+int x;
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-env33-c.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-env33-c.c
new file mode 100644
index 0000000..5846b49
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-env33-c.c
@@ -0,0 +1,20 @@
+// RUN: %check_clang_tidy %s cert-env33-c %t
+
+typedef struct FILE {} FILE;
+
+extern int system(const char *);
+extern FILE *popen(const char *, const char *);
+extern FILE *_popen(const char *, const char *);
+
+void f(void) {
+ // It is permissible to check for the presence of a command processor.
+ system(0);
+
+ system("test");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'system' uses a command processor [cert-env33-c]
+
+ popen("test", "test");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling 'popen' uses a command processor
+ _popen("test", "test");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling '_popen' uses a command processor
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-err34-c.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-err34-c.c
new file mode 100644
index 0000000..e2cfc21
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-err34-c.c
@@ -0,0 +1,103 @@
+// RUN: %check_clang_tidy %s cert-err34-c %t -- -- -std=c11
+
+typedef __SIZE_TYPE__ size_t;
+typedef signed ptrdiff_t;
+typedef long long intmax_t;
+typedef unsigned long long uintmax_t;
+typedef void * FILE;
+
+extern FILE *stdin;
+
+extern int fscanf(FILE * restrict stream, const char * restrict format, ...);
+extern int scanf(const char * restrict format, ...);
+extern int sscanf(const char * restrict s, const char * restrict format, ...);
+
+extern double atof(const char *nptr);
+extern int atoi(const char *nptr);
+extern long int atol(const char *nptr);
+extern long long int atoll(const char *nptr);
+
+void f1(const char *in) {
+ int i;
+ long long ll;
+ unsigned int ui;
+ unsigned long long ull;
+ intmax_t im;
+ uintmax_t uim;
+ float f;
+ double d;
+ long double ld;
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c]
+ sscanf(in, "%d", &i);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoll' instead [cert-err34-c]
+ fscanf(stdin, "%lld", &ll);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to an unsigned integer value, but function will not report conversion errors; consider using 'strtoul' instead [cert-err34-c]
+ sscanf(in, "%u", &ui);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to an unsigned integer value, but function will not report conversion errors; consider using 'strtoull' instead [cert-err34-c]
+ fscanf(stdin, "%llu", &ull);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoimax' instead [cert-err34-c]
+ scanf("%jd", &im);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to an unsigned integer value, but function will not report conversion errors; consider using 'strtoumax' instead [cert-err34-c]
+ fscanf(stdin, "%ju", &uim);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtof' instead [cert-err34-c]
+ sscanf(in, "%f", &f); // to float
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtod' instead [cert-err34-c]
+ fscanf(stdin, "%lg", &d);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtold' instead [cert-err34-c]
+ sscanf(in, "%Le", &ld);
+
+ // These are conversions with other modifiers
+ short s;
+ char c;
+ size_t st;
+ ptrdiff_t pt;
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%hhd", &c);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%hd", &s);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%zu", &st);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%td", &pt);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%o", ui);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%X", ui);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%x", ui);
+}
+
+void f2(const char *in) {
+ // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: 'atoi' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c]
+ int i = atoi(in); // to int
+ // CHECK-MESSAGES: :[[@LINE+1]]:12: warning: 'atol' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c]
+ long l = atol(in); // to long
+ // CHECK-MESSAGES: :[[@LINE+1]]:18: warning: 'atoll' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoll' instead [cert-err34-c]
+ long long ll = atoll(in); // to long long
+ // CHECK-MESSAGES: :[[@LINE+1]]:14: warning: 'atof' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtod' instead [cert-err34-c]
+ double d = atof(in); // to double
+}
+
+void f3(void) {
+ int i;
+ unsigned int u;
+ float f;
+ char str[32];
+
+ // Test that we don't report multiple infractions for a single call.
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%d%u%f", &i, &u, &f);
+
+ // Test that we still catch infractions that are not the first specifier.
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'scanf' used to convert
+ scanf("%s%d", str, &i);
+}
+
+void do_not_diagnose(void) {
+ char str[32];
+
+ scanf("%s", str); // Not a numerical conversion
+ scanf("%*d"); // Assignment suppressed
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-err34-c.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-err34-c.cpp
new file mode 100644
index 0000000..dde7dc1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-err34-c.cpp
@@ -0,0 +1,43 @@
+// RUN: %check_clang_tidy %s cert-err34-c %t -- -- -std=c++11
+
+typedef void * FILE;
+
+extern FILE *stdin;
+
+extern int fscanf(FILE * stream, const char * format, ...);
+extern int sscanf(const char * s, const char * format, ...);
+
+extern double atof(const char *nptr);
+extern int atoi(const char *nptr);
+extern long int atol(const char *nptr);
+extern long long int atoll(const char *nptr);
+
+namespace std {
+using ::FILE; using ::stdin;
+using ::fscanf; using ::sscanf;
+using ::atof; using ::atoi; using ::atol; using ::atoll;
+}
+
+void f1(const char *in) {
+ int i;
+ long long ll;
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'sscanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c]
+ std::sscanf(in, "%d", &i);
+ // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: 'fscanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoll' instead [cert-err34-c]
+ std::fscanf(std::stdin, "%lld", &ll);
+}
+
+void f2(const char *in) {
+ // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: 'atoi' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c]
+ int i = std::atoi(in); // to int
+ // CHECK-MESSAGES: :[[@LINE+1]]:12: warning: 'atol' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead [cert-err34-c]
+ long l = std::atol(in); // to long
+
+ using namespace std;
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:18: warning: 'atoll' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtoll' instead [cert-err34-c]
+ long long ll = atoll(in); // to long long
+ // CHECK-MESSAGES: :[[@LINE+1]]:14: warning: 'atof' used to convert a string to a floating-point value, but function will not report conversion errors; consider using 'strtod' instead [cert-err34-c]
+ double d = atof(in); // to double
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-flp30-c.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-flp30-c.c
new file mode 100644
index 0000000..eee16be
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-flp30-c.c
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy %s cert-flp30-c %t
+
+float g(void);
+
+void func(void) {
+ for (float x = 0.1f; x <= 1.0f; x += 0.1f) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: loop induction expression should not have floating-point type [cert-flp30-c]
+
+ float f = 1.0f;
+ for (; f > 0; --f) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: loop induction expression
+
+ for (;;g()) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: loop induction expression
+
+ for (int i = 0; i < 10; i += 1.0f) {}
+
+ for (int i = 0; i < 10; ++i) {}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-limited-randomness.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-limited-randomness.c
new file mode 100644
index 0000000..c8009b5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-limited-randomness.c
@@ -0,0 +1,13 @@
+// RUN: %check_clang_tidy %s cert-msc30-c %t
+
+extern int rand(void);
+int nonrand();
+
+int cTest() {
+ int i = rand();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: rand() has limited randomness [cert-msc30-c]
+
+ int k = nonrand();
+
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-limited-randomness.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-limited-randomness.cpp
new file mode 100644
index 0000000..845b735
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-limited-randomness.cpp
@@ -0,0 +1,28 @@
+// RUN: %check_clang_tidy %s cert-msc50-cpp %t
+
+int rand();
+int rand(int);
+
+namespace std {
+using ::rand;
+}
+
+namespace nonstd {
+ int rand();
+}
+
+void testFunction1() {
+ int i = std::rand();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: rand() has limited randomness; use C++11 random library instead [cert-msc50-cpp]
+
+ int j = ::rand();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: rand() has limited randomness; use C++11 random library instead [cert-msc50-cpp]
+
+ int k = rand(i);
+
+ int l = nonstd::rand();
+
+ int m = rand();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: rand() has limited randomness; use C++11 random library instead [cert-msc50-cpp]
+}
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-msc32-c.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-msc32-c.c
new file mode 100644
index 0000000..6cc40fa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-msc32-c.c
@@ -0,0 +1,27 @@
+// RUN: %check_clang_tidy %s cert-msc32-c %t -- -config="{CheckOptions: [{key: cert-msc32-c.DisallowedSeedTypes, value: 'some_type,time_t'}]}" -- -std=c99
+
+void srand(int seed);
+typedef int time_t;
+time_t time(time_t *t);
+
+void f() {
+ srand(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc32-c]
+
+ const int a = 1;
+ srand(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc32-c]
+
+ time_t t;
+ srand(time(&t)); // Disallowed seed type
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc32-c]
+}
+
+void g() {
+ typedef int user_t;
+ user_t a = 1;
+ srand(a);
+
+ int b = 1;
+ srand(b); // Can not evaluate as int
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-msc51-cpp.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-msc51-cpp.cpp
new file mode 100644
index 0000000..8a8d778
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-msc51-cpp.cpp
@@ -0,0 +1,210 @@
+// RUN: %check_clang_tidy %s cert-msc51-cpp %t -- -config="{CheckOptions: [{key: cert-msc51-cpp.DisallowedSeedTypes, value: 'some_type,time_t'}]}" -- -std=c++11
+
+namespace std {
+
+void srand(int seed);
+
+template <class UIntType, UIntType a, UIntType c, UIntType m>
+struct linear_congruential_engine {
+ linear_congruential_engine(int _ = 0);
+ void seed(int _ = 0);
+};
+using default_random_engine = linear_congruential_engine<unsigned int, 1, 2, 3>;
+
+using size_t = int;
+template <class UIntType, size_t w, size_t n, size_t m, size_t r,
+ UIntType a, size_t u, UIntType d, size_t s,
+ UIntType b, size_t t,
+ UIntType c, size_t l, UIntType f>
+struct mersenne_twister_engine {
+ mersenne_twister_engine(int _ = 0);
+ void seed(int _ = 0);
+};
+using mt19937 = mersenne_twister_engine<unsigned int, 32, 624, 397, 21, 0x9908b0df, 11, 0xffffffff, 7, 0x9d2c5680, 15, 0xefc60000, 18, 1812433253>;
+
+template <class UIntType, size_t w, size_t s, size_t r>
+struct subtract_with_carry_engine {
+ subtract_with_carry_engine(int _ = 0);
+ void seed(int _ = 0);
+};
+using ranlux24_base = subtract_with_carry_engine<unsigned int, 24, 10, 24>;
+
+template <class Engine, size_t p, size_t r>
+struct discard_block_engine {
+ discard_block_engine();
+ discard_block_engine(int _);
+ void seed();
+ void seed(int _);
+};
+using ranlux24 = discard_block_engine<ranlux24_base, 223, 23>;
+
+template <class Engine, size_t w, class UIntType>
+struct independent_bits_engine {
+ independent_bits_engine();
+ independent_bits_engine(int _);
+ void seed();
+ void seed(int _);
+};
+using independent_bits = independent_bits_engine<ranlux24_base, 223, int>;
+
+template <class Engine, size_t k>
+struct shuffle_order_engine {
+ shuffle_order_engine();
+ shuffle_order_engine(int _);
+ void seed();
+ void seed(int _);
+};
+using shuffle_order = shuffle_order_engine<ranlux24_base, 223>;
+
+struct random_device {
+ random_device();
+ int operator()();
+};
+} // namespace std
+
+using time_t = unsigned int;
+time_t time(time_t *t);
+
+void f() {
+ const int seed = 2;
+ time_t t;
+
+ std::srand(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::srand(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::srand(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+
+ // One instantiation for every engine
+ std::default_random_engine engine1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ std::default_random_engine engine2(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::default_random_engine engine3(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::default_random_engine engine4(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine1.seed();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ engine1.seed(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine1.seed(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine1.seed(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+
+ std::mt19937 engine5;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ std::mt19937 engine6(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::mt19937 engine7(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::mt19937 engine8(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine5.seed();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ engine5.seed(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine5.seed(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine5.seed(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+
+ std::ranlux24_base engine9;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ std::ranlux24_base engine10(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::ranlux24_base engine11(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::ranlux24_base engine12(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine9.seed();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ engine9.seed(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine9.seed(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine9.seed(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+
+ std::ranlux24 engine13;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ std::ranlux24 engine14(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::ranlux24 engine15(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::ranlux24 engine16(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine13.seed();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ engine13.seed(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine13.seed(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine13.seed(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+
+ std::independent_bits engine17;
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ std::independent_bits engine18(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::independent_bits engine19(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::independent_bits engine20(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine17.seed();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ engine17.seed(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine17.seed(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine17.seed(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+
+ std::shuffle_order engine21;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ std::shuffle_order engine22(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::shuffle_order engine23(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ std::shuffle_order engine24(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine21.seed();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a default argument will generate a predictable sequence of values [cert-msc51-cpp]
+ engine21.seed(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine21.seed(seed);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a constant value will generate a predictable sequence of values [cert-msc51-cpp]
+ engine21.seed(time(&t));
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: random number generator seeded with a disallowed source of seed value will generate a predictable sequence of values [cert-msc51-cpp]
+}
+
+struct A {
+ A(int _ = 0);
+ void seed(int _ = 0);
+};
+
+void g() {
+ int n = 1;
+ std::default_random_engine engine1(n);
+ std::mt19937 engine2(n);
+ std::ranlux24_base engine3(n);
+ std::ranlux24 engine4(n);
+ std::independent_bits engine5(n);
+ std::shuffle_order engine6(n);
+
+ std::random_device dev;
+ std::default_random_engine engine7(dev());
+ std::mt19937 engine8(dev());
+ std::ranlux24_base engine9(dev());
+ std::ranlux24 engine10(dev());
+ std::independent_bits engine11(dev());
+ std::shuffle_order engine12(dev());
+
+ A a1;
+ A a2(1);
+ a1.seed();
+ a1.seed(1);
+ a1.seed(n);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-oop11-cpp.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-oop11-cpp.cpp
new file mode 100644
index 0000000..650d6ec
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-oop11-cpp.cpp
@@ -0,0 +1,21 @@
+// RUN: %check_clang_tidy %s cert-oop11-cpp %t -- -- -std=c++11
+
+struct B {
+ B(B&&) noexcept = default;
+
+ B(const B &) = default;
+ B& operator=(const B&) = default;
+ ~B() {}
+};
+
+struct D {
+ B b;
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:14: warning: move constructor initializes class member by calling a copy constructor [cert-oop11-cpp]
+ D(D &&d) : b(d.b) {}
+
+ // This should not produce a diagnostic because it is not covered under
+ // the CERT guideline for OOP11-CPP. However, this will produce a diagnostic
+ // under performance-move-constructor-init.
+ D(B b) : b(b) {}
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-setlongjmp.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-setlongjmp.cpp
new file mode 100644
index 0000000..1bf5444
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-setlongjmp.cpp
@@ -0,0 +1,26 @@
+// RUN: %check_clang_tidy %s cert-err52-cpp %t -- -- -std=c++11
+
+typedef void *jmp_buf;
+extern int __setjmpimpl(jmp_buf);
+#define setjmp(x) __setjmpimpl(x)
+[[noreturn]] extern void longjmp(jmp_buf, int);
+
+namespace std {
+using ::jmp_buf;
+using ::longjmp;
+}
+
+static jmp_buf env;
+void g() {
+ std::longjmp(env, 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call 'longjmp'; consider using exception handling instead [cert-err52-cpp]
+ ::longjmp(env, 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call 'longjmp'; consider using exception handling instead
+ longjmp(env, 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call 'longjmp'; consider using exception handling instead
+}
+
+void f() {
+ (void)setjmp(env);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not call 'setjmp'; consider using exception handling instead
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-static-object-exception.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-static-object-exception.cpp
new file mode 100644
index 0000000..aa34bbd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-static-object-exception.cpp
@@ -0,0 +1,225 @@
+// RUN: clang-tidy %s -checks="-*,cert-err58-cpp" -- -std=c++11 -target x86_64-pc-linux-gnu \
+// RUN: | FileCheck %s -check-prefix=CHECK-EXCEPTIONS \
+// RUN: -implicit-check-not="{{warning|error}}:"
+// RUN: clang-tidy %s -checks="-*,cert-err58-cpp" -- -fno-exceptions -std=c++11 -target x86_64-pc-linux-gnu \
+// RUN: | FileCheck %s -allow-empty -check-prefix=CHECK-NONEXCEPTIONS \
+// RUN: -implicit-check-not="{{warning|error}}:"
+
+struct S {
+ S() noexcept(false);
+};
+
+struct T {
+ T() noexcept;
+};
+
+struct U {
+ U() {}
+};
+
+struct V {
+ explicit V(const char *) {} // Can throw
+};
+
+struct Cleanup {
+ ~Cleanup() {}
+};
+
+struct W {
+ W(Cleanup c = {}) noexcept(false);
+};
+
+struct X {
+ X(S = {}) noexcept;
+};
+
+struct Y {
+ S s;
+};
+
+struct Z {
+ T t;
+};
+
+int f();
+int g() noexcept(false);
+int h() noexcept(true);
+
+struct UserConv_Bad {
+ operator int() noexcept(false);
+};
+
+struct UserConv_Good {
+ operator int() noexcept;
+};
+
+UserConv_Bad some_bad_func() noexcept;
+UserConv_Good some_good_func() noexcept;
+
+S s;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp]
+// CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+T t; // ok
+U u;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'u' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 17:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+V v("v");
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'v' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 21:12: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+W w;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'w' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 29:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+X x1(S{});
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'x1' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+X x2;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'x2' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+Y y;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'y' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 36:8: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+Z z;
+
+int i = f();
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:5: warning: initialization of 'i' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 44:5: note: possibly throwing function declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+int j = g();
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:5: warning: initialization of 'j' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 45:5: note: possibly throwing function declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+int k = h();
+int l = some_bad_func();
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:5: warning: initialization of 'l' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 49:3: note: possibly throwing function declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+int m = some_good_func();
+
+typedef decltype(sizeof(int)) size_t;
+inline void *operator new(size_t sz, void *here) noexcept { return here; }
+char n[sizeof(int)];
+int *o = new (n) int();
+int *p = new int();
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:6: warning: initialization of 'p' with static storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+
+thread_local S s3;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 's3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+thread_local T t3; // ok
+thread_local U u3;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'u3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+thread_local V v3("v");
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'v3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+thread_local W w3;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'w3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+
+void f(S s1, T t1, U u1, V v1, W w1) { // ok, ok, ok, ok, ok
+ S s2; // ok
+ T t2; // ok
+ U u2; // ok
+ V v2("v"); // ok
+ W w2; // ok
+
+ thread_local S s3; // ok
+ thread_local T t3; // ok
+ thread_local U u3; // ok
+ thread_local V v3("v"); // ok
+ thread_local W w3; // ok
+
+ static S s4; // ok
+ static T t4; // ok
+ static U u4; // ok
+ static V v4("v"); // ok
+ static W w4; // ok
+}
+
+namespace {
+S s;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp]
+// CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+T t; // ok
+U u;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'u' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 17:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+V v("v");
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'v' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 21:12: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+W w;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:3: warning: initialization of 'w' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 29:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+
+thread_local S s3;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 's3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+thread_local T t3; // ok
+thread_local U u3;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'u3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+thread_local V v3("v");
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'v3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+thread_local W w3;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:16: warning: initialization of 'w3' with thread_local storage duration may throw an exception that cannot be caught
+// CHECK-NONEXCEPTIONS-NOT: warning:
+}; // namespace
+
+class Statics {
+ static S s; // warn when initialized
+ static T t; // ok
+ static U u; // warn when initialized
+ static V v; // warn when initialized
+ static W w; // warn when initialized
+
+ void f(S s, T t, U u, V v) {
+ S s2; // ok
+ T t2; // ok
+ U u2; // ok
+ V v2("v"); // ok
+ W w2; // ok
+
+ thread_local S s3; // ok
+ thread_local T t3; // ok
+ thread_local U u3; // ok
+ thread_local V v3("v"); // ok
+ thread_local W w3; // ok
+
+ static S s4; // ok
+ static T t4; // ok
+ static U u4; // ok
+ static V v4("v"); // ok
+ static W w4; // ok
+ }
+};
+
+S Statics::s;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:12: warning: initialization of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp]
+// CHECK-EXCEPTIONS: 9:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+T Statics::t;
+U Statics::u;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:12: warning: initialization of 'u' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 17:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+V Statics::v("v");
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:12: warning: initialization of 'v' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 21:12: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
+W Statics::w;
+// CHECK-EXCEPTIONS: :[[@LINE-1]]:12: warning: initialization of 'w' with static storage duration may throw an exception that cannot be caught
+// CHECK-EXCEPTIONS: 29:3: note: possibly throwing constructor declared here
+// CHECK-NONEXCEPTIONS-NOT: warning:
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-throw-exception-type.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-throw-exception-type.cpp
new file mode 100644
index 0000000..2ff9be5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-throw-exception-type.cpp
@@ -0,0 +1,127 @@
+// RUN: %check_clang_tidy %s cert-err60-cpp %t -- -- -std=c++11 -fcxx-exceptions
+
+struct S {};
+struct T : S {};
+struct U {
+ U() = default;
+ U(const U&) = default;
+};
+
+struct V {
+ V() = default;
+ V(const V&) noexcept;
+};
+
+struct W {
+ W() = default;
+ W(const W&) noexcept(false);
+};
+
+struct X {
+ X() = default;
+ X(const X&) {}
+};
+
+struct Y {
+ Y() = default;
+ Y(const Y&) throw();
+};
+
+struct Z {
+ Z() = default;
+ Z(const Z&) throw(int);
+};
+
+void g() noexcept(false);
+
+struct A {
+ A() = default;
+ A(const A&) noexcept(noexcept(g()));
+};
+
+struct B {
+ B() = default;
+ B(const B&) = default;
+ B(const A&) noexcept(false);
+};
+
+class C {
+ W M; // W is not no-throw copy constructible
+public:
+ C() = default;
+ C(const C&) = default;
+};
+
+struct D {
+ D() = default;
+ D(const D&) noexcept(false);
+ D(D&) noexcept(true);
+};
+
+struct E {
+ E() = default;
+ E(E&) noexcept(true);
+ E(const E&) noexcept(false);
+};
+
+struct Allocates {
+ int *x;
+ Allocates() : x(new int(0)) {}
+ Allocates(const Allocates &other) : x(new int(*other.x)) {}
+};
+
+struct OptionallyAllocates {
+ int *x;
+ OptionallyAllocates() : x(new int(0)) {}
+ OptionallyAllocates(const Allocates &other) noexcept(true) {
+ try {
+ x = new int(*other.x);
+ } catch (...) {
+ x = nullptr;
+ }
+ }
+};
+
+void f() {
+ throw 12; // ok
+ throw "test"; // ok
+ throw S(); // ok
+ throw T(); // ok
+ throw U(); // ok
+ throw V(); // ok
+ throw W(); // match, noexcept(false)
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible [cert-err60-cpp]
+ throw X(); // match, no noexcept clause, nontrivial
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw Y(); // ok
+ throw Z(); // match, throw(int)
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw A(); // match, noexcept(false)
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw B(); // ok
+ throw C(); // match, C has a member variable that makes it throwing on copy
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw D(); // match, has throwing copy constructor
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw E(); // match, has throwing copy constructor
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw Allocates(); // match, copy constructor throws
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+ throw OptionallyAllocates(); // ok
+}
+
+namespace PR25574 {
+struct B {
+ B(const B&) noexcept;
+};
+
+struct D : B {
+ D();
+ virtual ~D() noexcept;
+};
+
+template <typename T>
+void f() {
+ throw D();
+}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-variadic-function-def.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-variadic-function-def.cpp
new file mode 100644
index 0000000..6b2421b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cert-variadic-function-def.cpp
@@ -0,0 +1,24 @@
+// RUN: %check_clang_tidy %s cert-dcl50-cpp %t
+
+// Variadic function definitions are diagnosed.
+void f1(int, ...) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: do not define a C-style variadic function; consider using a function parameter pack or currying instead [cert-dcl50-cpp]
+
+// Variadic function *declarations* are not diagnosed.
+void f2(int, ...); // ok
+
+// Function parameter packs are good, however.
+template <typename Arg, typename... Ts>
+void f3(Arg F, Ts... Rest) {}
+
+struct S {
+ void f(int, ...); // ok
+ void f1(int, ...) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: do not define a C-style variadic function; consider using a function parameter pack or currying instead
+};
+
+// Function definitions that are extern "C" are good.
+extern "C" void f4(int, ...) {} // ok
+extern "C" {
+ void f5(int, ...) {} // ok
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/check_clang_tidy.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/check_clang_tidy.cpp
new file mode 100644
index 0000000..5c1bf92
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/check_clang_tidy.cpp
@@ -0,0 +1,21 @@
+// RUN: %check_clang_tidy -check-suffix=USING-A %s misc-unused-using-decls %t -- -- -DUSING_A
+// RUN: %check_clang_tidy -check-suffix=USING-B %s misc-unused-using-decls %t -- -- -DUSING_B
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t
+
+namespace a {class A {}; class B {}; class C {}; }
+namespace b {
+#if defined(USING_A)
+using a::A;
+#elif defined(USING_B)
+using a::B;
+#else
+using a::C;
+#endif
+}
+namespace c {}
+// CHECK-MESSAGES-USING-A: :[[@LINE-8]]:10: warning: using decl 'A' {{.*}}
+// CHECK-MESSAGES-USING-B: :[[@LINE-7]]:10: warning: using decl 'B' {{.*}}
+// CHECK-MESSAGES: :[[@LINE-6]]:10: warning: using decl 'C' {{.*}}
+// CHECK-FIXES-USING-A-NOT: using a::A;$
+// CHECK-FIXES-USING-B-NOT: using a::B;$
+// CHECK-FIXES-NOT: using a::C;$
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/check_clang_tidy.py b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/check_clang_tidy.py
new file mode 100755
index 0000000..bb2c5a2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/check_clang_tidy.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+#
+#===- check_clang_tidy.py - ClangTidy Test Helper ------------*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+r"""
+ClangTidy Test Helper
+=====================
+
+This script runs clang-tidy in fix mode and verify fixes, messages or both.
+
+Usage:
+ check_clang_tidy.py [-resource-dir=<resource-dir>] \
+ [-assume-filename=<file-with-source-extension>] \
+ [-check-suffix=<file-check-suffix>] \
+ <source-file> <check-name> <temp-file> \
+ -- [optional clang-tidy arguments]
+
+Example:
+ // RUN: %check_clang_tidy %s llvm-include-order %t -- -- -isystem %S/Inputs
+"""
+
+import argparse
+import os
+import re
+import subprocess
+import sys
+
+
+def write_file(file_name, text):
+ with open(file_name, 'w') as f:
+ f.write(text)
+ f.truncate()
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-expect-clang-tidy-error', action='store_true')
+ parser.add_argument('-resource-dir')
+ parser.add_argument('-assume-filename')
+ parser.add_argument('-check-suffix', default='')
+ parser.add_argument('input_file_name')
+ parser.add_argument('check_name')
+ parser.add_argument('temp_file_name')
+
+ args, extra_args = parser.parse_known_args()
+
+ resource_dir = args.resource_dir
+ assume_file_name = args.assume_filename
+ input_file_name = args.input_file_name
+ check_name = args.check_name
+ temp_file_name = args.temp_file_name
+ expect_clang_tidy_error = args.expect_clang_tidy_error
+
+ file_name_with_extension = assume_file_name or input_file_name
+ _, extension = os.path.splitext(file_name_with_extension)
+ if extension not in ['.c', '.hpp', '.m', '.mm']:
+ extension = '.cpp'
+ temp_file_name = temp_file_name + extension
+
+ clang_tidy_extra_args = extra_args
+ if len(clang_tidy_extra_args) == 0:
+ clang_tidy_extra_args = ['--']
+ if extension in ['.cpp', '.hpp', '.mm']:
+ clang_tidy_extra_args.append('--std=c++11')
+ if extension in ['.m', '.mm']:
+ clang_tidy_extra_args.extend(
+ ['-fobjc-abi-version=2', '-fobjc-arc'])
+
+ if args.check_suffix and not re.match('^[A-Z0-9\-]+$', args.check_suffix):
+ sys.exit('Only A..Z, 0..9 and "-" are allowed in check suffix, but "%s" was given' % (args.check_suffix))
+
+ file_check_suffix = ('-' + args.check_suffix) if args.check_suffix else ''
+ check_fixes_prefix = 'CHECK-FIXES' + file_check_suffix
+ check_messages_prefix = 'CHECK-MESSAGES' + file_check_suffix
+
+ # Tests should not rely on STL being available, and instead provide mock
+ # implementations of relevant APIs.
+ clang_tidy_extra_args.append('-nostdinc++')
+
+ if resource_dir is not None:
+ clang_tidy_extra_args.append('-resource-dir=%s' % resource_dir)
+
+ with open(input_file_name, 'r') as input_file:
+ input_text = input_file.read()
+
+ has_check_fixes = check_fixes_prefix in input_text
+ has_check_messages = check_messages_prefix in input_text
+
+ if not has_check_fixes and not has_check_messages:
+ sys.exit('Neither %s nor %s found in the input' % (check_fixes_prefix, check_messages_prefix) )
+
+ # Remove the contents of the CHECK lines to avoid CHECKs matching on
+ # themselves. We need to keep the comments to preserve line numbers while
+ # avoiding empty lines which could potentially trigger formatting-related
+ # checks.
+ cleaned_test = re.sub('// *CHECK-[A-Z0-9\-]*:[^\r\n]*', '//', input_text)
+
+ write_file(temp_file_name, cleaned_test)
+
+ original_file_name = temp_file_name + ".orig"
+ write_file(original_file_name, cleaned_test)
+
+ args = ['clang-tidy', temp_file_name, '-fix', '--checks=-*,' + check_name] + \
+ clang_tidy_extra_args
+ if expect_clang_tidy_error:
+ args.insert(0, 'not')
+ print('Running ' + repr(args) + '...')
+ try:
+ clang_tidy_output = \
+ subprocess.check_output(args, stderr=subprocess.STDOUT).decode()
+ except subprocess.CalledProcessError as e:
+ print('clang-tidy failed:\n' + e.output.decode())
+ raise
+
+ print('------------------------ clang-tidy output -----------------------\n' +
+ clang_tidy_output +
+ '\n------------------------------------------------------------------')
+
+ try:
+ diff_output = subprocess.check_output(
+ ['diff', '-u', original_file_name, temp_file_name],
+ stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as e:
+ diff_output = e.output
+
+ print('------------------------------ Fixes -----------------------------\n' +
+ diff_output.decode() +
+ '\n------------------------------------------------------------------')
+
+ if has_check_fixes:
+ try:
+ subprocess.check_output(
+ ['FileCheck', '-input-file=' + temp_file_name, input_file_name,
+ '-check-prefix=' + check_fixes_prefix, '-strict-whitespace'],
+ stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as e:
+ print('FileCheck failed:\n' + e.output.decode())
+ raise
+
+ if has_check_messages:
+ messages_file = temp_file_name + '.msg'
+ write_file(messages_file, clang_tidy_output)
+ try:
+ subprocess.check_output(
+ ['FileCheck', '-input-file=' + messages_file, input_file_name,
+ '-check-prefix=' + check_messages_prefix,
+ '-implicit-check-not={{warning|error}}:'],
+ stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as e:
+ print('FileCheck failed:\n' + e.output.decode())
+ raise
+
+if __name__ == '__main__':
+ main()
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-__clang_analyzer__macro.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-__clang_analyzer__macro.cpp
new file mode 100644
index 0000000..0fda1a3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-__clang_analyzer__macro.cpp
@@ -0,0 +1,5 @@
+// RUN: clang-tidy %s -checks=-*,modernize-use-nullptr -- | count 0
+
+#if !defined(__clang_analyzer__)
+#error __clang_analyzer__ is not defined
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-diff.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-diff.cpp
new file mode 100644
index 0000000..146287b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-diff.cpp
@@ -0,0 +1,27 @@
+// REQUIRES: shell
+// RUN: sed 's/placeholder_for_f/f/' %s > %t.cpp
+// RUN: clang-tidy -checks=-*,modernize-use-override %t.cpp -- -std=c++11 | FileCheck -check-prefix=CHECK-SANITY %s
+// RUN: not diff -U0 %s %t.cpp | %clang_tidy_diff -checks=-*,modernize-use-override -- -std=c++11 2>&1 | FileCheck %s
+// RUN: not diff -U0 %s %t.cpp | %clang_tidy_diff -checks=-*,modernize-use-override -quiet -- -std=c++11 2>&1 | FileCheck -check-prefix=CHECK-QUIET %s
+// RUN: mkdir -p %T/compilation-database-test/
+// RUN: echo '[{"directory": "%T", "command": "clang++ -o test.o -std=c++11 %t.cpp", "file": "%t.cpp"}]' > %T/compilation-database-test/compile_commands.json
+// RUN: not diff -U0 %s %t.cpp | %clang_tidy_diff -checks=-*,modernize-use-override -path %T/compilation-database-test 2>&1 | FileCheck -check-prefix=CHECK %s
+struct A {
+ virtual void f() {}
+ virtual void g() {}
+};
+// CHECK-NOT: warning:
+// CHECK-QUIET-NOT: warning:
+struct B : public A {
+ void placeholder_for_f() {}
+// CHECK-SANITY: [[@LINE-1]]:8: warning: annotate this
+// CHECK: [[@LINE-2]]:8: warning: annotate this
+// CHECK-QUIET: [[@LINE-3]]:8: warning: annotate this
+ void g() {}
+// CHECK-SANITY: [[@LINE-1]]:8: warning: annotate this
+// CHECK-NOT: warning:
+// CHECK-QUIET-NOT: warning:
+};
+// CHECK-SANITY-NOT: Suppressed
+// CHECK: Suppressed 1 warnings (1 due to line filter).
+// CHECK-QUIET-NOT: Suppressed
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-enable-check-profile-one-tu.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-enable-check-profile-one-tu.cpp
new file mode 100644
index 0000000..df4cb93
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-enable-check-profile-one-tu.cpp
@@ -0,0 +1,24 @@
+// RUN: clang-tidy -enable-check-profile -checks='-*,readability-function-size' %s -- 2>&1 | FileCheck --match-full-lines -implicit-check-not='{{warning:|error:}}' %s
+
+// CHECK: ===-------------------------------------------------------------------------===
+// CHECK-NEXT: clang-tidy checks profiling
+// CHECK-NEXT: ===-------------------------------------------------------------------------===
+// CHECK-NEXT: Total Execution Time: {{.*}} seconds ({{.*}} wall clock)
+
+// CHECK: {{.*}} --- Name ---
+// CHECK-NEXT: {{.*}} readability-function-size
+// CHECK-NEXT: {{.*}} Total
+
+// CHECK-NOT: ===-------------------------------------------------------------------------===
+// CHECK-NOT: clang-tidy checks profiling
+// CHECK-NOT: ===-------------------------------------------------------------------------===
+// CHECK-NOT: Total Execution Time: {{.*}} seconds ({{.*}} wall clock)
+
+// CHECK-NOT: {{.*}} --- Name ---
+// CHECK-NOT: {{.*}} readability-function-size
+// CHECK-NOT: {{.*}} Total
+
+class A {
+ A() {}
+ ~A() {}
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-enable-check-profile-two-tu.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-enable-check-profile-two-tu.cpp
new file mode 100644
index 0000000..30603a2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-enable-check-profile-two-tu.cpp
@@ -0,0 +1,33 @@
+// RUN: clang-tidy -enable-check-profile -checks='-*,readability-function-size' %s %s -- 2>&1 | FileCheck --match-full-lines -implicit-check-not='{{warning:|error:}}' %s
+
+// CHECK: ===-------------------------------------------------------------------------===
+// CHECK-NEXT: clang-tidy checks profiling
+// CHECK-NEXT: ===-------------------------------------------------------------------------===
+// CHECK-NEXT: Total Execution Time: {{.*}} seconds ({{.*}} wall clock)
+
+// CHECK: {{.*}} --- Name ---
+// CHECK-NEXT: {{.*}} readability-function-size
+// CHECK-NEXT: {{.*}} Total
+
+// CHECK: ===-------------------------------------------------------------------------===
+// CHECK-NEXT: clang-tidy checks profiling
+// CHECK-NEXT: ===-------------------------------------------------------------------------===
+// CHECK-NEXT: Total Execution Time: {{.*}} seconds ({{.*}} wall clock)
+
+// CHECK: {{.*}} --- Name ---
+// CHECK-NEXT: {{.*}} readability-function-size
+// CHECK-NEXT: {{.*}} Total
+
+// CHECK-NOT: ===-------------------------------------------------------------------------===
+// CHECK-NOT: clang-tidy checks profiling
+// CHECK-NOT: ===-------------------------------------------------------------------------===
+// CHECK-NOT: Total Execution Time: {{.*}} seconds ({{.*}} wall clock)
+
+// CHECK-NOT: {{.*}} --- Name ---
+// CHECK-NOT: {{.*}} readability-function-size
+// CHECK-NOT: {{.*}} Total
+
+class A {
+ A() {}
+ ~A() {}
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-run-with-database.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-run-with-database.cpp
new file mode 100644
index 0000000..05bc14c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-run-with-database.cpp
@@ -0,0 +1,23 @@
+// RUN: mkdir -p %T/compilation-database-test/include
+// RUN: mkdir -p %T/compilation-database-test/a
+// RUN: mkdir -p %T/compilation-database-test/b
+// RUN: echo 'int *AA = 0;' > %T/compilation-database-test/a/a.cpp
+// RUN: echo 'int *AB = 0;' > %T/compilation-database-test/a/b.cpp
+// RUN: echo 'int *BB = 0;' > %T/compilation-database-test/b/b.cpp
+// RUN: echo 'int *BC = 0;' > %T/compilation-database-test/b/c.cpp
+// RUN: echo 'int *HP = 0;' > %T/compilation-database-test/include/header.h
+// RUN: echo '#include "header.h"' > %T/compilation-database-test/b/d.cpp
+// RUN: sed 's|test_dir|%/T/compilation-database-test|g' %S/Inputs/compilation-database/template.json > %T/compile_commands.json
+// RUN: clang-tidy --checks=-*,modernize-use-nullptr -p %T %T/compilation-database-test/b/not-exist -header-filter=.*
+// RUN: clang-tidy --checks=-*,modernize-use-nullptr -p %T %T/compilation-database-test/a/a.cpp %T/compilation-database-test/a/b.cpp %T/compilation-database-test/b/b.cpp %T/compilation-database-test/b/c.cpp %T/compilation-database-test/b/d.cpp -header-filter=.* -fix
+// RUN: FileCheck -input-file=%T/compilation-database-test/a/a.cpp %s -check-prefix=CHECK-FIX1
+// RUN: FileCheck -input-file=%T/compilation-database-test/a/b.cpp %s -check-prefix=CHECK-FIX2
+// RUN: FileCheck -input-file=%T/compilation-database-test/b/b.cpp %s -check-prefix=CHECK-FIX3
+// RUN: FileCheck -input-file=%T/compilation-database-test/b/c.cpp %s -check-prefix=CHECK-FIX4
+// RUN: FileCheck -input-file=%T/compilation-database-test/include/header.h %s -check-prefix=CHECK-FIX5
+
+// CHECK-FIX1: int *AA = nullptr;
+// CHECK-FIX2: int *AB = nullptr;
+// CHECK-FIX3: int *BB = nullptr;
+// CHECK-FIX4: int *BC = nullptr;
+// CHECK-FIX5: int *HP = nullptr;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-store-check-profile-one-tu.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-store-check-profile-one-tu.cpp
new file mode 100644
index 0000000..832723b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clang-tidy-store-check-profile-one-tu.cpp
@@ -0,0 +1,37 @@
+// RUN: rm -rf %T/out
+// RUN: clang-tidy -enable-check-profile -checks='-*,readability-function-size' -store-check-profile=%T/out %s -- 2>&1 | not FileCheck --match-full-lines -implicit-check-not='{{warning:|error:}}' -check-prefix=CHECK-CONSOLE %s
+// RUN: cat %T/out/*-clang-tidy-store-check-profile-one-tu.cpp.json | FileCheck --match-full-lines -implicit-check-not='{{warning:|error:}}' -check-prefix=CHECK-FILE %s
+// RUN: rm -rf %T/out
+// RUN: clang-tidy -enable-check-profile -checks='-*,readability-function-size' -store-check-profile=%T/out %s -- 2>&1
+// RUN: cat %T/out/*-clang-tidy-store-check-profile-one-tu.cpp.json | FileCheck --match-full-lines -implicit-check-not='{{warning:|error:}}' -check-prefix=CHECK-FILE %s
+
+// CHECK-CONSOLE-NOT: ===-------------------------------------------------------------------------===
+// CHECK-CONSOLE-NOT: {{.*}} --- Name ---
+// CHECK-CONSOLE-NOT: {{.*}} readability-function-size
+// CHECK-CONSOLE-NOT: {{.*}} Total
+// CHECK-CONSOLE-NOT: ===-------------------------------------------------------------------------===
+
+// CHECK-FILE: {
+// CHECK-FILE-NEXT:"file": "{{.*}}clang-tidy-store-check-profile-one-tu.cpp",
+// CHECK-FILE-NEXT:"timestamp": "{{[0-9]+}}-{{[0-9]+}}-{{[0-9]+}} {{[0-9]+}}:{{[0-9]+}}:{{[0-9]+}}.{{[0-9]+}}",
+// CHECK-FILE-NEXT:"profile": {
+// CHECK-FILE-NEXT: "time.clang-tidy.readability-function-size.wall": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}},
+// CHECK-FILE-NEXT: "time.clang-tidy.readability-function-size.user": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}},
+// CHECK-FILE-NEXT: "time.clang-tidy.readability-function-size.sys": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}}
+// CHECK-FILE-NEXT: }
+// CHECK-FILE-NEXT: }
+
+// CHECK-FILE-NOT: {
+// CHECK-FILE-NOT: "file": {{.*}}clang-tidy-store-check-profile-one-tu.cpp{{.*}},
+// CHECK-FILE-NOT: "timestamp": "{{[0-9]+}}-{{[0-9]+}}-{{[0-9]+}} {{[0-9]+}}:{{[0-9]+}}:{{[0-9]+}}.{{[0-9]+}}",
+// CHECK-FILE-NOT: "profile": {
+// CHECK-FILE-NOT: "time.clang-tidy.readability-function-size.wall": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}},
+// CHECK-FILE-NOT: "time.clang-tidy.readability-function-size.user": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}},
+// CHECK-FILE-NOT: "time.clang-tidy.readability-function-size.sys": {{.*}}{{[0-9]}}.{{[0-9]+}}e{{[-+]}}{{[0-9]}}{{[0-9]}}
+// CHECK-FILE-NOT: }
+// CHECK-FILE-NOT: }
+
+class A {
+ A() {}
+ ~A() {}
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clean-up-code.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clean-up-code.cpp
new file mode 100644
index 0000000..15873ed
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/clean-up-code.cpp
@@ -0,0 +1,14 @@
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t -- -format-style=none --
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t -- -format-style=llvm --
+namespace a { class A {}; }
+namespace b {
+using a::A;
+}
+namespace c {}
+// CHECK-MESSAGES: :[[@LINE-3]]:10: warning: using decl 'A' is unused [misc-unused-using-decls]
+// CHECK-FIXES: {{^namespace a { class A {}; }$}}
+// CHECK-FIXES-NOT: namespace
+// CHECK-FIXES: {{^namespace c {}$}}
+// FIXME: cleanupAroundReplacements leaves whitespace. Otherwise we could just
+// check the next line.
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/config-files.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/config-files.cpp
new file mode 100644
index 0000000..65ac54a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/config-files.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-tidy -dump-config %S/Inputs/config-files/- -- | FileCheck %s -check-prefix=CHECK-BASE
+// CHECK-BASE: Checks: {{.*}}from-parent
+// CHECK-BASE: HeaderFilterRegex: parent
+// RUN: clang-tidy -dump-config %S/Inputs/config-files/1/- -- | FileCheck %s -check-prefix=CHECK-CHILD1
+// CHECK-CHILD1: Checks: {{.*}}from-child1
+// CHECK-CHILD1: HeaderFilterRegex: child1
+// RUN: clang-tidy -dump-config %S/Inputs/config-files/2/- -- | FileCheck %s -check-prefix=CHECK-CHILD2
+// CHECK-CHILD2: Checks: {{.*}}from-parent
+// CHECK-CHILD2: HeaderFilterRegex: parent
+// RUN: clang-tidy -dump-config -checks='from-command-line' -header-filter='from command line' %S/Inputs/config-files/- -- | FileCheck %s -check-prefix=CHECK-COMMAND-LINE
+// CHECK-COMMAND-LINE: Checks: {{.*}}from-parent,from-command-line
+// CHECK-COMMAND-LINE: HeaderFilterRegex: from command line
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-avoid-goto.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-avoid-goto.cpp
new file mode 100644
index 0000000..213947f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-avoid-goto.cpp
@@ -0,0 +1,139 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-avoid-goto %t
+
+void noop() {}
+
+int main() {
+ noop();
+ goto jump_to_me;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: avoid using 'goto' for flow control
+ // CHECK-MESSAGES: [[@LINE+3]]:1: note: label defined here
+ noop();
+
+jump_to_me:;
+
+jump_backwards:;
+ noop();
+ goto jump_backwards;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: avoid using 'goto' for flow control
+ // CHECK-MESSAGES: [[@LINE-4]]:1: note: label defined here
+
+ goto jump_in_line;
+ ;
+jump_in_line:;
+ // CHECK-MESSAGES: [[@LINE-3]]:3: warning: avoid using 'goto' for flow control
+ // CHECK-MESSAGES: [[@LINE-2]]:1: note: label defined here
+
+ // Test the GNU extension https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
+some_label:;
+ void *dynamic_label = &&some_label;
+
+ // FIXME: `IndirectGotoStmt` is not detected.
+ goto *dynamic_label;
+}
+
+void forward_jump_out_nested_loop() {
+ int array[] = {1, 2, 3, 4, 5};
+ for (int i = 0; i < 10; ++i) {
+ noop();
+ for (int j = 0; j < 10; ++j) {
+ noop();
+ if (i + j > 10)
+ goto early_exit1;
+ }
+ noop();
+ }
+
+ for (int i = 0; i < 10; ++i) {
+ noop();
+ while (true) {
+ noop();
+ if (i > 5)
+ goto early_exit1;
+ }
+ noop();
+ }
+
+ for (auto value : array) {
+ noop();
+ for (auto number : array) {
+ noop();
+ if (number == 5)
+ goto early_exit1;
+ }
+ }
+
+ do {
+ noop();
+ do {
+ noop();
+ goto early_exit1;
+ } while (true);
+ } while (true);
+
+ do {
+ for (auto number : array) {
+ noop();
+ if (number == 2)
+ goto early_exit1;
+ }
+ } while (true);
+
+ // Jumping further results in error, because the variable declaration would
+ // be skipped.
+early_exit1:;
+
+ int i = 0;
+ while (true) {
+ noop();
+ while (true) {
+ noop();
+ if (i > 5)
+ goto early_exit2;
+ i++;
+ }
+ noop();
+ }
+
+ while (true) {
+ noop();
+ for (int j = 0; j < 10; ++j) {
+ noop();
+ if (j > 5)
+ goto early_exit2;
+ }
+ noop();
+ }
+
+ while (true) {
+ noop();
+ for (auto number : array) {
+ if (number == 1)
+ goto early_exit2;
+ noop();
+ }
+ }
+
+ while (true) {
+ noop();
+ do {
+ noop();
+ goto early_exit2;
+ } while (true);
+ }
+early_exit2:;
+}
+
+void jump_out_backwards() {
+
+before_the_loop:
+ noop();
+
+ for (int i = 0; i < 10; ++i) {
+ for (int j = 0; j < 10; ++j) {
+ if (i * j > 80)
+ goto before_the_loop;
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: avoid using 'goto' for flow control
+ // CHECK-MESSAGES: [[@LINE-8]]:1: note: label defined here
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-interfaces-global-init.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-interfaces-global-init.cpp
new file mode 100644
index 0000000..51f79e5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-interfaces-global-init.cpp
@@ -0,0 +1,84 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-interfaces-global-init %t
+
+constexpr int makesInt() { return 3; }
+constexpr int takesInt(int i) { return i + 1; }
+constexpr int takesIntPtr(int *i) { return *i; }
+
+extern int ExternGlobal;
+static int GlobalScopeBadInit1 = ExternGlobal;
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
+static int GlobalScopeBadInit2 = takesInt(ExternGlobal);
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
+static int GlobalScopeBadInit3 = takesIntPtr(&ExternGlobal);
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
+static int GlobalScopeBadInit4 = 3 * (ExternGlobal + 2);
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
+
+namespace ns {
+static int NamespaceScope = makesInt();
+static int NamespaceScopeBadInit = takesInt(ExternGlobal);
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
+
+struct A {
+ static int ClassScope;
+ static int ClassScopeBadInit;
+};
+
+int A::ClassScopeBadInit = takesInt(ExternGlobal);
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ExternGlobal'
+
+static int FromClassBadInit = takesInt(A::ClassScope);
+// CHECK-MESSAGES: [[@LINE-1]]:12: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'ClassScope'
+} // namespace ns
+
+// "const int B::I;" is fine, it just ODR-defines B::I. See [9.4.3] Static
+// members [class.static]. However the ODR-definitions are not in the right
+// order (C::I after C::J, see [3.6.2.3]).
+class B1 {
+ static const int I = 0;
+ static const int J = I;
+};
+const int B1::J;
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: initializing non-local variable with non-const expression depending on uninitialized non-local variable 'I'
+const int B1::I;
+
+void f() {
+ // This is fine, it's executed after dynamic initialization occurs.
+ static int G = takesInt(ExternGlobal);
+}
+
+// Declaration then definition then usage is fine.
+extern int ExternGlobal2;
+extern int ExternGlobal2;
+int ExternGlobal2 = 123;
+static int GlobalScopeGoodInit1 = ExternGlobal2;
+
+
+// Defined global variables are fine:
+static int GlobalScope = makesInt();
+static int GlobalScopeGoodInit2 = takesInt(GlobalScope);
+static int GlobalScope2 = takesInt(ns::NamespaceScope);
+// Enums are fine.
+enum Enum { kEnumValue = 1 };
+static int GlobalScopeFromEnum = takesInt(kEnumValue);
+
+// Leave constexprs alone.
+extern constexpr int GlobalScopeConstexpr = makesInt();
+static constexpr int GlobalScopeConstexprOk =
+ takesInt(GlobalScopeConstexpr);
+
+// This is a pretty common instance: People are usually not using constexpr, but
+// this is what they should write:
+static constexpr const char kValue[] = "value";
+constexpr int Fingerprint(const char *value) { return 0; }
+static int kFingerprint = Fingerprint(kValue);
+
+// This is fine because the ODR-definitions are in the right order (C::J after
+// C::I).
+class B2 {
+ static const int I = 0;
+ static const int J = I;
+};
+const int B2::I;
+const int B2::J;
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp
new file mode 100644
index 0000000..ecffba6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp
@@ -0,0 +1,103 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-narrowing-conversions %t
+
+float ceil(float);
+namespace std {
+double ceil(double);
+long double floor(long double);
+} // namespace std
+
+namespace floats {
+
+struct ConvertsToFloat {
+ operator float() const { return 0.5; }
+};
+
+float operator "" _Pa(unsigned long long);
+
+void not_ok(double d) {
+ int i = 0;
+ i = d;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i = 0.5f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i = static_cast<float>(d);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i = ConvertsToFloat();
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i = 15_Pa;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+}
+
+void not_ok_binary_ops(double d) {
+ int i = 0;
+ i += 0.5;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i += 0.5f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i += d;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+ // We warn on the following even though it's not dangerous because there is no
+ // reason to use a double literal here.
+ // TODO(courbet): Provide an automatic fix.
+ i += 2.0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i += 2.0f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+
+ i *= 0.5f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i /= 0.5f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+ i += (double)0.5f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+}
+
+void ok(double d) {
+ int i = 0;
+ i = 1;
+ i = static_cast<int>(0.5);
+ i = static_cast<int>(d);
+ i = std::ceil(0.5);
+ i = ::std::floor(0.5);
+ {
+ using std::ceil;
+ i = ceil(0.5f);
+ }
+ i = ceil(0.5f);
+}
+
+void ok_binary_ops(double d) {
+ int i = 0;
+ i += 1;
+ i += static_cast<int>(0.5);
+ i += static_cast<int>(d);
+ i += (int)d;
+ i += std::ceil(0.5);
+ i += ::std::floor(0.5);
+ {
+ using std::ceil;
+ i += ceil(0.5f);
+ }
+ i += ceil(0.5f);
+}
+
+// We're bailing out in templates and macros.
+template <typename T1, typename T2>
+void f(T1 one, T2 two) {
+ one += two;
+}
+
+void template_context() {
+ f(1, 2);
+ f(1, .5);
+}
+
+#define DERP(i, j) (i += j)
+
+void macro_context() {
+ int i = 0;
+ DERP(i, 2);
+ DERP(i, .5);
+}
+
+} // namespace floats
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-no-malloc-custom.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-no-malloc-custom.cpp
new file mode 100644
index 0000000..89142fb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-no-malloc-custom.cpp
@@ -0,0 +1,59 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-no-malloc %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: cppcoreguidelines-no-malloc.Allocations, value: "::malloc;::align_malloc;::calloc"},\
+// RUN: {key: cppcoreguidelines-no-malloc.Reallocations, value: "::realloc;::align_realloc"},\
+// RUN: {key: cppcoreguidelines-no-malloc.Deallocations, value: "::free;::align_free"}]}' \
+// RUN: --
+
+using size_t = __SIZE_TYPE__;
+
+void *malloc(size_t size);
+void *align_malloc(size_t size, unsigned short aligmnent);
+void *calloc(size_t num, size_t size);
+void *realloc(void *ptr, size_t size);
+void *align_realloc(void *ptr, size_t size, unsigned short alignment);
+void free(void *ptr);
+void *align_free(void *ptr);
+
+void malloced_array() {
+ int *array0 = (int *)malloc(sizeof(int) * 20);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+
+ int *zeroed = (int *)calloc(20, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+
+ int *aligned = (int *)align_malloc(20 * sizeof(int), 16);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+
+ // reallocation memory, std::vector shall be used
+ char *realloced = (char *)realloc(array0, 50 * sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: do not manage memory manually; consider std::vector or std::string [cppcoreguidelines-no-malloc]
+
+ char *align_realloced = (char *)align_realloc(aligned, 50 * sizeof(int), 16);
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: do not manage memory manually; consider std::vector or std::string [cppcoreguidelines-no-malloc]
+
+ // freeing memory the bad way
+ free(realloced);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc]
+
+ align_free(align_realloced);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc]
+
+ // check if a call to malloc as function argument is found as well
+ free(malloc(20));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc]
+ // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+}
+
+/// newing an array is still not good, but not relevant to this checker
+void newed_array() {
+ int *new_array = new int[10]; // OK(1)
+}
+
+void arbitrary_call() {
+ // we dont want every function to raise the warning even if malloc is in the name
+ malloced_array(); // OK(2)
+
+ // completly unrelated function call to malloc
+ newed_array(); // OK(3)
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-no-malloc-no-functions.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-no-malloc-no-functions.cpp
new file mode 100644
index 0000000..8b4d464
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-no-malloc-no-functions.cpp
@@ -0,0 +1,17 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-no-malloc %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: cppcoreguidelines-no-malloc.Allocations, value: "::malloc"},\
+// RUN: {key: cppcoreguidelines-no-malloc.Reallocations, value: ""},\
+// RUN: {key: cppcoreguidelines-no-malloc.Deallocations, value: ""}]}' \
+// RUN: --
+
+// Just ensure, the check will not crash, when no functions shall be checked.
+
+using size_t = __SIZE_TYPE__;
+
+void *malloc(size_t size);
+
+void malloced_array() {
+ int *array0 = (int *)malloc(sizeof(int) * 20);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-no-malloc.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-no-malloc.cpp
new file mode 100644
index 0000000..7b7ccf3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-no-malloc.cpp
@@ -0,0 +1,42 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-no-malloc %t
+
+using size_t = __SIZE_TYPE__;
+
+void *malloc(size_t size);
+void *calloc(size_t num, size_t size);
+void *realloc(void *ptr, size_t size);
+void free(void *ptr);
+
+void malloced_array() {
+ int *array0 = (int *)malloc(sizeof(int) * 20);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+
+ int *zeroed = (int *)calloc(20, sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+
+ // reallocation memory, std::vector shall be used
+ char *realloced = (char *)realloc(array0, 50 * sizeof(int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: do not manage memory manually; consider std::vector or std::string [cppcoreguidelines-no-malloc]
+
+ // freeing memory the bad way
+ free(realloced);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc]
+
+ // check if a call to malloc as function argument is found as well
+ free(malloc(20));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc]
+ // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
+}
+
+/// newing an array is still not good, but not relevant to this checker
+void newed_array() {
+ int *new_array = new int[10]; // OK(1)
+}
+
+void arbitrary_call() {
+ // we dont want every function to raise the warning even if malloc is in the name
+ malloced_array(); // OK(2)
+
+ // completly unrelated function call to malloc
+ newed_array(); // OK(3)
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-owning-memory-containers.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-owning-memory-containers.cpp
new file mode 100644
index 0000000..929b33d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-owning-memory-containers.cpp
@@ -0,0 +1,61 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-owning-memory %t
+
+namespace gsl {
+template <typename T>
+using owner = T;
+}
+
+namespace std {
+
+// Not actually a vector, but more a dynamic, fixed size array. Just to demonstrate
+// functionality or the lack of the same.
+template <typename T>
+class vector {
+public:
+ vector(unsigned long size, T val) : data{new T[size]}, size{size} {
+ for (unsigned long i = 0ul; i < size; ++i) {
+ data[i] = val;
+ }
+ }
+
+ T *begin() { return data; }
+ T *end() { return &data[size]; }
+ T &operator[](unsigned long index) { return data[index]; }
+
+private:
+ T *data;
+ unsigned long size;
+};
+
+} // namespace std
+
+// All of the following codesnippets should be valid with appropriate 'owner<>' anaylsis,
+// but currently the type information of 'gsl::owner<>' gets lost in typededuction.
+int main() {
+ std::vector<gsl::owner<int *>> OwnerStdVector(100, nullptr);
+
+ // Rangebased looping in resource vector.
+ for (auto *Element : OwnerStdVector) {
+ Element = new int(42);
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: assigning newly created 'gsl::owner<>' to non-owner 'int *'
+ }
+ for (auto *Element : OwnerStdVector) {
+ delete Element;
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead
+ // CHECK-MESSAGES: [[@LINE-3]]:8: note: variable declared here
+ }
+
+ // Indexbased looping in resource vector.
+ for (int i = 0; i < 100; ++i) {
+ OwnerStdVector[i] = new int(42);
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: assigning newly created 'gsl::owner<>' to non-owner 'int *'
+ }
+ for (int i = 0; i < 100; ++i) {
+ delete OwnerStdVector[i];
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead
+ // A note gets emitted here pointing to the return value of the operator[] from the
+ // vector implementation. Maybe this is considered misleading.
+ }
+
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-owning-memory-legacy-functions.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-owning-memory-legacy-functions.cpp
new file mode 100644
index 0000000..5785e9f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-owning-memory-legacy-functions.cpp
@@ -0,0 +1,194 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-owning-memory %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: cppcoreguidelines-owning-memory.LegacyResourceProducers, value: "::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile"}, \
+// RUN: {key: cppcoreguidelines-owning-memory.LegacyResourceConsumers, value: "::free;::realloc;::freopen;::fclose"}]}' \
+// RUN: -- -std=c++11 -nostdlib -nostdinc++
+
+namespace gsl {
+template <class T>
+using owner = T;
+} // namespace gsl
+
+extern "C" {
+using size_t = decltype(sizeof(void*));
+using FILE = int;
+
+void *malloc(size_t ByteCount);
+void *aligned_alloc(size_t Alignment, size_t Size);
+void *calloc(size_t Count, size_t SizeSingle);
+void *realloc(void *Resource, size_t NewByteCount);
+void free(void *Resource);
+
+FILE *tmpfile(void);
+FILE *fopen(const char *filename, const char *mode);
+FILE *freopen(const char *filename, const char *mode, FILE *stream);
+void fclose(FILE *Resource);
+}
+
+namespace std {
+using ::FILE;
+using ::size_t;
+
+using ::fclose;
+using ::fopen;
+using ::freopen;
+using ::tmpfile;
+
+using ::aligned_alloc;
+using ::calloc;
+using ::free;
+using ::malloc;
+using ::realloc;
+} // namespace std
+
+void nonOwningCall(int *Resource, size_t Size) {}
+void nonOwningCall(FILE *Resource) {}
+
+void consumesResource(gsl::owner<int *> Resource, size_t Size) {}
+void consumesResource(gsl::owner<FILE *> Resource) {}
+
+void testNonCasted(void *Resource) {}
+
+void testNonCastedOwner(gsl::owner<void *> Resource) {}
+
+FILE *fileFactory1() { return ::fopen("new_file.txt", "w"); }
+// CHECK-MESSAGES: [[@LINE-1]]:24: warning: returning a newly created resource of type 'FILE *' (aka 'int *') or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
+gsl::owner<FILE *> fileFactory2() { return std::fopen("new_file.txt", "w"); } // Ok
+
+int *arrayFactory1() { return (int *)std::malloc(100); }
+// CHECK-MESSAGES: [[@LINE-1]]:24: warning: returning a newly created resource of type 'int *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
+gsl::owner<int *> arrayFactory2() { return (int *)std::malloc(100); } // Ok
+void *dataFactory1() { return std::malloc(100); }
+// CHECK-MESSAGES: [[@LINE-1]]:24: warning: returning a newly created resource of type 'void *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
+gsl::owner<void *> dataFactory2() { return std::malloc(100); } // Ok
+
+void test_resource_creators() {
+ const unsigned int ByteCount = 25 * sizeof(int);
+ int Bad = 42;
+
+ int *IntArray1 = (int *)std::malloc(ByteCount);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ int *IntArray2 = static_cast<int *>(std::malloc(ByteCount)); // Bad
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ void *IntArray3 = std::malloc(ByteCount);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'void *' with a newly created 'gsl::owner<>'
+
+ int *IntArray4 = (int *)::malloc(ByteCount);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ int *IntArray5 = static_cast<int *>(::malloc(ByteCount)); // Bad
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ void *IntArray6 = ::malloc(ByteCount);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'void *' with a newly created 'gsl::owner<>'
+
+ gsl::owner<int *> IntArray7 = (int *)malloc(ByteCount); // Ok
+ gsl::owner<void *> IntArray8 = malloc(ByteCount); // Ok
+
+ gsl::owner<int *> IntArray9 = &Bad;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
+
+ nonOwningCall((int *)malloc(ByteCount), 25);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: initializing non-owner argument of type 'int *' with a newly created 'gsl::owner<>'
+ nonOwningCall((int *)::malloc(ByteCount), 25);
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: initializing non-owner argument of type 'int *' with a newly created 'gsl::owner<>'
+
+ consumesResource((int *)malloc(ByteCount), 25); // Ok
+ consumesResource((int *)::malloc(ByteCount), 25); // Ok
+
+ testNonCasted(malloc(ByteCount));
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'void *' with a newly created 'gsl::owner<>'
+ testNonCastedOwner(gsl::owner<void *>(malloc(ByteCount))); // Ok
+ testNonCastedOwner(malloc(ByteCount)); // Ok
+
+ FILE *File1 = std::fopen("test_name.txt", "w+");
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+ FILE *File2 = ::fopen("test_name.txt", "w+");
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+
+ gsl::owner<FILE *> File3 = ::fopen("test_name.txt", "w+"); // Ok
+
+ FILE *File4;
+ File4 = ::fopen("test_name.txt", "w+");
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: assigning newly created 'gsl::owner<>' to non-owner 'FILE *' (aka 'int *')
+
+ gsl::owner<FILE *> File5;
+ File5 = ::fopen("test_name.txt", "w+"); // Ok
+ File5 = File1;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'FILE *' (aka 'int *')
+
+ gsl::owner<FILE *> File6 = File1;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'FILE *' (aka 'int *')
+
+ FILE *File7 = tmpfile();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+ gsl::owner<FILE *> File8 = tmpfile(); // Ok
+
+ nonOwningCall(::fopen("test_name.txt", "r"));
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+ nonOwningCall(std::fopen("test_name.txt", "r"));
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+
+ consumesResource(::fopen("test_name.txt", "r")); // Ok
+
+ int *HeapPointer3 = (int *)aligned_alloc(16ul, 4ul * 32ul);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ gsl::owner<int *> HeapPointer4 = static_cast<int *>(aligned_alloc(16ul, 4ul * 32ul)); // Ok
+
+ void *HeapPointer5 = calloc(10ul, 4ul);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'void *' with a newly created 'gsl::owner<>'
+ gsl::owner<void *> HeapPointer6 = calloc(10ul, 4ul); // Ok
+}
+
+void test_legacy_consumers() {
+ int StackInteger = 42;
+
+ int *StackPointer = &StackInteger;
+ int *HeapPointer1 = (int *)malloc(100);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ gsl::owner<int *> HeapPointer2 = (int *)malloc(100);
+
+ std::free(StackPointer);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: calling legacy resource function without passing a 'gsl::owner<>'
+ std::free(HeapPointer1);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: calling legacy resource function without passing a 'gsl::owner<>'
+ std::free(HeapPointer2); // Ok
+ // CHECK MESSAGES: [[@LINE-1]]:3: warning: calling legacy resource function without passing a 'gsl::owner<>'
+
+ // FIXME: the check complains about initialization of 'void *' with new created owner.
+ // This happens, because the argument of `free` is not marked as 'owner<>' (and cannot be),
+ // and the check will not figure out could be meant as owner.
+ // This property will probably never be fixed, because it is probably a rather rare
+ // use-case and 'owner<>' should be wrapped in RAII classes anyway!
+ std::free(std::malloc(100)); // Ok but silly :)
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: initializing non-owner argument of type 'void *' with a newly created 'gsl::owner<>'
+
+ // Demonstrate, that multi-argument functions are diagnosed as well.
+ std::realloc(StackPointer, 200);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: calling legacy resource function without passing a 'gsl::owner<>'
+ std::realloc(HeapPointer1, 200);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: calling legacy resource function without passing a 'gsl::owner<>'
+ std::realloc(HeapPointer2, 200); // Ok
+ std::realloc(std::malloc(100), 200); // Ok but silly
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: initializing non-owner argument of type 'void *' with a newly created 'gsl::owner<>'
+
+ fclose(fileFactory1());
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: calling legacy resource function without passing a 'gsl::owner<>'
+ fclose(fileFactory2()); // Ok, same as FIXME with `free(malloc(100))` applies here
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: initializing non-owner argument of type 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+
+ gsl::owner<FILE *> File1 = fopen("testfile.txt", "r"); // Ok
+ FILE *File2 = freopen("testfile.txt", "w", File1);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+ // CHECK-MESSAGES: [[@LINE-2]]:17: warning: calling legacy resource function without passing a 'gsl::owner<>'
+ // FIXME: The warning for not passing and owner<> is a false positive since both the filename and the
+ // mode are not supposed to be owners but still pointers. The check is to coarse for
+ // this function. Maybe `freopen` gets special treatment.
+
+ gsl::owner<FILE *> File3 = freopen("testfile.txt", "w", File2); // Bad, File2 no owner
+ // CHECK-MESSAGES: [[@LINE-1]]:30: warning: calling legacy resource function without passing a 'gsl::owner<>'
+
+ FILE *TmpFile = tmpfile();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+ FILE *File6 = freopen("testfile.txt", "w", TmpFile); // Bad, both return and argument
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'FILE *' (aka 'int *') with a newly created 'gsl::owner<>'
+ // CHECK-MESSAGES: [[@LINE-2]]:17: warning: calling legacy resource function without passing a 'gsl::owner<>'
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-owning-memory.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-owning-memory.cpp
new file mode 100644
index 0000000..47b12fb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-owning-memory.cpp
@@ -0,0 +1,391 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-owning-memory %t
+
+namespace gsl {
+template <class T>
+using owner = T;
+} // namespace gsl
+
+template <typename T>
+class unique_ptr {
+public:
+ unique_ptr(gsl::owner<T> resource) : memory(resource) {}
+ unique_ptr(const unique_ptr<T> &) = default;
+
+ ~unique_ptr() { delete memory; }
+
+private:
+ gsl::owner<T> memory;
+};
+
+void takes_owner(gsl::owner<int *> owned_int) {
+}
+
+void takes_pointer(int *unowned_int) {
+}
+
+void takes_owner_and_more(int some_int, gsl::owner<int *> owned_int, float f) {
+}
+
+template <typename T>
+void takes_templated_owner(gsl::owner<T> owned_T) {
+}
+
+gsl::owner<int *> returns_owner1() { return gsl::owner<int *>(new int(42)); } // Ok
+gsl::owner<int *> returns_owner2() { return new int(42); } // Ok
+
+int *returns_no_owner1() { return nullptr; }
+int *returns_no_owner2() {
+ return new int(42);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: returning a newly created resource of type 'int *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
+}
+int *returns_no_owner3() {
+ int *should_be_owner = new int(42);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ return should_be_owner;
+}
+int *returns_no_owner4() {
+ gsl::owner<int *> owner = new int(42);
+ return owner;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: returning a newly created resource of type 'int *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
+}
+
+unique_ptr<int *> returns_no_owner5() {
+ return unique_ptr<int *>(new int(42)); // Ok
+}
+
+/// FIXME: CSA finds it, but the report is misleading. Ownersemantics can catch this
+/// by flow analysis similar to bugprone-use-after-move.
+void csa_not_finding_leak() {
+ gsl::owner<int *> o1 = new int(42); // Ok
+
+ gsl::owner<int *> o2 = o1; // Ok
+ o2 = new int(45); // conceptual leak, the memory from o1 is now leaked, since its considered moved in the guidelines
+
+ delete o2;
+ // actual leak occurs here, its found, but mixed
+ delete o1;
+}
+
+void test_assignment_and_initialization() {
+ int stack_int1 = 15;
+ int stack_int2;
+
+ gsl::owner<int *> owned_int1 = &stack_int1; // BAD
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
+
+ gsl::owner<int *> owned_int2;
+ owned_int2 = &stack_int2; // BAD since no owner, bad since uninitialized
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *'
+
+ gsl::owner<int *> owned_int3 = new int(42); // Good
+ owned_int3 = nullptr; // Good
+
+ gsl::owner<int *> owned_int4(nullptr); // Ok
+ owned_int4 = new int(42); // Good
+
+ gsl::owner<int *> owned_int5 = owned_int3; // Good
+
+ gsl::owner<int *> owned_int6{nullptr}; // Ok
+ owned_int6 = owned_int4; // Good
+
+ // FIXME:, flow analysis for the case of reassignment. Value must be released before
+ owned_int6 = owned_int3; // BAD, because reassignment without resource release
+
+ auto owned_int7 = returns_owner1(); // Bad, since type deduction eliminates the owner wrapper
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ // CHECK-MESSAGES: [[@LINE-2]]:3: note: type deduction did not result in an owner
+
+ const auto owned_int8 = returns_owner2(); // Bad, since type deduction eliminates the owner wrapper
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *const' with a newly created 'gsl::owner<>'
+ // CHECK-MESSAGES: [[@LINE-2]]:3: note: type deduction did not result in an owner
+
+ gsl::owner<int *> owned_int9 = returns_owner1(); // Ok
+ int *unowned_int3 = returns_owner1(); // Bad
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+
+ gsl::owner<int *> owned_int10;
+ owned_int10 = returns_owner1(); // Ok
+
+ int *unowned_int4;
+ unowned_int4 = returns_owner1(); // Bad
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: assigning newly created 'gsl::owner<>' to non-owner 'int *'
+
+ gsl::owner<int *> owned_int11 = returns_no_owner1(); // Bad since no owner
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
+
+ gsl::owner<int *> owned_int12;
+ owned_int12 = returns_no_owner1(); // Bad since no owner
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *'
+
+ int *unowned_int5 = returns_no_owner1(); // Ok
+ int *unowned_int6;
+ unowned_int6 = returns_no_owner1(); // Ok
+
+ int *unowned_int7 = new int(42); // Bad, since resource not assigned to an owner
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+
+ int *unowned_int8;
+ unowned_int8 = new int(42);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: assigning newly created 'gsl::owner<>' to non-owner 'int *'
+
+ gsl::owner<int *> owned_int13 = nullptr; // Ok
+}
+
+void test_deletion() {
+ gsl::owner<int *> owned_int1 = new int(42);
+ delete owned_int1; // Good
+
+ gsl::owner<int *> owned_int2 = new int[42];
+ delete[] owned_int2; // Good
+
+ int *unowned_int1 = new int(42); // BAD, since new creates and owner
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ delete unowned_int1; // BAD, since no owner
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead
+ // CHECK-MESSAGES: [[@LINE-4]]:3: note: variable declared here
+
+ int *unowned_int2 = new int[42]; // BAD, since new creates and owner
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
+ delete[] unowned_int2; // BAD since no owner
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead
+ // CHECK-MESSAGES: [[@LINE-4]]:3: note: variable declared here
+
+ delete new int(42); // Technically ok, but stupid
+ delete[] new int[42]; // Technically ok, but stupid
+}
+
+void test_owner_function_calls() {
+ int stack_int = 42;
+ int *unowned_int1 = &stack_int;
+ takes_owner(&stack_int); // BAD
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *'
+ takes_owner(unowned_int1); // BAD
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *'
+
+ gsl::owner<int *> owned_int1 = new int(42);
+ takes_owner(owned_int1); // Ok
+
+ takes_owner_and_more(42, &stack_int, 42.0f); // BAD
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: expected argument of type 'gsl::owner<>'; got 'int *'
+ takes_owner_and_more(42, unowned_int1, 42.0f); // BAD
+ // CHECK-MESSAGES: [[@LINE-1]]:28: warning: expected argument of type 'gsl::owner<>'; got 'int *'
+
+ takes_owner_and_more(42, new int(42), 42.0f); // Ok, since new is consumed by owner
+ takes_owner_and_more(42, owned_int1, 42.0f); // Ok, since owner as argument
+
+ takes_templated_owner(owned_int1); // Ok
+ takes_templated_owner(new int(42)); // Ok
+ takes_templated_owner(unowned_int1); // Bad
+ // CHECK-MESSAGES: [[@LINE-1]]:25: warning: expected argument of type 'gsl::owner<>'; got 'int *'
+
+ takes_owner(returns_owner1()); // Ok
+ takes_owner(returns_no_owner1()); // BAD
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *'
+}
+
+void test_unowned_function_calls() {
+ int stack_int = 42;
+ int *unowned_int1 = &stack_int;
+ gsl::owner<int *> owned_int1 = new int(42);
+
+ takes_pointer(&stack_int); // Ok
+ takes_pointer(unowned_int1); // Ok
+ takes_pointer(owned_int1); // Ok
+ takes_pointer(new int(42)); // Bad, since new creates and owner
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'int *' with a newly created 'gsl::owner<>'
+
+ takes_pointer(returns_owner1()); // Bad
+ // CHECK-MESSAGES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'int *' with a newly created 'gsl::owner<>'
+
+ takes_pointer(returns_no_owner1()); // Ok
+}
+
+// FIXME: Typedefing owner<> to something else does not work.
+// This might be necessary for code already having a similar typedef like owner<> and
+// replacing it with owner<>. This might be the same problem as with templates.
+// The canonical type will ignore the owner<> alias, since its a typedef as well.
+//
+// Check, if owners hidden by typedef are handled the same as 'obvious' owners.
+#if 0
+using heap_int = gsl::owner<int *>;
+typedef gsl::owner<float *> heap_float;
+
+// This tests only a subset, assuming that the check will either see through the
+// typedef or not (it doesn't!).
+void test_typedefed_values() {
+ // Modern typedef.
+ int StackInt1 = 42;
+ heap_int HeapInt1 = &StackInt1;
+ // CHECK MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *'
+
+ //FIXME: Typedef not considered correctly here.
+ // heap_int HeapInt2 = new int(42); // Ok
+ takes_pointer(HeapInt1); // Ok
+ takes_owner(HeapInt1); // Ok
+
+ // Traditional typedef.
+ float StackFloat1 = 42.0f;
+ heap_float HeapFloat1 = &StackFloat1;
+ // CHECK MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'float *'
+
+ //FIXME: Typedef not considered correctly here.
+ // heap_float HeapFloat2 = new float(42.0f);
+ HeapFloat2 = HeapFloat1; // Ok
+}
+#endif
+
+struct ArbitraryClass {};
+struct ClassWithOwner { // Does not define destructor, necessary with owner
+ ClassWithOwner() : owner_var(nullptr) {} // Ok
+
+ ClassWithOwner(ArbitraryClass &other) : owner_var(&other) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:43: warning: expected initialization of owner member variable with value of type 'gsl::owner<>'; got 'ArbitraryClass *'
+
+ ClassWithOwner(gsl::owner<ArbitraryClass *> other) : owner_var(other) {} // Ok
+
+ ClassWithOwner(gsl::owner<ArbitraryClass *> data, int /* unused */) { // Ok
+ owner_var = data; // Ok
+ }
+
+ ClassWithOwner(ArbitraryClass *bad_data, int /* unused */, int /* unused */) {
+ owner_var = bad_data;
+ // CHECK-MESSAGES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *'
+ }
+
+ ClassWithOwner(ClassWithOwner &&other) : owner_var{other.owner_var} {} // Ok
+
+ ClassWithOwner &operator=(ClassWithOwner &&other) {
+ owner_var = other.owner_var; // Ok
+ return *this;
+ }
+
+ // Returning means, that the owner is "moved", so the class should not access this
+ // variable anymore after this method gets called.
+ gsl::owner<ArbitraryClass *> buggy_but_returns_owner() { return owner_var; }
+
+ gsl::owner<ArbitraryClass *> owner_var;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: member variable of type 'gsl::owner<>' requires the class 'ClassWithOwner' to implement a destructor to release the owned resource
+};
+
+class DefaultedDestructor { // Bad since default constructor with owner
+ ~DefaultedDestructor() = default; // Bad, since will not destroy the owner
+ gsl::owner<int *> Owner;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: member variable of type 'gsl::owner<>' requires the class 'DefaultedDestructor' to implement a destructor to release the owned resource
+};
+
+struct DeletedDestructor {
+ ~DeletedDestructor() = delete;
+ gsl::owner<int *> Owner;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: member variable of type 'gsl::owner<>' requires the class 'DeletedDestructor' to implement a destructor to release the owned resource
+};
+
+void test_class_with_owner() {
+ ArbitraryClass A;
+ ClassWithOwner C1; // Ok
+ ClassWithOwner C2{A}; // Bad, since the owner would be initialized with an non-owner, but catched in the class
+ ClassWithOwner C3{gsl::owner<ArbitraryClass *>(new ArbitraryClass)}; // Ok
+
+ const auto Owner1 = C3.buggy_but_returns_owner(); // BAD, deduces Owner1 to ArbitraryClass *const
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'ArbitraryClass *const' with a newly created 'gsl::owner<>'
+ // CHECK-MESSAGES: [[@LINE-2]]:3: note: type deduction did not result in an owner
+
+ auto Owner2 = C2.buggy_but_returns_owner(); // BAD, deduces Owner2 to ArbitraryClass *
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: initializing non-owner 'ArbitraryClass *' with a newly created 'gsl::owner<>'
+ // CHECK-MESSAGES: [[@LINE-2]]:3: note: type deduction did not result in an owner
+
+ Owner2 = &A; // Ok, since type deduction did NOT result in owner<int*>
+
+ gsl::owner<ArbitraryClass *> Owner3 = C1.buggy_but_returns_owner(); // Ok, still an owner
+ Owner3 = &A; // Bad, since assignment of non-owner to owner
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *'
+}
+
+template <typename T>
+struct HeapArray { // Ok, since destructor with owner
+ HeapArray() : _data(nullptr), size(0) {} // Ok
+ HeapArray(int size) : _data(new int[size]), size(size) {} // Ok
+ HeapArray(int size, T val) {
+ _data = new int[size]; // Ok
+ size = size;
+ for (auto i = 0u; i < size; ++i)
+ _data[i] = val; // Ok
+ }
+ HeapArray(int size, T val, int *problematic) : _data{problematic}, size(size) {} // Bad
+ // CHECK-MESSAGES: [[@LINE-1]]:50: warning: expected initialization of owner member variable with value of type 'gsl::owner<>'; got 'void'
+ // FIXME: void is incorrect type, probably wrong thing matched
+
+ HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok
+ other._data = nullptr; // Ok
+ other.size = 0;
+ }
+
+ HeapArray<T> &operator=(HeapArray<T> &&other) {
+ _data = other._data; // Ok, NOLINT warning here about bad types, why?
+ size = other.size;
+ return *this;
+ }
+
+ ~HeapArray() { delete[] _data; } // Ok
+
+ T *data() { return _data; } // Ok NOLINT, because it "looks" like a factory
+
+ gsl::owner<T *> _data;
+ unsigned int size;
+};
+
+void test_inner_template() {
+ HeapArray<int> Array1;
+ HeapArray<int> Array2(100);
+ HeapArray<int> Array3(100, 0);
+ HeapArray<int> Array4(100, 0, nullptr);
+
+ Array1 = static_cast<HeapArray<int> &&>(Array2);
+ HeapArray<int> Array5(static_cast<HeapArray<int> &&>(Array3));
+
+ int *NonOwningPtr = Array1.data(); // Ok
+ gsl::owner<int *> OwningPtr = Array1.data(); // Bad, since it does not return the owner
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
+}
+
+// FIXME: Typededuction removes the owner - wrapper, therefore gsl::owner can not be used
+// with Template classes like this. Is there a walkaround?
+template <typename T>
+struct TemplateValue {
+ TemplateValue() = default;
+ TemplateValue(T t) : val{t} {}
+
+ void setVal(const T &t) { val = t; }
+ const T getVal() const { return val; }
+
+ T val;
+};
+
+// FIXME: Same typededcution problems
+template <typename T>
+void template_function(T t) {
+ gsl::owner<int *> owner_t = t; // Probably bad, since type deduction still wrong
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'T'
+ // CHECK-MESSAGES: [[@LINE-2]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
+}
+
+// FIXME: Same typededcution problems
+void test_templates() {
+ int stack_int = 42;
+ int *stack_ptr1 = &stack_int;
+
+ TemplateValue<gsl::owner<int *>> Owner0; // Ok, T should be owner, but is int*
+
+ TemplateValue<gsl::owner<int *>> Owner1(new int(42)); // Ok, T should be owner, but is int*
+ Owner1.setVal(&stack_int); // Bad since non-owner assignment
+ Owner1.setVal(stack_ptr1); // Bad since non-owner assignment
+ //Owner1.setVal(new int(42)); // Ok, but since type deduction is wrong, this one is considered harmful
+
+ int *stack_ptr2 = Owner1.getVal(); // Bad, initializing non-owner with owner
+
+ TemplateValue<int *> NonOwner1(new int(42)); // Bad, T is int *, hence dynamic memory to non-owner
+ gsl::owner<int *> IntOwner1 = NonOwner1.getVal(); // Bad, since owner initialized with non-owner
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
+
+ template_function(IntOwner1); // Ok, but not actually ok, since type deduction removes owner
+ template_function(stack_ptr1); // Bad, but type deduction gets it wrong
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-array-to-pointer-decay.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-array-to-pointer-decay.cpp
new file mode 100644
index 0000000..ce19280
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-array-to-pointer-decay.cpp
@@ -0,0 +1,47 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-array-to-pointer-decay %t
+#include <stddef.h>
+
+namespace gsl {
+template <class T>
+class array_view {
+public:
+ template <class U, size_t N>
+ array_view(U (&arr)[N]);
+};
+}
+
+void pointerfun(int *p);
+void arrayfun(int p[]);
+void arrayviewfun(gsl::array_view<int> &p);
+size_t s();
+
+void f() {
+ int a[5];
+ pointerfun(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay]
+ pointerfun((int *)a); // OK, explicit cast
+ arrayfun(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not implicitly decay an array into a pointer
+
+ pointerfun(a + s() - 10); // Convert to &a[g() - 10];
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not implicitly decay an array into a pointer
+
+ gsl::array_view<int> av(a);
+ arrayviewfun(av); // OK
+
+ int i = a[0]; // OK
+ pointerfun(&a[0]); // OK
+
+ for (auto &e : a) // OK, iteration internally decays array to pointer
+ e = 1;
+}
+
+const char *g() {
+ return "clang"; // OK, decay string literal to pointer
+}
+
+void f2(void *const *);
+void bug25362() {
+ void *a[2];
+ f2(static_cast<void *const*>(a)); // OK, explicit cast
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-constant-array-index-c++03.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-constant-array-index-c++03.cpp
new file mode 100644
index 0000000..ad9fcd9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-constant-array-index-c++03.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-tidy %s -checks=-*,cppcoreguidelines-pro-bounds-constant-array-index -- -std=c++03 | count 0
+
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+template <int index> struct B {
+ int get() {
+ // The next line used to crash the check (in C++03 mode only).
+ return x[index];
+ }
+ int x[3];
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-constant-array-index-gslheader.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-constant-array-index-gslheader.cpp
new file mode 100644
index 0000000..a88a2d9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-constant-array-index-gslheader.cpp
@@ -0,0 +1,79 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-constant-array-index %t -- -config='{CheckOptions: [{key: cppcoreguidelines-pro-bounds-constant-array-index.GslHeader, value: "dir1/gslheader.h"}]}' -- -std=c++11
+// CHECK-FIXES: #include "dir1/gslheader.h"
+
+typedef __SIZE_TYPE__ size_t;
+
+namespace std {
+ template<typename T, size_t N>
+ struct array {
+ T& operator[](size_t n);
+ T& at(size_t n);
+ };
+}
+
+
+namespace gsl {
+ template<class T, size_t N>
+ T& at( T(&a)[N], size_t index );
+
+ template<class T, size_t N>
+ T& at( std::array<T, N> &a, size_t index );
+}
+
+constexpr int const_index(int base) {
+ return base + 3;
+}
+
+void f(std::array<int, 10> a, int pos) {
+ a [ pos / 2 /*comment*/] = 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use array subscript when the index is not an integer constant expression; use gsl::at() instead [cppcoreguidelines-pro-bounds-constant-array-index]
+ // CHECK-FIXES: gsl::at(a, pos / 2 /*comment*/) = 1;
+ int j = a[pos - 1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use array subscript when the index is not an integer constant expression; use gsl::at() instead
+ // CHECK-FIXES: int j = gsl::at(a, pos - 1);
+
+ a.at(pos-1) = 2; // OK, at() instead of []
+ gsl::at(a, pos-1) = 2; // OK, gsl::at() instead of []
+
+ a[-1] = 3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]
+ a[10] = 4;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements) [cppcoreguidelines-pro-bounds-constant-array-index]
+
+ a[const_index(7)] = 3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)
+
+ a[0] = 3; // OK, constant index and inside bounds
+ a[1] = 3; // OK, constant index and inside bounds
+ a[9] = 3; // OK, constant index and inside bounds
+ a[const_index(6)] = 3; // OK, constant index and inside bounds
+}
+
+void g() {
+ int a[10];
+ for (int i = 0; i < 10; ++i) {
+ a[i] = i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use array subscript when the index is not an integer constant expression; use gsl::at() instead
+ // CHECK-FIXES: gsl::at(a, i) = i;
+ gsl::at(a, i) = i; // OK, gsl::at() instead of []
+ }
+
+ a[-1] = 3; // flagged by clang-diagnostic-array-bounds
+ a[10] = 4; // flagged by clang-diagnostic-array-bounds
+ a[const_index(7)] = 3; // flagged by clang-diagnostic-array-bounds
+
+ a[0] = 3; // OK, constant index and inside bounds
+ a[1] = 3; // OK, constant index and inside bounds
+ a[9] = 3; // OK, constant index and inside bounds
+ a[const_index(6)] = 3; // OK, constant index and inside bounds
+}
+
+struct S {
+ int& operator[](int i);
+};
+
+void customOperator() {
+ S s;
+ int i = 0;
+ s[i] = 3; // OK, custom operator
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-constant-array-index.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-constant-array-index.cpp
new file mode 100644
index 0000000..3519410
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-constant-array-index.cpp
@@ -0,0 +1,87 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-constant-array-index %t
+
+typedef __SIZE_TYPE__ size_t;
+
+namespace std {
+ template<typename T, size_t N>
+ struct array {
+ T& operator[](size_t n);
+ T& at(size_t n);
+ };
+}
+
+
+namespace gsl {
+ template<class T, size_t N>
+ T& at( T(&a)[N], size_t index );
+
+ template<class T, size_t N>
+ T& at( std::array<T, N> &a, size_t index );
+}
+
+constexpr int const_index(int base) {
+ return base + 3;
+}
+
+void f(std::array<int, 10> a, int pos) {
+ a [ pos / 2 /*comment*/] = 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use array subscript when the index is not an integer constant expression; use gsl::at() instead [cppcoreguidelines-pro-bounds-constant-array-index]
+ int j = a[pos - 1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use array subscript when the index is not an integer constant expression; use gsl::at() instead
+
+ a.at(pos-1) = 2; // OK, at() instead of []
+ gsl::at(a, pos-1) = 2; // OK, gsl::at() instead of []
+
+ a[-1] = 3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index -1 is negative [cppcoreguidelines-pro-bounds-constant-array-index]
+ a[10] = 4;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements) [cppcoreguidelines-pro-bounds-constant-array-index]
+
+ a[const_index(7)] = 3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: std::array<> index 10 is past the end of the array (which contains 10 elements)
+
+ a[0] = 3; // OK, constant index and inside bounds
+ a[1] = 3; // OK, constant index and inside bounds
+ a[9] = 3; // OK, constant index and inside bounds
+ a[const_index(6)] = 3; // OK, constant index and inside bounds
+}
+
+void g() {
+ int a[10];
+ for (int i = 0; i < 10; ++i) {
+ a[i] = i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use array subscript when the index is not an integer constant expression; use gsl::at() instead
+ // CHECK-FIXES: gsl::at(a, i) = i;
+ gsl::at(a, i) = i; // OK, gsl::at() instead of []
+ }
+
+ a[-1] = 3; // flagged by clang-diagnostic-array-bounds
+ a[10] = 4; // flagged by clang-diagnostic-array-bounds
+ a[const_index(7)] = 3; // flagged by clang-diagnostic-array-bounds
+
+ a[0] = 3; // OK, constant index and inside bounds
+ a[1] = 3; // OK, constant index and inside bounds
+ a[9] = 3; // OK, constant index and inside bounds
+ a[const_index(6)] = 3; // OK, constant index and inside bounds
+}
+
+struct S {
+ int& operator[](int i);
+};
+
+void customOperator() {
+ S s;
+ int i = 0;
+ s[i] = 3; // OK, custom operator
+}
+
+struct A {
+ // The compiler-generated copy constructor uses an ArraySubscriptExpr. Don't warn.
+ int x[3];
+};
+
+void use_A() {
+ // Force the compiler to generate a copy constructor.
+ A a;
+ A a2(a);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-pointer-arithmetic-pr36489.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-pointer-arithmetic-pr36489.cpp
new file mode 100644
index 0000000..4710952
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-pointer-arithmetic-pr36489.cpp
@@ -0,0 +1,53 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-pointer-arithmetic %t -- -- -std=c++14
+
+// Fix PR36489 and detect auto-deduced value correctly.
+char *getPtr();
+auto getPtrAuto() { return getPtr(); }
+decltype(getPtr()) getPtrDeclType();
+decltype(auto) getPtrDeclTypeAuto() { return getPtr(); }
+auto getPtrWithTrailingReturnType() -> char *;
+
+void auto_deduction_binary() {
+ auto p1 = getPtr() + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not use pointer arithmetic
+ auto p2 = getPtrAuto() + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not use pointer arithmetic
+ auto p3 = getPtrWithTrailingReturnType() + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: do not use pointer arithmetic
+ auto p4 = getPtr();
+ auto *p5 = getPtr();
+ p4 = p4 + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use pointer arithmetic
+ p5 = p5 + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use pointer arithmetic
+ auto p6 = getPtrDeclType() + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: do not use pointer arithmetic
+ auto p7 = getPtrDeclTypeAuto() + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: do not use pointer arithmetic
+ auto *p8 = getPtrDeclType() + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: do not use pointer arithmetic
+ auto *p9 = getPtrDeclTypeAuto() + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: do not use pointer arithmetic
+}
+
+void auto_deduction_subscript() {
+ char p1 = getPtr()[2];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+ auto p2 = getPtr()[3];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+
+ char p3 = getPtrAuto()[4];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+ auto p4 = getPtrAuto()[5];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+
+ char p5 = getPtrWithTrailingReturnType()[6];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+ auto p6 = getPtrWithTrailingReturnType()[7];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+
+ auto p7 = getPtrDeclType()[8];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+ auto p8 = getPtrDeclTypeAuto()[9];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use pointer arithmetic
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-pointer-arithmetic.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-pointer-arithmetic.cpp
new file mode 100644
index 0000000..7cbc6dd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-pointer-arithmetic.cpp
@@ -0,0 +1,89 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-pointer-arithmetic %t
+
+enum E {
+ ENUM_LITERAL = 1
+};
+
+int i = 4;
+int j = 1;
+int *p = 0;
+int *q = 0;
+
+void fail() {
+ q = p + 4;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
+ p = q + i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
+ p = q + ENUM_LITERAL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
+
+ q = p - 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
+ p = q - i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
+ p = q - ENUM_LITERAL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
+
+ p += 4;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
+ p += i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
+ p += ENUM_LITERAL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
+
+ q -= 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
+ q -= i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
+ q -= ENUM_LITERAL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
+
+ p++;
+ // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: do not use pointer arithmetic
+ ++p;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use pointer arithmetic
+
+ p--;
+ // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: do not use pointer arithmetic
+ --p;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use pointer arithmetic
+
+ i = p[1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use pointer arithmetic
+}
+
+struct S {
+ operator int() const;
+};
+
+void f(S &s) {
+ int *i;
+ i = i + s;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
+}
+
+void f2(int i[]) {
+ i[1] = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use pointer arithmetic
+}
+
+void okay() {
+ int a[3];
+ i = a[2]; // OK, access to array
+
+ p = q;
+ p = &i;
+
+ i++;
+ ++i;
+ i--;
+ --i;
+ i += 1;
+ i -= 1;
+ i = j + 1;
+ i = j - 1;
+
+ auto diff = p - q; // OK, result is arithmetic
+
+ for(int ii : a) ; // OK, pointer arithmetic generated by compiler
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-const-cast.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-const-cast.cpp
new file mode 100644
index 0000000..2d32e13
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-const-cast.cpp
@@ -0,0 +1,6 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-const-cast %t
+
+const int *i;
+int *j;
+void f() { j = const_cast<int *>(i); }
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: do not use const_cast [cppcoreguidelines-pro-type-const-cast]
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-cstyle-cast.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-cstyle-cast.cpp
new file mode 100644
index 0000000..31f59e3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-cstyle-cast.cpp
@@ -0,0 +1,141 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-cstyle-cast %t
+
+void reinterpretcast() {
+ int i = 0;
+ void *j;
+ j = (int*)j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]
+}
+
+void constcast() {
+ int* i;
+ const int* j;
+ i = (int*)j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use C-style cast to cast away constness
+ j = (const int*)i; // OK, const added
+ (void)j; // OK, not a const_cast
+}
+
+void const_and_reinterpret() {
+ int* i;
+ const void* j;
+ i = (int*)j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use C-style cast to convert between unrelated types
+}
+
+class Base {
+};
+
+class Derived : public Base {
+};
+
+class Base2 {
+};
+
+class MultiDerived : public Base, public Base2 {
+};
+
+class PolymorphicBase {
+public:
+ virtual ~PolymorphicBase();
+};
+
+class PolymorphicDerived : public PolymorphicBase {
+};
+
+class PolymorphicMultiDerived : public Base, public PolymorphicBase {
+};
+
+void pointers() {
+
+ auto P0 = (Derived*)new Base();
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use C-style cast to downcast from a base to a derived class
+
+ const Base* B0;
+ auto PC0 = (const Derived*)(B0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class
+
+ auto P1 = (Base*)new Derived(); // OK, upcast to a public base
+ auto P2 = (Base*)new MultiDerived(); // OK, upcast to a public base
+ auto P3 = (Base2*)new MultiDerived(); // OK, upcast to a public base
+}
+
+void pointers_polymorphic() {
+
+ auto PP0 = (PolymorphicDerived*)new PolymorphicBase();
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto PP0 = dynamic_cast<PolymorphicDerived*>(new PolymorphicBase());
+
+ const PolymorphicBase* B0;
+ auto PPC0 = (const PolymorphicDerived*)B0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto PPC0 = dynamic_cast<const PolymorphicDerived*>(B0);
+
+
+ auto B1 = (PolymorphicBase*)new PolymorphicDerived(); // OK, upcast to a public base
+ auto B2 = (PolymorphicBase*)new PolymorphicMultiDerived(); // OK, upcast to a public base
+ auto B3 = (Base*)new PolymorphicMultiDerived(); // OK, upcast to a public base
+}
+
+void arrays() {
+ Base ArrayOfBase[10];
+ auto A0 = (Derived*)ArrayOfBase;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use C-style cast to downcast from a base to a derived class
+}
+
+void arrays_polymorphic() {
+ PolymorphicBase ArrayOfPolymorphicBase[10];
+ auto AP0 = (PolymorphicDerived*)ArrayOfPolymorphicBase;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto AP0 = dynamic_cast<PolymorphicDerived*>(ArrayOfPolymorphicBase);
+}
+
+void references() {
+ Base B0;
+ auto R0 = (Derived&)B0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use C-style cast to downcast from a base to a derived class
+ Base& RefToBase = B0;
+ auto R1 = (Derived&)RefToBase;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use C-style cast to downcast from a base to a derived class
+
+ const Base& ConstRefToBase = B0;
+ auto RC1 = (const Derived&)ConstRefToBase;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class
+
+
+ Derived RD1;
+ auto R2 = (Base&)RD1; // OK, upcast to a public base
+}
+
+void references_polymorphic() {
+ PolymorphicBase B0;
+ auto RP0 = (PolymorphicDerived&)B0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto RP0 = dynamic_cast<PolymorphicDerived&>(B0);
+
+ PolymorphicBase& RefToPolymorphicBase = B0;
+ auto RP1 = (PolymorphicDerived&)RefToPolymorphicBase;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto RP1 = dynamic_cast<PolymorphicDerived&>(RefToPolymorphicBase);
+
+ const PolymorphicBase& ConstRefToPolymorphicBase = B0;
+ auto RPC2 = (const PolymorphicDerived&)(ConstRefToPolymorphicBase);
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: do not use C-style cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto RPC2 = dynamic_cast<const PolymorphicDerived&>(ConstRefToPolymorphicBase);
+
+ PolymorphicDerived d1;
+ auto RP2 = (PolymorphicBase&)d1; // OK, upcast to a public base
+}
+
+template<class B, class D>
+void templ() {
+ auto B0 = (B*)new D();
+}
+
+void templ_bad_call() {
+ templ<Derived, Base>(); //FIXME: this should trigger a warning
+}
+
+void templ_good_call() {
+ templ<Base, Derived>(); // OK, upcast to a public base
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx2a.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx2a.cpp
new file mode 100644
index 0000000..d3e3ade
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx2a.cpp
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -std=c++2a -fno-delayed-template-parsing
+
+struct PositiveBitfieldMember {
+ PositiveBitfieldMember() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
+ unsigned F : 5;
+ // CHECK-FIXES: unsigned F : 5{};
+};
+
+struct NegativeUnnamedBitfieldMember {
+ NegativeUnnamedBitfieldMember() {}
+ unsigned : 5;
+};
+
+struct NegativeInitializedBitfieldMembers {
+ NegativeInitializedBitfieldMembers() : F(3) { G = 2; }
+ unsigned F : 5;
+ unsigned G : 5;
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp
new file mode 100644
index 0000000..db97bb4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp
@@ -0,0 +1,116 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -std=c++98 -fno-delayed-template-parsing
+
+struct PositiveFieldBeforeConstructor {
+ int F;
+ PositiveFieldBeforeConstructor() /* some comment */ {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
+ // CHECK-FIXES: PositiveFieldBeforeConstructor() : F() /* some comment */ {}
+};
+
+struct PositiveFieldAfterConstructor {
+ PositiveFieldAfterConstructor() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F, G, H
+ // CHECK-FIXES: PositiveFieldAfterConstructor() : F(), G(), H() {}
+ int F;
+ bool G /* with comment */;
+ int *H;
+ PositiveFieldBeforeConstructor IgnoredField;
+};
+
+struct PositiveSeparateDefinition {
+ PositiveSeparateDefinition();
+ int F;
+};
+
+PositiveSeparateDefinition::PositiveSeparateDefinition() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: F
+// CHECK-FIXES: PositiveSeparateDefinition::PositiveSeparateDefinition() : F() {}
+
+struct PositiveMixedFieldOrder {
+ PositiveMixedFieldOrder() : /* some comment */ J(0), L(0), M(0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: I, K, N
+ // CHECK-FIXES: PositiveMixedFieldOrder() : I(), /* some comment */ J(0), K(), L(0), M(0), N() {}
+ int I;
+ int J;
+ int K;
+ int L;
+ int M;
+ int N;
+};
+
+struct PositiveAfterBaseInitializer : public PositiveMixedFieldOrder {
+ PositiveAfterBaseInitializer() : PositiveMixedFieldOrder() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
+ // CHECK-FIXES: PositiveAfterBaseInitializer() : PositiveMixedFieldOrder(), F() {}
+ int F;
+};
+
+struct NegativeFieldInitialized {
+ int F;
+
+ NegativeFieldInitialized() : F() {}
+};
+
+struct NegativeFieldInitializedInDefinition {
+ int F;
+
+ NegativeFieldInitializedInDefinition();
+};
+
+NegativeFieldInitializedInDefinition::NegativeFieldInitializedInDefinition() : F() {}
+
+struct NegativeInitializedInBody {
+ NegativeInitializedInBody() { I = 0; }
+ int I;
+};
+
+struct NegativeAggregateType {
+ int X;
+ int Y;
+ int Z;
+};
+
+struct TrivialType {
+ int X;
+ int Y;
+};
+
+struct PositiveUninitializedBaseOrdering : public NegativeAggregateType,
+ public TrivialType {
+ PositiveUninitializedBaseOrdering() : NegativeAggregateType(), TrivialType(), B() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A
+ // CHECK-FIXES: PositiveUninitializedBaseOrdering() : NegativeAggregateType(), TrivialType(), A(), B() {}
+
+ // This is somewhat pathological with the base class initializer at the end...
+ PositiveUninitializedBaseOrdering(int) : B(), TrivialType(), A() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NegativeAggregateType
+ // CHECK-FIXES: PositiveUninitializedBaseOrdering(int) : B(), NegativeAggregateType(), TrivialType(), A() {}
+
+ PositiveUninitializedBaseOrdering(float) : NegativeAggregateType(), A() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: TrivialType
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: constructor does not initialize these fields: B
+ // CHECK-FIXES: PositiveUninitializedBaseOrdering(float) : NegativeAggregateType(), TrivialType(), A(), B() {}
+
+ int A, B;
+};
+
+template <class T>
+class PositiveTemplateBase : T {
+public:
+ PositiveTemplateBase() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: X
+ // CHECK-FIXES: PositiveTemplateBase() : X() {}
+
+ int X;
+};
+
+class PositiveIndirectMember {
+ struct {
+ int *A;
+ };
+
+ PositiveIndirectMember() : A() {}
+ PositiveIndirectMember(int) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A
+ // CHECK-FIXES: PositiveIndirectMember(int) : A() {}
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-delayed.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-delayed.cpp
new file mode 100644
index 0000000..d3436ba
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init-delayed.cpp
@@ -0,0 +1,32 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -fdelayed-template-parsing
+
+template <class T>
+struct PositiveFieldBeforeConstructor {
+ int F;
+ bool G /* with comment */;
+ int *H;
+ PositiveFieldBeforeConstructor() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F, G, H
+};
+// Explicit instantiation.
+template class PositiveFieldBeforeConstructor<int>;
+
+template <class T>
+struct PositiveFieldAfterConstructor {
+ PositiveFieldAfterConstructor() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F, G, H
+ int F;
+ bool G /* with comment */;
+ int *H;
+};
+// Explicit instantiation.
+template class PositiveFieldAfterConstructor<int>;
+
+// This declaration isn't used and won't be parsed 'delayed-template-parsing'.
+// The body of the declaration is 'null' and may cause crash if not handled
+// properly by checkers.
+template <class T>
+struct UnusedDelayedConstructor {
+ UnusedDelayedConstructor() {}
+ int F;
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp
new file mode 100644
index 0000000..86f094d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp
@@ -0,0 +1,502 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -std=c++11 -fno-delayed-template-parsing
+
+struct PositiveFieldBeforeConstructor {
+ int F;
+ // CHECK-FIXES: int F{};
+ PositiveFieldBeforeConstructor() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
+ // CHECK-FIXES: PositiveFieldBeforeConstructor() {}
+};
+
+struct PositiveFieldAfterConstructor {
+ PositiveFieldAfterConstructor() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F, G
+ // CHECK-FIXES: PositiveFieldAfterConstructor() {}
+ int F;
+ // CHECK-FIXES: int F{};
+ bool G /* with comment */;
+ // CHECK-FIXES: bool G{} /* with comment */;
+ PositiveFieldBeforeConstructor IgnoredField;
+};
+
+struct PositiveSeparateDefinition {
+ PositiveSeparateDefinition();
+ int F;
+ // CHECK-FIXES: int F{};
+};
+
+PositiveSeparateDefinition::PositiveSeparateDefinition() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: F
+// CHECK-FIXES: PositiveSeparateDefinition::PositiveSeparateDefinition() {}
+
+struct PositiveMixedFieldOrder {
+ PositiveMixedFieldOrder() : J(0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: I, K
+ // CHECK-FIXES: PositiveMixedFieldOrder() : J(0) {}
+ int I;
+ // CHECK-FIXES: int I{};
+ int J;
+ int K;
+ // CHECK-FIXES: int K{};
+};
+
+template <typename T>
+struct Template {
+ Template() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
+ int F;
+ // CHECK-FIXES: int F{};
+ T T1;
+ // CHECK-FIXES: T T1;
+};
+
+void instantiate() {
+ Template<int> TInt;
+}
+
+struct NegativeFieldInitialized {
+ int F;
+
+ NegativeFieldInitialized() : F() {}
+};
+
+struct NegativeFieldInitializedInDefinition {
+ int F;
+
+ NegativeFieldInitializedInDefinition();
+};
+NegativeFieldInitializedInDefinition::NegativeFieldInitializedInDefinition() : F() {}
+
+struct NegativeInClassInitialized {
+ int F = 0;
+
+ NegativeInClassInitialized() {}
+};
+
+struct NegativeInClassInitializedDefaulted {
+ int F = 0;
+ NegativeInClassInitializedDefaulted() = default;
+};
+
+struct NegativeConstructorDelegated {
+ int F;
+
+ NegativeConstructorDelegated(int F) : F(F) {}
+ NegativeConstructorDelegated() : NegativeConstructorDelegated(0) {}
+};
+
+struct NegativeInitializedInBody {
+ NegativeInitializedInBody() { I = 0; }
+ int I;
+};
+
+struct A {};
+template <class> class AA;
+template <class T> class NegativeTemplateConstructor {
+ NegativeTemplateConstructor(const AA<T> &, A) {}
+ bool Bool{false};
+ // CHECK-FIXES: bool Bool{false};
+};
+
+#define UNINITIALIZED_FIELD_IN_MACRO_BODY(FIELD) \
+ struct UninitializedField##FIELD { \
+ UninitializedField##FIELD() {} \
+ int FIELD; \
+ }; \
+// Ensure FIELD is not initialized since fixes inside of macros are disabled.
+// CHECK-FIXES: int FIELD;
+
+UNINITIALIZED_FIELD_IN_MACRO_BODY(F);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: F
+UNINITIALIZED_FIELD_IN_MACRO_BODY(G);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: G
+
+#define UNINITIALIZED_FIELD_IN_MACRO_ARGUMENT(ARGUMENT) \
+ ARGUMENT
+
+UNINITIALIZED_FIELD_IN_MACRO_ARGUMENT(struct UninitializedFieldInMacroArg {
+ UninitializedFieldInMacroArg() {}
+ int Field;
+});
+// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: constructor does not initialize these fields: Field
+// Ensure FIELD is not initialized since fixes inside of macros are disabled.
+// CHECK-FIXES: int Field;
+
+struct NegativeAggregateType {
+ int X;
+ int Y;
+ int Z;
+};
+
+struct PositiveTrivialType {
+ PositiveTrivialType() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
+
+ NegativeAggregateType F;
+ // CHECK-FIXES: NegativeAggregateType F{};
+};
+
+struct NegativeNonTrivialType {
+ PositiveTrivialType F;
+};
+
+static void PositiveUninitializedTrivialType() {
+ NegativeAggregateType X;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: uninitialized record type: 'X'
+ // CHECK-FIXES: NegativeAggregateType X{};
+
+ NegativeAggregateType A[10]; // Don't warn because this isn't an object type.
+}
+
+static void NegativeInitializedTrivialType() {
+ NegativeAggregateType X{};
+ NegativeAggregateType Y = {};
+ NegativeAggregateType Z = NegativeAggregateType();
+ NegativeAggregateType A[10]{};
+ NegativeAggregateType B[10] = {};
+ int C; // No need to initialize this because we don't have a constructor.
+ int D[8];
+ NegativeAggregateType E = {0, 1, 2};
+ NegativeAggregateType F({});
+}
+
+struct NonTrivialType {
+ NonTrivialType() = default;
+ NonTrivialType(const NonTrivialType &RHS) : X(RHS.X), Y(RHS.Y) {}
+
+ int X;
+ int Y;
+};
+
+static void PositiveNonTrivialTypeWithCopyConstructor() {
+ NonTrivialType T;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: uninitialized record type: 'T'
+ // CHECK-FIXES: NonTrivialType T{};
+
+ NonTrivialType A[8];
+ // Don't warn because this isn't an object type
+}
+
+struct ComplexNonTrivialType {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: constructor does not initialize these fields: Y
+ NegativeFieldInitialized X;
+ int Y;
+ // CHECK-FIXES: int Y{};
+};
+
+static void PositiveComplexNonTrivialType() {
+ ComplexNonTrivialType T;
+}
+
+struct NegativeStaticMember {
+ static NonTrivialType X;
+ static NonTrivialType Y;
+ static constexpr NonTrivialType Z{};
+};
+
+NonTrivialType NegativeStaticMember::X;
+NonTrivialType NegativeStaticMember::Y{};
+
+struct PositiveMultipleConstructors {
+ PositiveMultipleConstructors() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A, B
+
+ PositiveMultipleConstructors(int) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A, B
+
+ PositiveMultipleConstructors(const PositiveMultipleConstructors &) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A, B
+
+ // FIXME: The fix-its here collide providing an erroneous fix
+ int A, B;
+ // CHECK-FIXES: int A{}{}{}, B{}{}{};
+};
+
+typedef struct {
+ int Member;
+} CStyleStruct;
+
+struct PositiveUninitializedBase : public NegativeAggregateType, CStyleStruct {
+ PositiveUninitializedBase() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NegativeAggregateType, CStyleStruct
+ // CHECK-FIXES: PositiveUninitializedBase() : NegativeAggregateType(), CStyleStruct() {}
+};
+
+struct PositiveUninitializedBaseOrdering : public NegativeAggregateType,
+ public NonTrivialType {
+ PositiveUninitializedBaseOrdering() : B() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NegativeAggregateType, NonTrivialType
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: constructor does not initialize these fields: A
+ // CHECK-FIXES: PositiveUninitializedBaseOrdering() : NegativeAggregateType(), NonTrivialType(), B() {}
+
+ // This is somewhat pathological with the base class initializer at the end...
+ PositiveUninitializedBaseOrdering(int) : B(), NonTrivialType(), A() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NegativeAggregateType
+ // CHECK-FIXES: PositiveUninitializedBaseOrdering(int) : B(), NegativeAggregateType(), NonTrivialType(), A() {}
+
+ PositiveUninitializedBaseOrdering(float) : B(), NegativeAggregateType(), A() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NonTrivialType
+ // CHECK-FIXES: PositiveUninitializedBaseOrdering(float) : B(), NegativeAggregateType(), NonTrivialType(), A() {}
+
+ int A, B;
+ // CHECK-FIXES: int A{}, B;
+};
+
+// We shouldn't need to initialize anything because PositiveUninitializedBase
+// has a user-defined constructor.
+struct NegativeUninitializedBase : public PositiveUninitializedBase {
+ NegativeUninitializedBase() {}
+};
+
+struct InheritedAggregate : public NegativeAggregateType {
+ int F;
+};
+
+static InheritedAggregate NegativeGlobal;
+
+enum TestEnum {
+ A,
+ B,
+ C
+};
+
+enum class TestScopedEnum {
+ A,
+ B,
+ C
+};
+
+struct PositiveEnumType {
+ PositiveEnumType() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: X, Y
+ // No proposed fixes, as we don't know whether value initialization for these
+ // enums really makes sense.
+
+ TestEnum X;
+ TestScopedEnum Y;
+};
+
+extern "C" {
+struct NegativeCStruct {
+ int X, Y, Z;
+};
+
+static void PositiveCStructVariable() {
+ NegativeCStruct X;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: uninitialized record type: 'X'
+ // CHECK-FIXES: NegativeCStruct X{};
+}
+}
+
+static void NegativeStaticVariable() {
+ static NegativeCStruct S;
+ (void)S;
+}
+
+union NegativeUnionInClass {
+ NegativeUnionInClass() {} // No message as a union can only initialize one member.
+ int X = 0;
+ float Y;
+};
+
+union PositiveUnion {
+ PositiveUnion() : X() {} // No message as a union can only initialize one member.
+ PositiveUnion(int) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: union constructor should initialize one of these fields: X, Y
+
+ int X;
+ // CHECK-FIXES: int X{};
+
+ // Make sure we don't give Y an initializer.
+ float Y;
+ // CHECK-FIXES-NOT: float Y{};
+};
+
+union PositiveUnionReversed {
+ PositiveUnionReversed() : X() {} // No message as a union can only initialize one member.
+ PositiveUnionReversed(int) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: union constructor should initialize one of these fields: Y, X
+
+ // Make sure we don't give Y an initializer.
+ TestEnum Y;
+ // CHECK-FIXES-NOT: TestEnum Y{};
+
+ int X;
+ // CHECK-FIXES: int X{};
+};
+
+struct PositiveAnonymousUnionAndStruct {
+ PositiveAnonymousUnionAndStruct() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A, B, Y, Z, C, D, E, F, X
+
+ union {
+ int A;
+ // CHECK-FIXES: int A{};
+ short B;
+ };
+
+ struct {
+ int Y;
+ // CHECK-FIXES: int Y{};
+ char *Z;
+ // CHECK-FIXES: char *Z{};
+
+ struct {
+ short C;
+ // CHECK-FIXES: short C{};
+ double D;
+ // CHECK-FIXES: double D{};
+ };
+
+ union {
+ long E;
+ // CHECK-FIXES: long E{};
+ float F;
+ };
+ };
+ int X;
+ // CHECK-FIXES: int X{};
+};
+
+// This check results in a CXXConstructorDecl with no body.
+struct NegativeDeletedConstructor : NegativeAggregateType {
+ NegativeDeletedConstructor() = delete;
+
+ Template<int> F;
+};
+
+// This pathological template fails to compile if actually instantiated. It
+// results in the check seeing a null RecordDecl when examining the base class
+// initializer list.
+template <typename T>
+class PositiveSelfInitialization : NegativeAggregateType
+{
+ PositiveSelfInitialization() : PositiveSelfInitialization() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NegativeAggregateType
+ // CHECK-FIXES: PositiveSelfInitialization() : NegativeAggregateType(), PositiveSelfInitialization() {}
+};
+
+class PositiveIndirectMember {
+ struct {
+ int *A;
+ // CHECK-FIXES: int *A{};
+ };
+
+ PositiveIndirectMember() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A
+};
+
+void Bug30487()
+{
+ NegativeInClassInitializedDefaulted s;
+}
+
+struct PositiveVirtualMethod {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: constructor does not initialize these fields: F
+ int F;
+ // CHECK-FIXES: int F{};
+ virtual int f() = 0;
+};
+
+struct PositiveVirtualDestructor {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: constructor does not initialize these fields: F
+ PositiveVirtualDestructor() = default;
+ int F;
+ // CHECK-FIXES: int F{};
+ virtual ~PositiveVirtualDestructor() {}
+};
+
+struct PositiveVirtualBase : public virtual NegativeAggregateType {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: constructor does not initialize these bases: NegativeAggregateType
+ // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: constructor does not initialize these fields: F
+ int F;
+ // CHECK-FIXES: int F{};
+};
+
+template <typename T>
+struct PositiveTemplateVirtualDestructor {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: constructor does not initialize these fields: F
+ T Val;
+ int F;
+ // CHECK-FIXES: int F{};
+ virtual ~PositiveTemplateVirtualDestructor() = default;
+};
+
+template struct PositiveTemplateVirtualDestructor<int>;
+
+#define UNINITIALIZED_FIELD_IN_MACRO_BODY_VIRTUAL(FIELD) \
+ struct UninitializedFieldVirtual##FIELD { \
+ int FIELD; \
+ virtual ~UninitializedFieldVirtual##FIELD() {} \
+ }; \
+// Ensure FIELD is not initialized since fixes inside of macros are disabled.
+// CHECK-FIXES: int FIELD;
+
+UNINITIALIZED_FIELD_IN_MACRO_BODY_VIRTUAL(F);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: F
+UNINITIALIZED_FIELD_IN_MACRO_BODY_VIRTUAL(G);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: G
+
+struct NegativeEmpty {
+};
+
+static void NegativeEmptyVar() {
+ NegativeEmpty e;
+ (void)e;
+}
+
+struct NegativeEmptyMember {
+ NegativeEmptyMember() {}
+ NegativeEmpty e;
+};
+
+struct NegativeEmptyBase : NegativeEmpty {
+ NegativeEmptyBase() {}
+};
+
+struct NegativeEmptyArrayMember {
+ NegativeEmptyArrayMember() {}
+ char e[0];
+};
+
+struct NegativeIncompleteArrayMember {
+ NegativeIncompleteArrayMember() {}
+ char e[];
+};
+
+template <typename T> class NoCrash {
+ class B : public NoCrash {
+ template <typename U> B(U u) {}
+ };
+};
+
+struct PositiveBitfieldMember {
+ PositiveBitfieldMember() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F
+ unsigned F : 5;
+ // CHECK-FIXES-NOT: unsigned F : 5{};
+};
+
+struct NegativeUnnamedBitfieldMember {
+ NegativeUnnamedBitfieldMember() {}
+ unsigned : 5;
+};
+
+struct NegativeInitializedBitfieldMembers {
+ NegativeInitializedBitfieldMembers() : F(3) { G = 2; }
+ unsigned F : 5;
+ unsigned G : 5;
+};
+
+struct NegativeImplicitInheritedCtorBase {
+ NegativeImplicitInheritedCtorBase(unsigned F) : F(F) {}
+ unsigned F;
+};
+
+struct NegativeImplicitInheritedCtor : NegativeImplicitInheritedCtorBase {
+ using NegativeImplicitInheritedCtorBase::NegativeImplicitInheritedCtorBase;
+};
+
+void Bug33557() {
+ NegativeImplicitInheritedCtor I(5);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-reinterpret-cast.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-reinterpret-cast.cpp
new file mode 100644
index 0000000..5420810
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-reinterpret-cast.cpp
@@ -0,0 +1,6 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-reinterpret-cast %t
+
+int i = 0;
+void *j;
+void f() { j = reinterpret_cast<void *>(i); }
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: do not use reinterpret_cast [cppcoreguidelines-pro-type-reinterpret-cast]
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-static-cast-downcast.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-static-cast-downcast.cpp
new file mode 100644
index 0000000..7a6c027
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-static-cast-downcast.cpp
@@ -0,0 +1,118 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-static-cast-downcast %t
+
+class Base {
+};
+
+class Derived : public Base {
+};
+
+class Base2 {
+};
+
+class MultiDerived : public Base, public Base2 {
+};
+
+class PolymorphicBase {
+public:
+ virtual ~PolymorphicBase();
+};
+
+class PolymorphicDerived : public PolymorphicBase {
+};
+
+class PolymorphicMultiDerived : public Base, public PolymorphicBase {
+};
+
+void pointers() {
+
+ auto P0 = static_cast<Derived*>(new Base());
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast]
+
+ const Base* B0;
+ auto PC0 = static_cast<const Derived*>(B0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast]
+
+ auto P1 = static_cast<Base*>(new Derived()); // OK, upcast to a public base
+ auto P2 = static_cast<Base*>(new MultiDerived()); // OK, upcast to a public base
+ auto P3 = static_cast<Base2*>(new MultiDerived()); // OK, upcast to a public base
+}
+
+void pointers_polymorphic() {
+
+ auto PP0 = static_cast<PolymorphicDerived*>(new PolymorphicBase());
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast]
+ // CHECK-FIXES: auto PP0 = dynamic_cast<PolymorphicDerived*>(new PolymorphicBase());
+
+ const PolymorphicBase* B0;
+ auto PPC0 = static_cast<const PolymorphicDerived*>(B0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast]
+ // CHECK-FIXES: auto PPC0 = dynamic_cast<const PolymorphicDerived*>(B0);
+
+
+ auto B1 = static_cast<PolymorphicBase*>(new PolymorphicDerived()); // OK, upcast to a public base
+ auto B2 = static_cast<PolymorphicBase*>(new PolymorphicMultiDerived()); // OK, upcast to a public base
+ auto B3 = static_cast<Base*>(new PolymorphicMultiDerived()); // OK, upcast to a public base
+}
+
+void arrays() {
+ Base ArrayOfBase[10];
+ auto A0 = static_cast<Derived*>(ArrayOfBase);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast]
+}
+
+void arrays_polymorphic() {
+ PolymorphicBase ArrayOfPolymorphicBase[10];
+ auto AP0 = static_cast<PolymorphicDerived*>(ArrayOfPolymorphicBase);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto AP0 = dynamic_cast<PolymorphicDerived*>(ArrayOfPolymorphicBase);
+}
+
+void references() {
+ Base B0;
+ auto R0 = static_cast<Derived&>(B0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast]
+ Base& RefToBase = B0;
+ auto R1 = static_cast<Derived&>(RefToBase);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast]
+
+ const Base& ConstRefToBase = B0;
+ auto RC1 = static_cast<const Derived&>(ConstRefToBase);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class [cppcoreguidelines-pro-type-static-cast-downcast]
+
+
+ Derived RD1;
+ auto R2 = static_cast<Base&>(RD1); // OK, upcast to a public base
+}
+
+void references_polymorphic() {
+ PolymorphicBase B0;
+ auto RP0 = static_cast<PolymorphicDerived&>(B0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead
+ // CHECK-FIXES: auto RP0 = dynamic_cast<PolymorphicDerived&>(B0);
+
+ PolymorphicBase& RefToPolymorphicBase = B0;
+ auto RP1 = static_cast<PolymorphicDerived&>(RefToPolymorphicBase);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast]
+ // CHECK-FIXES: auto RP1 = dynamic_cast<PolymorphicDerived&>(RefToPolymorphicBase);
+
+ const PolymorphicBase& ConstRefToPolymorphicBase = B0;
+ auto RPC2 = static_cast<const PolymorphicDerived&>(ConstRefToPolymorphicBase);
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: do not use static_cast to downcast from a base to a derived class; use dynamic_cast instead [cppcoreguidelines-pro-type-static-cast-downcast]
+ // CHECK-FIXES: auto RPC2 = dynamic_cast<const PolymorphicDerived&>(ConstRefToPolymorphicBase);
+
+ PolymorphicDerived d1;
+ auto RP2 = static_cast<PolymorphicBase&>(d1); // OK, upcast to a public base
+}
+
+template<class B, class D>
+void templ() {
+ auto B0 = static_cast<B*>(new D());
+}
+
+void templ_bad_call() {
+ templ<Derived, Base>(); //FIXME: this should trigger a warning
+}
+
+void templ_good_call() {
+ templ<Base, Derived>(); // OK, upcast to a public base
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-union-access.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-union-access.cpp
new file mode 100644
index 0000000..6abc22b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-union-access.cpp
@@ -0,0 +1,41 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-union-access %t
+
+union U {
+ bool union_member1;
+ char union_member2;
+} u;
+
+struct S {
+ int non_union_member;
+ union {
+ bool union_member;
+ };
+ union {
+ char union_member2;
+ } u;
+} s;
+
+
+void f(char);
+void f2(U);
+void f3(U&);
+void f4(U*);
+
+void check()
+{
+ u.union_member1 = true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not access members of unions; use (boost::)variant instead [cppcoreguidelines-pro-type-union-access]
+ auto b = u.union_member2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: do not access members of unions; use (boost::)variant instead
+ auto a = &s.union_member;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: do not access members of unions; use (boost::)variant instead
+ f(s.u.union_member2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not access members of unions; use (boost::)variant instead
+
+ s.non_union_member = 2; // OK
+
+ U u2 = u; // OK
+ f2(u); // OK
+ f3(u); // OK
+ f4(&u); // OK
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-vararg.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-vararg.cpp
new file mode 100644
index 0000000..021322a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-type-vararg.cpp
@@ -0,0 +1,51 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-vararg %t
+
+void f(int i);
+void f_vararg(int i, ...);
+
+struct C {
+ void g_vararg(...);
+ void g(const char*);
+} c;
+
+template<typename... P>
+void cpp_vararg(P... p);
+
+void check() {
+ f_vararg(1, 7, 9);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call c-style vararg functions [cppcoreguidelines-pro-type-vararg]
+ c.g_vararg("foo");
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not call c-style vararg functions
+
+ f(3); // OK
+ c.g("foo"); // OK
+ cpp_vararg(1, 7, 9); // OK
+}
+
+// ... as a parameter is allowed (e.g. for SFINAE)
+template <typename T>
+void CallFooIfAvailableImpl(T& t, ...) {
+ // nothing
+}
+template <typename T>
+void CallFooIfAvailableImpl(T& t, decltype(t.foo())*) {
+ t.foo();
+}
+template <typename T>
+void CallFooIfAvailable(T& t) {
+ CallFooIfAvailableImpl(t, 0); // OK to call variadic function when the argument is a literal 0
+}
+
+#include <stdarg.h>
+void my_printf(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call c-style vararg functions
+ va_list n;
+ va_copy(n, ap); // Don't warn, va_copy is anyway useless without va_start
+ int i = va_arg(ap, int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use va_start/va_arg to define c-style vararg functions; use variadic templates instead
+ va_end(ap); // Don't warn, va_end is anyway useless without va_start
+}
+
+int my_vprintf(const char* format, va_list arg ); // OK to declare function taking va_list
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-slicing.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-slicing.cpp
new file mode 100644
index 0000000..6856f52
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-slicing.cpp
@@ -0,0 +1,100 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-slicing %t
+
+class Base {
+ int i;
+ void f() {}
+ virtual void g() {}
+};
+
+class DerivedWithMemberVariables : public Base {
+ void f();
+ int j;
+};
+
+class TwiceDerivedWithNoMemberVariables : public DerivedWithMemberVariables {
+ void f();
+};
+
+class DerivedWithOverride : public Base {
+ void f();
+ void g() override {}
+};
+
+class TwiceDerivedWithNoOverride : public DerivedWithOverride {
+ void f();
+};
+
+void TakesBaseByValue(Base base);
+
+DerivedWithMemberVariables ReturnsDerived();
+
+void positivesWithMemberVariables() {
+ DerivedWithMemberVariables b;
+ Base a{b};
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state [cppcoreguidelines-slicing]
+ a = b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state
+ TakesBaseByValue(b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state
+
+ TwiceDerivedWithNoMemberVariables c;
+ a = c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'TwiceDerivedWithNoMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state
+
+ a = ReturnsDerived();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithMemberVariables' to 'Base' discards {{[0-9]*}} bytes of state
+}
+
+void positivesWithOverride() {
+ DerivedWithOverride b;
+ Base a{b};
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g'
+ a = b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g'
+ TakesBaseByValue(b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g'
+
+ TwiceDerivedWithNoOverride c;
+ a = c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedWithOverride' to 'Base' discards override 'g'
+}
+
+void TakesBaseByReference(Base &base);
+
+class DerivedThatAddsVirtualH : public Base {
+ virtual void h();
+};
+
+class DerivedThatOverridesH : public DerivedThatAddsVirtualH {
+ void h() override;
+};
+
+void negatives() {
+ // OK, simple copying from the same type.
+ Base a;
+ TakesBaseByValue(a);
+ DerivedWithMemberVariables b;
+ DerivedWithMemberVariables c{b};
+ b = c;
+
+ // OK, derived type does not have extra state.
+ TwiceDerivedWithNoMemberVariables d;
+ DerivedWithMemberVariables e{d};
+ e = d;
+
+ // OK, derived does not override any method.
+ TwiceDerivedWithNoOverride f;
+ DerivedWithOverride g{f};
+ g = f;
+
+ // OK, no copying.
+ TakesBaseByReference(d);
+ TakesBaseByReference(f);
+
+ // Derived type overrides methods, but these methods are not in the base type,
+ // so cannot be called accidentally. Right now this triggers, but we might
+ // want to allow it.
+ DerivedThatOverridesH h;
+ a = h;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: slicing object from type 'DerivedThatOverridesH' to 'Base' discards override 'h'
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-special-member-functions-cxx-03.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-special-member-functions-cxx-03.cpp
new file mode 100644
index 0000000..8fe5e42
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-special-member-functions-cxx-03.cpp
@@ -0,0 +1,26 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-special-member-functions %t -- -- -std=c++03
+
+class DefinesDestructor {
+ ~DefinesDestructor();
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesDestructor' defines a non-default destructor but does not define a copy constructor or a copy assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesCopyConstructor {
+ DefinesCopyConstructor(const DefinesCopyConstructor &);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesCopyConstructor' defines a copy constructor but does not define a destructor or a copy assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesCopyAssignment {
+ DefinesCopyAssignment &operator=(const DefinesCopyAssignment &);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesCopyAssignment' defines a copy assignment operator but does not define a destructor or a copy constructor [cppcoreguidelines-special-member-functions]
+
+class DefinesNothing {
+};
+
+class DefinesEverything {
+ DefinesEverything(const DefinesEverything &);
+ DefinesEverything &operator=(const DefinesEverything &);
+ ~DefinesEverything();
+};
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-special-member-functions-relaxed.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-special-member-functions-relaxed.cpp
new file mode 100644
index 0000000..4fff02d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-special-member-functions-relaxed.cpp
@@ -0,0 +1,71 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-special-member-functions %t -- -config="{CheckOptions: [{key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions, value: 1}, {key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor, value: 1}]}" --
+
+class DefinesDestructor {
+ ~DefinesDestructor();
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesDestructor' defines a non-default destructor but does not define a copy constructor or a copy assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesDefaultedDestructor {
+ ~DefinesDefaultedDestructor() = default;
+};
+
+class DefinesCopyConstructor {
+ DefinesCopyConstructor(const DefinesCopyConstructor &);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesCopyConstructor' defines a copy constructor but does not define a destructor or a copy assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesCopyAssignment {
+ DefinesCopyAssignment &operator=(const DefinesCopyAssignment &);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesCopyAssignment' defines a copy assignment operator but does not define a destructor or a copy constructor [cppcoreguidelines-special-member-functions]
+
+class DefinesMoveConstructor {
+ DefinesMoveConstructor(DefinesMoveConstructor &&);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveConstructor' defines a move constructor but does not define a destructor, a copy constructor, a copy assignment operator or a move assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesMoveAssignment {
+ DefinesMoveAssignment &operator=(DefinesMoveAssignment &&);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveAssignment' defines a move assignment operator but does not define a destructor, a copy constructor, a copy assignment operator or a move constructor [cppcoreguidelines-special-member-functions]
+class DefinesNothing {
+};
+
+class DefinesEverything {
+ DefinesEverything(const DefinesEverything &);
+ DefinesEverything &operator=(const DefinesEverything &);
+ DefinesEverything(DefinesEverything &&);
+ DefinesEverything &operator=(DefinesEverything &&);
+ ~DefinesEverything();
+};
+
+class DeletesEverything {
+ DeletesEverything(const DeletesEverything &) = delete;
+ DeletesEverything &operator=(const DeletesEverything &) = delete;
+ DeletesEverything(DeletesEverything &&) = delete;
+ DeletesEverything &operator=(DeletesEverything &&) = delete;
+ ~DeletesEverything() = delete;
+};
+
+class DeletesCopyDefaultsMove {
+ DeletesCopyDefaultsMove(const DeletesCopyDefaultsMove &) = delete;
+ DeletesCopyDefaultsMove &operator=(const DeletesCopyDefaultsMove &) = delete;
+ DeletesCopyDefaultsMove(DeletesCopyDefaultsMove &&) = default;
+ DeletesCopyDefaultsMove &operator=(DeletesCopyDefaultsMove &&) = default;
+ ~DeletesCopyDefaultsMove() = default;
+};
+
+template <typename T>
+struct TemplateClass {
+ TemplateClass() = default;
+ TemplateClass(const TemplateClass &);
+ TemplateClass &operator=(const TemplateClass &);
+ TemplateClass(TemplateClass &&);
+ TemplateClass &operator=(TemplateClass &&);
+ ~TemplateClass();
+};
+
+// Multiple instantiations of a class template will trigger multiple matches for defined special members.
+// This should not cause problems.
+TemplateClass<int> InstantiationWithInt;
+TemplateClass<double> InstantiationWithDouble;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-special-member-functions.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-special-member-functions.cpp
new file mode 100644
index 0000000..013ba86
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/cppcoreguidelines-special-member-functions.cpp
@@ -0,0 +1,72 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-special-member-functions %t
+
+class DefinesDestructor {
+ ~DefinesDestructor();
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesDestructor' defines a non-default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesDefaultedDestructor {
+ ~DefinesDefaultedDestructor() = default;
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesDefaultedDestructor' defines a default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesCopyConstructor {
+ DefinesCopyConstructor(const DefinesCopyConstructor &);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesCopyConstructor' defines a copy constructor but does not define a destructor, a copy assignment operator, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesCopyAssignment {
+ DefinesCopyAssignment &operator=(const DefinesCopyAssignment &);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesCopyAssignment' defines a copy assignment operator but does not define a destructor, a copy constructor, a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesMoveConstructor {
+ DefinesMoveConstructor(DefinesMoveConstructor &&);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveConstructor' defines a move constructor but does not define a destructor, a copy constructor, a copy assignment operator or a move assignment operator [cppcoreguidelines-special-member-functions]
+
+class DefinesMoveAssignment {
+ DefinesMoveAssignment &operator=(DefinesMoveAssignment &&);
+};
+// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveAssignment' defines a move assignment operator but does not define a destructor, a copy constructor, a copy assignment operator or a move constructor [cppcoreguidelines-special-member-functions]
+class DefinesNothing {
+};
+
+class DefinesEverything {
+ DefinesEverything(const DefinesEverything &);
+ DefinesEverything &operator=(const DefinesEverything &);
+ DefinesEverything(DefinesEverything &&);
+ DefinesEverything &operator=(DefinesEverything &&);
+ ~DefinesEverything();
+};
+
+class DeletesEverything {
+ DeletesEverything(const DeletesEverything &) = delete;
+ DeletesEverything &operator=(const DeletesEverything &) = delete;
+ DeletesEverything(DeletesEverything &&) = delete;
+ DeletesEverything &operator=(DeletesEverything &&) = delete;
+ ~DeletesEverything() = delete;
+};
+
+class DeletesCopyDefaultsMove {
+ DeletesCopyDefaultsMove(const DeletesCopyDefaultsMove &) = delete;
+ DeletesCopyDefaultsMove &operator=(const DeletesCopyDefaultsMove &) = delete;
+ DeletesCopyDefaultsMove(DeletesCopyDefaultsMove &&) = default;
+ DeletesCopyDefaultsMove &operator=(DeletesCopyDefaultsMove &&) = default;
+ ~DeletesCopyDefaultsMove() = default;
+};
+
+template <typename T>
+struct TemplateClass {
+ TemplateClass() = default;
+ TemplateClass(const TemplateClass &);
+ TemplateClass &operator=(const TemplateClass &);
+ TemplateClass(TemplateClass &&);
+ TemplateClass &operator=(TemplateClass &&);
+ ~TemplateClass();
+};
+
+// Multiple instantiations of a class template will trigger multiple matches for defined special members.
+// This should not cause problems.
+TemplateClass<int> InstantiationWithInt;
+TemplateClass<double> InstantiationWithDouble;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/custom-diagnostics.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/custom-diagnostics.cpp
new file mode 100644
index 0000000..8183770
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/custom-diagnostics.cpp
@@ -0,0 +1,27 @@
+// RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-shadow,clang-diagnostic-float-conversion' %s -- | count 0
+//
+// Enable warnings using -config:
+// RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-shadow,clang-diagnostic-float-conversion' \
+// RUN: -config='{ExtraArgs: ["-Wshadow","-Wno-unused-variable"], ExtraArgsBefore: ["-Wno-shadow","-Wfloat-conversion","-Wunused-variable"]}' %s -- \
+// RUN: | FileCheck -implicit-check-not='{{warning:|error:}}' %s
+//
+// ... -extra-arg:
+// RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-shadow,clang-diagnostic-float-conversion' \
+// RUN: -extra-arg=-Wshadow -extra-arg=-Wno-unused-variable \
+// RUN: -extra-arg-before=-Wno-shadow -extra-arg-before=-Wfloat-conversion \
+// RUN: -extra-arg-before=-Wunused-variable %s -- \
+// RUN: | FileCheck -implicit-check-not='{{warning:|error:}}' %s
+//
+// ... a combination of -config and -extra-arg(-before):
+// RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-shadow,clang-diagnostic-float-conversion' \
+// RUN: -config='{ExtraArgs: ["-Wno-unused-variable"], ExtraArgsBefore: ["-Wno-shadow","-Wfloat-conversion"]}' \
+// RUN: -extra-arg=-Wshadow -extra-arg-before=-Wunused-variable %s -- \
+// RUN: | FileCheck -implicit-check-not='{{warning:|error:}}' %s
+
+void f(float x) {
+ int a;
+ { int a; }
+ // CHECK: :[[@LINE-1]]:9: warning: declaration shadows a local variable [clang-diagnostic-shadow]
+ int b = x;
+ // CHECK: :[[@LINE-1]]:11: warning: implicit conversion turns floating-point number into integer: 'float' to 'int' [clang-diagnostic-float-conversion]
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/deduplication.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/deduplication.cpp
new file mode 100644
index 0000000..056fe4e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/deduplication.cpp
@@ -0,0 +1,10 @@
+// RUN: %check_clang_tidy %s google-explicit-constructor %t
+
+template<typename T>
+struct A { A(T); };
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: single-argument constructors must be marked explicit
+
+void f() {
+ A<int> a(0);
+ A<double> b(0);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/diagnostic.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/diagnostic.cpp
new file mode 100644
index 0000000..d12fc7b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/diagnostic.cpp
@@ -0,0 +1,50 @@
+// RUN: not clang-tidy -checks='-*,modernize-use-override' %s.nonexistent.cpp -- | FileCheck -check-prefix=CHECK1 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: not clang-tidy -checks='-*,clang-diagnostic-*,google-explicit-constructor' %s -- -fan-unknown-option | FileCheck -check-prefix=CHECK2 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: not clang-tidy -checks='-*,google-explicit-constructor,clang-diagnostic-literal-conversion' %s -- -fan-unknown-option | FileCheck -check-prefix=CHECK3 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-macro-redefined' %s -- -DMACRO_FROM_COMMAND_LINE | FileCheck -check-prefix=CHECK4 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: not clang-tidy -checks='-*,modernize-use-override' %s -- -DCOMPILATION_ERROR | FileCheck -check-prefix=CHECK6 -implicit-check-not='{{warning:|error:}}' %s
+//
+// Now repeat the tests and ensure no other errors appear on stderr:
+// RUN: not clang-tidy -checks='-*,modernize-use-override' %s.nonexistent.cpp -- 2>&1 | FileCheck -check-prefix=CHECK1 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: not clang-tidy -checks='-*,clang-diagnostic-*,google-explicit-constructor' %s -- -fan-unknown-option 2>&1 | FileCheck -check-prefix=CHECK2 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: not clang-tidy -checks='-*,google-explicit-constructor,clang-diagnostic-literal-conversion' %s -- -fan-unknown-option 2>&1 | FileCheck -check-prefix=CHECK3 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-macro-redefined' %s -- -DMACRO_FROM_COMMAND_LINE 2>&1 | FileCheck -check-prefix=CHECK4 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: not clang-tidy -checks='-*,modernize-use-override' %s -- -DCOMPILATION_ERROR 2>&1 | FileCheck -check-prefix=CHECK6 -implicit-check-not='{{warning:|error:}}' %s
+//
+// Now create a directory with a compilation database file and ensure we don't
+// use it after failing to parse commands from the command line:
+//
+// RUN: mkdir -p %T/diagnostics/
+// RUN: echo '[{"directory": "%/T/diagnostics/","command": "clang++ -fan-option-from-compilation-database -c %/T/diagnostics/input.cpp", "file": "%/T/diagnostics/input.cpp"}]' > %T/diagnostics/compile_commands.json
+// RUN: cat %s > %T/diagnostics/input.cpp
+// RUN: not clang-tidy -checks='-*,modernize-use-override' %T/diagnostics/nonexistent.cpp -- 2>&1 | FileCheck -check-prefix=CHECK1 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: not clang-tidy -checks='-*,clang-diagnostic-*,google-explicit-constructor' %T/diagnostics/input.cpp -- -fan-unknown-option 2>&1 | FileCheck -check-prefix=CHECK2 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: not clang-tidy -checks='-*,google-explicit-constructor,clang-diagnostic-literal-conversion' %T/diagnostics/input.cpp -- -fan-unknown-option 2>&1 | FileCheck -check-prefix=CHECK3 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-macro-redefined' %T/diagnostics/input.cpp -- -DMACRO_FROM_COMMAND_LINE 2>&1 | FileCheck -check-prefix=CHECK4 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: not clang-tidy -checks='-*,clang-diagnostic-*,google-explicit-constructor' %T/diagnostics/input.cpp 2>&1 | FileCheck -check-prefix=CHECK5 -implicit-check-not='{{warning:|error:}}' %s
+// RUN: not clang-tidy -checks='-*,modernize-use-override' %T/diagnostics/input.cpp -- -DCOMPILATION_ERROR 2>&1 | FileCheck -check-prefix=CHECK6 -implicit-check-not='{{warning:|error:}}' %s
+
+// CHECK1: error: error reading '{{.*}}nonexistent.cpp' [clang-diagnostic-error]
+// CHECK2: error: unknown argument: '-fan-unknown-option' [clang-diagnostic-error]
+// CHECK3: error: unknown argument: '-fan-unknown-option' [clang-diagnostic-error]
+// CHECK5: error: unknown argument: '-fan-option-from-compilation-database' [clang-diagnostic-error]
+
+// CHECK2: :[[@LINE+3]]:9: warning: implicit conversion from 'double' to 'int' changes value from 1.5 to 1 [clang-diagnostic-literal-conversion]
+// CHECK3: :[[@LINE+2]]:9: warning: implicit conversion from 'double' to 'int' changes value
+// CHECK5: :[[@LINE+1]]:9: warning: implicit conversion from 'double' to 'int' changes value
+int a = 1.5;
+
+// CHECK2: :[[@LINE+3]]:11: warning: single-argument constructors must be marked explicit
+// CHECK3: :[[@LINE+2]]:11: warning: single-argument constructors must be marked explicit
+// CHECK5: :[[@LINE+1]]:11: warning: single-argument constructors must be marked explicit
+class A { A(int) {} };
+
+#define MACRO_FROM_COMMAND_LINE
+// CHECK4: :[[@LINE-1]]:9: warning: 'MACRO_FROM_COMMAND_LINE' macro redefined
+
+#ifdef COMPILATION_ERROR
+void f(int a) {
+ &(a + 1);
+ // CHECK6: :[[@LINE-1]]:3: error: cannot take the address of an rvalue of type 'int' [clang-diagnostic-error]
+}
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/enable-alpha-checks.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/enable-alpha-checks.cpp
new file mode 100644
index 0000000..b1e5130
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/enable-alpha-checks.cpp
@@ -0,0 +1,6 @@
+// Check if '-allow-enabling-analyzer-alpha-checkers' is visible for users.
+// RUN: clang-tidy -help | not grep 'allow-enabling-analyzer-alpha-checkers'
+
+// Check if '-allow-enabling-analyzer-alpha-checkers' enables alpha checks.
+// RUN: clang-tidy -checks=* -list-checks | not grep 'clang-analyzer-alpha'
+// RUN: clang-tidy -checks=* -list-checks -allow-enabling-analyzer-alpha-checkers | grep 'clang-analyzer-alpha'
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/explain-checks.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/explain-checks.cpp
new file mode 100644
index 0000000..9bff30c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/explain-checks.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-tidy -checks=-*,modernize-use-nullptr -explain-config | FileCheck --check-prefix=CHECK-MESSAGE1 %s
+// RUN: clang-tidy -config="{Checks: '-*,modernize-use-nullptr'}" -explain-config | FileCheck --check-prefix=CHECK-MESSAGE2 %s
+// RUN: clang-tidy -checks=modernize-use-nullptr -config="{Checks: '-*,modernize-use-nullptr'}" -explain-config | FileCheck --check-prefix=CHECK-MESSAGE3 %s
+// RUN: clang-tidy -checks=modernize-use-nullptr -config="{Checks: '-*,-modernize-use-nullptr'}" %S/Inputs/explain-config/a.cc -explain-config -- | FileCheck --check-prefix=CHECK-MESSAGE4 %s
+// RUN: clang-tidy -checks=modernize-use-nullptr -config="{Checks: '-*,modernize-*'}" -explain-config | FileCheck --check-prefix=CHECK-MESSAGE5 %s
+// RUN: clang-tidy -explain-config %S/Inputs/explain-config/a.cc -- | grep "'modernize-use-nullptr' is enabled in the .*[/\\]Inputs[/\\]explain-config[/\\].clang-tidy."
+
+// CHECK-MESSAGE1: 'modernize-use-nullptr' is enabled in the command-line option '-checks'.
+// CHECK-MESSAGE2: 'modernize-use-nullptr' is enabled in the command-line option '-config'.
+// CHECK-MESSAGE3: 'modernize-use-nullptr' is enabled in the command-line option '-checks'.
+// CHECK-MESSAGE4: 'modernize-use-nullptr' is enabled in the command-line option '-checks'.
+// CHECK-MESSAGE5: 'modernize-use-nullptr' is enabled in the command-line option '-checks'.
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/extra-args.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/extra-args.cpp
new file mode 100644
index 0000000..d65aacc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/extra-args.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-tidy -checks='-*,modernize-use-override' \
+// RUN: -config='{ExtraArgs: ["-DTEST4"], ExtraArgsBefore: ["-DTEST1"]}' \
+// RUN: -extra-arg=-DTEST3 -extra-arg-before=-DTEST2 %s -- -v 2>&1 \
+// RUN: | FileCheck -implicit-check-not='{{warning:|error:}}' %s
+
+// CHECK: {{^}}clang Invocation:{{$}}
+// CHECK-NEXT: {{"-D" "TEST1" .*"-D" "TEST2" .*"-D" "TEST3" .*"-D" "TEST4"}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/file-filter.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/file-filter.cpp
new file mode 100644
index 0000000..9ee5cad
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/file-filter.cpp
@@ -0,0 +1,73 @@
+// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='' %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck %s
+// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='' -quiet %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK-QUIET %s
+// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK2 %s
+// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' -quiet %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK2-QUIET %s
+// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header2\.h' %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK3 %s
+// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='header2\.h' -quiet %s -- -I %S/Inputs/file-filter -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK3-QUIET %s
+// FIXME: "-I %S/Inputs/file-filter/system/.." must be redundant.
+// On Win32, file-filter/system\system-header1.h precedes
+// file-filter\header*.h due to code order between '/' and '\\'.
+// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' -system-headers %s -- -I %S/Inputs/file-filter/system/.. -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK4 %s
+// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' -system-headers -quiet %s -- -I %S/Inputs/file-filter/system/.. -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK4-QUIET %s
+
+#include "header1.h"
+// CHECK-NOT: warning:
+// CHECK-QUIET-NOT: warning:
+// CHECK2: header1.h:1:12: warning: single-argument constructors must be marked explicit
+// CHECK2-QUIET: header1.h:1:12: warning: single-argument constructors must be marked explicit
+// CHECK3-NOT: warning:
+// CHECK3-QUIET-NOT: warning:
+// CHECK4: header1.h:1:12: warning: single-argument constructors
+// CHECK4-QUIET: header1.h:1:12: warning: single-argument constructors
+
+#include "header2.h"
+// CHECK-NOT: warning:
+// CHECK-QUIET-NOT: warning:
+// CHECK2: header2.h:1:12: warning: single-argument constructors
+// CHECK2-QUIET: header2.h:1:12: warning: single-argument constructors
+// CHECK3: header2.h:1:12: warning: single-argument constructors
+// CHECK3-QUIET: header2.h:1:12: warning: single-argument constructors
+// CHECK4: header2.h:1:12: warning: single-argument constructors
+// CHECK4-QUIET: header2.h:1:12: warning: single-argument constructors
+
+#include <system-header.h>
+// CHECK-NOT: warning:
+// CHECK-QUIET-NOT: warning:
+// CHECK2-NOT: warning:
+// CHECK2-QUIET-NOT: warning:
+// CHECK3-NOT: warning:
+// CHECK3-QUIET-NOT: warning:
+// CHECK4: system-header.h:1:12: warning: single-argument constructors
+// CHECK4-QUIET: system-header.h:1:12: warning: single-argument constructors
+
+class A { A(int); };
+// CHECK: :[[@LINE-1]]:11: warning: single-argument constructors
+// CHECK-QUIET: :[[@LINE-2]]:11: warning: single-argument constructors
+// CHECK2: :[[@LINE-3]]:11: warning: single-argument constructors
+// CHECK2-QUIET: :[[@LINE-4]]:11: warning: single-argument constructors
+// CHECK3: :[[@LINE-5]]:11: warning: single-argument constructors
+// CHECK3-QUIET: :[[@LINE-6]]:11: warning: single-argument constructors
+// CHECK4: :[[@LINE-7]]:11: warning: single-argument constructors
+// CHECK4-QUIET: :[[@LINE-8]]:11: warning: single-argument constructors
+
+// CHECK-NOT: warning:
+// CHECK-QUIET-NOT: warning:
+// CHECK2-NOT: warning:
+// CHECK2-QUIET-NOT: warning:
+// CHECK3-NOT: warning:
+// CHECK3-QUIET-NOT: warning:
+// CHECK4-NOT: warning:
+// CHECK4-QUIET-NOT: warning:
+
+// CHECK: Suppressed 3 warnings (3 in non-user code)
+// CHECK: Use -header-filter=.* to display errors from all non-system headers.
+// CHECK-QUIET-NOT: Suppressed
+// CHECK2: Suppressed 1 warnings (1 in non-user code)
+// CHECK2: Use -header-filter=.* {{.*}}
+// CHECK2-QUIET-NOT: Suppressed
+// CHECK3: Suppressed 2 warnings (2 in non-user code)
+// CHECK3: Use -header-filter=.* {{.*}}
+// CHECK3-QUIET-NOT: Suppressed
+// CHECK4-NOT: Suppressed {{.*}} warnings
+// CHECK4-NOT: Use -header-filter=.* {{.*}}
+// CHECK4-QUIET-NOT: Suppressed
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fix-errors.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fix-errors.cpp
new file mode 100644
index 0000000..0c02616
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fix-errors.cpp
@@ -0,0 +1,15 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: not clang-tidy %t.cpp -checks='-*,google-explicit-constructor' -fix -- > %t.msg 2>&1
+// RUN: FileCheck -input-file=%t.cpp -check-prefix=CHECK-FIX %s
+// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MESSAGES %s
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-tidy %t.cpp -checks='-*,google-explicit-constructor' -fix-errors -- > %t.msg 2>&1
+// RUN: FileCheck -input-file=%t.cpp -check-prefix=CHECK-FIX2 %s
+// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MESSAGES2 %s
+
+class A { A(int i); }
+// CHECK-FIX: class A { A(int i); }{{$}}
+// CHECK-MESSAGES: Fixes have NOT been applied.
+// CHECK-FIX2: class A { explicit A(int i); };
+// CHECK-MESSAGES2: note: FIX-IT applied suggested code changes
+// CHECK-MESSAGES2: clang-tidy applied 2 of 2 suggested fixes.
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fix.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fix.cpp
new file mode 100644
index 0000000..db6bc22
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fix.cpp
@@ -0,0 +1,18 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-tidy %t.cpp -checks='-*,google-explicit-constructor,llvm-namespace-comment' -fix -export-fixes=%t.yaml -- > %t.msg 2>&1
+// RUN: FileCheck -input-file=%t.cpp %s
+// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MESSAGES %s
+// RUN: FileCheck -input-file=%t.yaml -check-prefix=CHECK-YAML %s
+
+namespace i {
+void f(); // So that the namespace isn't empty.
+}
+// CHECK: } // namespace i
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-YAML: ReplacementText: ' // namespace i'
+
+class A { A(int i); };
+// CHECK: class A { explicit A(int i); };
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-MESSAGES: clang-tidy applied 2 of 2 suggested fixes.
+// CHECK-YAML: ReplacementText: 'explicit '
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-default-arguments.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-default-arguments.cpp
new file mode 100644
index 0000000..f7b1ae6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-default-arguments.cpp
@@ -0,0 +1,81 @@
+// RUN: %check_clang_tidy %s fuchsia-default-arguments %t
+
+int foo(int value = 5) { return value; }
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: declaring a parameter with a default argument is disallowed [fuchsia-default-arguments]
+// CHECK-FIXES: int foo(int value) { return value; }
+
+int f() {
+ foo();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: calling a function that uses a default argument is disallowed [fuchsia-default-arguments]
+ // CHECK-NEXT: note: default parameter was declared here:
+ // CHECK-NEXT: int foo(int value = 5) { return value; }
+}
+
+int bar(int value) { return value; }
+
+int n() {
+ foo(0);
+ bar(0);
+}
+
+class Baz {
+public:
+ int a(int value = 5) { return value; }
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: declaring a parameter with a default argument is disallowed [fuchsia-default-arguments]
+ // CHECK-FIXES: int a(int value) { return value; }
+
+ int b(int value) { return value; }
+};
+
+class Foo {
+ // Fix should be suggested in declaration
+ int a(int value = 53);
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: declaring a parameter with a default argument is disallowed [fuchsia-default-arguments]
+ // CHECK-FIXES: int a(int value);
+};
+
+// Fix shouldn't be suggested in implementation
+int Foo::a(int value) {
+ return value;
+}
+
+// Elided functions
+void f(int = 5) {};
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: declaring a parameter with a default argument is disallowed [fuchsia-default-arguments]
+// CHECK-FIXES: void f(int) {};
+
+void g(int) {};
+
+// Should not suggest fix for macro-defined parameters
+#define D(val) = val
+
+void h(int i D(5));
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: declaring a parameter with a default argument is disallowed [fuchsia-default-arguments]
+// CHECK-FIXES-NOT: void h(int i);
+
+void x(int i);
+void x(int i = 12);
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: declaring a parameter with a default argument is disallowed [fuchsia-default-arguments]
+// CHECK-FIXES: void x(int i);
+
+void x(int i) {}
+
+struct S {
+ void x(int i);
+};
+
+void S::x(int i = 12) {}
+// CHECK-MESSAGES: [[@LINE-1]]:11: warning: declaring a parameter with a default argument is disallowed [fuchsia-default-arguments]
+// CHECK-FIXES: void S::x(int i) {}
+
+int main() {
+ S s;
+ s.x();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: calling a function that uses a default argument is disallowed [fuchsia-default-arguments]
+ // CHECK-NEXT: note: default parameter was declared here:
+ // CHECK-NEXT: void S::x(int i = 12) {}
+ x();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: calling a function that uses a default argument is disallowed [fuchsia-default-arguments]
+ // CHECK-NEXT: note: default parameter was declared here:
+ // CHECK-NEXT: void x(int i = 12);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-multiple-inheritance.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-multiple-inheritance.cpp
new file mode 100644
index 0000000..fd2ed14
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-multiple-inheritance.cpp
@@ -0,0 +1,147 @@
+// RUN: %check_clang_tidy %s fuchsia-multiple-inheritance %t
+
+class Base_A {
+public:
+ virtual int foo() { return 0; }
+};
+
+class Base_B {
+public:
+ virtual int bar() { return 0; }
+};
+
+class Base_A_child : public Base_A {
+public:
+ virtual int baz() { return 0; }
+};
+
+class Interface_A {
+public:
+ virtual int foo() = 0;
+};
+
+class Interface_B {
+public:
+ virtual int bar() = 0;
+};
+
+class Interface_C {
+public:
+ virtual int blat() = 0;
+};
+
+class Interface_A_with_member {
+public:
+ virtual int foo() = 0;
+ int val = 0;
+};
+
+class Interface_with_A_Parent : public Base_A {
+public:
+ virtual int baz() = 0;
+};
+
+// Inherits from multiple concrete classes.
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: class Bad_Child1 : public Base_A, Base_B {};
+class Bad_Child1 : public Base_A, Base_B {};
+
+// CHECK-MESSAGES: [[@LINE+1]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+class Bad_Child2 : public Base_A, Interface_A_with_member {
+ virtual int foo() override { return 0; }
+};
+
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: class Bad_Child3 : public Interface_with_A_Parent, Base_B {
+class Bad_Child3 : public Interface_with_A_Parent, Base_B {
+ virtual int baz() override { return 0; }
+};
+
+// Easy cases of single inheritance
+class Simple_Child1 : public Base_A {};
+class Simple_Child2 : public Interface_A {
+ virtual int foo() override { return 0; }
+};
+
+// Valid uses of multiple inheritance
+class Good_Child1 : public Interface_A, Interface_B {
+ virtual int foo() override { return 0; }
+ virtual int bar() override { return 0; }
+};
+
+class Good_Child2 : public Base_A, Interface_B {
+ virtual int bar() override { return 0; }
+};
+
+class Good_Child3 : public Base_A_child, Interface_C, Interface_B {
+ virtual int bar() override { return 0; }
+ virtual int blat() override { return 0; }
+};
+
+struct B1 { int x; };
+struct B2 { int x;};
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: struct D : B1, B2 {};
+struct D1 : B1, B2 {};
+
+struct Base1 { virtual void foo() = 0; };
+struct V1 : virtual Base1 {};
+struct V2 : virtual Base1 {};
+struct D2 : V1, V2 {};
+
+struct Base2 { virtual void foo(); };
+struct V3 : virtual Base2 {};
+struct V4 : virtual Base2 {};
+struct D3 : V3, V4 {};
+
+struct Base3 {};
+struct V5 : virtual Base3 { virtual void f(); };
+struct V6 : virtual Base3 { virtual void g(); };
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: struct D4 : V5, V6 {};
+struct D4 : V5, V6 {};
+
+struct Base4 {};
+struct V7 : virtual Base4 { virtual void f() = 0; };
+struct V8 : virtual Base4 { virtual void g() = 0; };
+struct D5 : V7, V8 {};
+
+struct Base5 { virtual void f() = 0; };
+struct V9 : virtual Base5 { virtual void f(); };
+struct V10 : virtual Base5 { virtual void g() = 0; };
+struct D6 : V9, V10 {};
+
+struct Base6 { virtual void f(); };
+struct Base7 { virtual void g(); };
+struct V15 : virtual Base6 { virtual void f() = 0; };
+struct V16 : virtual Base7 { virtual void g() = 0; };
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: inheriting mulitple classes that aren't pure virtual is discouraged [fuchsia-multiple-inheritance]
+// CHECK-NEXT: struct D9 : V15, V16 {};
+struct D9 : V15, V16 {};
+
+struct Static_Base { static void foo(); };
+struct V11 : virtual Static_Base {};
+struct V12 : virtual Static_Base {};
+struct D7 : V11, V12 {};
+
+struct Static_Base_2 {};
+struct V13 : virtual Static_Base_2 { static void f(); };
+struct V14 : virtual Static_Base_2 { static void g(); };
+struct D8 : V13, V14 {};
+
+template<typename T> struct A : T {};
+template<typename T> struct B : virtual T {};
+
+template<typename> struct C {};
+template<typename T> struct D : C<T> {};
+
+// Check clang_tidy does not crash on this code.
+template <class T>
+struct WithTemplBase : T {
+ WithTemplBase();
+};
+
+int test_no_crash() {
+ auto foo = []() {};
+ WithTemplBase<decltype(foo)>();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-overloaded-operator.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-overloaded-operator.cpp
new file mode 100644
index 0000000..be65a32
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-overloaded-operator.cpp
@@ -0,0 +1,21 @@
+// RUN: %check_clang_tidy %s fuchsia-overloaded-operator %t
+
+class A {
+public:
+ int operator+(int);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: overloading 'operator+' is disallowed
+};
+
+class B {
+public:
+ B &operator=(const B &Other);
+ // CHECK-MESSAGES-NOT: [[@LINE-1]]:3: warning: overloading 'operator=' is disallowed
+ B &operator=(B &&Other);
+ // CHECK-MESSAGES-NOT: [[@LINE-1]]:3: warning: overloading 'operator=' is disallowed
+};
+
+A operator-(const A &A1, const A &A2);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: overloading 'operator-' is disallowed
+
+void operator delete(void*, void*) throw();
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: overloading 'operator delete' is disallowed
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-restrict-system-includes-all.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-restrict-system-includes-all.cpp
new file mode 100644
index 0000000..21f4b68
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-restrict-system-includes-all.cpp
@@ -0,0 +1,10 @@
+// RUN: %check_clang_tidy %s fuchsia-restrict-system-includes %t \
+// RUN: -- -config="{CheckOptions: [{key: fuchsia-restrict-system-includes.Includes, value: ''}]}" \
+// RUN: -- -std=c++11 -I %S/Inputs/fuchsia-restrict-system-includes -isystem %S/Inputs/fuchsia-restrict-system-includes/system
+
+#include <cstdlib.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include cstdlib.h not allowed
+#include <cstdarg.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include cstdarg.h not allowed
+#include <t.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include t.h not allowed
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-restrict-system-includes-glob.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-restrict-system-includes-glob.cpp
new file mode 100644
index 0000000..334990d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-restrict-system-includes-glob.cpp
@@ -0,0 +1,9 @@
+// RUN: %check_clang_tidy %s fuchsia-restrict-system-includes %t \
+// RUN: -- -config="{CheckOptions: [{key: fuchsia-restrict-system-includes.Includes, value: 'cstd*'}]}" \
+// RUN: -- -std=c++11 -I %S/Inputs/fuchsia-restrict-system-includes -isystem %S/Inputs/fuchsia-restrict-system-includes/system
+
+#include <cstdlib.h>
+#include <cstdarg.h>
+#include <t.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include t.h not allowed
+// CHECK-FIXES-NOT: #include <t.h>
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-restrict-system-includes-headers.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-restrict-system-includes-headers.cpp
new file mode 100644
index 0000000..f392eac
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-restrict-system-includes-headers.cpp
@@ -0,0 +1,23 @@
+// RUN: rm -rf %T/Headers
+// RUN: mkdir %T/Headers
+// RUN: cp -r %S/Inputs/fuchsia-restrict-system-includes %T/Headers/fuchsia-restrict-system-includes
+// RUN: %check_clang_tidy %s fuchsia-restrict-system-includes %t \
+// RUN: -- -config="{CheckOptions: [{key: fuchsia-restrict-system-includes.Includes, value: 'transitive.h,s.h'}]}" \
+// RUN: -system-headers -header-filter=.* \
+// RUN: -- -std=c++11 -I %T/Headers/fuchsia-restrict-system-includes -isystem %T/Headers/fuchsia-restrict-system-includes/system
+// RUN: FileCheck -input-file=%T/Headers/fuchsia-restrict-system-includes/transitive2.h %s -check-prefix=CHECK-FIXES
+// RUN: rm -rf %T/Headers
+
+// transitive.h includes <r.h> and <t.h>
+#include <transitive.h>
+// CHECK-MESSAGES: :1:1: warning: system include r.h not allowed, transitively included from {{.*}}
+// CHECK-MESSAGES: :2:1: warning: system include t.h not allowed, transitively included from {{.*}}
+
+// transitive.h includes <s.h> and <t.h>
+#include "transitive2.h"
+// CHECK-MESSAGES: :2:1: warning: system include t.h not allowed, transitively included from {{.*}}
+// CHECK-FIXES-NOT: #include <t.h>
+
+int main() {
+ // f() is declared in r.h
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-restrict-system-includes.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-restrict-system-includes.cpp
new file mode 100644
index 0000000..e2ba710
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-restrict-system-includes.cpp
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s fuchsia-restrict-system-includes %t \
+// RUN: -- -config="{CheckOptions: [{key: fuchsia-restrict-system-includes.Includes, value: 's.h'}]}" \
+// RUN: -- -std=c++11 -I %S/Inputs/fuchsia-restrict-system-includes -isystem %S/Inputs/fuchsia-restrict-system-includes/system
+
+#include "a.h"
+
+#include <s.h>
+#include <t.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include t.h not allowed
+// CHECK-FIXES-NOT: #include <t.h>
+
+#include "s.h"
+#include "t.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include t.h not allowed
+// CHECK-FIXES-NOT: #include "t.h"
+
+#define foo <j.h>
+
+#include foo
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include j.h not allowed
+// CHECK-FIXES-NOT: #include foo
+
+#/* comment */ include /* comment */ foo
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system include j.h not allowed
+// CHECK-FIXES-NOT: # /* comment */ include /* comment */ foo
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-statically-constructed-objects.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-statically-constructed-objects.cpp
new file mode 100644
index 0000000..006494e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-statically-constructed-objects.cpp
@@ -0,0 +1,91 @@
+// RUN: %check_clang_tidy %s fuchsia-statically-constructed-objects %t
+
+// Trivial static is fine
+static int i;
+
+class ClassWithNoCtor {};
+
+class ClassWithCtor {
+public:
+ ClassWithCtor(int Val) : Val(Val) {}
+private:
+ int Val;
+};
+
+class ClassWithConstexpr {
+public:
+ ClassWithConstexpr(int Val1, int Val2) : Val(Val1) {}
+ constexpr ClassWithConstexpr(int Val) : Val(Val) {}
+
+private:
+ int Val;
+};
+
+ClassWithNoCtor A;
+ClassWithConstexpr C(0);
+ClassWithConstexpr E(0, 1);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: ClassWithConstexpr E(0, 1);
+ClassWithCtor G(0);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: ClassWithCtor G(0);
+
+static ClassWithNoCtor A2;
+static ClassWithConstexpr C2(0);
+static ClassWithConstexpr E2(0, 1);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: static ClassWithConstexpr E2(0, 1);
+static ClassWithCtor G2(0);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: static ClassWithCtor G2(0);
+
+struct StructWithConstexpr { constexpr StructWithConstexpr(int Val) {} };
+struct StructWithNoCtor {};
+struct StructWithCtor { StructWithCtor(); };
+
+StructWithNoCtor SNoCtor;
+StructWithConstexpr SConstexpr(0);
+StructWithCtor SCtor;
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: StructWithCtor SCtor;
+
+static StructWithConstexpr SConstexpr2(0);
+static StructWithNoCtor SNoCtor2;
+static StructWithCtor SCtor2;
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: static StructWithCtor SCtor2;
+
+extern StructWithCtor SCtor3;
+
+class ClassWithStaticMember {
+private:
+ static StructWithNoCtor S;
+};
+
+ClassWithStaticMember Z();
+
+class S {
+ int Val;
+public:
+ constexpr S(int i) : Val(100 / i) {}
+ int getVal() const { return Val; }
+};
+
+static S s1(1);
+static S s2(0);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: static S s2(0);
+
+extern int get_i();
+static S s3(get_i());
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: static objects are disallowed; if possible, use a constexpr constructor instead [fuchsia-statically-constructed-objects]
+// CHECK-MESSAGES-NEXT: static S s3(get_i());
+
+void f() {
+ // Locally static is fine
+ static int i;
+ static ClassWithNoCtor A2;
+ static ClassWithConstexpr C2(0);
+ static ClassWithConstexpr E2(0, 1);
+ static ClassWithCtor G2(0);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-trailing-return.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-trailing-return.cpp
new file mode 100644
index 0000000..f6c943a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-trailing-return.cpp
@@ -0,0 +1,23 @@
+// RUN: %check_clang_tidy %s fuchsia-trailing-return %t
+
+int add_one(const int arg) { return arg; }
+
+auto get_add_one() -> int (*)(const int) {
+ // CHECK-MESSAGES: [[@LINE-1]]:1: warning: a trailing return type is disallowed for this type of declaration
+ // CHECK-NEXT: auto get_add_one() -> int (*)(const int) {
+ return add_one;
+}
+
+auto lambda = [](double x, double y) {return x + y;};
+
+auto lambda2 = [](double x, double y) -> double {return x + y;};
+
+int main() {
+ get_add_one()(5);
+ return 0;
+}
+
+template <typename T1, typename T2>
+auto fn(const T1 &lhs, const T2 &rhs) -> decltype(lhs + rhs) {
+ return lhs + rhs;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-virtual-inheritance.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-virtual-inheritance.cpp
new file mode 100644
index 0000000..0c3311a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/fuchsia-virtual-inheritance.cpp
@@ -0,0 +1,42 @@
+// RUN: %check_clang_tidy %s fuchsia-virtual-inheritance %t
+
+class A {
+public:
+ A(int value) : val(value) {}
+
+ int do_A() { return val; }
+
+private:
+ int val;
+};
+
+class B : public virtual A {
+ // CHECK-MESSAGES: [[@LINE-1]]:1: warning: direct virtual inheritance is disallowed [fuchsia-virtual-inheritance]
+ // CHECK-NEXT: class B : public virtual A {
+public:
+ B() : A(0) {}
+ int do_B() { return 1 + do_A(); }
+};
+
+class C : public virtual A {
+ // CHECK-MESSAGES: [[@LINE-1]]:1: warning: direct virtual inheritance is disallowed [fuchsia-virtual-inheritance]
+ // CHECK-NEXT: class C : public virtual A {
+public:
+ C() : A(0) {}
+ int do_C() { return 2 + do_A(); }
+};
+
+class D : public B, public C {
+public:
+ D(int value) : A(value), B(), C() {}
+
+ int do_D() { return do_A() + do_B() + do_C(); }
+};
+
+int main() {
+ A *a = new A(0);
+ B *b = new B();
+ C *c = new C();
+ D *d = new D(0);
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-build-explicit-make-pair.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-build-explicit-make-pair.cpp
new file mode 100644
index 0000000..6dcd357
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-build-explicit-make-pair.cpp
@@ -0,0 +1,51 @@
+// RUN: %check_clang_tidy %s google-build-explicit-make-pair %t
+
+namespace std {
+template <class T1, class T2>
+struct pair {
+ pair(T1 x, T2 y) {}
+};
+
+template <class T1, class T2>
+pair<T1, T2> make_pair(T1 x, T2 y) {
+ return pair<T1, T2>(x, y);
+}
+}
+
+template <typename T>
+void templ(T a, T b) {
+ std::make_pair<T, unsigned>(a, b);
+ std::make_pair<int, int>(1, 2);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: for C++11-compatibility, omit template arguments from make_pair
+// CHECK-FIXES: std::make_pair(1, 2)
+}
+
+template <typename T>
+int t();
+
+void test(int i) {
+ std::make_pair<int, int>(i, i);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: for C++11-compatibility, omit template arguments from make_pair
+// CHECK-FIXES: std::make_pair(i, i)
+
+ std::make_pair<unsigned, int>(i, i);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: for C++11-compatibility, use pair directly
+// CHECK-FIXES: std::pair<unsigned, int>(i, i)
+
+ std::make_pair<int, unsigned>(i, i);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: for C++11-compatibility, use pair directly
+// CHECK-FIXES: std::pair<int, unsigned>(i, i)
+
+#define M std::make_pair<int, unsigned>(i, i);
+M
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: for C++11-compatibility, use pair directly
+// Can't fix in macros.
+// CHECK-FIXES: #define M std::make_pair<int, unsigned>(i, i);
+// CHECK-FIXES-NEXT: M
+
+ templ(i, i);
+ templ(1U, 2U);
+
+ std::make_pair(i, 1); // no-warning
+ std::make_pair(t<int>, 1);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-default-arguments.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-default-arguments.cpp
new file mode 100644
index 0000000..48d3f2d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-default-arguments.cpp
@@ -0,0 +1,29 @@
+// RUN: %check_clang_tidy %s google-default-arguments %t
+
+struct A {
+ virtual void f(int I, int J = 3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: default arguments on virtual or override methods are prohibited [google-default-arguments]
+};
+
+struct B : public A {
+ void f(int I, int J = 5);
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: default arguments on virtual or override methods are prohibited
+};
+
+struct C : public B {
+ void f(int I, int J = 5) override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: default arguments on virtual or override methods are prohibited
+};
+
+// Negatives.
+struct D : public B {
+ void f(int I, int J) override;
+};
+
+struct X {
+ void f(int I, int J = 3);
+};
+
+struct Y : public X {
+ void f(int I, int J = 5);
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-explicit-constructor.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-explicit-constructor.cpp
new file mode 100644
index 0000000..921237a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-explicit-constructor.cpp
@@ -0,0 +1,188 @@
+// RUN: %check_clang_tidy %s google-explicit-constructor %t
+
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ // libc++'s implementation
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const {return __size_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
+struct A {
+ A() {}
+ A(int x, int y) {}
+
+ explicit A(void *x) {}
+ explicit A(void *x, void *y) {}
+ explicit operator bool() const { return true; }
+
+ operator double() const = delete;
+
+ explicit A(const A& a) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: copy constructor should not be declared explicit [google-explicit-constructor]
+ // CHECK-FIXES: {{^ }}A(const A& a) {}
+
+ A(int x1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: single-argument constructors must be marked explicit to avoid unintentional implicit conversions [google-explicit-constructor]
+ // CHECK-FIXES: {{^ }}explicit A(int x1);
+
+ A(double x2, double y = 3.14) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructors that are callable with a single argument must be marked explicit to avoid unintentional implicit conversions [google-explicit-constructor]
+ // CHECK-FIXES: {{^ }}explicit A(double x2, double y = 3.14) {}
+
+ template <typename... T>
+ A(T&&... args);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructors that are callable with a single argument
+ // CHECK-FIXES: {{^ }}explicit A(T&&... args);
+};
+
+inline A::A(int x1) {}
+
+struct B {
+ B(std::initializer_list<int> list1) {}
+ B(const std::initializer_list<unsigned> &list2) {}
+ B(std::initializer_list<unsigned> &&list3) {}
+
+ operator bool() const { return true; }
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'operator bool' must be marked explicit to avoid unintentional implicit conversions [google-explicit-constructor]
+ // CHECK-FIXES: {{^ }}explicit operator bool() const { return true; }
+
+ operator double() const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'operator double' must be marked explicit to avoid unintentional implicit conversions [google-explicit-constructor]
+ // CHECK-FIXES: {{^ }}explicit operator double() const;
+
+ explicit B(::std::initializer_list<double> list4) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initializer-list constructor should not be declared explicit [google-explicit-constructor]
+ // CHECK-FIXES: {{^ }}B(::std::initializer_list<double> list4) {}
+
+ explicit B(const ::std::initializer_list<char> &list5) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initializer-list constructor
+ // CHECK-FIXES: {{^ }}B(const ::std::initializer_list<char> &list5) {}
+
+ explicit B(::std::initializer_list<char> &&list6) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initializer-list constructor
+ // CHECK-FIXES: {{^ }}B(::std::initializer_list<char> &&list6) {}
+};
+
+inline B::operator double() const { return 0.0; }
+
+struct StructWithFnPointer {
+ void (*f)();
+} struct_with_fn_pointer = {[] {}};
+
+using namespace std;
+
+struct C {
+ C(initializer_list<int> list1) {}
+ C(const initializer_list<unsigned> &list2) {}
+ C(initializer_list<unsigned> &&list3) {}
+};
+
+template <typename T>
+struct C2 {
+ C2(initializer_list<int> list1) {}
+ C2(const initializer_list<unsigned> &list2) {}
+ C2(initializer_list<unsigned> &&list3) {}
+
+ explicit C2(initializer_list<double> list4) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initializer-list constructor
+ // CHECK-FIXES: {{^ }}C2(initializer_list<double> list4) {}
+};
+
+template <typename T>
+struct C3 {
+ C3(initializer_list<T> list1) {}
+ C3(const std::initializer_list<T*> &list2) {}
+ C3(::std::initializer_list<T**> &&list3) {}
+
+ template <typename U>
+ C3(initializer_list<U> list3) {}
+};
+
+struct D {
+ template <typename T>
+ explicit D(T t) {}
+};
+
+template <typename T>
+struct E {
+ E(T *pt) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: single-argument constructors
+ // CHECK-FIXES: {{^ }}explicit E(T *pt) {}
+ template <typename U>
+ E(U *pu) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: single-argument constructors
+ // CHECK-FIXES: {{^ }}explicit E(U *pu) {}
+
+ explicit E(T t) {}
+ template <typename U>
+ explicit E(U u) {}
+};
+
+void f(std::initializer_list<int> list) {
+ D d(list);
+ E<decltype(list)> e(list);
+ E<int> e2(list);
+}
+
+template <typename T>
+struct F {};
+
+template<typename T>
+struct G {
+ operator bool() const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'operator bool' must be marked
+ // CHECK-FIXES: {{^}} explicit operator bool() const;
+ operator F<T>() const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'operator F<type-parameter-0-0>' must be marked
+ // CHECK-FIXES: {{^}} explicit operator F<T>() const;
+ template<typename U>
+ operator F<U>*() const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'operator F<type-parameter-1-0> *' must be marked
+ // CHECK-FIXES: {{^}} explicit operator F<U>*() const;
+};
+
+void f2() {
+ G<int> a;
+ (void)(F<int>)a;
+ if (a) {}
+ (void)(F<int>*)a;
+ (void)(F<int*>*)a;
+
+ G<double> b;
+ (void)(F<double>)b;
+ if (b) {}
+ (void)(F<double>*)b;
+ (void)(F<double*>*)b;
+}
+
+#define DEFINE_STRUCT_WITH_OPERATOR_BOOL(name) \
+ struct name { \
+ operator bool() const; \
+ }
+
+DEFINE_STRUCT_WITH_OPERATOR_BOOL(H);
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-module.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-module.cpp
new file mode 100644
index 0000000..494ac48
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-module.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-tidy -checks='-*,google*' -config='{}' -dump-config - -- | FileCheck %s
+// CHECK: CheckOptions:
+// CHECK: {{- key: *google-readability-braces-around-statements.ShortStatementLines}}
+// CHECK-NEXT: {{value: *'1'}}
+// CHECK: {{- key: *google-readability-function-size.StatementThreshold}}
+// CHECK-NEXT: {{value: *'800'}}
+// CHECK: {{- key: *google-readability-namespace-comments.ShortNamespaceLines}}
+// CHECK-NEXT: {{value: *'10'}}
+// CHECK: {{- key: *google-readability-namespace-comments.SpacesBeforeComments}}
+// CHECK-NEXT: {{value: *'2'}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-namespaces.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-namespaces.cpp
new file mode 100644
index 0000000..9bda3c0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-namespaces.cpp
@@ -0,0 +1,52 @@
+// RUN: clang-tidy %s -checks='-*,google-build-namespaces,google-build-using-namespace' -header-filter='.*' -- | FileCheck %s -implicit-check-not="{{warning|error}}:"
+#include "Inputs/google-namespaces.h"
+// CHECK: warning: do not use unnamed namespaces in header files [google-build-namespaces]
+
+using namespace spaaaace;
+// CHECK: :[[@LINE-1]]:1: warning: do not use namespace using-directives; use using-declarations instead [google-build-using-namespace]
+
+using spaaaace::core; // no-warning
+
+namespace std {
+inline namespace literals {
+inline namespace chrono_literals {
+}
+inline namespace complex_literals {
+}
+inline namespace string_literals {
+}
+}
+}
+
+using namespace std::chrono_literals; // no-warning
+using namespace std::complex_literals; // no-warning
+using namespace std::literals; // no-warning
+using namespace std::literals::chrono_literals; // no-warning
+using namespace std::literals::complex_literals; // no-warning
+using namespace std::literals::string_literals; // no-warning
+using namespace std::string_literals; // no-warning
+
+namespace literals {}
+
+using namespace literals;
+// CHECK: :[[@LINE-1]]:1: warning: do not use namespace using-directives; use using-declarations instead [google-build-using-namespace]
+
+namespace foo {
+inline namespace literals {
+inline namespace bar_literals {}
+}
+}
+
+using namespace foo::literals;
+// CHECK: :[[@LINE-1]]:1: warning: do not use namespace using-directives; use using-declarations instead [google-build-using-namespace]
+
+using namespace foo::bar_literals;
+// CHECK: :[[@LINE-1]]:1: warning: do not use namespace using-directives; use using-declarations instead [google-build-using-namespace]
+
+using namespace foo::literals::bar_literals;
+// CHECK: :[[@LINE-1]]:1: warning: do not use namespace using-directives; use using-declarations instead [google-build-using-namespace]
+
+namespace foo_literals {}
+
+using namespace foo_literals;
+// CHECK: :[[@LINE-1]]:1: warning: do not use namespace using-directives; use using-declarations instead [google-build-using-namespace]
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-objc-avoid-throwing-exception.m b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-objc-avoid-throwing-exception.m
new file mode 100644
index 0000000..7fa32e7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-objc-avoid-throwing-exception.m
@@ -0,0 +1,32 @@
+// RUN: %check_clang_tidy %s google-objc-avoid-throwing-exception %t
+@class NSString;
+
+@interface NSException
+
++ (void)raise:(NSString *)name format:(NSString *)format;
++ (void)raise:(NSString *)name format:(NSString *)format arguments:(NSString *)args; // using NSString type since va_list cannot be recognized here
+
+@end
+
+@interface NotException
+
++ (void)raise:(NSString *)name format:(NSString *)format;
+
+@end
+
+@implementation Foo
+- (void)f {
+ NSString *foo = @"foo";
+ @throw foo;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass in NSError ** instead of throwing exception to indicate Objective-C errors [google-objc-avoid-throwing-exception]
+}
+
+- (void)f2 {
+ [NSException raise:@"TestException" format:@"Test"];
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: pass in NSError ** instead of throwing exception to indicate Objective-C errors [google-objc-avoid-throwing-exception]
+ [NSException raise:@"TestException" format:@"Test %@" arguments:@"bar"];
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: pass in NSError ** instead of throwing exception to indicate Objective-C errors [google-objc-avoid-throwing-exception]
+ [NotException raise:@"NotException" format:@"Test"];
+}
+@end
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-objc-global-variable-declaration.m b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-objc-global-variable-declaration.m
new file mode 100644
index 0000000..346ddec
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-objc-global-variable-declaration.m
@@ -0,0 +1,49 @@
+// RUN: %check_clang_tidy %s google-objc-global-variable-declaration %t
+
+@class NSString;
+static NSString* const myConstString = @"hello";
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: const global variable 'myConstString' must have a name which starts with an appropriate prefix [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* const kMyConstString = @"hello";
+
+static NSString* MyString = @"hi";
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: non-const global variable 'MyString' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* gMyString = @"hi";
+
+NSString* globalString = @"test";
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: non-const global variable 'globalString' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration]
+// CHECK-FIXES: NSString* gGlobalString = @"test";
+
+static NSString* a = @"too simple";
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: non-const global variable 'a' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* a = @"too simple";
+
+static NSString* noDef;
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: non-const global variable 'noDef' must have a name which starts with 'g[A-Z]' [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* gNoDef;
+
+static NSString* const _notAlpha = @"NotBeginWithAlpha";
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: const global variable '_notAlpha' must have a name which starts with an appropriate prefix [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* const _notAlpha = @"NotBeginWithAlpha";
+
+static NSString* const k_Alpha = @"SecondNotAlpha";
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: const global variable 'k_Alpha' must have a name which starts with an appropriate prefix [google-objc-global-variable-declaration]
+// CHECK-FIXES: static NSString* const k_Alpha = @"SecondNotAlpha";
+
+static NSString* const kGood = @"hello";
+static NSString* const XYGood = @"hello";
+static NSString* gMyIntGood = 0;
+
+extern NSString* const GTLServiceErrorDomain;
+
+enum GTLServiceError {
+ GTLServiceErrorQueryResultMissing = -3000,
+ GTLServiceErrorWaitTimedOut = -3001,
+};
+
+@implementation Foo
+- (void)f {
+ int x = 0;
+ static int bar;
+ static const int baz = 42;
+}
+@end
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-overloaded-unary-and.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-overloaded-unary-and.cpp
new file mode 100644
index 0000000..16893d2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-overloaded-unary-and.cpp
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s google-runtime-operator %t
+
+struct Foo {
+ void *operator&();
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not overload unary operator&, it is dangerous. [google-runtime-operator]
+};
+
+template <typename T>
+struct TFoo {
+ T *operator&();
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not overload unary operator&
+};
+
+TFoo<int> tfoo;
+
+struct Bar;
+void *operator&(Bar &b);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not overload unary operator&
+
+// No warnings on binary operators.
+struct Qux {
+ void *operator&(Qux &q);
+};
+
+void *operator&(Qux &q, Qux &r);
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-casting.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-casting.c
new file mode 100644
index 0000000..488bcd7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-casting.c
@@ -0,0 +1,24 @@
+// RUN: %check_clang_tidy %s google-readability-casting %t -- -- -x c
+// The testing script always adds .cpp extension to the input file name, so we
+// need to run clang-tidy directly in order to verify handling of .c files:
+// RUN: clang-tidy --checks=-*,google-readability-casting %s -- -x c++ | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not='{{warning|error}}:'
+// RUN: cp %s %t.main_file.cpp
+// RUN: clang-tidy --checks=-*,google-readability-casting -header-filter='.*' %t.main_file.cpp -- -I%S -DTEST_INCLUDE -x c++ | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not='{{warning|error}}:'
+
+#ifdef TEST_INCLUDE
+
+#undef TEST_INCLUDE
+#include "google-readability-casting.c"
+
+#else
+
+void f(const char *cpc) {
+ const char *cpc2 = (const char*)cpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: redundant cast to the same type [google-readability-casting]
+ // CHECK-FIXES: const char *cpc2 = cpc;
+ char *pc = (char*)cpc;
+ typedef const char *Typedef1;
+ (Typedef1)cpc;
+}
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-casting.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-casting.cpp
new file mode 100644
index 0000000..d36fef6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-casting.cpp
@@ -0,0 +1,323 @@
+// RUN: %check_clang_tidy %s google-readability-casting %t
+
+bool g() { return false; }
+
+enum Enum { Enum1 };
+struct X {};
+struct Y : public X {};
+
+void f(int a, double b, const char *cpc, const void *cpv, X *pX) {
+ const char *cpc2 = (const char*)cpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: redundant cast to the same type [google-readability-casting]
+ // CHECK-FIXES: const char *cpc2 = cpc;
+
+ typedef const char *Typedef1;
+ typedef const char *Typedef2;
+ Typedef1 t1;
+ (Typedef2)t1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C-style casts are discouraged; use static_cast (if needed, the cast may be redundant) [google-readability-casting]
+ // CHECK-FIXES: {{^}} static_cast<Typedef2>(t1);
+ (const char*)t1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: {{.*}}; use static_cast (if needed
+ // CHECK-FIXES: {{^}} static_cast<const char*>(t1);
+ (Typedef1)cpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: {{.*}}; use static_cast (if needed
+ // CHECK-FIXES: {{^}} static_cast<Typedef1>(cpc);
+ (Typedef1)t1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant cast to the same type
+ // CHECK-FIXES: {{^}} t1;
+
+ char *pc = (char*)cpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use const_cast [google-readability-casting]
+ // CHECK-FIXES: char *pc = const_cast<char*>(cpc);
+ typedef char Char;
+ Char *pChar = (Char*)pc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}}; use static_cast (if needed
+ // CHECK-FIXES: {{^}} Char *pChar = static_cast<Char*>(pc);
+
+ (Char)*cpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: {{.*}}; use static_cast (if needed
+ // CHECK-FIXES: {{^}} static_cast<Char>(*cpc);
+
+ (char)*pChar;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: {{.*}}; use static_cast (if needed
+ // CHECK-FIXES: {{^}} static_cast<char>(*pChar);
+
+ (const char*)cpv;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: {{.*}}; use static_cast [
+ // CHECK-FIXES: static_cast<const char*>(cpv);
+
+ char *pc2 = (char*)(cpc + 33);
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: {{.*}}; use const_cast [
+ // CHECK-FIXES: char *pc2 = const_cast<char*>(cpc + 33);
+
+ const char &crc = *cpc;
+ char &rc = (char&)crc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}}; use const_cast [
+ // CHECK-FIXES: char &rc = const_cast<char&>(crc);
+
+ char &rc2 = (char&)*cpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: {{.*}}; use const_cast [
+ // CHECK-FIXES: char &rc2 = const_cast<char&>(*cpc);
+
+ char ** const* const* ppcpcpc;
+ char ****ppppc = (char****)ppcpcpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: {{.*}}; use const_cast [
+ // CHECK-FIXES: char ****ppppc = const_cast<char****>(ppcpcpc);
+
+ char ***pppc = (char***)*(ppcpcpc);
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: {{.*}}; use const_cast [
+ // CHECK-FIXES: char ***pppc = const_cast<char***>(*(ppcpcpc));
+
+ char ***pppc2 = (char***)(*ppcpcpc);
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: {{.*}}; use const_cast [
+ // CHECK-FIXES: char ***pppc2 = const_cast<char***>(*ppcpcpc);
+
+ char *pc5 = (char*)(const char*)(cpv);
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: {{.*}}; use const_cast [
+ // CHECK-MESSAGES: :[[@LINE-2]]:22: warning: {{.*}}; use static_cast [
+ // CHECK-FIXES: char *pc5 = const_cast<char*>(static_cast<const char*>(cpv));
+
+ int b1 = (int)b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}}; use static_cast [
+ // CHECK-FIXES: int b1 = static_cast<int>(b);
+ b1 = (const int&)b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: {{.*}}; use static_cast/const_cast/reinterpret_cast [
+ // CHECK-FIXES: b1 = (const int&)b;
+
+ b1 = (int) b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: {{.*}}; use static_cast {{.*}}
+ // CHECK-FIXES: b1 = static_cast<int>(b);
+
+ b1 = (int) b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: {{.*}}; use static_cast {{.*}}
+ // CHECK-FIXES: b1 = static_cast<int>(b);
+
+ b1 = (int) (b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: {{.*}}; use static_cast {{.*}}
+ // CHECK-FIXES: b1 = static_cast<int>(b);
+
+ b1 = (int) (b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: {{.*}}; use static_cast {{.*}}
+ // CHECK-FIXES: b1 = static_cast<int>(b);
+
+ Y *pB = (Y*)pX;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}}; use static_cast/const_cast/reinterpret_cast [
+ Y &rB = (Y&)*pX;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}}; use static_cast/const_cast/reinterpret_cast [
+
+ const char *pc3 = (const char*)cpv;
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}}; use static_cast [
+ // CHECK-FIXES: const char *pc3 = static_cast<const char*>(cpv);
+
+ char *pc4 = (char*)cpv;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: {{.*}}; use static_cast/const_cast/reinterpret_cast [
+ // CHECK-FIXES: char *pc4 = (char*)cpv;
+
+ b1 = (int)Enum1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: {{.*}}; use static_cast [
+ // CHECK-FIXES: b1 = static_cast<int>(Enum1);
+
+ Enum e = (Enum)b1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}}; use static_cast [
+ // CHECK-FIXES: Enum e = static_cast<Enum>(b1);
+
+ e = (Enum)Enum1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant cast to the same type
+ // CHECK-FIXES: {{^}} e = Enum1;
+
+ e = (Enum)e;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant cast to the same type
+ // CHECK-FIXES: {{^}} e = e;
+
+ e = (Enum) e;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant cast to the same type
+ // CHECK-FIXES: {{^}} e = e;
+
+ e = (Enum) (e);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant cast to the same type
+ // CHECK-FIXES: {{^}} e = (e);
+
+ static const int kZero = 0;
+ (int)kZero;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant cast to the same type
+ // CHECK-FIXES: {{^}} kZero;
+
+ int b2 = int(b);
+ int b3 = static_cast<double>(b);
+ int b4 = b;
+ double aa = a;
+ (void)b2;
+ return (void)g();
+}
+
+template <typename T>
+void template_function(T t, int n) {
+ int i = (int)t;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}}; use static_cast/const_cast/reinterpret_cast [
+ // CHECK-FIXES: int i = (int)t;
+ int j = (int)n;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant cast to the same type
+ // CHECK-FIXES: int j = n;
+}
+
+template <typename T>
+struct TemplateStruct {
+ void f(T t, int n) {
+ int k = (int)t;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}}; use static_cast/const_cast/reinterpret_cast
+ // CHECK-FIXES: int k = (int)t;
+ int l = (int)n;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant cast to the same type
+ // CHECK-FIXES: int l = n;
+ }
+};
+
+void test_templates() {
+ template_function(1, 42);
+ template_function(1.0, 42);
+ TemplateStruct<int>().f(1, 42);
+ TemplateStruct<double>().f(1.0, 42);
+}
+
+extern "C" {
+void extern_c_code(const char *cpc) {
+ const char *cpc2 = (const char*)cpc;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: redundant cast to the same type
+ // CHECK-FIXES: const char *cpc2 = cpc;
+ char *pc = (char*)cpc;
+}
+}
+
+#define CAST(type, value) (type)(value)
+void macros(double d) {
+ int i = CAST(int, d);
+}
+
+enum E { E1 = 1 };
+template <E e>
+struct A {
+ // Usage of template argument e = E1 is represented as (E)1 in the AST for
+ // some reason. We have a special treatment of this case to avoid warnings
+ // here.
+ static const E ee = e;
+};
+struct B : public A<E1> {};
+
+
+void overloaded_function();
+void overloaded_function(int);
+
+template<typename Fn>
+void g(Fn fn) {
+ fn();
+}
+
+void function_casts() {
+ typedef void (*FnPtrVoid)();
+ typedef void (&FnRefVoid)();
+ typedef void (&FnRefInt)(int);
+
+ g((void (*)())overloaded_function);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: g(static_cast<void (*)()>(overloaded_function));
+ g((void (*)())&overloaded_function);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: g(static_cast<void (*)()>(&overloaded_function));
+ g((void (&)())overloaded_function);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: g(static_cast<void (&)()>(overloaded_function));
+
+ g((FnPtrVoid)overloaded_function);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: g(static_cast<FnPtrVoid>(overloaded_function));
+ g((FnPtrVoid)&overloaded_function);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: g(static_cast<FnPtrVoid>(&overloaded_function));
+ g((FnRefVoid)overloaded_function);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: g(static_cast<FnRefVoid>(overloaded_function));
+
+ FnPtrVoid fn0 = (void (*)())&overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: FnPtrVoid fn0 = static_cast<void (*)()>(&overloaded_function);
+ FnPtrVoid fn1 = (void (*)())overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: FnPtrVoid fn1 = static_cast<void (*)()>(overloaded_function);
+ FnPtrVoid fn1a = (FnPtrVoid)overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: FnPtrVoid fn1a = static_cast<FnPtrVoid>(overloaded_function);
+ FnRefInt fn2 = (void (&)(int))overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: FnRefInt fn2 = static_cast<void (&)(int)>(overloaded_function);
+ auto fn3 = (void (*)())&overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: auto fn3 = static_cast<void (*)()>(&overloaded_function);
+ auto fn4 = (void (*)())overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: auto fn4 = static_cast<void (*)()>(overloaded_function);
+ auto fn5 = (void (&)(int))overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: auto fn5 = static_cast<void (&)(int)>(overloaded_function);
+
+ void (*fn6)() = (void (*)())&overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: void (*fn6)() = static_cast<void (*)()>(&overloaded_function);
+ void (*fn7)() = (void (*)())overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: void (*fn7)() = static_cast<void (*)()>(overloaded_function);
+ void (*fn8)() = (FnPtrVoid)overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: void (*fn8)() = static_cast<FnPtrVoid>(overloaded_function);
+ void (&fn9)(int) = (void (&)(int))overloaded_function;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: void (&fn9)(int) = static_cast<void (&)(int)>(overloaded_function);
+
+ void (*correct1)() = static_cast<void (*)()>(overloaded_function);
+ FnPtrVoid correct2 = static_cast<void (*)()>(&overloaded_function);
+ FnRefInt correct3 = static_cast<void (&)(int)>(overloaded_function);
+}
+
+struct S {
+ S(const char *);
+};
+struct ConvertibleToS {
+ operator S() const;
+};
+struct ConvertibleToSRef {
+ operator const S&() const;
+};
+
+void conversions() {
+ //auto s1 = (const S&)"";
+ // C HECK-MESSAGES: :[[@LINE-1]]:10: warning: C-style casts are discouraged; use static_cast [
+ // C HECK-FIXES: S s1 = static_cast<const S&>("");
+ auto s2 = (S)"";
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: C-style casts are discouraged; use constructor call syntax [
+ // CHECK-FIXES: auto s2 = S("");
+ auto s2a = (struct S)"";
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use static_cast [
+ // CHECK-FIXES: auto s2a = static_cast<struct S>("");
+ auto s2b = (const S)"";
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: C-style casts are discouraged; use static_cast [
+ // FIXME: This should be constructor call syntax: S("").
+ // CHECK-FIXES: auto s2b = static_cast<const S>("");
+ ConvertibleToS c;
+ auto s3 = (const S&)c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: C-style casts are discouraged; use static_cast/const_cast/reinterpret_cast [
+ // CHECK-FIXES: auto s3 = (const S&)c;
+ // FIXME: This should be a static_cast.
+ // C HECK-FIXES: auto s3 = static_cast<const S&>(c);
+ auto s4 = (S)c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: C-style casts are discouraged; use constructor call syntax [
+ // CHECK-FIXES: auto s4 = S(c);
+ ConvertibleToSRef cr;
+ auto s5 = (const S&)cr;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: C-style casts are discouraged; use static_cast/const_cast/reinterpret_cast [
+ // CHECK-FIXES: auto s5 = (const S&)cr;
+ // FIXME: This should be a static_cast.
+ // C HECK-FIXES: auto s5 = static_cast<const S&>(cr);
+ auto s6 = (S)cr;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: C-style casts are discouraged; use constructor call syntax [
+ // CHECK-FIXES: auto s6 = S(cr);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-casting.mm b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-casting.mm
new file mode 100644
index 0000000..b987dc2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-casting.mm
@@ -0,0 +1,179 @@
+// RUN: clang-tidy %s -checks=-*,google-readability-casting -- \
+// RUN: -xobjective-c++ -fobjc-abi-version=2 -fobjc-arc | count 0
+
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+
+bool g() { return false; }
+
+enum Enum { Enum1 };
+struct X {};
+struct Y : public X {};
+
+void f(int a, double b, const char *cpc, const void *cpv, X *pX) {
+
+ typedef const char *Typedef1;
+ typedef const char *Typedef2;
+ Typedef1 t1;
+ (Typedef2)t1;
+ (const char*)t1;
+ (Typedef1)cpc;
+
+ typedef char Char;
+ char *pc;
+ Char *pChar = (Char*)pc;
+
+ (Char)*cpc;
+
+ (char)*pChar;
+
+ (const char*)cpv;
+
+ char *pc2 = (char*)(cpc + 33);
+
+ const char &crc = *cpc;
+ char &rc = (char&)crc;
+
+ char &rc2 = (char&)*cpc;
+
+ char ** const* const* ppcpcpc;
+ char ****ppppc = (char****)ppcpcpc;
+
+ char ***pppc = (char***)*(ppcpcpc);
+
+ char ***pppc2 = (char***)(*ppcpcpc);
+
+ char *pc5 = (char*)(const char*)(cpv);
+
+ int b1 = (int)b;
+ b1 = (const int&)b;
+
+ b1 = (int) b;
+
+ b1 = (int) b;
+
+ b1 = (int) (b);
+
+ b1 = (int) (b);
+
+ Y *pB = (Y*)pX;
+ Y &rB = (Y&)*pX;
+
+ const char *pc3 = (const char*)cpv;
+
+ char *pc4 = (char*)cpv;
+
+ b1 = (int)Enum1;
+
+ Enum e = (Enum)b1;
+
+ int b2 = int(b);
+ int b3 = static_cast<double>(b);
+ int b4 = b;
+ double aa = a;
+ (void)b2;
+ return (void)g();
+}
+
+template <typename T>
+void template_function(T t, int n) {
+ int i = (int)t;
+}
+
+template <typename T>
+struct TemplateStruct {
+ void f(T t, int n) {
+ int k = (int)t;
+ }
+};
+
+void test_templates() {
+ template_function(1, 42);
+ template_function(1.0, 42);
+ TemplateStruct<int>().f(1, 42);
+ TemplateStruct<double>().f(1.0, 42);
+}
+
+extern "C" {
+void extern_c_code(const char *cpc) {
+ char *pc = (char*)cpc;
+}
+}
+
+#define CAST(type, value) (type)(value)
+void macros(double d) {
+ int i = CAST(int, d);
+}
+
+enum E { E1 = 1 };
+template <E e>
+struct A {
+ // Usage of template argument e = E1 is represented as (E)1 in the AST for
+ // some reason. We have a special treatment of this case to avoid warnings
+ // here.
+ static const E ee = e;
+};
+struct B : public A<E1> {};
+
+
+void overloaded_function();
+void overloaded_function(int);
+
+template<typename Fn>
+void g(Fn fn) {
+ fn();
+}
+
+void function_casts() {
+ typedef void (*FnPtrVoid)();
+ typedef void (&FnRefVoid)();
+ typedef void (&FnRefInt)(int);
+
+ g((void (*)())overloaded_function);
+ g((void (*)())&overloaded_function);
+ g((void (&)())overloaded_function);
+
+ g((FnPtrVoid)overloaded_function);
+ g((FnPtrVoid)&overloaded_function);
+ g((FnRefVoid)overloaded_function);
+
+ FnPtrVoid fn0 = (void (*)())&overloaded_function;
+ FnPtrVoid fn1 = (void (*)())overloaded_function;
+ FnPtrVoid fn1a = (FnPtrVoid)overloaded_function;
+ FnRefInt fn2 = (void (&)(int))overloaded_function;
+ auto fn3 = (void (*)())&overloaded_function;
+ auto fn4 = (void (*)())overloaded_function;
+ auto fn5 = (void (&)(int))overloaded_function;
+
+ void (*fn6)() = (void (*)())&overloaded_function;
+ void (*fn7)() = (void (*)())overloaded_function;
+ void (*fn8)() = (FnPtrVoid)overloaded_function;
+ void (&fn9)(int) = (void (&)(int))overloaded_function;
+
+ void (*correct1)() = static_cast<void (*)()>(overloaded_function);
+ FnPtrVoid correct2 = static_cast<void (*)()>(&overloaded_function);
+ FnRefInt correct3 = static_cast<void (&)(int)>(overloaded_function);
+}
+
+struct S {
+ S(const char *);
+};
+struct ConvertibleToS {
+ operator S() const;
+};
+struct ConvertibleToSRef {
+ operator const S&() const;
+};
+
+void conversions() {
+ //auto s1 = (const S&)"";
+ auto s2 = (S)"";
+ auto s2a = (struct S)"";
+ auto s2b = (const S)"";
+ ConvertibleToS c;
+ auto s3 = (const S&)c;
+ auto s4 = (S)c;
+ ConvertibleToSRef cr;
+ auto s5 = (const S&)cr;
+ auto s6 = (S)cr;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-namespace-comments.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-namespace-comments.cpp
new file mode 100644
index 0000000..9abb984
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-namespace-comments.cpp
@@ -0,0 +1,54 @@
+// RUN: %check_clang_tidy %s google-readability-namespace-comments %t
+
+namespace n1 {
+namespace n2 {
+
+
+void f(); // So that the namespace isn't empty.
+
+
+// CHECK-MESSAGES: :[[@LINE+4]]:2: warning: namespace 'n2' not terminated with a closing comment [google-readability-namespace-comments]
+// CHECK-MESSAGES: :[[@LINE-7]]:11: note: namespace 'n2' starts here
+// CHECK-MESSAGES: :[[@LINE+2]]:3: warning: namespace 'n1' not terminated with
+// CHECK-MESSAGES: :[[@LINE-10]]:11: note: namespace 'n1' starts here
+}}
+// CHECK-FIXES: } // namespace n2
+// CHECK-FIXES: } // namespace n1
+
+#define MACRO macro_expansion
+namespace MACRO {
+void f(); // So that the namespace isn't empty.
+// 1
+// 2
+// 3
+// 4
+// 5
+// 6
+// 7
+// CHECK-MESSAGES: :[[@LINE+2]]:2: warning: namespace 'macro_expansion' not terminated with
+// CHECK-MESSAGES: :[[@LINE-10]]:11: note: namespace 'macro_expansion' starts here
+}
+// CHECK-FIXES: } // namespace macro_expansion
+
+namespace short1 {
+namespace short2 {
+// Namespaces covering 10 lines or fewer are exempt from this rule.
+
+
+
+
+
+}
+}
+
+namespace n3 {
+
+
+
+
+
+
+
+
+
+}; // namespace n3
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-nested-namespace-comments.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-nested-namespace-comments.cpp
new file mode 100644
index 0000000..d7765c6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-nested-namespace-comments.cpp
@@ -0,0 +1,17 @@
+// RUN: %check_clang_tidy %s google-readability-namespace-comments %t
+
+namespace n1::n2 {
+namespace n3 {
+
+// So that namespace is not empty.
+void f();
+
+
+// CHECK-MESSAGES: :[[@LINE+4]]:2: warning: namespace 'n3' not terminated with
+// CHECK-MESSAGES: :[[@LINE-7]]:11: note: namespace 'n3' starts here
+// CHECK-MESSAGES: :[[@LINE+2]]:3: warning: namespace 'n1::n2' not terminated with a closing comment [google-readability-namespace-comments]
+// CHECK-MESSAGES: :[[@LINE-10]]:11: note: namespace 'n1::n2' starts here
+}}
+// CHECK-FIXES: } // namespace n3
+// CHECK-FIXES: } // namespace n1::n2
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-todo.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-todo.cpp
new file mode 100644
index 0000000..6b900aa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-readability-todo.cpp
@@ -0,0 +1,26 @@
+// RUN: %check_clang_tidy %s google-readability-todo %t -- -config="{User: 'some user'}" --
+
+// TODOfix this1
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
+// CHECK-FIXES: // TODO(some user): fix this1
+
+// TODO fix this2
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
+// CHECK-FIXES: // TODO(some user): fix this2
+
+// TODO fix this3
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
+// CHECK-FIXES: // TODO(some user): fix this3
+
+// TODO: fix this4
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: missing username/bug in TODO
+// CHECK-FIXES: // TODO(some user): fix this4
+
+// TODO(clang)fix this5
+
+// TODO(foo):shave yaks
+// TODO(bar):
+// TODO(foo): paint bikeshed
+// TODO(b/12345): find the holy grail
+// TODO (b/12345): allow spaces before parentheses
+// TODO(asdf) allow missing semicolon
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-runtime-int-std.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-runtime-int-std.cpp
new file mode 100644
index 0000000..c5d3112
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-runtime-int-std.cpp
@@ -0,0 +1,57 @@
+// RUN: %check_clang_tidy %s google-runtime-int %t -- \
+// RUN: -config='{CheckOptions: [ \
+// RUN: {key: google-runtime-int.UnsignedTypePrefix, value: "std::uint"}, \
+// RUN: {key: google-runtime-int.SignedTypePrefix, value: "std::int"}, \
+// RUN: {key: google-runtime-int.TypeSuffix, value: "_t"}, \
+// RUN: ]}' -- -std=c++11
+
+long a();
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: consider replacing 'long' with 'std::int{{..}}_t'
+
+typedef unsigned long long uint64; // NOLINT
+
+long b(long = 1);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: consider replacing 'long' with 'std::int{{..}}_t'
+// CHECK-MESSAGES: [[@LINE-2]]:8: warning: consider replacing 'long' with 'std::int{{..}}_t'
+
+template <typename T>
+void tmpl() {
+ T i;
+}
+
+short bar(const short, unsigned short) {
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: consider replacing 'short' with 'std::int16_t'
+// CHECK-MESSAGES: [[@LINE-2]]:17: warning: consider replacing 'short' with 'std::int16_t'
+// CHECK-MESSAGES: [[@LINE-3]]:24: warning: consider replacing 'unsigned short' with 'std::uint16_t'
+ long double foo = 42;
+ uint64 qux = 42;
+ unsigned short port;
+
+ const unsigned short bar = 0;
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: consider replacing 'unsigned short' with 'std::uint16_t'
+ long long *baar;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'long long' with 'std::int64_t'
+ const unsigned short &bara = bar;
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: consider replacing 'unsigned short' with 'std::uint16_t'
+ long const long moo = 1;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'long long' with 'std::int64_t'
+ long volatile long wat = 42;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'long long' with 'std::int64_t'
+ unsigned long y;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned long' with 'std::uint{{..}}_t'
+ unsigned long long **const *tmp;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned long long' with 'std::uint64_t'
+ unsigned long long **const *&z = tmp;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned long long' with 'std::uint64_t'
+ unsigned short porthole;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned short' with 'std::uint16_t'
+
+ uint64 cast = (short)42;
+// CHECK-MESSAGES: [[@LINE-1]]:18: warning: consider replacing 'short' with 'std::int16_t'
+
+#define l long
+ l x;
+
+ tmpl<short>();
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: consider replacing 'short' with 'std::int16_t'
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-runtime-int.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-runtime-int.c
new file mode 100644
index 0000000..8657e2d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-runtime-int.c
@@ -0,0 +1,27 @@
+// RUN: clang-tidy -checks=-*,google-runtime-int %s -- -x c 2>&1 | not grep 'warning:\|error:'
+
+long a();
+
+long b(long x);
+
+short bar(const short q, unsigned short w) {
+ long double foo;
+ unsigned short port;
+
+ const unsigned short bar;
+ long long *baar;
+ const unsigned short bara;
+ long const long moo;
+ long volatile long wat;
+ unsigned long y;
+ unsigned long long **const *tmp;
+ unsigned short porthole;
+
+ unsigned cast;
+ cast = (short)42;
+ return q;
+}
+
+void qux() {
+ short port;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-runtime-int.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-runtime-int.cpp
new file mode 100644
index 0000000..4bb7398
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-runtime-int.cpp
@@ -0,0 +1,91 @@
+// RUN: %check_clang_tidy %s google-runtime-int %t
+
+long a();
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: consider replacing 'long' with 'int{{..}}'
+
+typedef unsigned long long uint64; // NOLINT
+
+long b(long = 1);
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: consider replacing 'long' with 'int{{..}}'
+// CHECK-MESSAGES: [[@LINE-2]]:8: warning: consider replacing 'long' with 'int{{..}}'
+
+template <typename T>
+void tmpl() {
+ T i;
+}
+
+short bar(const short, unsigned short) {
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: consider replacing 'short' with 'int16'
+// CHECK-MESSAGES: [[@LINE-2]]:17: warning: consider replacing 'short' with 'int16'
+// CHECK-MESSAGES: [[@LINE-3]]:24: warning: consider replacing 'unsigned short' with 'uint16'
+ long double foo = 42;
+ uint64 qux = 42;
+ unsigned short port;
+
+ const unsigned short bar = 0;
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: consider replacing 'unsigned short' with 'uint16'
+ long long *baar;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'long long' with 'int64'
+ const unsigned short &bara = bar;
+// CHECK-MESSAGES: [[@LINE-1]]:9: warning: consider replacing 'unsigned short' with 'uint16'
+ long const long moo = 1;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'long long' with 'int64'
+ long volatile long wat = 42;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'long long' with 'int64'
+ unsigned long y;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned long' with 'uint{{..}}'
+ unsigned long long **const *tmp;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned long long' with 'uint64'
+ unsigned long long **const *&z = tmp;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned long long' with 'uint64'
+ unsigned short porthole;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'unsigned short' with 'uint16'
+
+ uint64 cast = (short)42;
+// CHECK-MESSAGES: [[@LINE-1]]:18: warning: consider replacing 'short' with 'int16'
+
+#define l long
+ l x;
+
+ tmpl<short>();
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: consider replacing 'short' with 'int16'
+ return 0;
+}
+
+void p(unsigned short port);
+
+void qux() {
+ short port;
+// CHECK-MESSAGES: [[@LINE-1]]:3: warning: consider replacing 'short' with 'int16'
+}
+
+// FIXME: This shouldn't warn, as UD-literal operators require one of a handful
+// of types as an argument.
+struct some_value {};
+constexpr some_value operator"" _some_literal(unsigned long long int i);
+// CHECK-MESSAGES: [[@LINE-1]]:47: warning: consider replacing 'unsigned long long'
+
+struct A { A& operator=(const A&); };
+class B { A a[0]; };
+
+void fff() {
+ B a, b;
+ a = b;
+}
+
+__attribute__((__format__ (__printf__, 1, 2)))
+void myprintf(const char* s, ...);
+
+void doprint_no_warning() {
+ uint64 foo = 23;
+ myprintf("foo %lu %lu", (unsigned long)42, (unsigned long)foo);
+}
+
+void myprintf_no_attribute(const char* s, ...);
+
+void doprint_warning() {
+ uint64 foo = 23;
+ myprintf_no_attribute("foo %lu %lu", (unsigned long)42, (unsigned long)foo);
+// CHECK-MESSAGES: [[@LINE-1]]:41: warning: consider replacing 'unsigned long'
+// CHECK-MESSAGES: [[@LINE-2]]:60: warning: consider replacing 'unsigned long'
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-runtime-references.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-runtime-references.cpp
new file mode 100644
index 0000000..b9f84b6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/google-runtime-references.cpp
@@ -0,0 +1,152 @@
+// RUN: %check_clang_tidy %s google-runtime-references %t -- \
+// RUN: -extra-arg="-std=c++11" \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: google-runtime-references.WhiteListTypes, \
+// RUN: value: 'whitelist::A; whitelist::B'}]}" --
+
+int a;
+int &b = a;
+int *c;
+void f1(int a);
+void f2(int *b);
+void f3(const int &c);
+void f4(int const &d);
+
+// Don't warn on implicit operator= in c++11 mode.
+class A {
+ virtual void f() {}
+};
+// Don't warn on rvalue-references.
+struct A2 {
+ A2(A2&&) = default;
+ void f(A2&&) {}
+};
+
+// Don't warn on iostream parameters.
+namespace xxx {
+class istream { };
+class ostringstream { };
+}
+void g1(xxx::istream &istr);
+void g1(xxx::ostringstream &istr);
+
+void g1(int &a);
+// CHECK-MESSAGES: [[@LINE-1]]:14: warning: non-const reference parameter 'a', make it const or use a pointer [google-runtime-references]
+
+struct s {};
+void g2(int a, int b, s c, s &d);
+// CHECK-MESSAGES: [[@LINE-1]]:31: warning: non-const reference parameter 'd', {{.*}}
+
+typedef int &ref;
+void g3(ref a);
+// CHECK-MESSAGES: [[@LINE-1]]:13: warning: non-const reference {{.*}}
+
+void g4(int &a, int &b, int &);
+// CHECK-MESSAGES: [[@LINE-1]]:14: warning: non-const reference parameter 'a', {{.*}}
+// CHECK-MESSAGES: [[@LINE-2]]:22: warning: non-const reference parameter 'b', {{.*}}
+// CHECK-MESSAGES: [[@LINE-3]]:30: warning: non-const reference parameter at index 2, {{.*}}
+
+class B {
+ B(B& a) {}
+// CHECK-MESSAGES: [[@LINE-1]]:8: warning: non-const reference {{.*}}
+ virtual void f(int &a) {}
+// CHECK-MESSAGES: [[@LINE-1]]:23: warning: non-const reference {{.*}}
+ void g(int &b);
+// CHECK-MESSAGES: [[@LINE-1]]:15: warning: non-const reference {{.*}}
+
+ // Don't warn on the parameter of stream extractors defined as members.
+ B& operator>>(int& val) { return *this; }
+};
+
+// Only warn on the first declaration of each function to reduce duplicate
+// warnings.
+void B::g(int &b) {}
+
+// Don't warn on the first parameter of stream inserters.
+A& operator<<(A& s, int&) { return s; }
+// CHECK-MESSAGES: [[@LINE-1]]:25: warning: non-const reference parameter at index 1, {{.*}}
+
+// Don't warn on either parameter of stream extractors. Both need to be
+// non-const references by convention.
+A& operator>>(A& input, int& val) { return input; }
+
+// Don't warn on lambdas.
+auto lambda = [] (int&) {};
+
+// Don't warn on typedefs, as we'll warn on the function itself.
+typedef int (*fp)(int &);
+
+// Don't warn on function references.
+typedef void F();
+void g5(const F& func) {}
+void g6(F& func) {}
+
+template<typename T>
+void g7(const T& t) {}
+
+template<typename T>
+void g8(T t) {}
+
+void f5() {
+ g5(f5);
+ g6(f5);
+ g7(f5);
+ g7<F&>(f5);
+ g8(f5);
+ g8<F&>(f5);
+}
+
+// Don't warn on dependent types.
+template<typename T>
+void g9(T& t) {}
+template<typename T>
+void g10(T t) {}
+
+void f6() {
+ int i;
+ float f;
+ g9<int>(i);
+ g9<const int>(i);
+ g9<int&>(i);
+ g10<int&>(i);
+ g10<float&>(f);
+}
+
+// Warn only on the overridden methods from the base class, as the child class
+// only implements the interface.
+class C : public B {
+ C();
+ virtual void f(int &a) {}
+};
+
+// Don't warn on operator<< with streams-like interface.
+A& operator<<(A& s, int) { return s; }
+
+// Don't warn on swap().
+void swap(C& c1, C& c2) {}
+
+// Don't warn on standalone operator++, operator--, operator+=, operator-=,
+// operator*=, etc. that all need non-const references to be functional.
+A& operator++(A& a) { return a; }
+A operator++(A& a, int) { return a; }
+A& operator--(A& a) { return a; }
+A operator--(A& a, int) { return a; }
+A& operator+=(A& a, const A& b) { return a; }
+A& operator-=(A& a, const A& b) { return a; }
+A& operator*=(A& a, const A& b) { return a; }
+A& operator/=(A& a, const A& b) { return a; }
+A& operator%=(A& a, const A& b) { return a; }
+A& operator<<=(A& a, const A& b) { return a; }
+A& operator>>=(A& a, const A& b) { return a; }
+A& operator|=(A& a, const A& b) { return a; }
+A& operator^=(A& a, const A& b) { return a; }
+A& operator&=(A& a, const A& b) { return a; }
+
+namespace whitelist {
+class A {};
+class B {};
+void f7(A &);
+void f8(B &);
+}
+void f9(whitelist::A &);
+void f10(whitelist::B &);
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-exception-baseclass.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-exception-baseclass.cpp
new file mode 100644
index 0000000..9a0638b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-exception-baseclass.cpp
@@ -0,0 +1,179 @@
+// RUN: %check_clang_tidy %s hicpp-exception-baseclass %t -- -- -fcxx-exceptions
+
+namespace std {
+class exception {};
+} // namespace std
+
+class derived_exception : public std::exception {};
+class deep_hierarchy : public derived_exception {};
+class non_derived_exception {};
+class terrible_idea : public non_derived_exception, public derived_exception {};
+
+// FIXME: More complicated kinds of inheritance should be checked later, but there is
+// currently no way use ASTMatchers for this kind of task.
+#if 0
+class bad_inheritance : private std::exception {};
+class no_good_inheritance : protected std::exception {};
+class really_creative : public non_derived_exception, private std::exception {};
+#endif
+
+void problematic() {
+ try {
+ throw int(42);
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+ } catch (int e) {
+ }
+ throw int(42);
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+
+ try {
+ throw 12;
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+ } catch (...) {
+ throw; // Ok, even if the type is not known, conforming code can never rethrow a non-std::exception object.
+ }
+
+ try {
+ throw non_derived_exception();
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception'
+ // CHECK-MESSAGES: 9:1: note: type defined here
+ } catch (non_derived_exception &e) {
+ }
+ throw non_derived_exception();
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception'
+ // CHECK-MESSAGES: 9:1: note: type defined here
+
+// FIXME: More complicated kinds of inheritance should be checked later, but there is
+// currently no way use ASTMatchers for this kind of task.
+#if 0
+ // Handle private inheritance cases correctly.
+ try {
+ throw bad_inheritance();
+ // CHECK MESSAGES: [[@LINE-1]]:11: warning: throwing an exception whose type 'bad_inheritance' is not derived from 'std::exception'
+ // CHECK MESSAGES: 10:1: note: type defined here
+ throw no_good_inheritance();
+ // CHECK MESSAGES: [[@LINE-1]]:11: warning: throwing an exception whose type 'no_good_inheritance' is not derived from 'std::exception'
+ // CHECK MESSAGES: 11:1: note: type defined here
+ throw really_creative();
+ // CHECK MESSAGES: [[@LINE-1]]:11: warning: throwing an exception whose type 'really_creative' is not derived from 'std::exception'
+ // CHECK MESSAGES: 12:1: note: type defined here
+ } catch (...) {
+ }
+ throw bad_inheritance();
+ // CHECK MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_inheritance' is not derived from 'std::exception'
+ // CHECK MESSAGES: 10:1: note: type defined here
+ throw no_good_inheritance();
+ // CHECK MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'no_good_inheritance' is not derived from 'std::exception'
+ // CHECK MESSAGES: 11:1: note: type defined here
+ throw really_creative();
+ // CHECK MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'really_creative' is not derived from 'std::exception'
+ // CHECK MESSAGES: 12:1: note: type defined here
+#endif
+}
+
+void allowed_throws() {
+ try {
+ throw std::exception(); // Ok
+ } catch (std::exception &e) { // Ok
+ }
+ throw std::exception();
+
+ try {
+ throw derived_exception(); // Ok
+ } catch (derived_exception &e) { // Ok
+ }
+ throw derived_exception(); // Ok
+
+ try {
+ throw deep_hierarchy(); // Ok, multiple levels of inheritance
+ } catch (deep_hierarchy &e) { // Ok
+ }
+ throw deep_hierarchy(); // Ok
+
+ try {
+ throw terrible_idea(); // Ok, but multiple inheritance isn't clean
+ } catch (std::exception &e) { // Can be caught as std::exception, even with multiple inheritance
+ }
+ throw terrible_idea(); // Ok, but multiple inheritance
+}
+
+// Templated function that throws exception based on template type
+template <typename T>
+void ThrowException() { throw T(); }
+// CHECK-MESSAGES: [[@LINE-1]]:31: warning: throwing an exception whose type 'bad_generic_exception<int>' is not derived from 'std::exception'
+// CHECK-MESSAGES: 120:1: note: type defined here
+// CHECK-MESSAGES: [[@LINE-3]]:31: warning: throwing an exception whose type 'bad_generic_exception<std::exception>' is not derived from 'std::exception'
+// CHECK-MESSAGES: 120:1: note: type defined here
+// CHECK-MESSAGES: [[@LINE-5]]:31: warning: throwing an exception whose type 'exotic_exception<non_derived_exception>' is not derived from 'std::exception'
+// CHECK-MESSAGES: 123:1: note: type defined here
+// CHECK-MESSAGES: [[@LINE-7]]:31: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+// CHECK-MESSAGES: [[@LINE-8]]:31: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception'
+// CHECK-MESSAGES: 9:1: note: type defined here
+#define THROW_EXCEPTION(CLASS) ThrowException<CLASS>()
+#define THROW_BAD_EXCEPTION throw int(42);
+#define THROW_GOOD_EXCEPTION throw std::exception();
+#define THROW_DERIVED_EXCEPTION throw deep_hierarchy();
+
+template <typename T>
+class generic_exception : std::exception {};
+
+template <typename T>
+class bad_generic_exception {};
+
+template <typename T>
+class exotic_exception : public T {};
+
+void generic_exceptions() {
+ THROW_EXCEPTION(int);
+ // CHECK MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+ THROW_EXCEPTION(non_derived_exception);
+ // CHECK MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception'
+ // CHECK MESSAGES: 9:1: note: type defined here
+ THROW_EXCEPTION(std::exception); // Ok
+ THROW_EXCEPTION(derived_exception); // Ok
+ THROW_EXCEPTION(deep_hierarchy); // Ok
+
+ THROW_BAD_EXCEPTION;
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type 'int' is not derived from 'std::exception'
+ // CHECK-MESSAGES: [[@LINE-25]]:35: note: expanded from macro 'THROW_BAD_EXCEPTION'
+ THROW_GOOD_EXCEPTION;
+ THROW_DERIVED_EXCEPTION;
+
+ throw generic_exception<int>(); // Ok,
+ THROW_EXCEPTION(generic_exception<float>); // Ok
+
+ throw bad_generic_exception<int>();
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_generic_exception<int>' is not derived from 'std::exception'
+ throw bad_generic_exception<std::exception>();
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_generic_exception<std::exception>' is not derived from 'std::exception'
+ THROW_EXCEPTION(bad_generic_exception<int>);
+ // CHECK MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type 'bad_generic_exception<int>' is not derived from 'std::exception'
+ THROW_EXCEPTION(bad_generic_exception<std::exception>);
+ // CHECK MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type 'bad_generic_exception<std::exception>' is not derived from 'std::exception'
+
+ throw exotic_exception<non_derived_exception>();
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'exotic_exception<non_derived_exception>' is not derived from 'std::exception'
+ THROW_EXCEPTION(exotic_exception<non_derived_exception>);
+ // CHECK MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type 'exotic_exception<non_derived_exception>' is not derived from 'std::exception'
+
+ throw exotic_exception<derived_exception>(); // Ok
+ THROW_EXCEPTION(exotic_exception<derived_exception>); // Ok
+}
+
+// Test for typedefed exception types
+typedef int TypedefedBad;
+typedef derived_exception TypedefedGood;
+using UsingBad = int;
+using UsingGood = deep_hierarchy;
+
+void typedefed() {
+ throw TypedefedBad();
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'TypedefedBad' (aka 'int') is not derived from 'std::exception'
+ // CHECK-MESSAGES: 164:1: note: type defined here
+ throw TypedefedGood(); // Ok
+
+ throw UsingBad();
+ // CHECK-MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'UsingBad' (aka 'int') is not derived from 'std::exception'
+ // CHECK-MESSAGES: 166:1: note: type defined here
+ throw UsingGood(); // Ok
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-multiway-paths-covered-else.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-multiway-paths-covered-else.cpp
new file mode 100644
index 0000000..34820b5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-multiway-paths-covered-else.cpp
@@ -0,0 +1,57 @@
+// RUN: %check_clang_tidy %s hicpp-multiway-paths-covered %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: hicpp-multiway-paths-covered.WarnOnMissingElse, value: 1}]}'\
+// RUN: --
+
+enum OS { Mac,
+ Windows,
+ Linux };
+
+void problematic_if(int i, enum OS os) {
+ if (i > 0) {
+ return;
+ } else if (i < 0) {
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: potentially uncovered codepath; add an ending else statement
+ return;
+ }
+
+ // Could be considered as false positive because all paths are covered logically.
+ // I still think this is valid since the possibility of a final 'everything else'
+ // codepath is expected from if-else if.
+ if (i > 0) {
+ return;
+ } else if (i <= 0) {
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: potentially uncovered codepath; add an ending else statement
+ return;
+ }
+
+ // Test if nesting of if-else chains does get caught as well.
+ if (os == Mac) {
+ return;
+ } else if (os == Linux) {
+ // These checks are kind of degenerated, but the check will not try to solve
+ // if logically all paths are covered, which is more the area of the static analyzer.
+ if (true) {
+ return;
+ } else if (false) {
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: potentially uncovered codepath; add an ending else statement
+ return;
+ }
+ return;
+ } else {
+ /* unreachable */
+ if (true) // check if the parent would match here as well
+ return;
+ // No warning for simple if statements, since it is common to just test one condition
+ // and ignore the opposite.
+ }
+
+ // Ok, because all paths are covered
+ if (i > 0) {
+ return;
+ } else if (i < 0) {
+ return;
+ } else {
+ /* error, maybe precondition failed */
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-multiway-paths-covered.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-multiway-paths-covered.cpp
new file mode 100644
index 0000000..15a3407
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-multiway-paths-covered.cpp
@@ -0,0 +1,468 @@
+// RUN: %check_clang_tidy %s hicpp-multiway-paths-covered %t
+
+enum OS { Mac,
+ Windows,
+ Linux };
+
+struct Bitfields {
+ unsigned UInt : 3;
+ int SInt : 1;
+};
+
+int return_integer() { return 42; }
+
+void bad_switch(int i) {
+ switch (i) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: switch with only one case; use an if statement
+ case 0:
+ break;
+ }
+ // No default in this switch
+ switch (i) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+ case 0:
+ break;
+ case 1:
+ break;
+ case 2:
+ break;
+ }
+
+ // degenerate, maybe even warning
+ switch (i) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: switch statement without labels has no effect
+ }
+
+ switch (int j = return_integer()) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+ case 0:
+ case 1:
+ case 2:
+ break;
+ }
+
+ // Degenerated, only default case.
+ switch (i) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: degenerated switch with default label only
+ default:
+ break;
+ }
+
+ // Degenerated, only one case label and default case -> Better as if-stmt.
+ switch (i) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: switch could be better written as an if/else statement
+ case 0:
+ break;
+ default:
+ break;
+ }
+
+ unsigned long long BigNumber = 0;
+ switch (BigNumber) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+ case 0:
+ case 1:
+ break;
+ }
+
+ const int &IntRef = i;
+ switch (IntRef) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+ case 0:
+ case 1:
+ break;
+ }
+
+ char C = 'A';
+ switch (C) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+ case 'A':
+ break;
+ case 'B':
+ break;
+ }
+
+ Bitfields Bf;
+ // UInt has 3 bits size.
+ switch (Bf.UInt) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+ case 0:
+ case 1:
+ break;
+ }
+ // All paths explicitly covered.
+ switch (Bf.UInt) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ break;
+ }
+ // SInt has 1 bit size, so this is somewhat degenerated.
+ switch (Bf.SInt) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: switch with only one case; use an if statement
+ case 0:
+ break;
+ }
+ // All paths explicitly covered.
+ switch (Bf.SInt) {
+ case 0:
+ case 1:
+ break;
+ }
+
+ bool Flag = false;
+ switch (Flag) {
+ // CHECK-MESSAGES:[[@LINE-1]]:3: warning: switch with only one case; use an if statement
+ case true:
+ break;
+ }
+
+ switch (Flag) {
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: degenerated switch with default label only
+ default:
+ break;
+ }
+
+ // This `switch` will create a frontend warning from '-Wswitch-bool' but is
+ // ok for this check.
+ switch (Flag) {
+ case true:
+ break;
+ case false:
+ break;
+ }
+}
+
+void unproblematic_switch(unsigned char c) {
+ //
+ switch (c) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ case 56:
+ case 57:
+ case 58:
+ case 59:
+ case 60:
+ case 61:
+ case 62:
+ case 63:
+ case 64:
+ case 65:
+ case 66:
+ case 67:
+ case 68:
+ case 69:
+ case 70:
+ case 71:
+ case 72:
+ case 73:
+ case 74:
+ case 75:
+ case 76:
+ case 77:
+ case 78:
+ case 79:
+ case 80:
+ case 81:
+ case 82:
+ case 83:
+ case 84:
+ case 85:
+ case 86:
+ case 87:
+ case 88:
+ case 89:
+ case 90:
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ case 95:
+ case 96:
+ case 97:
+ case 98:
+ case 99:
+ case 100:
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 106:
+ case 107:
+ case 108:
+ case 109:
+ case 110:
+ case 111:
+ case 112:
+ case 113:
+ case 114:
+ case 115:
+ case 116:
+ case 117:
+ case 118:
+ case 119:
+ case 120:
+ case 121:
+ case 122:
+ case 123:
+ case 124:
+ case 125:
+ case 126:
+ case 127:
+ case 128:
+ case 129:
+ case 130:
+ case 131:
+ case 132:
+ case 133:
+ case 134:
+ case 135:
+ case 136:
+ case 137:
+ case 138:
+ case 139:
+ case 140:
+ case 141:
+ case 142:
+ case 143:
+ case 144:
+ case 145:
+ case 146:
+ case 147:
+ case 148:
+ case 149:
+ case 150:
+ case 151:
+ case 152:
+ case 153:
+ case 154:
+ case 155:
+ case 156:
+ case 157:
+ case 158:
+ case 159:
+ case 160:
+ case 161:
+ case 162:
+ case 163:
+ case 164:
+ case 165:
+ case 166:
+ case 167:
+ case 168:
+ case 169:
+ case 170:
+ case 171:
+ case 172:
+ case 173:
+ case 174:
+ case 175:
+ case 176:
+ case 177:
+ case 178:
+ case 179:
+ case 180:
+ case 181:
+ case 182:
+ case 183:
+ case 184:
+ case 185:
+ case 186:
+ case 187:
+ case 188:
+ case 189:
+ case 190:
+ case 191:
+ case 192:
+ case 193:
+ case 194:
+ case 195:
+ case 196:
+ case 197:
+ case 198:
+ case 199:
+ case 200:
+ case 201:
+ case 202:
+ case 203:
+ case 204:
+ case 205:
+ case 206:
+ case 207:
+ case 208:
+ case 209:
+ case 210:
+ case 211:
+ case 212:
+ case 213:
+ case 214:
+ case 215:
+ case 216:
+ case 217:
+ case 218:
+ case 219:
+ case 220:
+ case 221:
+ case 222:
+ case 223:
+ case 224:
+ case 225:
+ case 226:
+ case 227:
+ case 228:
+ case 229:
+ case 230:
+ case 231:
+ case 232:
+ case 233:
+ case 234:
+ case 235:
+ case 236:
+ case 237:
+ case 238:
+ case 239:
+ case 240:
+ case 241:
+ case 242:
+ case 243:
+ case 244:
+ case 245:
+ case 246:
+ case 247:
+ case 248:
+ case 249:
+ case 250:
+ case 251:
+ case 252:
+ case 253:
+ case 254:
+ case 255:
+ break;
+ }
+
+ // Some paths are covered by the switch and a default case is present.
+ switch (c) {
+ case 1:
+ case 2:
+ case 3:
+ default:
+ break;
+ }
+}
+
+OS return_enumerator() {
+ return Linux;
+}
+
+// Enumpaths are already covered by a warning, this is just to ensure, that there is
+// no interference or false positives.
+// -Wswitch warns about uncovered enum paths and each here described case is already
+// covered.
+void switch_enums(OS os) {
+ switch (os) {
+ case Linux:
+ break;
+ }
+
+ switch (OS another_os = return_enumerator()) {
+ case Linux:
+ break;
+ }
+
+ switch (os) {
+ }
+}
+
+/// All of these cases will not emit a warning per default, but with explicit activation.
+/// Covered in extra test file.
+void problematic_if(int i, enum OS os) {
+ if (i > 0) {
+ return;
+ } else if (i < 0) {
+ return;
+ }
+
+ if (os == Mac) {
+ return;
+ } else if (os == Linux) {
+ if (true) {
+ return;
+ } else if (false) {
+ return;
+ }
+ return;
+ } else {
+ /* unreachable */
+ if (true) // check if the parent would match here as well
+ return;
+ }
+
+ // Ok, because all paths are covered
+ if (i > 0) {
+ return;
+ } else if (i < 0) {
+ return;
+ } else {
+ /* error, maybe precondition failed */
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-no-assembler-msvc.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-no-assembler-msvc.cpp
new file mode 100644
index 0000000..d29a9e9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-no-assembler-msvc.cpp
@@ -0,0 +1,11 @@
+// REQUIRES: system-windows
+// FIXME: Re-enable test on windows (PR36855)
+// UNSUPPORTED: system-windows
+// RUN: %check_clang_tidy %s hicpp-no-assembler %t
+
+void f() {
+ _asm {
+ mov al, 2;
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: do not use inline assembler in safety-critical code [hicpp-no-assembler]
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-no-assembler.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-no-assembler.cpp
new file mode 100644
index 0000000..d08ea74
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-no-assembler.cpp
@@ -0,0 +1,12 @@
+// RUN: %check_clang_tidy %s hicpp-no-assembler %t
+
+__asm__(".symver foo, bar@v");
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: do not use inline assembler in safety-critical code [hicpp-no-assembler]
+
+static int s asm("spam");
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use inline assembler in safety-critical code [hicpp-no-assembler]
+
+void f() {
+ __asm("mov al, 2");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use inline assembler in safety-critical code [hicpp-no-assembler]
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-signed-bitwise-bug34747.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-signed-bitwise-bug34747.cpp
new file mode 100644
index 0000000..217df71
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-signed-bitwise-bug34747.cpp
@@ -0,0 +1,29 @@
+// RUN: %check_clang_tidy %s hicpp-signed-bitwise %t --
+
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+
+template <typename C>
+struct OutputStream {
+ OutputStream &operator<<(C);
+};
+
+template <typename C>
+struct foo {
+ typedef OutputStream<C> stream_type;
+ foo(stream_type &o) {
+ o << 'x'; // warning occured here, fixed now
+ }
+};
+
+void bar(OutputStream<signed char> &o) {
+ foo<signed char> f(o);
+}
+
+void silence_lit() {
+ int SValue = 42;
+ int SResult;
+
+ SResult = SValue & 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-signed-bitwise-standard-types.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-signed-bitwise-standard-types.cpp
new file mode 100644
index 0000000..c85fe20
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-signed-bitwise-standard-types.cpp
@@ -0,0 +1,197 @@
+// RUN: clang-tidy %s -checks='-*,hicpp-signed-bitwise' -- -std=c++11
+
+#include "hicpp-signed-bitwise-standard-types.h"
+
+void pure_bitmask_types() {
+ // std::locale::category
+ int SResult = 0;
+ std::locale::category C = std::locale::category::ctype;
+
+ SResult = std::locale::category::none | std::locale::category::collate;
+ SResult|= std::locale::category::collate;
+ SResult = std::locale::category::ctype & std::locale::category::monetary;
+ SResult&= std::locale::category::monetary;
+ SResult = std::locale::category::numeric ^ std::locale::category::time;
+ SResult^= std::locale::category::time;
+ SResult = std::locale::category::messages | std::locale::category::all;
+
+ SResult = std::locale::category::all & C;
+ SResult&= std::locale::category::all;
+ SResult = std::locale::category::all | C;
+ SResult|= std::locale::category::all;
+ SResult = std::locale::category::all ^ C;
+ SResult^= std::locale::category::all;
+
+ // std::ctype_base::mask
+ std::ctype_base::mask M = std::ctype_base::mask::punct;
+
+ SResult = std::ctype_base::mask::space | std::ctype_base::mask::print;
+ SResult = std::ctype_base::mask::cntrl & std::ctype_base::mask::upper;
+ SResult = std::ctype_base::mask::lower ^ std::ctype_base::mask::alpha;
+ SResult|= std::ctype_base::mask::digit | std::ctype_base::mask::punct;
+ SResult&= std::ctype_base::mask::xdigit & std::ctype_base::mask::alnum;
+ SResult^= std::ctype_base::mask::alnum ^ std::ctype_base::mask::graph;
+
+ SResult&= std::ctype_base::mask::space & M;
+ SResult|= std::ctype_base::mask::space | M;
+ SResult^= std::ctype_base::mask::space ^ M;
+
+ // std::ios_base::fmtflags
+ std::ios_base::fmtflags F = std::ios_base::fmtflags::floatfield;
+
+ SResult = std::ios_base::fmtflags::dec | std::ios_base::fmtflags::oct;
+ SResult = std::ios_base::fmtflags::hex & std::ios_base::fmtflags::basefield;
+ SResult = std::ios_base::fmtflags::left ^ std::ios_base::fmtflags::right;
+ SResult|= std::ios_base::fmtflags::internal | std::ios_base::fmtflags::adjustfield;
+ SResult&= std::ios_base::fmtflags::scientific & std::ios_base::fmtflags::fixed;
+ SResult^= std::ios_base::fmtflags::floatfield ^ std::ios_base::fmtflags::boolalpha;
+ SResult = std::ios_base::fmtflags::showbase | std::ios_base::fmtflags::showpoint;
+ SResult = std::ios_base::fmtflags::showpos & std::ios_base::fmtflags::skipws;
+ SResult = std::ios_base::fmtflags::unitbuf ^ std::ios_base::fmtflags::uppercase;
+
+ SResult|= std::ios_base::fmtflags::unitbuf | F;
+ SResult&= std::ios_base::fmtflags::unitbuf & F;
+ SResult^= std::ios_base::fmtflags::unitbuf ^ F;
+
+ // std::ios_base::iostate
+ std::ios_base::iostate S = std::ios_base::iostate::goodbit;
+
+ SResult^= std::ios_base::iostate::goodbit | std::ios_base::iostate::badbit;
+ SResult|= std::ios_base::iostate::failbit & std::ios_base::iostate::eofbit;
+ SResult&= std::ios_base::iostate::failbit ^ std::ios_base::iostate::eofbit;
+
+ SResult = std::ios_base::iostate::goodbit | S;
+ SResult = std::ios_base::iostate::goodbit & S;
+ SResult = std::ios_base::iostate::goodbit ^ S;
+
+ // std::ios_base::openmode
+ std::ios_base::openmode B = std::ios_base::openmode::binary;
+
+ SResult = std::ios_base::openmode::app | std::ios_base::openmode::binary;
+ SResult = std::ios_base::openmode::in & std::ios_base::openmode::out;
+ SResult = std::ios_base::openmode::trunc ^ std::ios_base::openmode::ate;
+
+ SResult&= std::ios_base::openmode::trunc | B;
+ SResult^= std::ios_base::openmode::trunc & B;
+ SResult|= std::ios_base::openmode::trunc ^ B;
+}
+
+void still_forbidden() {
+ // std::locale::category
+ unsigned int UResult = 0u;
+ int SResult = 0;
+
+ SResult = std::ctype_base::mask::print ^ 8u;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult = std::ctype_base::mask::cntrl | 8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult = std::ctype_base::mask::upper & 8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult = std::ctype_base::mask::lower ^ -8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ // Staying within the allowed standard types is ok for bitwise assignment
+ // operations.
+ std::ctype_base::mask var = std::ctype_base::mask::print;
+ SResult<<= std::ctype_base::mask::upper;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult>>= std::ctype_base::mask::upper;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult &= std::ctype_base::mask::upper;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult |= std::ctype_base::mask::upper;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult ^= std::ctype_base::mask::upper;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = std::locale::category::collate << 1u;
+ UResult = std::locale::category::ctype << 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::locale::category::monetary >> 1u;
+ UResult = std::locale::category::numeric >> 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = ~std::locale::category::messages;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+ SResult = ~std::locale::category::all;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+
+ // std::ctype_base::mask
+ UResult = std::ctype_base::mask::space | 8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ctype_base::mask::print & 8u;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ctype_base::mask::cntrl ^ -8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = std::ctype_base::mask::upper << 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ctype_base::mask::lower << 1u;
+ UResult = std::ctype_base::mask::alpha >> 1u;
+ UResult = std::ctype_base::mask::digit >> 1u;
+
+ UResult = ~std::ctype_base::mask::punct;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+ SResult = ~std::ctype_base::mask::xdigit;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+
+ // std::ios_base::fmtflags
+ UResult = std::ios_base::fmtflags::dec | 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::fmtflags::oct & 1u;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::fmtflags::hex ^ -1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = std::ios_base::fmtflags::basefield >> 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::fmtflags::left >> 1u;
+ UResult = std::ios_base::fmtflags::right << 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::fmtflags::internal << 1u;
+
+ UResult = ~std::ios_base::fmtflags::adjustfield;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+ SResult = ~std::ios_base::fmtflags::scientific;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+
+ // std::ios_base::iostate
+ UResult = std::ios_base::iostate::goodbit | 8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::iostate::badbit & 8u;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::iostate::failbit ^ -8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = std::ios_base::iostate::eofbit << 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::iostate::goodbit << 1u;
+ UResult = std::ios_base::iostate::badbit >> 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::iostate::failbit >> 1u;
+
+ UResult = ~std::ios_base::iostate::eofbit;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+ SResult = ~std::ios_base::iostate::goodbit;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+
+ // std::ios_base::openmode
+ UResult = std::ios_base::app | 8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::binary & 8u;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::in ^ -8;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = std::ios_base::out >> 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::trunc >> 1u;
+ UResult = std::ios_base::ate << 1;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = std::ios_base::ate << 1u;
+
+ UResult = ~std::ios_base::openmode::app;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+ SResult = ~std::ios_base::openmode::binary;
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-signed-bitwise-standard-types.h b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-signed-bitwise-standard-types.h
new file mode 100644
index 0000000..e66fd09
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-signed-bitwise-standard-types.h
@@ -0,0 +1,81 @@
+#pragma clang system_header
+
+// Implement standard types that are known to be defined as unsigned in some
+// implementations like MSVC.
+namespace std {
+namespace locale {
+enum category : int {
+ none = 0u,
+ collate = 1u << 1u,
+ ctype = 1u << 2u,
+ monetary = 1u << 3u,
+ numeric = 1u << 4u,
+ time = 1u << 5u,
+ messages = 1u << 6u,
+ all = none | collate | ctype | monetary | numeric | time | messages
+ // CHECK MESSAGES: [[@LINE-1]]:9: warning: use of a signed integer operand with a binary bitwise operator
+};
+} // namespace locale
+
+namespace ctype_base {
+enum mask : int {
+ space,
+ print,
+ cntrl,
+ upper,
+ lower,
+ alpha,
+ digit,
+ punct,
+ xdigit,
+ /* blank, // C++11 */
+ alnum = alpha | digit,
+ // CHECK MESSAGES: [[@LINE-1]]:11: warning: use of a signed integer operand with a binary bitwise operator
+ graph = alnum | punct
+ // CHECK MESSAGES: [[@LINE-1]]:11: warning: use of a signed integer operand with a binary bitwise operator
+};
+} // namespace ctype_base
+
+namespace ios_base {
+enum fmtflags : int {
+ dec = 0u,
+ oct = 1u << 2u,
+ hex = 1u << 3u,
+ basefield = dec | oct | hex | 0u,
+ // CHECK MESSAGES: [[@LINE-1]]:15: warning: use of a signed integer operand with a binary bitwise operator
+ left = 1u << 4u,
+ right = 1u << 5u,
+ internal = 1u << 6u,
+ adjustfield = left | right | internal,
+ // CHECK MESSAGES: [[@LINE-1]]:17: warning: use of a signed integer operand with a binary bitwise operator
+ scientific = 1u << 7u,
+ fixed = 1u << 8u,
+ floatfield = scientific | fixed | (scientific | fixed) | 0u,
+ // CHECK MESSAGES: [[@LINE-1]]:16: warning: use of a signed integer operand with a binary bitwise operator
+ // CHECK MESSAGES: [[@LINE-2]]:38: warning: use of a signed integer operand with a binary bitwise operator
+ boolalpha = 1u << 9u,
+ showbase = 1u << 10u,
+ showpoint = 1u << 11u,
+ showpos = 1u << 12u,
+ skipws = 1u << 13u,
+ unitbuf = 1u << 14u,
+ uppercase = 1u << 15u
+};
+
+enum iostate : int {
+ goodbit = 0u,
+ badbit = 1u << 1u,
+ failbit = 1u << 2u,
+ eofbit = 1u << 3u
+};
+
+enum openmode : int {
+ app = 0u,
+ binary = 0u << 1u,
+ in = 0u << 2u,
+ out = 0u << 3u,
+ trunc = 0u << 4u,
+ ate = 0u << 5u
+};
+} // namespace ios_base
+} // namespace std
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-signed-bitwise.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-signed-bitwise.cpp
new file mode 100644
index 0000000..97a24b6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/hicpp-signed-bitwise.cpp
@@ -0,0 +1,240 @@
+// RUN: %check_clang_tidy %s hicpp-signed-bitwise %t -- -- -std=c++11 --target=x86_64-linux
+
+// These could cause false positives and should not be considered.
+struct StreamClass {
+};
+StreamClass &operator<<(StreamClass &os, unsigned int i) {
+ return os;
+}
+StreamClass &operator<<(StreamClass &os, int i) {
+ return os;
+}
+StreamClass &operator>>(StreamClass &os, unsigned int i) {
+ return os;
+}
+StreamClass &operator>>(StreamClass &os, int i) {
+ return os;
+}
+struct AnotherStream {
+ AnotherStream &operator<<(unsigned char c) { return *this; }
+ AnotherStream &operator<<(signed char c) { return *this; }
+
+ AnotherStream &operator>>(unsigned char c) { return *this; }
+ AnotherStream &operator>>(signed char c) { return *this; }
+};
+
+void binary_bitwise() {
+ int SValue = 42;
+ int SResult;
+
+ unsigned int UValue = 42;
+ unsigned int UResult;
+
+ SResult = SValue & 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult = SValue & -1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ SResult = SValue & SValue;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = SValue & 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult = SValue & -1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ UResult&= 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+
+ UResult = UValue & 1u; // Ok
+ UResult = UValue & UValue; // Ok
+ UResult&= 2u; // Ok
+
+ unsigned char UByte1 = 0u;
+ unsigned char UByte2 = 16u;
+ signed char SByte1 = 0;
+ signed char SByte2 = 16;
+
+ UByte1 = UByte1 & UByte2; // Ok
+ UByte1 = SByte1 & UByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1 = SByte1 & SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a binary bitwise operator
+ SByte1 = SByte1 & SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a binary bitwise operator
+
+ // More complex expressions.
+ UResult = UValue & (SByte1 + (SByte1 | SByte2));
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+ // CHECK-MESSAGES: :[[@LINE-2]]:33: warning: use of a signed integer operand with a binary bitwise operator
+
+ // The rest is to demonstrate functionality but all operators are matched equally.
+ // Therefore functionality is the same for all binary operations.
+ UByte1 = UByte1 | UByte2; // Ok
+ UByte1 = UByte1 | SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1|= SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1|= UByte2; // Ok
+
+ UByte1 = UByte1 ^ UByte2; // Ok
+ UByte1 = UByte1 ^ SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1^= SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1^= UByte2; // Ok
+
+ UByte1 = UByte1 >> UByte2; // Ok
+ UByte1 = UByte1 >> SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1>>= SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1>>= UByte2; // Ok
+
+ UByte1 = UByte1 << UByte2; // Ok
+ UByte1 = UByte1 << SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1<<= SByte2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+ UByte1<<= UByte2; // Ok
+
+ int SignedInt1 = 1 << 12;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use of a signed integer operand with a binary bitwise operator
+ int SignedInt2 = 1u << 12;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use of a signed integer operand with a binary bitwise operator
+}
+
+void f1(unsigned char c) {}
+void f2(signed char c) {}
+void f3(int c) {}
+
+void unary_bitwise() {
+ unsigned char UByte1 = 0u;
+ signed char SByte1 = 0;
+
+ UByte1 = ~UByte1; // Ok
+ SByte1 = ~UByte1;
+ SByte1 = ~SByte1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a unary bitwise operator
+ UByte1 = ~SByte1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use of a signed integer operand with a unary bitwise operator
+
+ unsigned int UInt = 0u;
+ int SInt = 0;
+
+ f1(~UByte1); // Ok
+ f1(~SByte1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use of a signed integer operand with a unary bitwise operator
+ f1(~UInt);
+ f1(~SInt);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use of a signed integer operand with a unary bitwise operator
+ f2(~UByte1);
+ f2(~SByte1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use of a signed integer operand with a unary bitwise operator
+ f2(~UInt);
+ f2(~SInt);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use of a signed integer operand with a unary bitwise operator
+ f3(~UByte1); // Ok
+ f3(~SByte1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use of a signed integer operand with a unary bitwise operator
+}
+
+/// HICPP uses these examples to demonstrate the rule.
+void standard_examples() {
+ int i = 3;
+ unsigned int k = 0u;
+
+ int r = i << -1; // Emits -Wshift-count-negative from clang
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use of a signed integer operand with a binary bitwise operator
+ r = i << 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a binary bitwise operator
+
+ r = -1 >> -1; // Emits -Wshift-count-negative from clang
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a binary bitwise operator
+ r = -1 >> 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a binary bitwise operator
+
+ r = -1 >> i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a binary bitwise operator
+ r = -1 >> -i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a binary bitwise operator
+
+ r = ~0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a unary bitwise operator
+ r = ~0u; // Ok
+ k = ~k; // Ok
+
+ unsigned int u = (-1) & 2u;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use of a signed integer operand with a binary bitwise operator
+ u = (-1) | 1u;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a binary bitwise operator
+ u = (-1) ^ 1u;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use of a signed integer operand with a binary bitwise operator
+}
+
+void streams_should_work() {
+ StreamClass s;
+ s << 1u; // Ok
+ s << 1; // Ok
+ s >> 1; // Ok
+ s >> 1u; // Ok
+
+ AnotherStream as;
+ unsigned char uc = 1u;
+ signed char sc = 1;
+ as << uc; // Ok
+ as << sc; // Ok
+ as >> uc; // Ok
+ as >> sc; // Ok
+}
+
+enum OldEnum {
+ ValueOne,
+ ValueTwo,
+};
+
+enum OldSigned : int {
+ IntOne,
+ IntTwo,
+};
+
+void classicEnums() {
+ OldEnum e1 = ValueOne, e2 = ValueTwo;
+ int e3; // Using the enum type, results in an error.
+ e3 = ValueOne | ValueTwo; // Ok
+ e3 = ValueOne & ValueTwo; // Ok
+ e3 = ValueOne ^ ValueTwo; // Ok
+ e3 = e1 | e2; // Ok
+ e3 = e1 & e2; // Ok
+ e3 = e1 ^ e2; // Ok
+
+ OldSigned s1 = IntOne, s2 = IntTwo;
+ int s3;
+ s3 = IntOne | IntTwo; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: use of a signed integer operand with a binary bitwise operator
+ s3|= IntTwo; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+ s3 = IntOne & IntTwo; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: use of a signed integer operand with a binary bitwise operator
+ s3&= IntTwo; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+ s3 = IntOne ^ IntTwo; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: use of a signed integer operand with a binary bitwise operator
+ s3^= IntTwo; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use of a signed integer operand with a binary bitwise operator
+ s3 = s1 | s2; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: use of a signed integer operand with a binary bitwise operator
+ s3 = s1 & s2; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: use of a signed integer operand with a binary bitwise operator
+ s3 = s1 ^ s2; // Signed
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: use of a signed integer operand with a binary bitwise operator
+}
+
+enum EnumConstruction {
+ one = 1,
+ two = 2,
+ test1 = 1 << 12,
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: use of a signed integer operand with a binary bitwise operator
+ test2 = one << two,
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: use of a signed integer operand with a binary bitwise operator
+ test3 = 1u << 12,
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: use of a signed integer operand with a binary bitwise operator
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/line-filter.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/line-filter.cpp
new file mode 100644
index 0000000..ad980cf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/line-filter.cpp
@@ -0,0 +1,27 @@
+// RUN: clang-tidy -checks='-*,google-explicit-constructor' -line-filter='[{"name":"line-filter.cpp","lines":[[18,18],[22,22]]},{"name":"header1.h","lines":[[1,2]]},{"name":"header2.h"},{"name":"header3.h"}]' -header-filter='header[12]\.h$' %s -- -I %S/Inputs/line-filter 2>&1 | FileCheck %s
+
+#include "header1.h"
+// CHECK-NOT: header1.h:{{.*}} warning
+// CHECK: header1.h:1:12: warning: single-argument constructors must be marked explicit
+// CHECK: header1.h:2:12: warning: single-argument constructors {{.*}}
+// CHECK-NOT: header1.h:{{.*}} warning
+
+#include "header2.h"
+// CHECK: header2.h:1:12: warning: single-argument constructors {{.*}}
+// CHECK: header2.h:2:12: warning: single-argument constructors {{.*}}
+// CHECK: header2.h:3:12: warning: single-argument constructors {{.*}}
+// CHECK-NOT: header2.h:{{.*}} warning
+
+#include "header3.h"
+// CHECK-NOT: header3.h:{{.*}} warning
+
+class A { A(int); };
+// CHECK: :[[@LINE-1]]:11: warning: single-argument constructors {{.*}}
+class B { B(int); };
+// CHECK-NOT: :[[@LINE-1]]:{{.*}} warning
+class C { C(int); };
+// CHECK: :[[@LINE-1]]:11: warning: single-argument constructors {{.*}}
+
+// CHECK-NOT: warning:
+
+// CHECK: Suppressed 3 warnings (1 in non-user code, 2 due to line filter)
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/list-checks.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/list-checks.cpp
new file mode 100644
index 0000000..674c118
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/list-checks.cpp
@@ -0,0 +1,4 @@
+// RUN: mkdir -p %T/clang-tidy/list-checks/
+// RUN: echo '{Checks: "-*,google-*"}' > %T/clang-tidy/.clang-tidy
+// RUN: cd %T/clang-tidy/list-checks
+// RUN: clang-tidy -list-checks | grep "^ *google-"
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/llvm-include-order.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/llvm-include-order.cpp
new file mode 100644
index 0000000..7272353
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/llvm-include-order.cpp
@@ -0,0 +1,42 @@
+// RUN: %check_clang_tidy %s llvm-include-order %t -- -- -isystem %S/Inputs/Headers
+
+// CHECK-MESSAGES: [[@LINE+2]]:1: warning: #includes are not sorted properly
+#include "j.h"
+#include "gtest/foo.h"
+#include "i.h"
+#include <s.h>
+#include "llvm/a.h"
+#include "clang/b.h"
+#include "clang-c/c.h" // hi
+#include "llvm-c/d.h" // -c
+
+// CHECK-FIXES: #include "j.h"
+// CHECK-FIXES-NEXT: #include "i.h"
+// CHECK-FIXES-NEXT: #include "clang-c/c.h" // hi
+// CHECK-FIXES-NEXT: #include "clang/b.h"
+// CHECK-FIXES-NEXT: #include "llvm-c/d.h" // -c
+// CHECK-FIXES-NEXT: #include "llvm/a.h"
+// CHECK-FIXES-NEXT: #include "gtest/foo.h"
+// CHECK-FIXES-NEXT: #include <s.h>
+
+#include "b.h"
+#ifdef FOO
+#include "a.h"
+#endif
+
+// CHECK-FIXES: #include "b.h"
+// CHECK-FIXES-NEXT: #ifdef FOO
+// CHECK-FIXES-NEXT: #include "a.h"
+// CHECK-FIXES-NEXT: #endif
+
+// CHECK-MESSAGES: [[@LINE+1]]:1: warning: #includes are not sorted properly
+#include "b.h"
+#include "a.h"
+
+// CHECK-FIXES: #include "a.h"
+// CHECK-FIXES-NEXT: #include "b.h"
+
+// CHECK-MESSAGES-NOT: [[@LINE+1]]:1: warning: #includes are not sorted properly
+#include "cross-file-c.h"
+// This line number should correspond to the position of the #include in cross-file-c.h
+#include "cross-file-a.h"
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/llvm-twine-local.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/llvm-twine-local.cpp
new file mode 100644
index 0000000..06eb761
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/llvm-twine-local.cpp
@@ -0,0 +1,64 @@
+// RUN: %check_clang_tidy %s llvm-twine-local %t
+
+namespace llvm {
+class Twine {
+public:
+ Twine(const char *);
+ Twine(int);
+ Twine();
+ Twine &operator+(const Twine &);
+};
+}
+
+using namespace llvm;
+
+void foo(const Twine &x);
+
+static Twine Moo = Twine("bark") + "bah";
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: static std::string Moo = (Twine("bark") + "bah").str();
+
+int main() {
+ const Twine t = Twine("a") + "b" + Twine(42);
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: std::string t = (Twine("a") + "b" + Twine(42)).str();
+ foo(Twine("a") + "b");
+
+ Twine Prefix = false ? "__INT_FAST" : "__UINT_FAST";
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: const char * Prefix = false ? "__INT_FAST" : "__UINT_FAST";
+
+ const Twine t2 = Twine();
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: std::string t2 = (Twine()).str();
+ foo(Twine() + "b");
+
+ const Twine t3 = Twine(42);
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: std::string t3 = (Twine(42)).str();
+
+ const Twine t4 = Twine(42) + "b";
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: std::string t4 = (Twine(42) + "b").str();
+
+ const Twine t5 = Twine() + "b";
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: std::string t5 = (Twine() + "b").str();
+
+ const Twine t6 = true ? Twine() : Twine(42);
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: std::string t6 = (true ? Twine() : Twine(42)).str();
+
+ const Twine t7 = false ? Twine() : Twine("b");
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: twine variables are prone to use-after-free bugs
+// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
+// CHECK-FIXES: std::string t7 = (false ? Twine() : Twine("b")).str();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/macros.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/macros.cpp
new file mode 100644
index 0000000..fa4f32a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/macros.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-tidy -checks='-*,google-explicit-constructor' %s -- | FileCheck %s
+
+#define Q(name) class name { name(int i); }
+
+Q(A);
+// CHECK: :[[@LINE-1]]:3: warning: single-argument constructors must be marked explicit
+// CHECK: :3:30: note: expanded from macro 'Q'
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-definitions-in-headers-1z.hpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-definitions-in-headers-1z.hpp
new file mode 100644
index 0000000..79fb7bc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-definitions-in-headers-1z.hpp
@@ -0,0 +1,10 @@
+// RUN: %check_clang_tidy %s misc-definitions-in-headers %t -- -- -std=c++1z
+
+class CE {
+ constexpr static int i = 5; // OK: inline variable definition.
+};
+
+inline int i = 5; // OK: inline variable definition.
+
+int b = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: variable 'b' defined in a header file; variable definitions in header files can lead to ODR violations [misc-definitions-in-headers]
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-definitions-in-headers.hpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-definitions-in-headers.hpp
new file mode 100644
index 0000000..5e83e68
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-definitions-in-headers.hpp
@@ -0,0 +1,181 @@
+// RUN: %check_clang_tidy %s misc-definitions-in-headers %t
+
+int f() {
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'f' defined in a header file; function definitions in header files can lead to ODR violations [misc-definitions-in-headers]
+// CHECK-FIXES: inline int f() {
+ return 1;
+}
+
+class CA {
+ void f1() {} // OK: inline class member function definition.
+ void f2();
+ template<typename T>
+ T f3() {
+ T a = 1;
+ return a;
+ }
+ template<typename T>
+ struct CAA {
+ struct CAB {
+ void f4();
+ };
+ };
+};
+
+void CA::f2() { }
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: function 'f2' defined in a header file;
+// CHECK-FIXES: inline void CA::f2() {
+
+template <>
+int CA::f3() {
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: full function template specialization 'f3<int>' defined in a header file;
+// CHECK-FIXES: inline int CA::f3() {
+ int a = 1;
+ return a;
+}
+
+template <typename T>
+void CA::CAA<T>::CAB::f4() {
+// OK: member function definition of a nested template class in a class.
+}
+
+template <typename T>
+struct CB {
+ void f1();
+ struct CCA {
+ void f2(T a);
+ };
+ struct CCB; // OK: forward declaration.
+ static int a; // OK: class static data member declaration.
+};
+
+template <typename T>
+void CB<T>::f1() { // OK: Member function definition of a class template.
+}
+
+template <typename T>
+void CB<T>::CCA::f2(T a) {
+// OK: member function definition of a nested class in a class template.
+}
+
+template <typename T>
+struct CB<T>::CCB {
+ void f3();
+};
+
+template <typename T>
+void CB<T>::CCB::f3() {
+// OK: member function definition of a nested class in a class template.
+}
+
+template <typename T>
+int CB<T>::a = 2; // OK: static data member definition of a class template.
+
+template class CB<int>; // OK: explicitly instantiated static data member of a class template.
+inline int callCB() {
+ CB<double> cb; // OK: implicitly instantiated static data member of a class template.
+ return cb.a;
+}
+
+template <typename T>
+T tf() { // OK: template function definition.
+ T a;
+ return a;
+}
+
+
+namespace NA {
+ int f() { return 1; }
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: function 'f' defined in a header file;
+// CHECK-FIXES: inline int f() { return 1; }
+}
+
+template <typename T>
+T f3() {
+ T a = 1;
+ return a;
+}
+
+template <>
+int f3() {
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: full function template specialization 'f3<int>' defined in a header file;
+// CHECK-FIXES: inline int f3() {
+ int a = 1;
+ return a;
+}
+
+int f5(); // OK: function declaration.
+inline int f6() { return 1; } // OK: inline function definition.
+namespace {
+ int f7() { return 1; }
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: function 'f7' defined in a header file;
+}
+
+int f8() = delete; // OK: the function being marked delete is not callable.
+
+template <typename T>
+int f9(T t) { return 1; }
+
+inline void callF9() { f9(1); } // OK: implicitly instantiated function.
+template int f9(double); // OK: explicitly instantiated function.
+
+int a = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: variable 'a' defined in a header file; variable definitions in header files can lead to ODR violations [misc-definitions-in-headers]
+CA a1;
+// CHECK-MESSAGES: :[[@LINE-1]]:4: warning: variable 'a1' defined in a header file;
+
+namespace NB {
+ int b = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: variable 'b' defined in a header file;
+ const int c = 1; // OK: internal linkage variable definition.
+}
+
+class CC {
+ static int d; // OK: class static data member declaration.
+};
+
+int CC::d = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: variable 'd' defined in a header file;
+
+const char* ca = "foo";
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: variable 'ca' defined in a header file;
+
+namespace {
+ int e = 2;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: variable 'e' defined in a header file;
+}
+
+const char* const g = "foo"; // OK: internal linkage variable definition.
+static int h = 1; // OK: internal linkage variable definition.
+const int i = 1; // OK: internal linkage variable definition.
+extern int j; // OK: internal linkage variable definition.
+
+template <typename T, typename U>
+struct CD {
+ int f();
+};
+
+template <typename T>
+struct CD<T, int> {
+ int f();
+};
+
+template <>
+struct CD<int, int> {
+ int f();
+};
+
+int CD<int, int>::f() {
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: function 'f' defined in a header file;
+// CHECK-FIXES: inline int CD<int, int>::f() {
+ return 0;
+}
+
+template <typename T>
+int CD<T, int>::f() { // OK: partial template specialization.
+ return 0;
+}
+
+constexpr int k = 1; // OK: constexpr variable has internal linkage.
+
+constexpr int f10() { return 0; } // OK: constexpr function definition.
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-misplaced-const-cxx17.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-misplaced-const-cxx17.cpp
new file mode 100644
index 0000000..7816a09
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-misplaced-const-cxx17.cpp
@@ -0,0 +1,15 @@
+// RUN: %check_clang_tidy -expect-clang-tidy-error %s misc-misplaced-const %t -- -- -std=c++17
+
+// This test previously would cause a failed assertion because the structured
+// binding declaration had no valid type associated with it. This ensures the
+// expected clang diagnostic is generated instead.
+// CHECK-MESSAGES: :[[@LINE+1]]:6: error: decomposition declaration '[x]' requires an initializer [clang-diagnostic-error]
+auto [x];
+
+struct S { int a; };
+S f();
+
+int main() {
+ auto [x] = f();
+}
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-misplaced-const.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-misplaced-const.c
new file mode 100644
index 0000000..cccf3a4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-misplaced-const.c
@@ -0,0 +1,45 @@
+// RUN: %check_clang_tidy %s misc-misplaced-const %t
+
+typedef int plain_i;
+typedef int *ip;
+typedef const int *cip;
+
+typedef void (*func_ptr)(void);
+
+void func(void) {
+ // ok
+ const int *i0 = 0;
+ const plain_i *i1 = 0;
+ const cip i2 = 0; // const applies to both pointer and pointee.
+
+ // Not ok
+ const ip i3 = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'i3' declared with a const-qualified typedef type; results in the type being 'int *const' instead of 'const int *'
+
+ ip const i4 = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'i4' declared with a const-qualified
+
+ const volatile ip i5 = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: 'i5' declared with a const-qualified typedef type; results in the type being 'int *const volatile' instead of 'const int *volatile'
+}
+
+void func2(const plain_i *i1,
+ const cip i2,
+ const ip i3,
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: 'i3' declared with a const-qualified
+ const int *i4) {
+}
+
+struct S {
+ const int *i0;
+ const plain_i *i1;
+ const cip i2;
+ const ip i3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'i3' declared with a const-qualified
+};
+
+// Function pointers should not be diagnosed because a function
+// pointer type can never be const.
+void func3(const func_ptr fp) {
+ const func_ptr fp2 = fp;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-misplaced-const.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-misplaced-const.cpp
new file mode 100644
index 0000000..d7ea893
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-misplaced-const.cpp
@@ -0,0 +1,44 @@
+// RUN: %check_clang_tidy %s misc-misplaced-const %t
+
+typedef int plain_i;
+typedef int *ip;
+typedef const int *cip;
+
+void func() {
+ if (const int *i = 0)
+ ;
+ if (const plain_i *i = 0)
+ ;
+ if (const cip i = 0)
+ ;
+
+ // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: 'i' declared with a const-qualified typedef type; results in the type being 'int *const' instead of 'const int *'
+ if (const ip i = 0)
+ ;
+}
+
+template <typename Ty>
+struct S {
+ const Ty *i;
+ const Ty &i2;
+};
+
+template struct S<int>;
+template struct S<ip>; // ok
+template struct S<cip>;
+
+template <typename Ty>
+struct U {
+ const Ty *i;
+ const Ty &i2;
+};
+
+template struct U<int *>; // ok
+
+struct T {
+ typedef void (T::*PMF)();
+
+ void f() {
+ const PMF val = &T::f; // ok
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-new-delete-overloads-sized-dealloc.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-new-delete-overloads-sized-dealloc.cpp
new file mode 100644
index 0000000..2ba60e4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-new-delete-overloads-sized-dealloc.cpp
@@ -0,0 +1,20 @@
+// RUN: %check_clang_tidy %s misc-new-delete-overloads %t -- -- -std=c++14 -fsized-deallocation
+
+typedef decltype(sizeof(int)) size_t;
+
+struct S {
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: declaration of 'operator delete' has no matching declaration of 'operator new' at the same scope [misc-new-delete-overloads]
+ void operator delete(void *ptr, size_t) noexcept; // not a placement delete
+};
+
+struct T {
+ // Because we have enabled sized deallocations explicitly, this new/delete
+ // pair matches.
+ void *operator new(size_t size) noexcept;
+ void operator delete(void *ptr, size_t) noexcept; // ok because sized deallocation is enabled
+};
+
+// While we're here, check that global operator delete with no operator new
+// is also matched.
+// CHECK-MESSAGES: :[[@LINE+1]]:6: warning: declaration of 'operator delete' has no matching declaration of 'operator new' at the same scope
+void operator delete(void *ptr) noexcept;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-new-delete-overloads.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-new-delete-overloads.cpp
new file mode 100644
index 0000000..3e60537
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-new-delete-overloads.cpp
@@ -0,0 +1,81 @@
+// RUN: %check_clang_tidy %s misc-new-delete-overloads %t -- -- -std=c++14
+
+typedef decltype(sizeof(int)) size_t;
+
+struct S {
+ // CHECK-MESSAGES: :[[@LINE+1]]:9: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope [misc-new-delete-overloads]
+ void *operator new(size_t size) noexcept;
+ // CHECK-MESSAGES: :[[@LINE+1]]:9: warning: declaration of 'operator new[]' has no matching declaration of 'operator delete[]' at the same scope
+ void *operator new[](size_t size) noexcept;
+};
+
+// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope
+void *operator new(size_t size) noexcept(false);
+
+struct T {
+ // Sized deallocations are not enabled by default, and so this new/delete pair
+ // does not match. However, we expect only one warning, for the new, because
+ // the operator delete is a placement delete and we do not warn on mismatching
+ // placement operations.
+ // CHECK-MESSAGES: :[[@LINE+1]]:9: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope
+ void *operator new(size_t size) noexcept;
+ void operator delete(void *ptr, size_t) noexcept; // ok only if sized deallocation is enabled
+};
+
+struct U {
+ void *operator new(size_t size) noexcept;
+ void operator delete(void *ptr) noexcept;
+
+ void *operator new[](size_t) noexcept;
+ void operator delete[](void *) noexcept;
+};
+
+struct Z {
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: declaration of 'operator delete' has no matching declaration of 'operator new' at the same scope
+ void operator delete(void *ptr) noexcept;
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: declaration of 'operator delete[]' has no matching declaration of 'operator new[]' at the same scope
+ void operator delete[](void *ptr) noexcept;
+};
+
+struct A {
+ void *operator new(size_t size, Z) noexcept; // ok, placement new
+};
+
+struct B {
+ void operator delete(void *ptr, A) noexcept; // ok, placement delete
+};
+
+// It is okay to have a class with an inaccessible free store operator.
+struct C {
+ void *operator new(size_t, A) noexcept; // ok, placement new
+private:
+ void operator delete(void *) noexcept;
+};
+
+// It is also okay to have a class with a delete free store operator.
+struct D {
+ void *operator new(size_t, A) noexcept; // ok, placement new
+ void operator delete(void *) noexcept = delete;
+};
+
+struct E : U {
+ void *operator new(size_t) noexcept; // okay, we inherit operator delete from U
+};
+
+struct F : S {
+ // CHECK-MESSAGES: :[[@LINE+1]]:9: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope
+ void *operator new(size_t) noexcept;
+};
+
+class G {
+ void operator delete(void *) noexcept;
+};
+
+struct H : G {
+ // CHECK-MESSAGES: :[[@LINE+1]]:9: warning: declaration of 'operator new' has no matching declaration of 'operator delete' at the same scope
+ void *operator new(size_t) noexcept; // base class operator is inaccessible
+};
+
+template <typename Base> struct Derived : Base {
+ void operator delete(void *);
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-non-copyable-objects.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-non-copyable-objects.c
new file mode 100644
index 0000000..ac6198e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-non-copyable-objects.c
@@ -0,0 +1,43 @@
+// RUN: %check_clang_tidy %s misc-non-copyable-objects %t
+
+typedef struct FILE {} FILE;
+typedef struct pthread_cond_t {} pthread_cond_t;
+typedef int pthread_mutex_t;
+
+// CHECK-MESSAGES: :[[@LINE+1]]:13: warning: 'f' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'? [misc-non-copyable-objects]
+void g(FILE f);
+// CHECK-MESSAGES: :[[@LINE+1]]:24: warning: 'm' declared as type 'pthread_mutex_t', which is unsafe to copy; did you mean 'pthread_mutex_t *'?
+void h(pthread_mutex_t m);
+// CHECK-MESSAGES: :[[@LINE+1]]:23: warning: 'c' declared as type 'pthread_cond_t', which is unsafe to copy; did you mean 'pthread_cond_t *'?
+void i(pthread_cond_t c);
+
+struct S {
+ pthread_cond_t c; // ok
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: 'f' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ FILE f;
+};
+
+void func(FILE *f) {
+ // CHECK-MESSAGES: :[[@LINE+1]]:8: warning: 'f1' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ FILE f1; // match
+ // CHECK-MESSAGES: :[[@LINE+2]]:8: warning: 'f2' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ // CHECK-MESSAGES: :[[@LINE+1]]:13: warning: expression has opaque data structure type 'FILE'; type should only be used as a pointer and not dereferenced
+ FILE f2 = *f;
+ // CHECK-MESSAGES: :[[@LINE+1]]:15: warning: 'f3' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ struct FILE f3;
+ // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: expression has opaque data structure type 'FILE'; type should only be used as a pointer and not dereferenced
+ (void)sizeof(*f);
+ (void)sizeof(FILE);
+ // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: expression has opaque data structure type 'FILE'; type should only be used as a pointer and not dereferenced
+ g(*f);
+
+ pthread_mutex_t m; // ok
+ h(m); // ok
+
+ pthread_cond_t c; // ok
+ i(c); // ok
+
+ pthread_mutex_t *m1 = &m; // ok
+ // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: expression has opaque data structure type 'pthread_mutex_t'; type should only be used as a pointer and not dereferenced
+ h(*m1);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-non-copyable-objects.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-non-copyable-objects.cpp
new file mode 100644
index 0000000..3d716f4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-non-copyable-objects.cpp
@@ -0,0 +1,26 @@
+// RUN: %check_clang_tidy %s misc-non-copyable-objects %t
+
+namespace std {
+typedef struct FILE {} FILE;
+}
+using namespace std;
+
+// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: 'f' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'? [misc-non-copyable-objects]
+void g(std::FILE f);
+
+struct S {
+ // CHECK-MESSAGES: :[[@LINE+1]]:10: warning: 'f' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ ::FILE f;
+};
+
+void func(FILE *f) {
+ // CHECK-MESSAGES: :[[@LINE+1]]:13: warning: 'f1' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ std::FILE f1; // match
+ // CHECK-MESSAGES: :[[@LINE+2]]:10: warning: 'f2' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ // CHECK-MESSAGES: :[[@LINE+1]]:15: warning: expression has opaque data structure type 'FILE'; type should only be used as a pointer and not dereferenced
+ ::FILE f2 = *f; // match, match
+ // CHECK-MESSAGES: :[[@LINE+1]]:15: warning: 'f3' declared as type 'FILE', which is unsafe to copy; did you mean 'FILE *'?
+ struct FILE f3; // match
+ // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: expression has opaque data structure type 'FILE'; type should only be used as a pointer and not dereferenced
+ (void)sizeof(*f); // match
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-redundant-expression.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-redundant-expression.cpp
new file mode 100644
index 0000000..3454318
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-redundant-expression.cpp
@@ -0,0 +1,727 @@
+// RUN: %check_clang_tidy %s misc-redundant-expression %t -- -- -std=c++11
+
+typedef __INT64_TYPE__ I64;
+
+struct Point {
+ int x;
+ int y;
+ int a[5];
+} P;
+
+extern Point P1;
+extern Point P2;
+
+extern int foo(int x);
+extern int bar(int x);
+extern int bat(int x, int y);
+
+int TestSimpleEquivalent(int X, int Y) {
+ if (X - X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent [misc-redundant-expression]
+ if (X / X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+ if (X % X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+
+ if (X & X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+ if (X | X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+ if (X ^ X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+
+ if (X < X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+ if (X <= X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+ if (X > X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+ if (X >= X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+
+ if (X && X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+ if (X || X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+
+ if (X != (((X)))) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent
+
+ if (X + 1 == X + 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent
+ if (X + 1 != X + 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent
+ if (X + 1 <= X + 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent
+ if (X + 1 >= X + 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent
+
+ if ((X != 1 || Y != 1) && (X != 1 || Y != 1)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: both sides of operator are equivalent
+ if (P.a[X - P.x] != P.a[X - P.x]) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: both sides of operator are equivalent
+
+ if ((int)X < (int)X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: both sides of operator are equivalent
+ if (int(X) < int(X)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: both sides of operator are equivalent
+
+ if ( + "dummy" == + "dummy") return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: both sides of operator are equivalent
+ if (L"abc" == L"abc") return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: both sides of operator are equivalent
+
+ if (foo(0) - 2 < foo(0) - 2) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: both sides of operator are equivalent
+ if (foo(bar(0)) < (foo(bar((0))))) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: both sides of operator are equivalent
+
+ if (P1.x < P2.x && P1.x < P2.x) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: both sides of operator are equivalent
+ if (P2.a[P1.x + 2] < P2.x && P2.a[(P1.x) + (2)] < (P2.x)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: both sides of operator are equivalent
+
+ return 0;
+}
+
+int Valid(int X, int Y) {
+ if (X != Y) return 1;
+ if (X == Y + 0) return 1;
+ if (P.x == P.y) return 1;
+ if (P.a[P.x] < P.a[P.y]) return 1;
+ if (P.a[0] < P.a[1]) return 1;
+
+ if (P.a[0] < P.a[0ULL]) return 1;
+ if (0 < 0ULL) return 1;
+ if ((int)0 < (int)0ULL) return 1;
+
+ if (++X != ++X) return 1;
+ if (P.a[X]++ != P.a[X]++) return 1;
+ if (P.a[X++] != P.a[X++]) return 1;
+
+ if ("abc" == "ABC") return 1;
+ if (foo(bar(0)) < (foo(bat(0, 1)))) return 1;
+ return 0;
+}
+
+#define COND_OP_MACRO 9
+#define COND_OP_OTHER_MACRO 9
+int TestConditional(int x, int y) {
+ int k = 0;
+ k += (y < 0) ? x : x;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: 'true' and 'false' expressions are equivalent
+ k += (y < 0) ? x + 1 : x + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: 'true' and 'false' expressions are equivalent
+ k += (y < 0) ? COND_OP_MACRO : COND_OP_MACRO;
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: 'true' and 'false' expressions are equivalent
+
+ // Do not match for conditional operators with a macro and a const.
+ k += (y < 0) ? COND_OP_MACRO : 9;
+ // Do not match for conditional operators with expressions from different macros.
+ k += (y < 0) ? COND_OP_MACRO : COND_OP_OTHER_MACRO;
+ return k;
+}
+#undef COND_OP_MACRO
+#undef COND_OP_OTHER_MACRO
+
+// Overloaded operators that compare two instances of a struct.
+struct MyStruct {
+ int x;
+ bool operator==(const MyStruct& rhs) const {return this->x == rhs.x; } // not modifing
+ bool operator>=(const MyStruct& rhs) const { return this->x >= rhs.x; } // not modifing
+ bool operator<=(MyStruct& rhs) const { return this->x <= rhs.x; }
+ bool operator&&(const MyStruct& rhs){ this->x++; return this->x && rhs.x; }
+} Q;
+
+bool operator!=(const MyStruct& lhs, const MyStruct& rhs) { return lhs.x == rhs.x; } // not modifing
+bool operator<(const MyStruct& lhs, const MyStruct& rhs) { return lhs.x < rhs.x; } // not modifing
+bool operator>(const MyStruct& lhs, MyStruct& rhs) { rhs.x--; return lhs.x > rhs.x; }
+bool operator||(MyStruct& lhs, const MyStruct& rhs) { lhs.x++; return lhs.x || rhs.x; }
+
+bool TestOverloadedOperator(MyStruct& S) {
+ if (S == Q) return false;
+
+ if (S <= S) return false;
+ if (S && S) return false;
+ if (S > S) return false;
+ if (S || S) return false;
+
+ if (S == S) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of overloaded operator are equivalent
+ if (S < S) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of overloaded operator are equivalent
+ if (S != S) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of overloaded operator are equivalent
+ if (S >= S) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of overloaded operator are equivalent
+
+ return true;
+}
+
+#define LT(x, y) (void)((x) < (y))
+#define COND(x, y, z) ((x)?(y):(z))
+#define EQUALS(x, y) (x) == (y)
+
+int TestMacro(int X, int Y) {
+ LT(0, 0);
+ LT(1, 0);
+ LT(X, X);
+ LT(X+1, X + 1);
+ COND(X < Y, X, X);
+ EQUALS(Q, Q);
+ return 0;
+}
+
+int TestFalsePositive(int* A, int X, float F) {
+ // Produced by bison.
+ X = A[(2) - (2)];
+ X = A['a' - 'a'];
+
+ // Testing NaN.
+ if (F != F && F == F) return 1;
+ return 0;
+}
+
+int TestBannedMacros() {
+#define EAGAIN 3
+#define NOT_EAGAIN 3
+ if (EAGAIN == 0 | EAGAIN == 0) return 0;
+ if (NOT_EAGAIN == 0 | NOT_EAGAIN == 0) return 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: both sides of operator are equivalent
+ return 0;
+}
+
+struct MyClass {
+static const int Value = 42;
+};
+template <typename T, typename U>
+void TemplateCheck() {
+ static_assert(T::Value == U::Value, "should be identical");
+ static_assert(T::Value == T::Value, "should be identical");
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: both sides of operator are equivalent
+}
+void TestTemplate() { TemplateCheck<MyClass, MyClass>(); }
+
+int TestArithmetic(int X, int Y) {
+ if (X + 1 == X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false
+ if (X + 1 != X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+ if (X - 1 == X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false
+ if (X - 1 != X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ if (X + 1LL == X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+ if (X + 1ULL == X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: logical expression is always false
+
+ if (X == X + 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always false
+ if (X != X + 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always true
+ if (X == X - 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always false
+ if (X != X - 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always true
+
+ if (X != X - 1U) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always true
+ if (X != X - 1LL) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always true
+
+ if ((X+X) != (X+X) - 1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ if (X + 1 == X + 2) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false
+ if (X + 1 != X + 2) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ if (X - 1 == X - 2) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false
+ if (X - 1 != X - 2) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ if (X + 1 == X - -1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+ if (X + 1 != X - -1) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false
+ if (X + 1 == X - -2) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false
+ if (X + 1 != X - -2) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ if (X + 1 == X - (~0)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+ if (X + 1 == X - (~0U)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ if (X + 1 == X - (~0ULL)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ // Should not match.
+ if (X + 0.5 == X) return 1;
+ if (X + 1 == Y) return 1;
+ if (X + 1 == Y + 1) return 1;
+ if (X + 1 == Y + 2) return 1;
+
+ return 0;
+}
+
+int TestBitwise(int X, int Y) {
+
+ if ((X & 0xFF) == 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+ if ((X & 0xFF) != 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true
+ if ((X | 0xFF) == 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+ if ((X | 0xFF) != 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true
+
+ if ((X | 0xFFULL) != 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: logical expression is always true
+ if ((X | 0xFF) != 0xF00ULL) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true
+
+ if ((0xFF & X) == 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+ if ((0xFF & X) != 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true
+ if ((0xFF & X) == 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+ if ((0xFF & X) != 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always true
+
+ if ((0xFFLL & X) == 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: logical expression is always false
+ if ((0xFF & X) == 0xF00ULL) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+
+ return 0;
+}
+
+// Overloaded operators that compare an instance of a struct and an integer
+// constant.
+struct S {
+ S() { x = 1; }
+ int x;
+ // Overloaded comparison operators without any possible side effect.
+ bool operator==(const int &i) const { return x == i; } // not modifying
+ bool operator!=(int i) const { return x != i; } // not modifying
+ bool operator>(const int &i) const { return x > i; } // not modifying
+ bool operator<(int i) const { return x < i; } // not modifying
+};
+
+bool operator<=(const S &s, int i) { return s.x <= i; } // not modifying
+bool operator>=(const S &s, const int &i) { return s.x >= i; } // not modifying
+
+struct S2 {
+ S2() { x = 1; }
+ int x;
+ // Overloaded comparison operators that are able to modify their params.
+ bool operator==(const int &i) {
+ this->x++;
+ return x == i;
+ }
+ bool operator!=(int i) { return x != i; }
+ bool operator>(const int &i) { return x > i; }
+ bool operator<(int i) {
+ this->x--;
+ return x < i;
+ }
+};
+
+bool operator>=(S2 &s, const int &i) { return s.x >= i; }
+bool operator<=(S2 &s, int i) {
+ s.x++;
+ return s.x <= i;
+}
+
+int TestLogical(int X, int Y){
+#define CONFIG 0
+ if (CONFIG && X) return 1;
+#undef CONFIG
+#define CONFIG 1
+ if (CONFIG || X) return 1;
+#undef CONFIG
+
+ if (X == 10 && X != 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+ if (X == 10 && (X != 10)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+ if (X == 10 && !(X == 10)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+ if (!(X != 10) && !(X == 10)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+
+ if (X == 10ULL && X != 10ULL) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+ if (!(X != 10U) && !(X == 10)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: logical expression is always false
+ if (!(X != 10LL) && !(X == 10)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: logical expression is always false
+ if (!(X != 10ULL) && !(X == 10)) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: logical expression is always false
+
+ if (X == 0 && X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+ if (X != 0 && !X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+ if (X && !X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: logical expression is always false
+
+ if (X && !!X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: equivalent expression on both sides of logical operator
+ if (X != 0 && X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: equivalent expression on both sides of logical operator
+ if (X != 0 && !!X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: equivalent expression on both sides of logical operator
+ if (X == 0 && !X) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: equivalent expression on both sides of logical operator
+
+ // Should not match.
+ if (X == 10 && Y == 10) return 1;
+ if (X != 10 && X != 12) return 1;
+ if (X == 10 || X == 12) return 1;
+ if (!X && !Y) return 1;
+ if (!X && Y) return 1;
+ if (!X && Y == 0) return 1;
+ if (X == 10 && Y != 10) return 1;
+
+ // Test for overloaded operators with constant params.
+ S s1;
+ if (s1 == 1 && s1 == 1) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: equivalent expression on both sides of logical operator
+ if (s1 == 1 || s1 != 1) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
+ if (s1 > 1 && s1 < 1) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+ if (s1 >= 1 || s1 <= 1) return true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
+
+ // Test for overloaded operators that may modify their params.
+ S2 s2;
+ if (s2 == 1 || s2 != 1) return true;
+ if (s2 == 1 || s2 == 1) return true;
+ if (s2 > 1 && s2 < 1) return true;
+ if (s2 >= 1 || s2 <= 1) return true;
+}
+
+int TestRelational(int X, int Y) {
+ if (X == 10 && X > 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+ if (X == 10 && X < 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+ if (X < 10 && X > 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+ if (X <= 10 && X > 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always false
+ if (X < 10 && X >= 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+ if (X < 10 && X == 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+
+ if (X > 5 && X <= 5) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always false
+ if (X > -5 && X <= -5) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always false
+
+ if (X < 10 || X >= 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always true
+ if (X <= 10 || X > 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
+ if (X <= 10 || X >= 11) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: logical expression is always true
+ if (X != 7 || X != 14) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always true
+ if (X == 7 || X != 5) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X != 7 || X == 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: logical expression is always true
+
+ if (X < 7 && X < 6) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X < 7 && X < 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent
+ if (X < 7 && X < 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: expression is redundant
+
+ if (X < 7 && X <= 5) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X < 7 && X <= 6) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: equivalent expression on both sides of logical operator
+ if (X < 7 && X <= 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: expression is redundant
+ if (X < 7 && X <= 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: expression is redundant
+
+ if (X <= 7 && X < 6) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X <= 7 && X < 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X <= 7 && X < 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: equivalent expression on both sides of logical operator
+
+ if (X >= 7 && X > 6) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: equivalent expression on both sides of logical operator
+ if (X >= 7 && X > 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X >= 7 && X > 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+
+ if (X <= 7 && X <= 5) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X <= 7 && X <= 6) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X <= 7 && X <= 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: both sides of operator are equivalent
+ if (X <= 7 && X <= 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: expression is redundant
+
+ if (X == 11 && X > 10) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: expression is redundant
+ if (X == 11 && X < 12) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: expression is redundant
+ if (X > 10 && X == 11) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X < 12 && X == 11) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+
+ if (X != 11 && X == 42) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X != 11 && X > 11) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X != 11 && X < 11) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X != 11 && X < 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X != 11 && X > 14) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+
+ if (X < 7 || X < 6) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: expression is redundant
+ if (X < 7 || X < 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent
+ if (X < 7 || X < 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+
+ if (X > 7 || X > 6) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X > 7 || X > 7) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent
+ if (X > 7 || X > 8) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: expression is redundant
+
+ // Should not match.
+ if (X < 10 || X > 12) return 1;
+ if (X > 10 && X < 12) return 1;
+ if (X < 10 || X >= 12) return 1;
+ if (X > 10 && X <= 12) return 1;
+ if (X <= 10 || X > 12) return 1;
+ if (X >= 10 && X < 12) return 1;
+ if (X <= 10 || X >= 12) return 1;
+ if (X >= 10 && X <= 12) return 1;
+ if (X >= 10 && X <= 11) return 1;
+ if (X >= 10 && X < 11) return 1;
+ if (X > 10 && X <= 11) return 1;
+ if (X > 10 && X != 11) return 1;
+ if (X >= 10 && X <= 10) return 1;
+ if (X <= 10 && X >= 10) return 1;
+ if (X < 0 || X > 0) return 1;
+}
+
+int TestRelationalMacros(int X){
+#define SOME_MACRO 3
+#define SOME_MACRO_SAME_VALUE 3
+#define SOME_OTHER_MACRO 9
+ // Do not match for redundant relational macro expressions that can be
+ // considered intentional, and for some particular values, non redundant.
+
+ // Test cases for expressions with the same macro on both sides.
+ if (X < SOME_MACRO && X > SOME_MACRO) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: logical expression is always false
+ if (X < SOME_MACRO && X == SOME_MACRO) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: logical expression is always false
+ if (X < SOME_MACRO || X >= SOME_MACRO) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: logical expression is always true
+ if (X <= SOME_MACRO || X > SOME_MACRO) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: logical expression is always true
+ if (X != SOME_MACRO && X > SOME_MACRO) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+ if (X != SOME_MACRO && X < SOME_MACRO) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: expression is redundant
+
+ // Test cases for two different macros.
+ if (X < SOME_MACRO && X > SOME_OTHER_MACRO) return 1;
+ if (X != SOME_MACRO && X >= SOME_OTHER_MACRO) return 1;
+ if (X != SOME_MACRO && X != SOME_OTHER_MACRO) return 1;
+ if (X == SOME_MACRO || X == SOME_MACRO_SAME_VALUE) return 1;
+ if (X == SOME_MACRO || X <= SOME_MACRO_SAME_VALUE) return 1;
+ if (X == SOME_MACRO || X > SOME_MACRO_SAME_VALUE) return 1;
+ if (X < SOME_MACRO && X <= SOME_OTHER_MACRO) return 1;
+ if (X == SOME_MACRO && X > SOME_OTHER_MACRO) return 1;
+ if (X == SOME_MACRO && X != SOME_OTHER_MACRO) return 1;
+ if (X == SOME_MACRO && X != SOME_MACRO_SAME_VALUE) return 1;
+ if (X == SOME_MACRO_SAME_VALUE && X == SOME_MACRO ) return 1;
+
+ // Test cases for a macro and a const.
+ if (X < SOME_MACRO && X > 9) return 1;
+ if (X != SOME_MACRO && X >= 9) return 1;
+ if (X != SOME_MACRO && X != 9) return 1;
+ if (X == SOME_MACRO || X == 3) return 1;
+ if (X == SOME_MACRO || X <= 3) return 1;
+ if (X < SOME_MACRO && X <= 9) return 1;
+ if (X == SOME_MACRO && X != 9) return 1;
+ if (X == SOME_MACRO && X == 9) return 1;
+
+#undef SOME_OTHER_MACRO
+#undef SOME_MACRO_SAME_VALUE
+#undef SOME_MACRO
+ return 0;
+}
+
+int TestValidExpression(int X) {
+ if (X - 1 == 1 - X) return 1;
+ if (2 * X == X) return 1;
+ if ((X << 1) == X) return 1;
+
+ return 0;
+}
+
+enum Color { Red, Yellow, Green };
+int TestRelationalWithEnum(enum Color C) {
+ if (C == Red && C == Yellow) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: logical expression is always false
+ if (C == Red && C != Red) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: logical expression is always false
+ if (C != Red || C != Yellow) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: logical expression is always true
+
+ // Should not match.
+ if (C == Red || C == Yellow) return 1;
+ if (C != Red && C != Yellow) return 1;
+
+ return 0;
+}
+
+template<class T>
+int TestRelationalTemplated(int X) {
+ // This test causes a corner case with |isIntegerConstantExpr| where the type
+ // is dependent. There is an assert failing when evaluating
+ // sizeof(<incomplet-type>).
+ if (sizeof(T) == 4 || sizeof(T) == 8) return 1;
+
+ if (X + 0 == -X) return 1;
+ if (X + 0 < X) return 1;
+
+ return 0;
+}
+
+int TestWithSignedUnsigned(int X) {
+ if (X + 1 == X + 1ULL) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: logical expression is always true
+
+ if ((X & 0xFFU) == 0xF00) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: logical expression is always false
+
+ if ((X & 0xFF) == 0xF00U) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: logical expression is always false
+
+ if ((X & 0xFFU) == 0xF00U) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: logical expression is always false
+
+ return 0;
+}
+
+int TestWithLong(int X, I64 Y) {
+ if (X + 0ULL == -X) return 1;
+ if (Y + 0 == -Y) return 1;
+ if (Y <= 10 && X >= 10LL) return 1;
+ if (Y <= 10 && X >= 10ULL) return 1;
+ if (X <= 10 || X > 12LL) return 1;
+ if (X <= 10 || X > 12ULL) return 1;
+ if (Y <= 10 || Y > 12) return 1;
+
+ return 0;
+}
+
+int TestWithMinMaxInt(int X) {
+ if (X <= X + 0xFFFFFFFFU) return 1;
+ if (X <= X + 0x7FFFFFFF) return 1;
+ if (X <= X + 0x80000000) return 1;
+
+ if (X <= 0xFFFFFFFFU && X > 0) return 1;
+ if (X <= 0xFFFFFFFFU && X > 0U) return 1;
+
+ if (X + 0x80000000 == X - 0x80000000) return 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: logical expression is always true
+
+ if (X > 0x7FFFFFFF || X < ((-0x7FFFFFFF)-1)) return 1;
+ if (X <= 0x7FFFFFFF && X >= ((-0x7FFFFFFF)-1)) return 1;
+
+ return 0;
+}
+
+#define FLAG1 1
+#define FLAG2 2
+#define FLAG3 4
+#define FLAGS (FLAG1 | FLAG2 | FLAG3)
+#define NOTFLAGS !(FLAG1 | FLAG2 | FLAG3)
+int operatorConfusion(int X, int Y, long Z)
+{
+ // Ineffective & expressions.
+ Y = (Y << 8) & 0xff;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and operation
+ Y = (Y << 12) & 0xfff;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
+ Y = (Y << 12) & 0xff;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
+ Y = (Y << 8) & 0x77;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and
+ Y = (Y << 5) & 0x11;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and
+
+ // Tests for unmatched types
+ Z = (Z << 8) & 0xff;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and operation
+ Y = (Y << 12) & 0xfffL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
+ Z = (Y << 12) & 0xffLL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
+ Y = (Z << 8L) & 0x77L;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: ineffective bitwise and
+
+ Y = (Y << 8) & 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and
+
+ Y = (Y << 8) & -1;
+
+ // Effective expressions. Do not check.
+ Y = (Y << 4) & 0x15;
+ Y = (Y << 3) & 0x250;
+ Y = (Y << 9) & 0xF33;
+
+ int K = !(1 | 2 | 4);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: ineffective logical negation operator used; did you mean '~'?
+ // CHECK-FIXES: {{^}} int K = ~(1 | 2 | 4);{{$}}
+ K = !(FLAG1 & FLAG2 & FLAG3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: ineffective logical negation operator
+ // CHECK-FIXES: {{^}} K = ~(FLAG1 & FLAG2 & FLAG3);{{$}}
+ K = !(3 | 4);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: ineffective logical negation operator
+ // CHECK-FIXES: {{^}} K = ~(3 | 4);{{$}}
+ int NotFlags = !FLAGS;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: ineffective logical negation operator
+ // CHECK-FIXES: {{^}} int NotFlags = ~FLAGS;{{$}}
+ NotFlags = NOTFLAGS;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: ineffective logical negation operator
+ return !(1 | 2 | 4);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: ineffective logical negation operator
+ // CHECK-FIXES: {{^}} return ~(1 | 2 | 4);{{$}}
+}
+#undef FLAG1
+#undef FLAG2
+#undef FLAG3
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-static-assert.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-static-assert.c
new file mode 100644
index 0000000..e3e8304
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-static-assert.c
@@ -0,0 +1,27 @@
+// RUN: %check_clang_tidy %s misc-static-assert %t -- -- -std=c11
+// RUN: clang-tidy %s -checks=-*,misc-static-assert -- -std=c99 | count 0
+
+void abort() {}
+#ifdef NDEBUG
+#define assert(x) 1
+#else
+#define assert(x) \
+ if (!(x)) \
+ abort()
+#endif
+
+void f(void) {
+ int x = 1;
+ assert(x == 0);
+ // CHECK-FIXES: {{^ }}assert(x == 0);
+
+ #define static_assert(x, msg) _Static_assert(x, msg)
+ assert(11 == 5 + 6);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(11 == 5 + 6, "");
+ #undef static_assert
+
+ assert(10 == 5 + 5);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(10 == 5 + 5, "");
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-static-assert.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-static-assert.cpp
new file mode 100644
index 0000000..85ae053
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-static-assert.cpp
@@ -0,0 +1,143 @@
+// RUN: %check_clang_tidy %s misc-static-assert %t
+
+void abort() {}
+#ifdef NDEBUG
+#define assert(x) 1
+#else
+#define assert(x) \
+ if (!(x)) \
+ abort()
+#endif
+
+void print(...);
+
+#define ZERO_MACRO 0
+
+#define False false
+#define FALSE 0
+
+#define my_macro() assert(0 == 1)
+// CHECK-FIXES: #define my_macro() assert(0 == 1)
+
+constexpr bool myfunc(int a, int b) { return a * b == 0; }
+
+typedef __SIZE_TYPE__ size_t;
+extern "C" size_t strlen(const char *s);
+
+class A {
+public:
+ bool method() { return true; }
+};
+
+class B {
+public:
+ constexpr bool method() { return true; }
+};
+
+template <class T> void doSomething(T t) {
+ assert(myfunc(1, 2));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be replaced by static_assert() [misc-static-assert]
+ // CHECK-FIXES: {{^ }}static_assert(myfunc(1, 2), "");
+
+ assert(t.method());
+ // CHECK-FIXES: {{^ }}assert(t.method());
+
+ assert(sizeof(T) == 123);
+}
+
+int main() {
+ my_macro();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}my_macro();
+
+ assert(myfunc(1, 2) && (3 == 4));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(myfunc(1, 2) && (3 == 4), "");
+
+ int x = 1;
+ assert(x == 0);
+ // CHECK-FIXES: {{^ }}assert(x == 0);
+
+ A a;
+ B b;
+
+ doSomething<A>(a);
+ doSomething<B>(b);
+
+ assert(false);
+ // CHECK-FIXES: {{^ }}assert(false);
+
+ assert(False);
+ // CHECK-FIXES: {{^ }}assert(False);
+ assert(FALSE);
+ // CHECK-FIXES: {{^ }}assert(FALSE);
+
+ assert(ZERO_MACRO);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(ZERO_MACRO, "");
+
+ assert(!"Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(!"Don't report me!");
+
+ assert(0 && "Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(0 && "Don't report me!");
+
+ assert(false && "Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(false && "Don't report me!");
+
+#define NULL ((void*)0)
+ assert(NULL && "Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(NULL && "Don't report me!");
+
+ assert(NULL == "Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(NULL == "Don't report me!");
+
+ assert("Don't report me!" == NULL);
+ // CHECK-FIXES: {{^ }}assert("Don't report me!" == NULL);
+
+ assert(0 == "Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(0 == "Don't report me!");
+
+#define NULL ((unsigned int)0)
+ assert(NULL && "Report me!");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(NULL , "Report me!");
+
+#define NULL __null
+ assert(__null == "Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(__null == "Don't report me!");
+ assert(NULL == "Don't report me!");
+ // CHECK-FIXES: {{^ }}assert(NULL == "Don't report me!");
+#undef NULL
+
+ assert(ZERO_MACRO && "Report me!");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(ZERO_MACRO , "Report me!");
+
+ assert(0);
+
+#define false false
+ assert(false);
+
+#define false 0
+ assert(false);
+#undef false
+
+ assert(10==5 && "Report me!");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(10==5 , "Report me!");
+
+ assert(strlen("12345") == 5);
+ // CHECK-FIXES: {{^ }}assert(strlen("12345") == 5);
+
+#define assert(e) (__builtin_expect(!(e), 0) ? print (#e, __FILE__, __LINE__) : (void)0)
+ assert(false);
+ // CHECK-FIXES: {{^ }}assert(false);
+
+ assert(10 == 5 + 5);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be
+ // CHECK-FIXES: {{^ }}static_assert(10 == 5 + 5, "");
+#undef assert
+
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-throw-by-value-catch-by-reference.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-throw-by-value-catch-by-reference.cpp
new file mode 100644
index 0000000..120b07e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-throw-by-value-catch-by-reference.cpp
@@ -0,0 +1,156 @@
+// RUN: %check_clang_tidy %s misc-throw-by-value-catch-by-reference %t -- -- -std=c++11 -fcxx-exceptions
+
+
+class logic_error {
+public:
+ logic_error(const char *message) {}
+};
+
+typedef logic_error *logic_ptr;
+typedef logic_ptr logic_double_typedef;
+
+int lastException;
+
+template <class T> struct remove_reference { typedef T type; };
+template <class T> struct remove_reference<T &> { typedef T type; };
+template <class T> struct remove_reference<T &&> { typedef T type; };
+
+template <typename T> typename remove_reference<T>::type &&move(T &&arg) {
+ return static_cast<typename remove_reference<T>::type &&>(arg);
+}
+
+logic_error CreateException() { return logic_error("created"); }
+
+void testThrowFunc() {
+ throw new logic_error("by pointer");
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression throws a pointer; it should throw a non-pointer value instead [misc-throw-by-value-catch-by-reference]
+ logic_ptr tmp = new logic_error("by pointer");
+ throw tmp;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
+ // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: throw expression throws a pointer; it should throw a non-pointer value instead [misc-throw-by-value-catch-by-reference]
+ throw logic_error("by value");
+ auto *literal = "test";
+ throw logic_error(literal);
+ throw "test string literal";
+ throw L"throw wide string literal";
+ const char *characters = 0;
+ throw characters;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
+ // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: throw expression throws a pointer; it should throw a non-pointer value instead [misc-throw-by-value-catch-by-reference]
+ logic_error lvalue("lvalue");
+ throw lvalue;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
+
+ throw move(lvalue);
+ int &ex = lastException;
+ throw ex;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
+ throw CreateException();
+}
+
+void throwReferenceFunc(logic_error &ref) { throw ref; }
+
+void catchByPointer() {
+ try {
+ testThrowFunc();
+ } catch (logic_error *e) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches a pointer value; should throw a non-pointer value and catch by reference instead [misc-throw-by-value-catch-by-reference]
+ }
+}
+
+void catchByValue() {
+ try {
+ testThrowFunc();
+ } catch (logic_error e) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches by value; should catch by reference instead [misc-throw-by-value-catch-by-reference]
+ }
+}
+
+void catchByReference() {
+ try {
+ testThrowFunc();
+ } catch (logic_error &e) {
+ }
+}
+
+void catchByConstReference() {
+ try {
+ testThrowFunc();
+ } catch (const logic_error &e) {
+ }
+}
+
+void catchTypedef() {
+ try {
+ testThrowFunc();
+ } catch (logic_ptr) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches a pointer value; should throw a non-pointer value and catch by reference instead [misc-throw-by-value-catch-by-reference]
+ }
+}
+
+void catchAll() {
+ try {
+ testThrowFunc();
+ } catch (...) {
+ }
+}
+
+void catchLiteral() {
+ try {
+ testThrowFunc();
+ } catch (const char *) {
+ } catch (const wchar_t *) {
+ // disabled for now until it is clear
+ // how to enable them in the test
+ //} catch (const char16_t*) {
+ //} catch (const char32_t*) {
+ }
+}
+
+// catching fundamentals should not warn
+void catchFundamental() {
+ try {
+ testThrowFunc();
+ } catch (int) {
+ } catch (double) {
+ } catch (unsigned long) {
+ }
+}
+
+struct TrivialType {
+ double x;
+ double y;
+};
+
+void catchTrivial() {
+ try {
+ testThrowFunc();
+ } catch (TrivialType) {
+ }
+}
+
+typedef logic_error &fine;
+void additionalTests() {
+ try {
+ } catch (int i) { // ok
+ throw i; // ok
+ } catch (fine e) { // ok
+ throw e; // ok
+ } catch (logic_error *e) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: catch handler catches a pointer value; should throw a non-pointer value and catch by reference instead [misc-throw-by-value-catch-by-reference]
+ throw e; // ok, despite throwing a pointer
+ } catch (...) { // ok
+ throw; // ok
+ }
+}
+
+struct S {};
+
+S &returnByReference();
+S returnByValue();
+
+void f() {
+ throw returnByReference(); // Should diagnose
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: throw expression should throw anonymous temporary values instead [misc-throw-by-value-catch-by-reference]
+ throw returnByValue(); // Should not diagnose
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unconventional-assign-operator-cxx17.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unconventional-assign-operator-cxx17.cpp
new file mode 100644
index 0000000..ba1a685
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unconventional-assign-operator-cxx17.cpp
@@ -0,0 +1,12 @@
+// RUN: %check_clang_tidy %s misc-unconventional-assign-operator %t -- -- -std=c++17 -fno-delayed-template-parsing
+
+struct BadModifier {
+ BadModifier& operator=(const BadModifier&) const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'const'
+};
+
+struct PR35468 {
+ template<typename T> auto &operator=(const T &) {
+ return *this;
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unconventional-assign-operator.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unconventional-assign-operator.cpp
new file mode 100644
index 0000000..4bd9cb2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unconventional-assign-operator.cpp
@@ -0,0 +1,111 @@
+// RUN: %check_clang_tidy %s misc-unconventional-assign-operator %t -- -- -std=c++11 -isystem %S/Inputs/Headers -fno-delayed-template-parsing
+
+namespace std {
+template <typename T>
+struct remove_reference { typedef T type; };
+template <typename T>
+struct remove_reference<T &> { typedef T type; };
+template <typename T>
+struct remove_reference<T &&> { typedef T type; };
+template <typename T>
+typename remove_reference<T>::type &&move(T &&t);
+}
+
+
+struct Good {
+ Good& operator=(const Good&);
+ Good& operator=(Good&&);
+
+ // Assign from other types is fine too.
+ Good& operator=(int);
+};
+
+struct AlsoGood {
+ // By value is also fine.
+ AlsoGood& operator=(AlsoGood);
+};
+
+struct BadReturnType {
+ void operator=(const BadReturnType&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'BadReturnType&' [misc-unconventional-assign-operator]
+ const BadReturnType& operator=(BadReturnType&&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
+ void operator=(int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
+};
+
+struct BadReturnType2 {
+ BadReturnType2&& operator=(const BadReturnType2&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
+ int operator=(BadReturnType2&&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
+};
+
+struct BadArgument {
+ BadArgument& operator=(BadArgument&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should take 'BadArgument const&', 'BadArgument&&' or 'BadArgument'
+ BadArgument& operator=(const BadArgument&&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should take 'BadAr
+};
+
+struct BadModifier {
+ BadModifier& operator=(const BadModifier&) const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'const'
+};
+
+struct Deleted {
+ // We don't check the return value of deleted operators.
+ void operator=(const Deleted&) = delete;
+ void operator=(Deleted&&) = delete;
+};
+
+class Private {
+ // We don't check the return value of private operators.
+ // Pre-C++11 way of disabling assignment.
+ void operator=(const Private &);
+};
+
+struct Virtual {
+ virtual Virtual& operator=(const Virtual &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'virtual'
+};
+
+class BadReturnStatement {
+ int n;
+
+public:
+ BadReturnStatement& operator=(BadReturnStatement&& rhs) {
+ n = std::move(rhs.n);
+ return rhs;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should always return '*this'
+ }
+
+ // Do not check if return type is different from '&BadReturnStatement'
+ int operator=(int i) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
+ n = i;
+ return n;
+ }
+};
+
+namespace pr31531 {
+enum E { e };
+// This declaration makes the 'return *this' below have an unresolved operator
+// in the class template, but not in an instantiation.
+E operator*(E, E);
+
+template <typename>
+struct UnresolvedOperator {
+ UnresolvedOperator &operator=(const UnresolvedOperator &) { return *this; }
+};
+
+UnresolvedOperator<int> UnresolvedOperatorInt;
+
+template <typename>
+struct Template {
+ Template &operator=(const Template &) { return this; }
+ // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: operator=() should always return '*this'
+};
+
+Template<int> TemplateInt;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-uniqueptr-reset-release.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-uniqueptr-reset-release.cpp
new file mode 100644
index 0000000..1bd6e6f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-uniqueptr-reset-release.cpp
@@ -0,0 +1,69 @@
+// RUN: %check_clang_tidy %s misc-uniqueptr-reset-release %t
+
+namespace std {
+
+template <typename T>
+struct default_delete {};
+
+template <typename T, class Deleter = std::default_delete<T>>
+struct unique_ptr {
+ unique_ptr();
+ explicit unique_ptr(T *);
+ template <typename U, typename E>
+ unique_ptr(unique_ptr<U, E> &&);
+ void reset(T *);
+ T *release();
+};
+} // namespace std
+
+struct Foo {};
+struct Bar : Foo {};
+
+std::unique_ptr<Foo> Create();
+std::unique_ptr<Foo> &Look();
+std::unique_ptr<Foo> *Get();
+
+using FooFunc = void (*)(Foo *);
+using BarFunc = void (*)(Bar *);
+
+void f() {
+ std::unique_ptr<Foo> a, b;
+ std::unique_ptr<Bar> c;
+ std::unique_ptr<Foo> *x = &a;
+ std::unique_ptr<Foo> *y = &b;
+
+ a.reset(b.release());
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer ptr1 = std::move(ptr2) over ptr1.reset(ptr2.release()) [misc-uniqueptr-reset-release]
+ // CHECK-FIXES: a = std::move(b);
+ a.reset(c.release());
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer ptr1 = std::move(ptr2)
+ // CHECK-FIXES: a = std::move(c);
+ a.reset(Create().release());
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: prefer ptr = ReturnUnique() over ptr.reset(ReturnUnique().release()) [misc-uniqueptr-reset-release]
+ // CHECK-FIXES: a = Create();
+ x->reset(y->release());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: prefer ptr1 = std::move(ptr2)
+ // CHECK-FIXES: *x = std::move(*y);
+ Look().reset(Look().release());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: prefer ptr1 = std::move(ptr2)
+ // CHECK-FIXES: Look() = std::move(Look());
+ Get()->reset(Get()->release());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: prefer ptr1 = std::move(ptr2)
+ // CHECK-FIXES: *Get() = std::move(*Get());
+
+ std::unique_ptr<Bar, FooFunc> func_a, func_b;
+ func_a.reset(func_b.release());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: prefer ptr1 = std::move(ptr2)
+ // CHECK-FIXES: func_a = std::move(func_b);
+}
+
+void negatives() {
+ std::unique_ptr<Foo> src;
+ struct OtherDeleter {};
+ std::unique_ptr<Foo, OtherDeleter> dest;
+ dest.reset(src.release());
+
+ std::unique_ptr<Bar, FooFunc> func_a;
+ std::unique_ptr<Bar, BarFunc> func_b;
+ func_a.reset(func_b.release());
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-alias-decls.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-alias-decls.cpp
new file mode 100644
index 0000000..6d63df4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-alias-decls.cpp
@@ -0,0 +1,12 @@
+// RUN: %check_clang_tidy %s misc-unused-alias-decls %t
+
+namespace my_namespace {
+class C {};
+}
+
+namespace unused_alias = ::my_namespace; // eol-comments aren't removed (yet)
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: namespace alias decl 'unused_alias' is unused
+// CHECK-FIXES: {{^}}// eol-comments aren't removed (yet)
+
+namespace used_alias = ::my_namespace;
+void f() { used_alias::C c; }
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-parameters-strict.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-parameters-strict.cpp
new file mode 100644
index 0000000..a334b45
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-parameters-strict.cpp
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s misc-unused-parameters %t -- \
+// RUN: -config="{CheckOptions: [{key: StrictMode, value: 1}]}" --
+
+// Warn on empty function bodies in StrictMode.
+namespace strict_mode {
+void f(int foo) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'foo' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void f(int /*foo*/) {}{{$}}
+class E {
+ int i;
+
+public:
+ E(int j) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'j' is unused
+// CHECK-FIXES: {{^}} E(int /*j*/) {}{{$}}
+};
+class F {
+ int i;
+
+public:
+ F(int j) : i() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'j' is unused
+// CHECK-FIXES: {{^}} F(int /*j*/) : i() {}{{$}}
+};
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-parameters.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-parameters.c
new file mode 100644
index 0000000..d824a80
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-parameters.c
@@ -0,0 +1,17 @@
+// RUN: %check_clang_tidy %s misc-unused-parameters %t -- -- -xc
+
+// Basic removal
+// =============
+void a(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void a(int /*i*/) {;}{{$}}
+
+static void b(); // In C, forward declarations can leave out parameters.
+static void b(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: parameter 'i' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}static void b() {;}{{$}}
+
+// Unchanged cases
+// ===============
+void h(i, c, d) int i; char *c, *d; {} // Don't mess with K&R style
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-parameters.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-parameters.cpp
new file mode 100644
index 0000000..ec1ee2d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-parameters.cpp
@@ -0,0 +1,277 @@
+// RUN: echo "static void staticFunctionHeader(int i) {;}" > %T/header.h
+// RUN: echo "static void staticFunctionHeader(int /*i*/) {;}" > %T/header-fixed.h
+// RUN: %check_clang_tidy %s misc-unused-parameters %t -- -header-filter='.*' -- -std=c++11 -fno-delayed-template-parsing
+// RUN: diff %T/header.h %T/header-fixed.h
+
+#include "header.h"
+// CHECK-MESSAGES: header.h:1:38: warning
+
+// Basic removal
+// =============
+void a(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void a(int /*i*/) {;}{{$}}
+
+void b(int i = 1) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void b(int /*i*/ = 1) {;}{{$}}
+
+void c(int *i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: parameter 'i' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void c(int * /*i*/) {;}{{$}}
+
+void d(int i[]) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void d(int /*i*/[]) {;}{{$}}
+
+void e(int i[1]) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: parameter 'i' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void e(int /*i*/[1]) {;}{{$}}
+
+void f(void (*fn)()) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: parameter 'fn' is unused [misc-unused-parameters]
+// CHECK-FIXES: {{^}}void f(void (* /*fn*/)()) {;}{{$}}
+
+// Unchanged cases
+// ===============
+void f(int i); // Don't remove stuff in declarations
+void g(int i = 1);
+void h(int i[]);
+void s(int i[1]);
+void u(void (*fn)());
+void w(int i) { (void)i; } // Don't remove used parameters
+
+bool useLambda(int (*fn)(int));
+static bool static_var = useLambda([] (int a) { return a; });
+
+// Remove parameters of local functions
+// ====================================
+static void staticFunctionA(int i);
+// CHECK-FIXES: {{^}}static void staticFunctionA();
+static void staticFunctionA(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
+// CHECK-FIXES: {{^}}static void staticFunctionA()
+
+static void staticFunctionB(int i, int j) { (void)i; }
+// CHECK-MESSAGES: :[[@LINE-1]]:40: warning
+// CHECK-FIXES: {{^}}static void staticFunctionB(int i)
+
+static void staticFunctionC(int i, int j) { (void)j; }
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
+// CHECK-FIXES: {{^}}static void staticFunctionC(int j)
+
+static void staticFunctionD(int i, int j, int k) { (void)i; (void)k; }
+// CHECK-MESSAGES: :[[@LINE-1]]:40: warning
+// CHECK-FIXES: {{^}}static void staticFunctionD(int i, int k)
+
+static void staticFunctionE(int i = 4) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
+// CHECK-FIXES: {{^}}static void staticFunctionE()
+
+static void staticFunctionF(int i = 4);
+// CHECK-FIXES: {{^}}static void staticFunctionF();
+static void staticFunctionF(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
+// CHECK-FIXES: {{^}}static void staticFunctionF()
+
+static void staticFunctionG(int i[]);
+// CHECK-FIXES: {{^}}static void staticFunctionG();
+static void staticFunctionG(int i[]) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning
+// CHECK-FIXES: {{^}}static void staticFunctionG()
+
+static void staticFunctionH(void (*fn)());
+// CHECK-FIXES: {{^}}static void staticFunctionH();
+static void staticFunctionH(void (*fn)()) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:36: warning
+// CHECK-FIXES: {{^}}static void staticFunctionH()
+
+static void someCallSites() {
+ staticFunctionA(1);
+// CHECK-FIXES: staticFunctionA();
+ staticFunctionB(1, 2);
+// CHECK-FIXES: staticFunctionB(1);
+ staticFunctionC(1, 2);
+// CHECK-FIXES: staticFunctionC(2);
+ staticFunctionD(1, 2, 3);
+// CHECK-FIXES: staticFunctionD(1, 3);
+ staticFunctionE(1);
+// CHECK-FIXES: staticFunctionE();
+ staticFunctionF(1);
+// CHECK-FIXES: staticFunctionF();
+ staticFunctionF();
+// CHECK-FIXES: staticFunctionF();
+ int t[] = {1};
+ staticFunctionG(t);
+// CHECK-FIXES: staticFunctionG();
+ void func();
+ staticFunctionH(&func);
+// CHECK-FIXES: staticFunctionH();
+}
+
+/*
+ * FIXME: This fails because the removals overlap and ClangTidy doesn't apply
+ * them.
+ * static void bothVarsUnused(int a, int b) {;}
+ */
+
+// Regression test for long variable names and expressions
+// =======================================================
+static int variableWithLongName1(int LongName1, int LongName2) {
+// CHECK-MESSAGES: :[[@LINE-1]]:53: warning: parameter 'LongName2' is unused
+// CHECK-FIXES: {{^}}static int variableWithLongName1(int LongName1) {
+ return LongName1;
+}
+static int variableWithLongName2(int LongName1, int LongName2) {
+// CHECK-MESSAGES: :[[@LINE-1]]:38: warning: parameter 'LongName1' is unused
+// CHECK-FIXES: {{^}}static int variableWithLongName2(int LongName2) {
+ return LongName2;
+}
+static void someLongNameCallSites() {
+ int LongName1 = 7, LongName2 = 17;
+ variableWithLongName1(LongName1, LongName2);
+// CHECK-FIXES: variableWithLongName1(LongName1);
+ variableWithLongName2(LongName1, LongName2);
+// CHECK-FIXES: variableWithLongName2(LongName2);
+}
+
+class SomeClass {
+ static void f(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning
+// CHECK-FIXES: static void f(int /*i*/) {;}
+ static void g(int i = 1) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning
+// CHECK-FIXES: static void g(int /*i*/ = 1) {;}
+ static void h(int i[]) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning
+// CHECK-FIXES: static void h(int /*i*/[]) {;}
+ static void s(void (*fn)()) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning
+// CHECK-FIXES: static void s(void (* /*fn*/)()) {;}
+};
+
+namespace {
+class C {
+public:
+ void f(int i);
+// CHECK-FIXES: void f();
+ void g(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
+// CHECK-FIXES: void g() {;}
+ void h(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
+// CHECK-FIXES: void h(int /*i*/) {;}
+ void s(int i = 1) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
+// CHECK-FIXES: void s(int /*i*/ = 1) {;}
+ void u(int i[]) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
+// CHECK-FIXES: void u(int /*i*/[]) {;}
+ void w(void (*fn)()) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning
+// CHECK-FIXES: void w(void (* /*fn*/)()) {;}
+};
+
+void C::f(int i) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning
+// CHECK-FIXES: void C::f() {;}
+
+template <typename T>
+void useFunction(T t);
+
+void someMoreCallSites() {
+ C c;
+ c.f(1);
+// CHECK-FIXES: c.f();
+ c.g(1);
+// CHECK-FIXES: c.g();
+
+ useFunction(&C::h);
+ useFunction(&C::s);
+ useFunction(&C::u);
+ useFunction(&C::w);
+}
+
+class Base {
+ virtual void f(int i);
+};
+
+class Derived : public Base {
+ void f(int i) override {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning
+// CHECK-FIXES: void f(int /*i*/) override {;}
+};
+
+} // end namespace
+
+template <typename T> void someFunctionTemplate(T b, T e) { (void)b; (void)e; }
+
+template <typename T> void someFunctionTemplateOneUnusedParam(T b, T e) { (void)e; }
+// CHECK-MESSAGES: :[[@LINE-1]]:65: warning
+// CHECK-FIXES: {{^}}template <typename T> void someFunctionTemplateOneUnusedParam(T /*b*/, T e) { (void)e; }
+
+template <typename T> void someFunctionTemplateAllUnusedParams(T b, T e) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:66: warning
+// CHECK-MESSAGES: :[[@LINE-2]]:71: warning
+// CHECK-FIXES: {{^}}template <typename T> void someFunctionTemplateAllUnusedParams(T /*b*/, T /*e*/) {;}
+
+static void dontGetConfusedByParametersInFunctionTypes() { void (*F)(int i); }
+
+template <typename T> class Function {};
+static Function<void(int, int i)> dontGetConfusedByFunctionReturnTypes() {
+ return Function<void(int, int)>();
+}
+
+namespace PR38055 {
+namespace {
+struct a {
+ void b(int c) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: parameter 'c' is unused
+// CHECK-FIXES: {{^}} void b() {;}{{$}}
+};
+template <class>
+class d {
+ a e;
+ void f() { e.b(); }
+};
+} // namespace
+} // namespace PR38055
+
+namespace strict_mode_off {
+// Do not warn on empty function bodies.
+void f1(int foo1) {}
+void f2(int foo2) {
+ // "empty" in the AST sense, not in textual sense.
+}
+void f3(int foo3) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: parameter 'foo3' is unused
+// CHECK-FIXES: {{^}}void f3(int /*foo3*/) {;}{{$}}
+
+class E {
+ int i;
+
+public:
+ E(int j) {}
+};
+class F {
+ int i;
+
+public:
+ // Constructor initializer counts as a non-empty body.
+ F(int j) : i() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'j' is unused
+// CHECK-FIXES: {{^}} F(int /*j*/) : i() {}{{$}}
+};
+
+class A {
+public:
+ A();
+ A(int);
+};
+class B : public A {
+public:
+ B(int i) : A() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'i' is unused
+// CHECK-FIXES: {{^}} B(int /*i*/) : A() {}{{$}}
+};
+} // namespace strict_mode_off
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-using-decls-errors.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-using-decls-errors.cpp
new file mode 100644
index 0000000..1c26a69
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-using-decls-errors.cpp
@@ -0,0 +1,12 @@
+// RUN: %check_clang_tidy -expect-clang-tidy-error %s misc-unused-using-decls %t
+
+namespace n {
+class C;
+}
+
+using n::C;
+
+void f() {
+ for (C *p : unknown()) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: error: use of undeclared identifier 'unknown' [clang-diagnostic-error]
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-using-decls.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-using-decls.cpp
new file mode 100644
index 0000000..65ef0da
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/misc-unused-using-decls.cpp
@@ -0,0 +1,203 @@
+// RUN: %check_clang_tidy %s misc-unused-using-decls %t -- -- -fno-delayed-template-parsing -isystem %S/Inputs/
+
+
+// ----- Definitions -----
+template <typename T> class vector {};
+namespace n {
+class A;
+class B;
+class C;
+class D;
+class D { public: static int i; };
+template <typename T> class E {};
+template <typename T> class F {};
+class G { public: static void func() {} };
+class H { public: static int i; };
+class I {
+ public:
+ static int ii;
+};
+template <typename T> class J {};
+class G;
+class H;
+
+template <typename T> class K {};
+template <template <typename> class S>
+class L {};
+
+template <typename T> class M {};
+class N {};
+
+template <int T> class P {};
+const int Constant = 0;
+
+class Base {
+ public:
+ void f();
+};
+
+D UsedInstance;
+D UnusedInstance;
+
+int UsedFunc() { return 1; }
+int UnusedFunc() { return 1; }
+template <typename T> int UsedTemplateFunc() { return 1; }
+template <typename T> int UnusedTemplateFunc() { return 1; }
+template <typename T> int UsedInTemplateFunc() { return 1; }
+void OverloadFunc(int);
+void OverloadFunc(double);
+int FuncUsedByUsingDeclInMacro() { return 1; }
+
+class ostream {
+public:
+ ostream &operator<<(ostream &(*PF)(ostream &));
+};
+extern ostream cout;
+ostream &endl(ostream &os);
+
+enum Color1 { Green };
+
+enum Color2 { Red };
+
+enum Color3 { Yellow };
+
+enum Color4 { Blue };
+
+} // namespace n
+
+#include "unused-using-decls.h"
+namespace ns {
+template <typename T>
+class AA {
+ T t;
+};
+template <typename T>
+T ff() { T t; return t; }
+} // namespace ns
+
+// ----- Using declarations -----
+// eol-comments aren't removed (yet)
+using n::A; // A
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'A' is unused
+// CHECK-FIXES: {{^}}// A
+using n::B;
+using n::C;
+using n::D;
+using n::E; // E
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'E' is unused
+// CHECK-FIXES: {{^}}// E
+using n::F;
+using n::G;
+using n::H;
+using n::I;
+int I::ii = 1;
+class Derived : public n::Base {
+ public:
+ using Base::f;
+};
+using n::UsedInstance;
+using n::UsedFunc;
+using n::UsedTemplateFunc;
+using n::UnusedInstance; // UnusedInstance
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'UnusedInstance' is unused
+// CHECK-FIXES: {{^}}// UnusedInstance
+using n::UnusedFunc; // UnusedFunc
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'UnusedFunc' is unused
+// CHECK-FIXES: {{^}}// UnusedFunc
+using n::cout;
+using n::endl;
+
+using n::UsedInTemplateFunc;
+using n::J;
+template <typename T> void Callee() {
+ J<T> j;
+ UsedInTemplateFunc<T>();
+}
+
+using n::OverloadFunc; // OverloadFunc
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'OverloadFunc' is unused
+// CHECK-FIXES: {{^}}// OverloadFunc
+
+#define DEFINE_INT(name) \
+ namespace INT { \
+ static const int _##name = 1; \
+ } \
+ using INT::_##name
+DEFINE_INT(test);
+#undef DEFIND_INT
+
+#define USING_FUNC \
+ using n::FuncUsedByUsingDeclInMacro;
+USING_FUNC
+#undef USING_FUNC
+
+namespace N1 {
+// n::G is used in namespace N2.
+// Currently, the check doesn't support multiple scopes. All the relevant
+// using-decls will be marked as used once we see an usage even the usage is in
+// other scope.
+using n::G;
+}
+
+namespace N2 {
+using n::G;
+void f(G g);
+}
+
+void IgnoreFunctionScope() {
+// Using-decls defined in function scope will be ignored.
+using n::H;
+}
+
+using n::Color1;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'Color1' is unused
+using n::Green;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'Green' is unused
+using n::Color2;
+using n::Color3;
+using n::Blue;
+
+using ns::AA;
+using ns::ff;
+
+using n::K;
+
+using n::N;
+
+// FIXME: Currently non-type template arguments are not supported.
+using n::Constant;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'Constant' is unused
+
+// ----- Usages -----
+void f(B b);
+void g() {
+ vector<C> data;
+ D::i = 1;
+ F<int> f;
+ void (*func)() = &G::func;
+ int *i = &H::i;
+ UsedInstance.i;
+ UsedFunc();
+ UsedTemplateFunc<int>();
+ cout << endl;
+ Color2 color2;
+ int t1 = Color3::Yellow;
+ int t2 = Blue;
+
+ MyClass a;
+ int t3 = 0;
+ a.func1<AA>(&t3);
+ a.func2<int, ff>(t3);
+
+ n::L<K> l;
+}
+
+template<class T>
+void h(n::M<T>* t) {}
+// n::N is used the explicit template instantiation.
+template void h(n::M<N>* t);
+
+// Test on Non-type template arguments.
+template <int T>
+void i(n::P<T>* t) {}
+template void i(n::P<Constant>* t);
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-avoid-bind.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-avoid-bind.cpp
new file mode 100644
index 0000000..1c78b9e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-avoid-bind.cpp
@@ -0,0 +1,79 @@
+// RUN: %check_clang_tidy %s modernize-avoid-bind %t -- -- -std=c++14
+
+namespace std {
+inline namespace impl {
+template <class Fp, class... Arguments>
+class bind_rt {};
+
+template <class Fp, class... Arguments>
+bind_rt<Fp, Arguments...> bind(Fp &&, Arguments &&...);
+}
+}
+
+int add(int x, int y) { return x + y; }
+
+void f() {
+ auto clj = std::bind(add, 2, 2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind [modernize-avoid-bind]
+ // CHECK-FIXES: auto clj = [] { return add(2, 2); };
+}
+
+void g() {
+ int x = 2;
+ int y = 2;
+ auto clj = std::bind(add, x, y);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
+ // CHECK-FIXES: auto clj = [=] { return add(x, y); };
+}
+
+struct placeholder {};
+placeholder _1;
+placeholder _2;
+
+void h() {
+ int x = 2;
+ auto clj = std::bind(add, x, _1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
+ // CHECK-FIXES: auto clj = [=](auto && arg1) { return add(x, arg1); };
+}
+
+struct A;
+struct B;
+bool ABTest(const A &, const B &);
+
+void i() {
+ auto BATest = std::bind(ABTest, _2, _1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: prefer a lambda to std::bind
+ // CHECK-FIXES: auto BATest = [](auto && arg1, auto && arg2) { return ABTest(arg2, arg1); };
+}
+
+void j() {
+ auto clj = std::bind(add, 2, 2, 2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
+ // No fix is applied for argument mismatches.
+ // CHECK-FIXES: auto clj = std::bind(add, 2, 2, 2);
+}
+
+void k() {
+ auto clj = std::bind(add, _1, _1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
+ // No fix is applied for reused placeholders.
+ // CHECK-FIXES: auto clj = std::bind(add, _1, _1);
+}
+
+void m() {
+ auto clj = std::bind(add, 1, add(2, 5));
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
+ // No fix is applied for nested calls.
+ // CHECK-FIXES: auto clj = std::bind(add, 1, add(2, 5));
+}
+
+namespace C {
+ int add(int x, int y){ return x + y; }
+}
+
+void n() {
+ auto clj = std::bind(C::add, 1, 1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: prefer a lambda to std::bind
+ // CHECK-FIXES: auto clj = [] { return C::add(1, 1); };
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-deprecated-headers-cxx03.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-deprecated-headers-cxx03.cpp
new file mode 100644
index 0000000..c604ba4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-deprecated-headers-cxx03.cpp
@@ -0,0 +1,148 @@
+// RUN: %check_clang_tidy %s modernize-deprecated-headers %t -- -extra-arg-before=-isystem%S/Inputs/modernize-deprecated-headers -- -std=c++03 -v
+
+#include <assert.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'assert.h'; consider using 'cassert' instead [modernize-deprecated-headers]
+// CHECK-FIXES: {{^}}#include <cassert>{{$}}
+#include <complex.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'complex.h'; consider using 'complex' instead
+// CHECK-FIXES: {{^}}#include <complex>{{$}}
+#include <ctype.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'ctype.h'; consider using 'cctype' instead
+// CHECK-FIXES: {{^}}#include <cctype>{{$}}
+#include <errno.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'errno.h'; consider using 'cerrno' instead
+// CHECK-FIXES: {{^}}#include <cerrno>{{$}}
+#include <float.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'float.h'; consider using 'cfloat' instead
+// CHECK-FIXES: {{^}}#include <cfloat>{{$}}
+#include <limits.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'limits.h'; consider using 'climits' instead
+// CHECK-FIXES: {{^}}#include <climits>{{$}}
+#include <locale.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'locale.h'; consider using 'clocale' instead
+// CHECK-FIXES: {{^}}#include <clocale>{{$}}
+#include <math.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'math.h'; consider using 'cmath' instead
+// CHECK-FIXES: {{^}}#include <cmath>{{$}}
+#include <setjmp.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'setjmp.h'; consider using 'csetjmp' instead
+// CHECK-FIXES: {{^}}#include <csetjmp>{{$}}
+#include <signal.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'signal.h'; consider using 'csignal' instead
+// CHECK-FIXES: {{^}}#include <csignal>{{$}}
+#include <stdarg.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdarg.h'; consider using 'cstdarg' instead
+// CHECK-FIXES: {{^}}#include <cstdarg>{{$}}
+#include <stddef.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stddef.h'; consider using 'cstddef' instead
+// CHECK-FIXES: {{^}}#include <cstddef>{{$}}
+#include <stdio.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdio.h'; consider using 'cstdio' instead
+// CHECK-FIXES: {{^}}#include <cstdio>{{$}}
+#include <stdlib.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdlib.h'; consider using 'cstdlib' instead
+// CHECK-FIXES: {{^}}#include <cstdlib>{{$}}
+#include <string.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'string.h'; consider using 'cstring' instead
+// CHECK-FIXES: {{^}}#include <cstring>{{$}}
+#include <time.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'time.h'; consider using 'ctime' instead
+// CHECK-FIXES: {{^}}#include <ctime>{{$}}
+#include <wchar.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wchar.h'; consider using 'cwchar' instead
+// CHECK-FIXES: {{^}}#include <cwchar>{{$}}
+#include <wctype.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wctype.h'; consider using 'cwctype' instead
+// CHECK-FIXES: {{^}}#include <cwctype>{{$}}
+
+// Headers that have no effect in C++; remove them
+#include <stdalign.h> // <stdalign.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdalign.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// <stdalign.h>{{$}}
+#include <stdbool.h> // <stdbool.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdbool.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// <stdbool.h>{{$}}
+#include <iso646.h> // <iso646.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'iso646.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// <iso646.h>{{$}}
+
+// Headers deprecated since C++11: expect no diagnostics.
+#include <fenv.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <tgmath.h>
+#include <uchar.h>
+
+
+#include "assert.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'assert.h'; consider using 'cassert' instead
+// CHECK-FIXES: {{^}}#include <cassert>{{$}}
+#include "complex.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'complex.h'; consider using 'complex' instead
+// CHECK-FIXES: {{^}}#include <complex>{{$}}
+#include "ctype.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'ctype.h'; consider using 'cctype' instead
+// CHECK-FIXES: {{^}}#include <cctype>{{$}}
+#include "errno.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'errno.h'; consider using 'cerrno' instead
+// CHECK-FIXES: {{^}}#include <cerrno>{{$}}
+#include "float.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'float.h'; consider using 'cfloat' instead
+// CHECK-FIXES: {{^}}#include <cfloat>{{$}}
+#include "limits.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'limits.h'; consider using 'climits' instead
+// CHECK-FIXES: {{^}}#include <climits>{{$}}
+#include "locale.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'locale.h'; consider using 'clocale' instead
+// CHECK-FIXES: {{^}}#include <clocale>{{$}}
+#include "math.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'math.h'; consider using 'cmath' instead
+// CHECK-FIXES: {{^}}#include <cmath>{{$}}
+#include "setjmp.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'setjmp.h'; consider using 'csetjmp' instead
+// CHECK-FIXES: {{^}}#include <csetjmp>{{$}}
+#include "signal.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'signal.h'; consider using 'csignal' instead
+// CHECK-FIXES: {{^}}#include <csignal>{{$}}
+#include "stdarg.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdarg.h'; consider using 'cstdarg' instead
+// CHECK-FIXES: {{^}}#include <cstdarg>{{$}}
+#include "stddef.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stddef.h'; consider using 'cstddef' instead
+// CHECK-FIXES: {{^}}#include <cstddef>{{$}}
+#include "stdio.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdio.h'; consider using 'cstdio' instead
+// CHECK-FIXES: {{^}}#include <cstdio>{{$}}
+#include "stdlib.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdlib.h'; consider using 'cstdlib' instead
+// CHECK-FIXES: {{^}}#include <cstdlib>{{$}}
+#include "string.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'string.h'; consider using 'cstring' instead
+// CHECK-FIXES: {{^}}#include <cstring>{{$}}
+#include "time.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'time.h'; consider using 'ctime' instead
+// CHECK-FIXES: {{^}}#include <ctime>{{$}}
+#include "wchar.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wchar.h'; consider using 'cwchar' instead
+// CHECK-FIXES: {{^}}#include <cwchar>{{$}}
+#include "wctype.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wctype.h'; consider using 'cwctype' instead
+// CHECK-FIXES: {{^}}#include <cwctype>
+
+// Headers that have no effect in C++; remove them
+#include "stdalign.h" // "stdalign.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdalign.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// "stdalign.h"{{$}}
+#include "stdbool.h" // "stdbool.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdbool.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// "stdbool.h"{{$}}
+#include "iso646.h" // "iso646.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'iso646.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// "iso646.h"{{$}}
+
+// Headers deprecated since C++11; expect no diagnostics
+#include "fenv.h"
+#include "inttypes.h"
+#include "stdint.h"
+#include "tgmath.h"
+#include "uchar.h"
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-deprecated-headers-cxx11.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-deprecated-headers-cxx11.cpp
new file mode 100644
index 0000000..366f045
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-deprecated-headers-cxx11.cpp
@@ -0,0 +1,163 @@
+// RUN: %check_clang_tidy %s modernize-deprecated-headers %t -- -extra-arg-before=-isystem%S/Inputs/modernize-deprecated-headers -- -std=c++11 -v
+
+#include <assert.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'assert.h'; consider using 'cassert' instead [modernize-deprecated-headers]
+// CHECK-FIXES: {{^}}#include <cassert>{{$}}
+#include <complex.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'complex.h'; consider using 'complex' instead
+// CHECK-FIXES: {{^}}#include <complex>{{$}}
+#include <ctype.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'ctype.h'; consider using 'cctype' instead
+// CHECK-FIXES: {{^}}#include <cctype>{{$}}
+#include <errno.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'errno.h'; consider using 'cerrno' instead
+// CHECK-FIXES: {{^}}#include <cerrno>{{$}}
+#include <fenv.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'fenv.h'; consider using 'cfenv' instead
+// CHECK-FIXES: {{^}}#include <cfenv>{{$}}
+#include <float.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'float.h'; consider using 'cfloat' instead
+// CHECK-FIXES: {{^}}#include <cfloat>{{$}}
+#include <inttypes.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'inttypes.h'; consider using 'cinttypes' instead
+// CHECK-FIXES: {{^}}#include <cinttypes>{{$}}
+#include <limits.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'limits.h'; consider using 'climits' instead
+// CHECK-FIXES: {{^}}#include <climits>{{$}}
+#include <locale.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'locale.h'; consider using 'clocale' instead
+// CHECK-FIXES: {{^}}#include <clocale>{{$}}
+#include <math.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'math.h'; consider using 'cmath' instead
+// CHECK-FIXES: {{^}}#include <cmath>{{$}}
+#include <setjmp.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'setjmp.h'; consider using 'csetjmp' instead
+// CHECK-FIXES: {{^}}#include <csetjmp>{{$}}
+#include <signal.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'signal.h'; consider using 'csignal' instead
+// CHECK-FIXES: {{^}}#include <csignal>{{$}}
+#include <stdarg.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdarg.h'; consider using 'cstdarg' instead
+// CHECK-FIXES: {{^}}#include <cstdarg>{{$}}
+#include <stddef.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stddef.h'; consider using 'cstddef' instead
+// CHECK-FIXES: {{^}}#include <cstddef>{{$}}
+#include <stdint.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdint.h'; consider using 'cstdint' instead
+// CHECK-FIXES: {{^}}#include <cstdint>{{$}}
+#include <stdio.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdio.h'; consider using 'cstdio' instead
+// CHECK-FIXES: {{^}}#include <cstdio>{{$}}
+#include <stdlib.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdlib.h'; consider using 'cstdlib' instead
+// CHECK-FIXES: {{^}}#include <cstdlib>{{$}}
+#include <string.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'string.h'; consider using 'cstring' instead
+// CHECK-FIXES: {{^}}#include <cstring>{{$}}
+#include <tgmath.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'tgmath.h'; consider using 'ctgmath' instead
+// CHECK-FIXES: {{^}}#include <ctgmath>{{$}}
+#include <time.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'time.h'; consider using 'ctime' instead
+// CHECK-FIXES: {{^}}#include <ctime>{{$}}
+#include <uchar.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'uchar.h'; consider using 'cuchar' instead
+// CHECK-FIXES: {{^}}#include <cuchar>{{$}}
+#include <wchar.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wchar.h'; consider using 'cwchar' instead
+// CHECK-FIXES: {{^}}#include <cwchar>{{$}}
+#include <wctype.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wctype.h'; consider using 'cwctype' instead
+// CHECK-FIXES: {{^}}#include <cwctype>
+
+// Headers that have no effect in C++; remove them
+#include <stdalign.h> // <stdalign.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdalign.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// <stdalign.h>{{$}}
+#include <stdbool.h> // <stdbool.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdbool.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// <stdbool.h>{{$}}
+#include <iso646.h> // <iso646.h>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'iso646.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// <iso646.h>{{$}}
+
+#include "assert.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'assert.h'; consider using 'cassert' instead
+// CHECK-FIXES: {{^}}#include <cassert>{{$}}
+#include "complex.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'complex.h'; consider using 'complex' instead
+// CHECK-FIXES: {{^}}#include <complex>{{$}}
+#include "ctype.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'ctype.h'; consider using 'cctype' instead
+// CHECK-FIXES: {{^}}#include <cctype>{{$}}
+#include "errno.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'errno.h'; consider using 'cerrno' instead
+// CHECK-FIXES: {{^}}#include <cerrno>{{$}}
+#include "fenv.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'fenv.h'; consider using 'cfenv' instead
+// CHECK-FIXES: {{^}}#include <cfenv>{{$}}
+#include "float.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'float.h'; consider using 'cfloat' instead
+// CHECK-FIXES: {{^}}#include <cfloat>{{$}}
+#include "inttypes.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'inttypes.h'; consider using 'cinttypes' instead
+// CHECK-FIXES: {{^}}#include <cinttypes>{{$}}
+#include "limits.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'limits.h'; consider using 'climits' instead
+// CHECK-FIXES: {{^}}#include <climits>{{$}}
+#include "locale.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'locale.h'; consider using 'clocale' instead
+// CHECK-FIXES: {{^}}#include <clocale>{{$}}
+#include "math.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'math.h'; consider using 'cmath' instead
+// CHECK-FIXES: {{^}}#include <cmath>{{$}}
+#include "setjmp.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'setjmp.h'; consider using 'csetjmp' instead
+// CHECK-FIXES: {{^}}#include <csetjmp>{{$}}
+#include "signal.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'signal.h'; consider using 'csignal' instead
+// CHECK-FIXES: {{^}}#include <csignal>{{$}}
+#include "stdarg.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdarg.h'; consider using 'cstdarg' instead
+// CHECK-FIXES: {{^}}#include <cstdarg>{{$}}
+#include "stddef.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stddef.h'; consider using 'cstddef' instead
+// CHECK-FIXES: {{^}}#include <cstddef>{{$}}
+#include "stdint.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdint.h'; consider using 'cstdint' instead
+// CHECK-FIXES: {{^}}#include <cstdint>{{$}}
+#include "stdio.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdio.h'; consider using 'cstdio' instead
+// CHECK-FIXES: {{^}}#include <cstdio>{{$}}
+#include "stdlib.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'stdlib.h'; consider using 'cstdlib' instead
+// CHECK-FIXES: {{^}}#include <cstdlib>{{$}}
+#include "string.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'string.h'; consider using 'cstring' instead
+// CHECK-FIXES: {{^}}#include <cstring>{{$}}
+#include "tgmath.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'tgmath.h'; consider using 'ctgmath' instead
+// CHECK-FIXES: {{^}}#include <ctgmath>{{$}}
+#include "time.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'time.h'; consider using 'ctime' instead
+// CHECK-FIXES: {{^}}#include <ctime>{{$}}
+#include "uchar.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'uchar.h'; consider using 'cuchar' instead
+// CHECK-FIXES: {{^}}#include <cuchar>{{$}}
+#include "wchar.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wchar.h'; consider using 'cwchar' instead
+// CHECK-FIXES: {{^}}#include <cwchar>{{$}}
+#include "wctype.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: inclusion of deprecated C++ header 'wctype.h'; consider using 'cwctype' instead
+// CHECK-FIXES: {{^}}#include <cwctype>
+
+// Headers that have no effect in C++; remove them
+#include "stdalign.h" // "stdalign.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdalign.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// "stdalign.h"{{$}}
+#include "stdbool.h" // "stdbool.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'stdbool.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// "stdbool.h"{{$}}
+#include "iso646.h" // "iso646.h"
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: including 'iso646.h' has no effect in C++; consider removing it
+// CHECK-FIXES: {{^}}// "iso646.h"{{$}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-assert-failure.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-assert-failure.cpp
new file mode 100644
index 0000000..fab51da
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-assert-failure.cpp
@@ -0,0 +1,18 @@
+// RUN: not clang-tidy %s -checks=-*,modernize-loop-convert --
+
+// Note: this test expects no assert failure happened in clang-tidy.
+
+class LinguisticItem {
+ LinguisticItem *x0;
+ class x1 {
+ bool operator!= ( const x1 &;
+ operator* ( ;
+ LinguisticItem * &operator-> ( ;
+ operator++ (
+ } begin() const;
+ x1 end() const {
+ LinguisticStream x2;
+ for (x1 x3 = x2.begin x3 != x2.end; ++x3)
+ x3->x0
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-basic.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-basic.cpp
new file mode 100644
index 0000000..def7c4b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-basic.cpp
@@ -0,0 +1,793 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t -- -- -std=c++11 -I %S/Inputs/modernize-loop-convert
+
+#include "structures.h"
+
+namespace Array {
+
+const int N = 6;
+const int NMinusOne = N - 1;
+int Arr[N] = {1, 2, 3, 4, 5, 6};
+const int ConstArr[N] = {1, 2, 3, 4, 5, 6};
+int (*PArr)[N] = &Arr;
+
+void f() {
+ int Sum = 0;
+
+ for (int I = 0; I < N; ++I) {
+ Sum += Arr[I];
+ int K;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead [modernize-loop-convert]
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: Sum += I;
+ // CHECK-FIXES-NEXT: int K;
+
+ for (int I = 0; I < N; ++I) {
+ printf("Fibonacci number is %d\n", Arr[I]);
+ Sum += Arr[I] + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2;
+
+ for (int I = 0; I < N; ++I) {
+ int X = Arr[I];
+ int Y = Arr[I] + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: int X = I;
+ // CHECK-FIXES-NEXT: int Y = I + 2;
+
+ for (int I = 0; I < N; ++I) {
+ int X = N;
+ X = Arr[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: int X = N;
+ // CHECK-FIXES-NEXT: X = I;
+
+ for (int I = 0; I < N; ++I) {
+ Arr[I] += 1;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Arr)
+ // CHECK-FIXES-NEXT: I += 1;
+
+ for (int I = 0; I < N; ++I) {
+ int X = Arr[I] + 2;
+ Arr[I]++;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Arr)
+ // CHECK-FIXES-NEXT: int X = I + 2;
+ // CHECK-FIXES-NEXT: I++;
+
+ for (int I = 0; I < N; ++I) {
+ Arr[I] = 4 + Arr[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Arr)
+ // CHECK-FIXES-NEXT: I = 4 + I;
+
+ for (int I = 0; I < NMinusOne + 1; ++I) {
+ Sum += Arr[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: Sum += I;
+
+ for (int I = 0; I < N; ++I) {
+ printf("Fibonacci number %d has address %p\n", Arr[I], &Arr[I]);
+ Sum += Arr[I] + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Arr)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number %d has address %p\n", I, &I);
+ // CHECK-FIXES-NEXT: Sum += I + 2;
+
+ Val Teas[N];
+ for (int I = 0; I < N; ++I) {
+ Teas[I].g();
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & Tea : Teas)
+ // CHECK-FIXES-NEXT: Tea.g();
+}
+
+const int *constArray() {
+ for (int I = 0; I < N; ++I) {
+ printf("2 * %d = %d\n", ConstArr[I], ConstArr[I] + ConstArr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : ConstArr)
+ // CHECK-FIXES-NEXT: printf("2 * %d = %d\n", I, I + I);
+
+ const NonTriviallyCopyable NonCopy[N]{};
+ for (int I = 0; I < N; ++I) {
+ printf("2 * %d = %d\n", NonCopy[I].X, NonCopy[I].X + NonCopy[I].X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (const auto & I : NonCopy)
+ // CHECK-FIXES-NEXT: printf("2 * %d = %d\n", I.X, I.X + I.X);
+
+ const TriviallyCopyableButBig Big[N]{};
+ for (int I = 0; I < N; ++I) {
+ printf("2 * %d = %d\n", Big[I].X, Big[I].X + Big[I].X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (const auto & I : Big)
+ // CHECK-FIXES-NEXT: printf("2 * %d = %d\n", I.X, I.X + I.X);
+
+ bool Something = false;
+ for (int I = 0; I < N; ++I) {
+ if (Something)
+ return &ConstArr[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (const int & I : ConstArr)
+ // CHECK-FIXES-NEXT: if (Something)
+ // CHECK-FIXES-NEXT: return &I;
+}
+
+struct HasArr {
+ int Arr[N];
+ Val ValArr[N];
+ void implicitThis() {
+ for (int I = 0; I < N; ++I) {
+ printf("%d", Arr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: printf("%d", I);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d", ValArr[I].X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : ValArr)
+ // CHECK-FIXES-NEXT: printf("%d", I.X);
+ }
+
+ void explicitThis() {
+ for (int I = 0; I < N; ++I) {
+ printf("%d", this->Arr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : this->Arr)
+ // CHECK-FIXES-NEXT: printf("%d", I);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d", this->ValArr[I].X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : this->ValArr)
+ // CHECK-FIXES-NEXT: printf("%d", I.X);
+ }
+};
+
+struct HasIndirectArr {
+ HasArr HA;
+ void implicitThis() {
+ for (int I = 0; I < N; ++I) {
+ printf("%d", HA.Arr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : HA.Arr)
+ // CHECK-FIXES-NEXT: printf("%d", I);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d", HA.ValArr[I].X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : HA.ValArr)
+ // CHECK-FIXES-NEXT: printf("%d", I.X);
+ }
+
+ void explicitThis() {
+ for (int I = 0; I < N; ++I) {
+ printf("%d", this->HA.Arr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : this->HA.Arr)
+ // CHECK-FIXES-NEXT: printf("%d", I);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d", this->HA.ValArr[I].X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : this->HA.ValArr)
+ // CHECK-FIXES-NEXT: printf("%d", I.X);
+ }
+};
+
+// Loops whose bounds are value-dependent should not be converted.
+template <int N>
+void dependentExprBound() {
+ for (int I = 0; I < N; ++I)
+ Arr[I] = 0;
+}
+template void dependentExprBound<20>();
+
+void memberFunctionPointer() {
+ Val V;
+ void (Val::*mfpArr[N])(void) = {&Val::g};
+ for (int I = 0; I < N; ++I)
+ (V.*mfpArr[I])();
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : mfpArr)
+ // CHECK-FIXES-NEXT: (V.*I)();
+
+ struct Foo {
+ int (Val::*f)();
+ } Foo[N];
+
+ for (int I = 0; I < N; ++I)
+ int R = (V.*(Foo[I].f))();
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Foo)
+ // CHECK-FIXES-NEXT: int R = (V.*(I.f))();
+
+}
+
+} // namespace Array
+
+namespace Iterator {
+
+void f() {
+ /// begin()/end() - based for loops here:
+ T Tt;
+ for (T::iterator It = Tt.begin(), E = Tt.end(); It != E; ++It) {
+ printf("I found %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : Tt)
+ // CHECK-FIXES-NEXT: printf("I found %d\n", It);
+
+ T *Pt;
+ for (T::iterator It = Pt->begin(), E = Pt->end(); It != E; ++It) {
+ printf("I found %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : *Pt)
+ // CHECK-FIXES-NEXT: printf("I found %d\n", It);
+
+ S Ss;
+ for (S::iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ S *Ps;
+ for (S::iterator It = Ps->begin(), E = Ps->end(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & P : *Ps)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", P.X);
+
+ for (S::const_iterator It = Ss.cbegin(), E = Ss.cend(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto It : Ss)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ for (S::iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ printf("s has value %d\n", It->X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ for (S::iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ It->X = 3;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: It.X = 3;
+
+ for (S::iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ (*It).X = 3;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: It.X = 3;
+
+ for (S::iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ It->nonConstFun(4, 5);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: It.nonConstFun(4, 5);
+
+ U Uu;
+ for (U::iterator It = Uu.begin(), E = Uu.end(); It != E; ++It) {
+ printf("s has value %d\n", It->X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Uu)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ for (U::iterator It = Uu.begin(), E = Uu.end(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Uu)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ for (U::iterator It = Uu.begin(), E = Uu.end(); It != E; ++It) {
+ Val* a = It.operator->();
+ }
+
+ U::iterator A;
+ for (U::iterator I = Uu.begin(), E = Uu.end(); I != E; ++I)
+ int K = A->X + I->X;
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Uu)
+ // CHECK-FIXES-NEXT: int K = A->X + I.X;
+
+ dependent<int> V;
+ for (dependent<int>::iterator It = V.begin(), E = V.end();
+ It != E; ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);
+
+ for (dependent<int>::iterator It(V.begin()), E = V.end();
+ It != E; ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);
+
+ doublyDependent<int, int> Intmap;
+ for (doublyDependent<int, int>::iterator It = Intmap.begin(), E = Intmap.end();
+ It != E; ++It) {
+ printf("Intmap[%d] = %d", It->first, It->second);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Intmap)
+ // CHECK-FIXES: printf("Intmap[%d] = %d", It.first, It.second);
+
+ // PtrSet's iterator dereferences by value so auto & can't be used.
+ {
+ PtrSet<int *> Val_int_ptrs;
+ for (PtrSet<int *>::iterator I = Val_int_ptrs.begin(),
+ E = Val_int_ptrs.end();
+ I != E; ++I) {
+ (void) *I;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto Val_int_ptr : Val_int_ptrs)
+ }
+
+ // This container uses an iterator where the derefence type is a typedef of
+ // a reference type. Make sure non-const auto & is still used. A failure here
+ // means canonical types aren't being tested.
+ {
+ TypedefDerefContainer<int> Int_ptrs;
+ for (TypedefDerefContainer<int>::iterator I = Int_ptrs.begin(),
+ E = Int_ptrs.end();
+ I != E; ++I) {
+ (void) *I;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & Int_ptr : Int_ptrs)
+ }
+
+ {
+ // Iterators returning an rvalue reference should disqualify the loop from
+ // transformation.
+ RValueDerefContainer<int> Container;
+ for (RValueDerefContainer<int>::iterator I = Container.begin(),
+ E = Container.end();
+ I != E; ++I) {
+ (void) *I;
+ }
+ }
+
+ dependent<Val *> Dpp;
+ for (dependent<Val *>::iterator I = Dpp.begin(), E = Dpp.end(); I != E; ++I) {
+ printf("%d\n", (**I).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Dpp)
+ // CHECK-FIXES-NEXT: printf("%d\n", (*I).X);
+
+ for (dependent<Val *>::iterator I = Dpp.begin(), E = Dpp.end(); I != E; ++I) {
+ printf("%d\n", (*I)->X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Dpp)
+ // CHECK-FIXES-NEXT: printf("%d\n", I->X);
+}
+
+// Tests to verify the proper use of auto where the init variable type and the
+// initializer type differ or are mostly the same except for const qualifiers.
+void different_type() {
+ // Ss.begin() returns a type 'iterator' which is just a non-const pointer and
+ // differs from const_iterator only on the const qualification.
+ S Ss;
+ for (S::const_iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto It : Ss)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ S *Ps;
+ for (S::const_iterator It = Ps->begin(), E = Ps->end(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto P : *Ps)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", P.X);
+
+ // V.begin() returns a user-defined type 'iterator' which, since it's
+ // different from const_iterator, disqualifies these loops from
+ // transformation.
+ dependent<int> V;
+ for (dependent<int>::const_iterator It = V.begin(), E = V.end();
+ It != E; ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+
+ for (dependent<int>::const_iterator It(V.begin()), E = V.end();
+ It != E; ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+}
+
+// Tests to ensure that an implicit 'this' is picked up as the container.
+// If member calls are made to 'this' within the loop, the transform becomes
+// risky as these calls may affect state that affects the loop.
+class C {
+public:
+ typedef MutableVal *iterator;
+ typedef const MutableVal *const_iterator;
+
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ void doSomething();
+ void doSomething() const;
+
+ void doLoop() {
+ for (iterator I = begin(), E = end(); I != E; ++I)
+ (void) *I;
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : *this)
+
+ for (iterator I = C::begin(), E = C::end(); I != E; ++I)
+ (void) *I;
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : *this)
+
+ for (iterator I = begin(), E = end(); I != E; ++I) {
+ (void) *I;
+ doSomething();
+ }
+
+ for (iterator I = begin(); I != end(); ++I)
+ (void) *I;
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : *this)
+
+ for (iterator I = begin(); I != end(); ++I) {
+ (void) *I;
+ doSomething();
+ }
+ }
+
+ void doLoop() const {
+ for (const_iterator I = begin(), E = end(); I != E; ++I)
+ (void) *I;
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto I : *this)
+
+ for (const_iterator I = C::begin(), E = C::end(); I != E; ++I)
+ (void) *I;
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto I : *this)
+
+ for (const_iterator I = begin(), E = end(); I != E; ++I) {
+ (void) *I;
+ doSomething();
+ }
+ }
+};
+
+class C2 {
+public:
+ typedef MutableVal *iterator;
+
+ iterator begin() const;
+ iterator end() const;
+
+ void doLoop() {
+ // The implicit 'this' will have an Implicit cast to const C2* wrapped
+ // around it. Make sure the replacement still happens.
+ for (iterator I = begin(), E = end(); I != E; ++I)
+ (void) *I;
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : *this)
+ }
+};
+
+} // namespace Iterator
+
+namespace PseudoArray {
+
+const int N = 6;
+dependent<int> V;
+dependent<int> *Pv;
+const dependent<NonTriviallyCopyable> Constv;
+const dependent<NonTriviallyCopyable> *Pconstv;
+
+transparent<dependent<int>> Cv;
+
+void f() {
+ int Sum = 0;
+ for (int I = 0, E = V.size(); I < E; ++I) {
+ printf("Fibonacci number is %d\n", V[I]);
+ Sum += V[I] + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2;
+
+ for (int I = 0, E = V.size(); I < E; ++I) {
+ printf("Fibonacci number is %d\n", V.at(I));
+ Sum += V.at(I) + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2;
+
+ for (int I = 0, E = Pv->size(); I < E; ++I) {
+ printf("Fibonacci number is %d\n", Pv->at(I));
+ Sum += Pv->at(I) + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : *Pv)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2;
+
+ // This test will fail if size() isn't called repeatedly, since it
+ // returns unsigned int, and 0 is deduced to be signed int.
+ // FIXME: Insert the necessary explicit conversion, or write out the types
+ // explicitly.
+ for (int I = 0; I < Pv->size(); ++I) {
+ printf("Fibonacci number is %d\n", (*Pv).at(I));
+ Sum += (*Pv)[I] + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : *Pv)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2;
+
+ for (int I = 0; I < Cv->size(); ++I) {
+ printf("Fibonacci number is %d\n", Cv->at(I));
+ Sum += Cv->at(I) + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : *Cv)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2;
+}
+
+// Ensure that 'const auto &' is used with containers of non-trivial types.
+void constness() {
+ int Sum = 0;
+ for (int I = 0, E = Constv.size(); I < E; ++I) {
+ printf("Fibonacci number is %d\n", Constv[I].X);
+ Sum += Constv[I].X + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (const auto & I : Constv)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I.X);
+ // CHECK-FIXES-NEXT: Sum += I.X + 2;
+
+ for (int I = 0, E = Constv.size(); I < E; ++I) {
+ printf("Fibonacci number is %d\n", Constv.at(I).X);
+ Sum += Constv.at(I).X + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (const auto & I : Constv)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I.X);
+ // CHECK-FIXES-NEXT: Sum += I.X + 2;
+
+ for (int I = 0, E = Pconstv->size(); I < E; ++I) {
+ printf("Fibonacci number is %d\n", Pconstv->at(I).X);
+ Sum += Pconstv->at(I).X + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (const auto & I : *Pconstv)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I.X);
+ // CHECK-FIXES-NEXT: Sum += I.X + 2;
+
+ // This test will fail if size() isn't called repeatedly, since it
+ // returns unsigned int, and 0 is deduced to be signed int.
+ // FIXME: Insert the necessary explicit conversion, or write out the types
+ // explicitly.
+ for (int I = 0; I < Pconstv->size(); ++I) {
+ printf("Fibonacci number is %d\n", (*Pconstv).at(I).X);
+ Sum += (*Pconstv)[I].X + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (const auto & I : *Pconstv)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I.X);
+ // CHECK-FIXES-NEXT: Sum += I.X + 2;
+}
+
+void constRef(const dependent<int>& ConstVRef) {
+ int sum = 0;
+ // FIXME: This does not work with size_t (probably due to the implementation
+ // of dependent); make dependent work exactly like a std container type.
+ for (int I = 0; I < ConstVRef.size(); ++I) {
+ sum += ConstVRef[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : ConstVRef)
+ // CHECK-FIXES-NEXT: sum += I;
+
+ for (auto I = ConstVRef.begin(), E = ConstVRef.end(); I != E; ++I) {
+ sum += *I;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : ConstVRef)
+ // CHECK-FIXES-NEXT: sum += I;
+}
+
+// Check for loops that don't mention containers.
+void noContainer() {
+ for (auto I = 0; I < V.size(); ++I) {
+ }
+
+ for (auto I = 0; I < V.size(); ++I)
+ ;
+}
+
+struct NoBeginEnd {
+ unsigned size() const;
+ unsigned& operator[](int);
+ const unsigned& operator[](int) const;
+};
+
+struct NoConstBeginEnd {
+ NoConstBeginEnd();
+ unsigned size() const;
+ unsigned* begin();
+ unsigned* end();
+ unsigned& operator[](int);
+ const unsigned& operator[](int) const;
+};
+
+struct ConstBeginEnd {
+ ConstBeginEnd();
+ unsigned size() const;
+ unsigned* begin() const;
+ unsigned* end() const;
+ unsigned& operator[](int);
+ const unsigned& operator[](int) const;
+};
+
+// Shouldn't transform pseudo-array uses if the container doesn't provide
+// begin() and end() of the right const-ness.
+void NoBeginEndTest() {
+ NoBeginEnd NBE;
+ for (unsigned I = 0, E = NBE.size(); I < E; ++I)
+ printf("%d\n", NBE[I]);
+
+ const NoConstBeginEnd Const_NCBE;
+ for (unsigned I = 0, E = Const_NCBE.size(); I < E; ++I)
+ printf("%d\n", Const_NCBE[I]);
+
+ ConstBeginEnd CBE;
+ for (unsigned I = 0, E = CBE.size(); I < E; ++I)
+ printf("%d\n", CBE[I]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (unsigned int I : CBE)
+ // CHECK-FIXES-NEXT: printf("%d\n", I);
+
+ const ConstBeginEnd Const_CBE;
+ for (unsigned I = 0, E = Const_CBE.size(); I < E; ++I)
+ printf("%d\n", Const_CBE[I]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (unsigned int I : Const_CBE)
+ // CHECK-FIXES-NEXT: printf("%d\n", I);
+}
+
+struct DerefByValue {
+ DerefByValue();
+ struct iter { unsigned operator*(); };
+ unsigned size() const;
+ iter begin();
+ iter end();
+ unsigned operator[](int);
+};
+
+void derefByValueTest() {
+ DerefByValue DBV;
+ for (unsigned I = 0, E = DBV.size(); I < E; ++I) {
+ printf("%d\n", DBV[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (unsigned int I : DBV)
+ // CHECK-FIXES-NEXT: printf("%d\n", I);
+
+ for (unsigned I = 0, E = DBV.size(); I < E; ++I) {
+ auto f = [DBV, I]() {};
+ printf("%d\n", DBV[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (unsigned int I : DBV)
+ // CHECK-FIXES-NEXT: auto f = [DBV, &I]() {};
+ // CHECK-FIXES-NEXT: printf("%d\n", I);
+}
+
+void fundamentalTypesTest() {
+ const int N = 10;
+ bool Bools[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", Bools[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (bool Bool : Bools)
+
+ int Ints[N];
+ unsigned short int Shorts[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", Shorts[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (unsigned short Short : Shorts)
+
+ signed long Longs[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", Longs[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (long Long : Longs)
+
+ long long int LongLongs[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", LongLongs[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (long long LongLong : LongLongs)
+
+ char Chars[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", Chars[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (char Char : Chars)
+
+ wchar_t WChars[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", WChars[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (wchar_t WChar : WChars)
+
+ float Floats[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", Floats[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (float Float : Floats)
+
+ double Doubles[N];
+ for (int i = 0; i < N; ++i)
+ printf("%d", Doubles[i]);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (double Double : Doubles)
+}
+
+} // namespace PseudoArray
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-camelback.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-camelback.cpp
new file mode 100644
index 0000000..50044de
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-camelback.cpp
@@ -0,0 +1,33 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-loop-convert.NamingStyle, value: 'camelBack'}]}" \
+// RUN: -- -std=c++11 -I %S/Inputs/modernize-loop-convert
+
+#include "structures.h"
+
+const int n = 10;
+int arr[n];
+int nums[n];
+
+void naming() {
+ for (int i = 0; i < n; ++i) {
+ printf("%d\n", arr[i]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead [modernize-loop-convert]
+ // CHECK-FIXES: for (int i : arr)
+ // CHECK-FIXES-NEXT: printf("%d\n", i);
+
+ for (int i = 0; i < n; ++i) {
+ printf("%d\n", nums[i]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int num : nums)
+ // CHECK-FIXES-NEXT: printf("%d\n", num);
+
+ int num = 0;
+ for (int i = 0; i < n; ++i) {
+ printf("%d\n", nums[i] + num);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int i : nums)
+ // CHECK-FIXES-NEXT: printf("%d\n", i + num);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-const.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-const.cpp
new file mode 100644
index 0000000..806b6c1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-const.cpp
@@ -0,0 +1,360 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t -- -- -std=c++11
+
+struct Str {
+ Str() = default;
+ Str(const Str &) = default;
+ void constMember(int) const;
+ void nonConstMember(int);
+ bool operator<(const Str &str) const; // const operator.
+ Str &operator=(const Str &str) = default; // non const operator.
+};
+
+// This class is non-trivially copyable because the copy-constructor and copy
+// assignment take non-const references.
+struct ModifiesRightSide {
+ ModifiesRightSide() = default;
+ ModifiesRightSide(ModifiesRightSide &) = default;
+ bool operator<(ModifiesRightSide &) const;
+ ModifiesRightSide &operator=(ModifiesRightSide &) = default;
+};
+
+template <typename T>
+void copyArg(T);
+
+template <typename T>
+void nonConstRefArg(T &);
+
+// If we define this as a template, the type is deduced to "T&",
+// and "const (T&) &" is the same as "T& &", and this collapses to "T&".
+void constRefArg(const Str &);
+void constRefArg(const ModifiesRightSide &);
+void constRefArg(const int &);
+
+void foo();
+
+const int N = 10;
+Str Array[N], OtherStr;
+ModifiesRightSide Right[N], OtherRight;
+int Ints[N], OtherInt;
+
+void memberFunctionsAndOperators() {
+ // Calling const member functions or operator is a const usage.
+ for (int I = 0; I < N; ++I) {
+ Array[I].constMember(0);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead [modernize-loop-convert]
+ // CHECK-FIXES: for (auto I : Array)
+ // CHECK-FIXES-NEXT: I.constMember(0);
+
+ for (int I = 0; I < N; ++I) {
+ if (Array[I] < OtherStr)
+ foo();
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto I : Array)
+ // CHECK-FIXES-NEXT: if (I < OtherStr)
+ for (int I = 0; I < N; ++I) {
+ if (Right[I] < OtherRight)
+ foo();
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (const auto & I : Right)
+ // CHECK-FIXES-NEXT: if (I < OtherRight)
+
+ // Calling non-const member functions is not.
+ for (int I = 0; I < N; ++I) {
+ Array[I].nonConstMember(0);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Array)
+ // CHECK-FIXES-NEXT: I.nonConstMember(0);
+
+ for (int I = 0; I < N; ++I) {
+ Array[I] = OtherStr;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Array)
+ // CHECK-FIXES-NEXT: I = OtherStr;
+
+ for (int I = 0; I < N; ++I) {
+ Right[I] = OtherRight;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Right)
+ // CHECK-FIXES-NEXT: I = OtherRight;
+}
+
+void usedAsParameterToFunctionOrOperator() {
+ // Copying is OK, as long as the copy constructor takes a const-reference.
+ for (int I = 0; I < N; ++I) {
+ copyArg(Array[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto I : Array)
+ // CHECK-FIXES-NEXT: copyArg(I);
+
+ for (int I = 0; I < N; ++I) {
+ copyArg(Right[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Right)
+ // CHECK-FIXES-NEXT: copyArg(I);
+
+ // Using as a const reference argument is allowed.
+ for (int I = 0; I < N; ++I) {
+ constRefArg(Array[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto I : Array)
+ // CHECK-FIXES-NEXT: constRefArg(I);
+
+ for (int I = 0; I < N; ++I) {
+ if (OtherStr < Array[I])
+ foo();
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto I : Array)
+ // CHECK-FIXES-NEXT: if (OtherStr < I)
+
+ for (int I = 0; I < N; ++I) {
+ constRefArg(Right[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (const auto & I : Right)
+ // CHECK-FIXES-NEXT: constRefArg(I);
+
+ // Using as a non-const reference is not.
+ for (int I = 0; I < N; ++I) {
+ nonConstRefArg(Array[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Array)
+ // CHECK-FIXES-NEXT: nonConstRefArg(I);
+ for (int I = 0; I < N; ++I) {
+ nonConstRefArg(Right[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Right)
+ // CHECK-FIXES-NEXT: nonConstRefArg(I);
+ for (int I = 0; I < N; ++I) {
+ if (OtherRight < Right[I])
+ foo();
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Right)
+ // CHECK-FIXES-NEXT: if (OtherRight < I)
+}
+
+void primitiveTypes() {
+ // As argument to a function.
+ for (int I = 0; I < N; ++I) {
+ copyArg(Ints[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: copyArg(Int);
+ for (int I = 0; I < N; ++I) {
+ constRefArg(Ints[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: constRefArg(Int);
+ for (int I = 0; I < N; ++I) {
+ nonConstRefArg(Ints[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int & Int : Ints)
+ // CHECK-FIXES-NEXT: nonConstRefArg(Int);
+
+ // Builtin operators.
+ // Comparisons.
+ for (int I = 0; I < N; ++I) {
+ if (Ints[I] < N)
+ foo();
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: if (Int < N)
+
+ for (int I = 0; I < N; ++I) {
+ if (N == Ints[I])
+ foo();
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: if (N == Int)
+
+ // Assignment.
+ for (int I = 0; I < N; ++I) {
+ Ints[I] = OtherInt;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int & Int : Ints)
+ // CHECK-FIXES-NEXT: Int = OtherInt;
+
+ for (int I = 0; I < N; ++I) {
+ OtherInt = Ints[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: OtherInt = Int;
+
+ for (int I = 0; I < N; ++I) {
+ OtherInt = Ints[I] = OtherInt;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int & Int : Ints)
+ // CHECK-FIXES-NEXT: OtherInt = Int = OtherInt;
+
+ // Arithmetic operations.
+ for (int I = 0; I < N; ++I) {
+ OtherInt += Ints[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: OtherInt += Int;
+
+ for (int I = 0; I < N; ++I) {
+ Ints[I] += Ints[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int & Int : Ints)
+ // CHECK-FIXES-NEXT: Int += Int;
+
+ for (int I = 0; I < N; ++I) {
+ int Res = 5 * (Ints[I] + 1) - Ints[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: int Res = 5 * (Int + 1) - Int;
+}
+
+void takingReferences() {
+ // We do it twice to prevent the check from thinking that they are aliases.
+
+ // Class type.
+ for (int I = 0; I < N; ++I) {
+ Str &J = Array[I];
+ Str &K = Array[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & I : Array)
+ // CHECK-FIXES-NEXT: Str &J = I;
+ // CHECK-FIXES-NEXT: Str &K = I;
+ for (int I = 0; I < N; ++I) {
+ const Str &J = Array[I];
+ const Str &K = Array[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto I : Array)
+ // CHECK-FIXES-NEXT: const Str &J = I;
+ // CHECK-FIXES-NEXT: const Str &K = I;
+
+ // Primitive type.
+ for (int I = 0; I < N; ++I) {
+ int &J = Ints[I];
+ int &K = Ints[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int & Int : Ints)
+ // CHECK-FIXES-NEXT: int &J = Int;
+ // CHECK-FIXES-NEXT: int &K = Int;
+ for (int I = 0; I < N; ++I) {
+ const int &J = Ints[I];
+ const int &K = Ints[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: const int &J = Int;
+ // CHECK-FIXES-NEXT: const int &K = Int;
+
+ // Aliases.
+ for (int I = 0; I < N; ++I) {
+ const Str &J = Array[I];
+ (void)J;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto J : Array)
+ for (int I = 0; I < N; ++I) {
+ Str &J = Array[I];
+ (void)J;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto & J : Array)
+
+ for (int I = 0; I < N; ++I) {
+ const int &J = Ints[I];
+ (void)J;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int J : Ints)
+
+ for (int I = 0; I < N; ++I) {
+ int &J = Ints[I];
+ (void)J;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int & J : Ints)
+}
+
+template <class T>
+struct vector {
+ unsigned size() const;
+ const T &operator[](int) const;
+ T &operator[](int);
+ T *begin();
+ T *end();
+ const T *begin() const;
+ const T *end() const;
+};
+
+// If the elements are already constant, we won't do any ImplicitCast to const.
+void testContainerOfConstIents() {
+ const int Ints[N]{};
+ for (int I = 0; I < N; ++I) {
+ OtherInt -= Ints[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+
+ vector<const Str> Strs;
+ for (int I = 0; I < Strs.size(); ++I) {
+ Strs[I].constMember(0);
+ constRefArg(Strs[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop
+ // CHECK-FIXES: for (auto Str : Strs)
+}
+
+// When we are inside a const-qualified member functions, all the data members
+// are implicitly set as const. As before, there won't be any ImplicitCast to
+// const in their usages.
+class TestInsideConstFunction {
+ const static int N = 10;
+ int Ints[N];
+ Str Array[N];
+ vector<int> V;
+
+ void foo() const {
+ for (int I = 0; I < N; ++I) {
+ if (Ints[I])
+ copyArg(Ints[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop
+ // CHECK-FIXES: for (int Int : Ints)
+
+ for (int I = 0; I < N; ++I) {
+ Array[I].constMember(0);
+ constRefArg(Array[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop
+ // CHECK-FIXES: for (auto I : Array)
+
+ for (int I = 0; I < V.size(); ++I) {
+ if (V[I])
+ copyArg(V[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop
+ // CHECK-FIXES: for (int I : V)
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-extra.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-extra.cpp
new file mode 100644
index 0000000..b46ff25
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-extra.cpp
@@ -0,0 +1,1074 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t -- -- -std=c++11 -I %S/Inputs/modernize-loop-convert
+
+#include "structures.h"
+
+namespace Dependency {
+
+void f() {
+ const int N = 6;
+ const int M = 8;
+ int Arr[N][M];
+
+ for (int I = 0; I < N; ++I) {
+ int A = 0;
+ int B = Arr[I][A];
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Arr)
+ // CHECK-FIXES-NEXT: int A = 0;
+ // CHECK-FIXES-NEXT: int B = I[A];
+
+ for (int J = 0; J < M; ++J) {
+ int A = 0;
+ int B = Arr[A][J];
+ }
+}
+
+} // namespace Dependency
+
+namespace NamingAlias {
+
+const int N = 10;
+
+Val Arr[N];
+dependent<Val> V;
+dependent<Val> *Pv;
+Val &func(Val &);
+void sideEffect(int);
+
+void aliasing() {
+ // If the loop container is only used for a declaration of a temporary
+ // variable to hold each element, we can name the new variable for the
+ // converted range-based loop as the temporary variable's name.
+
+ // In the following case, "T" is used as a temporary variable to hold each
+ // element, and thus we consider the name "T" aliased to the loop.
+ // The extra blank braces are left as a placeholder for after the variable
+ // declaration is deleted.
+ for (int I = 0; I < N; ++I) {
+ Val &T = Arr[I];
+ {}
+ int Y = T.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & T : Arr)
+ // CHECK-FIXES-NOT: Val &{{[a-z_]+}} =
+ // CHECK-FIXES-NEXT: {}
+ // CHECK-FIXES-NEXT: int Y = T.X;
+
+ // The container was not only used to initialize a temporary loop variable for
+ // the container's elements, so we do not alias the new loop variable.
+ for (int I = 0; I < N; ++I) {
+ Val &T = Arr[I];
+ int Y = T.X;
+ int Z = Arr[I].X + T.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Arr)
+ // CHECK-FIXES-NEXT: Val &T = I;
+ // CHECK-FIXES-NEXT: int Y = T.X;
+ // CHECK-FIXES-NEXT: int Z = I.X + T.X;
+
+ for (int I = 0; I < N; ++I) {
+ Val T = Arr[I];
+ int Y = T.X;
+ int Z = Arr[I].X + T.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Arr)
+ // CHECK-FIXES-NEXT: Val T = I;
+ // CHECK-FIXES-NEXT: int Y = T.X;
+ // CHECK-FIXES-NEXT: int Z = I.X + T.X;
+
+ // The same for pseudo-arrays like std::vector<T> (or here dependent<Val>)
+ // which provide a subscript operator[].
+ for (int I = 0; I < V.size(); ++I) {
+ Val &T = V[I];
+ {}
+ int Y = T.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & T : V)
+ // CHECK-FIXES-NEXT: {}
+ // CHECK-FIXES-NEXT: int Y = T.X;
+
+ // The same with a call to at()
+ for (int I = 0; I < Pv->size(); ++I) {
+ Val &T = Pv->at(I);
+ {}
+ int Y = T.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & T : *Pv)
+ // CHECK-FIXES-NEXT: {}
+ // CHECK-FIXES-NEXT: int Y = T.X;
+
+ for (int I = 0; I < N; ++I) {
+ Val &T = func(Arr[I]);
+ int Y = T.X;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Arr)
+ // CHECK-FIXES-NEXT: Val &T = func(I);
+ // CHECK-FIXES-NEXT: int Y = T.X;
+
+ int IntArr[N];
+ for (unsigned I = 0; I < N; ++I) {
+ if (int Alias = IntArr[I]) {
+ sideEffect(Alias);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Alias : IntArr)
+ // CHECK-FIXES-NEXT: if (Alias)
+
+ for (unsigned I = 0; I < N; ++I) {
+ while (int Alias = IntArr[I]) {
+ sideEffect(Alias);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Alias : IntArr)
+ // CHECK-FIXES-NEXT: while (Alias)
+
+ for (unsigned I = 0; I < N; ++I) {
+ switch (int Alias = IntArr[I]) {
+ default:
+ sideEffect(Alias);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-6]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Alias : IntArr)
+ // CHECK-FIXES-NEXT: switch (Alias)
+
+ for (unsigned I = 0; I < N; ++I) {
+ for (int Alias = IntArr[I]; Alias < N; ++Alias) {
+ sideEffect(Alias);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Alias : IntArr)
+ // CHECK-FIXES-NEXT: for (; Alias < N; ++Alias)
+
+ for (unsigned I = 0; I < N; ++I) {
+ for (unsigned J = 0; int Alias = IntArr[I]; ++J) {
+ sideEffect(Alias);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Alias : IntArr)
+ // CHECK-FIXES-NEXT: for (unsigned J = 0; Alias; ++J)
+
+ struct IntRef { IntRef(); IntRef(const int& i); operator int*(); };
+ for (int I = 0; I < N; ++I) {
+ IntRef Int(IntArr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : IntArr)
+ // CHECK-FIXES-NEXT: IntRef Int(I);
+
+ int *PtrArr[N];
+ for (unsigned I = 0; I < N; ++I) {
+ const int* const P = PtrArr[I];
+ printf("%d\n", *P);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto P : PtrArr)
+ // CHECK-FIXES-NEXT: printf("%d\n", *P);
+
+ IntRef Refs[N];
+ for (unsigned I = 0; I < N; ++I) {
+ int *P = Refs[I];
+ printf("%d\n", *P);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & Ref : Refs)
+ // CHECK-FIXES-NEXT: int *P = Ref;
+ // CHECK-FIXES-NEXT: printf("%d\n", *P);
+
+ // Ensure that removing the alias doesn't leave empty lines behind.
+ for (int I = 0; I < N; ++I) {
+ auto &X = IntArr[I];
+ X = 0;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & X : IntArr) {
+ // CHECK-FIXES-NEXT: {{^ X = 0;$}}
+ // CHECK-FIXES-NEXT: {{^ }$}}
+}
+
+void refs_and_vals() {
+ // The following tests check that the transform correctly preserves the
+ // reference or value qualifiers of the aliased variable. That is, if the
+ // variable was declared as a value, the loop variable will be declared as a
+ // value and vice versa for references.
+
+ S Ss;
+ const S S_const = Ss;
+
+ for (S::const_iterator It = S_const.begin(); It != S_const.end(); ++It) {
+ MutableVal Alias = *It;
+ {}
+ Alias.X = 0;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto Alias : S_const)
+ // CHECK-FIXES-NOT: MutableVal {{[a-z_]+}} =
+ // CHECK-FIXES-NEXT: {}
+ // CHECK-FIXES-NEXT: Alias.X = 0;
+
+ for (S::iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ MutableVal Alias = *It;
+ {}
+ Alias.X = 0;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto Alias : Ss)
+ // CHECK-FIXES-NOT: MutableVal {{[a-z_]+}} =
+ // CHECK-FIXES-NEXT: {}
+ // CHECK-FIXES-NEXT: Alias.X = 0;
+
+ for (S::iterator It = Ss.begin(), E = Ss.end(); It != E; ++It) {
+ MutableVal &Alias = *It;
+ {}
+ Alias.X = 0;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & Alias : Ss)
+ // CHECK-FIXES-NOT: MutableVal &{{[a-z_]+}} =
+ // CHECK-FIXES-NEXT: {}
+ // CHECK-FIXES-NEXT: Alias.X = 0;
+
+ dependent<int> Dep, Other;
+ for (dependent<int>::iterator It = Dep.begin(), E = Dep.end(); It != E; ++It) {
+ printf("%d\n", *It);
+ const int& Idx = Other[0];
+ unsigned Othersize = Other.size();
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : Dep)
+ // CHECK-FIXES-NEXT: printf("%d\n", It);
+ // CHECK-FIXES-NEXT: const int& Idx = Other[0];
+ // CHECK-FIXES-NEXT: unsigned Othersize = Other.size();
+
+ for (int i = 0; i < Other.size(); ++i) {
+ Other.at(i);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & i : Other)
+ // CHECK-FIXES: i;
+
+ for (int I = 0, E = Dep.size(); I != E; ++I) {
+ int Idx = Other.at(I);
+ Other.at(I, I); // Should not trigger assert failure.
+ }
+}
+
+struct MemberNaming {
+ const static int N = 10;
+ int Ints[N], Ints_[N];
+ dependent<int> DInts;
+ void loops() {
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", Ints[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: printf("%d\n", Int);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", Ints_[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Int : Ints_)
+ // CHECK-FIXES-NEXT: printf("%d\n", Int);
+
+ for (int I = 0; I < DInts.size(); ++I) {
+ printf("%d\n", DInts[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int DInt : DInts)
+ // CHECK-FIXES-NEXT: printf("%d\n", DInt);
+ }
+
+ void outOfLine();
+};
+void MemberNaming::outOfLine() {
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", Ints[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Int : Ints)
+ // CHECK-FIXES-NEXT: printf("%d\n", Int);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", Ints_[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Int : Ints_)
+ // CHECK-FIXES-NEXT: printf("%d\n", Int);
+}
+
+} // namespace NamingAlias
+
+namespace NamingConlict {
+
+#define MAX(a, b) (a > b) ? a : b
+#define DEF 5
+
+const int N = 10;
+int Nums[N];
+int Sum = 0;
+
+namespace ns {
+struct St {
+ int X;
+};
+}
+
+void sameNames() {
+ int Num = 0;
+ for (int I = 0; I < N; ++I) {
+ printf("Fibonacci number is %d\n", Nums[I]);
+ Sum += Nums[I] + 2 + Num;
+ (void)Nums[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Nums)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2 + Num;
+ // CHECK-FIXES-NEXT: (void)I;
+
+ int Elem = 0;
+ for (int I = 0; I < N; ++I) {
+ printf("Fibonacci number is %d\n", Nums[I]);
+ Sum += Nums[I] + 2 + Num + Elem;
+ (void)Nums[I];
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Nums)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", I);
+ // CHECK-FIXES-NEXT: Sum += I + 2 + Num + Elem;
+ // CHECK-FIXES-NEXT: (void)I;
+}
+
+void oldIndexConflict() {
+ for (int Num = 0; Num < N; ++Num) {
+ printf("Num: %d\n", Nums[Num]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int Num : Nums)
+ // CHECK-FIXES-NEXT: printf("Num: %d\n", Num);
+
+ S Things;
+ for (S::iterator Thing = Things.begin(), End = Things.end(); Thing != End; ++Thing) {
+ printf("Thing: %d %d\n", Thing->X, (*Thing).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & Thing : Things)
+ // CHECK-FIXES-NEXT: printf("Thing: %d %d\n", Thing.X, Thing.X);
+}
+
+void macroConflict() {
+ S MAXs;
+ for (S::iterator It = MAXs.begin(), E = MAXs.end(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ printf("Max of 3 and 5: %d\n", MAX(3, 5));
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : MAXs)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+ // CHECK-FIXES-NEXT: printf("Max of 3 and 5: %d\n", MAX(3, 5));
+
+ for (S::const_iterator It = MAXs.begin(), E = MAXs.end(); It != E; ++It) {
+ printf("s has value %d\n", (*It).X);
+ printf("Max of 3 and 5: %d\n", MAX(3, 5));
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto It : MAXs)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+ // CHECK-FIXES-NEXT: printf("Max of 3 and 5: %d\n", MAX(3, 5));
+
+ T DEFs;
+ for (T::iterator It = DEFs.begin(), E = DEFs.end(); It != E; ++It) {
+ if (*It == DEF) {
+ printf("I found %d\n", *It);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : DEFs)
+ // CHECK-FIXES-NEXT: if (It == DEF)
+ // CHECK-FIXES-NEXT: printf("I found %d\n", It);
+}
+
+void keywordConflict() {
+ T ints;
+ for (T::iterator It = ints.begin(), E = ints.end(); It != E; ++It) {
+ *It = 5;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : ints)
+ // CHECK-FIXES-NEXT: It = 5;
+
+ U __FUNCTION__s;
+ for (U::iterator It = __FUNCTION__s.begin(), E = __FUNCTION__s.end();
+ It != E; ++It) {
+ int __FUNCTION__s_It = (*It).X + 2;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : __FUNCTION__s)
+ // CHECK-FIXES-NEXT: int __FUNCTION__s_It = It.X + 2;
+}
+
+void typeConflict() {
+ T Vals;
+ // Using the name "Val", although it is the name of an existing struct, is
+ // safe in this loop since it will only exist within this scope.
+ for (T::iterator It = Vals.begin(), E = Vals.end(); It != E; ++It)
+ (void) *It;
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & Val : Vals)
+
+ // We cannot use the name "Val" in this loop since there is a reference to
+ // it in the body of the loop.
+ for (T::iterator It = Vals.begin(), E = Vals.end(); It != E; ++It) {
+ *It = sizeof(Val);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : Vals)
+ // CHECK-FIXES-NEXT: It = sizeof(Val);
+
+ typedef struct Val TD;
+ U TDs;
+ // Naming the variable "TD" within this loop is safe because the typedef
+ // was never used within the loop.
+ for (U::iterator It = TDs.begin(), E = TDs.end(); It != E; ++It)
+ (void) *It;
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & TD : TDs)
+
+ // "TD" cannot be used in this loop since the typedef is being used.
+ for (U::iterator It = TDs.begin(), E = TDs.end(); It != E; ++It) {
+ TD V;
+ V.X = 5;
+ (void) *It;
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : TDs)
+ // CHECK-FIXES-NEXT: TD V;
+ // CHECK-FIXES-NEXT: V.X = 5;
+
+ using ns::St;
+ T Sts;
+ for (T::iterator It = Sts.begin(), E = Sts.end(); It != E; ++It) {
+ *It = sizeof(St);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : Sts)
+ // CHECK-FIXES-NEXT: It = sizeof(St);
+}
+
+} // namespace NamingConflict
+
+namespace FreeBeginEnd {
+
+// FIXME: Loop Convert should detect free begin()/end() functions.
+
+struct MyArray {
+ unsigned size();
+};
+
+template <typename T>
+struct MyContainer {
+};
+
+int *begin(const MyArray &Arr);
+int *end(const MyArray &Arr);
+
+template <typename T>
+T *begin(const MyContainer<T> &C);
+template <typename T>
+T *end(const MyContainer<T> &C);
+
+// The Loop Convert Transform doesn't detect free functions begin()/end() and
+// so fails to transform these cases which it should.
+void f() {
+ MyArray Arr;
+ for (unsigned I = 0, E = Arr.size(); I < E; ++I) {
+ }
+
+ MyContainer<int> C;
+ for (int *I = begin(C), *E = end(C); I != E; ++I) {
+ }
+}
+
+} // namespace FreeBeginEnd
+
+namespace Nesting {
+
+void g(S::iterator It);
+void const_g(S::const_iterator It);
+class Foo {
+ public:
+ void g(S::iterator It);
+ void const_g(S::const_iterator It);
+};
+
+void f() {
+ const int N = 10;
+ const int M = 15;
+ Val Arr[N];
+ for (int I = 0; I < N; ++I) {
+ for (int J = 0; J < N; ++J) {
+ int K = Arr[I].X + Arr[J].X;
+ // The repeat is there to allow FileCheck to make sure the two variable
+ // names aren't the same.
+ int L = Arr[I].X + Arr[J].X;
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-8]]:3: warning: use range-based for loop instead
+ // CHECK-MESSAGES: :[[@LINE-8]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Arr)
+ // CHECK-FIXES-NEXT: for (auto & J : Arr)
+ // CHECK-FIXES-NEXT: int K = I.X + J.X;
+ // CHECK-FIXES-NOT: int L = I.X + I.X;
+
+ // The inner loop is also convertible, but doesn't need to be converted
+ // immediately. FIXME: update this test when that changes.
+ Val Nest[N][M];
+ for (int I = 0; I < N; ++I) {
+ for (int J = 0; J < M; ++J) {
+ printf("Got item %d", Nest[I][J].X);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Nest)
+ // CHECK-FIXES-NEXT: for (int J = 0; J < M; ++J)
+ // CHECK-FIXES-NEXT: printf("Got item %d", I[J].X);
+
+ // Note that the order of M and N are switched for this test.
+ for (int J = 0; J < M; ++J) {
+ for (int I = 0; I < N; ++I) {
+ printf("Got item %d", Nest[I][J].X);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use range-based for loop instead
+ // CHECK-FIXES-NOT: for (auto & {{[a-zA-Z_]+}} : Nest[I])
+ // CHECK-FIXES: for (int J = 0; J < M; ++J)
+ // CHECK-FIXES-NEXT: for (auto & I : Nest)
+ // CHECK-FIXES-NEXT: printf("Got item %d", I[J].X);
+
+ // The inner loop is also convertible.
+ Nested<T> NestT;
+ for (Nested<T>::iterator I = NestT.begin(), E = NestT.end(); I != E; ++I) {
+ for (T::iterator TI = (*I).begin(), TE = (*I).end(); TI != TE; ++TI) {
+ printf("%d", *TI);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : NestT)
+ // CHECK-FIXES-NEXT: for (T::iterator TI = I.begin(), TE = I.end(); TI != TE; ++TI)
+ // CHECK-FIXES-NEXT: printf("%d", *TI);
+
+ // The inner loop is also convertible.
+ Nested<S> NestS;
+ for (Nested<S>::const_iterator I = NestS.begin(), E = NestS.end(); I != E; ++I) {
+ for (S::const_iterator SI = (*I).begin(), SE = (*I).end(); SI != SE; ++SI) {
+ printf("%d", *SI);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto I : NestS)
+ // CHECK-FIXES-NEXT: for (S::const_iterator SI = I.begin(), SE = I.end(); SI != SE; ++SI)
+ // CHECK-FIXES-NEXT: printf("%d", *SI);
+
+ for (Nested<S>::const_iterator I = NestS.begin(), E = NestS.end(); I != E; ++I) {
+ const S &Ss = *I;
+ for (S::const_iterator SI = Ss.begin(), SE = Ss.end(); SI != SE; ++SI) {
+ printf("%d", *SI);
+ const_g(SI);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-7]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto Ss : NestS)
+
+ for (Nested<S>::iterator I = NestS.begin(), E = NestS.end(); I != E; ++I) {
+ S &Ss = *I;
+ for (S::iterator SI = Ss.begin(), SE = Ss.end(); SI != SE; ++SI) {
+ printf("%d", *SI);
+ g(SI);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-7]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & Ss : NestS)
+
+ Foo foo;
+ for (Nested<S>::const_iterator I = NestS.begin(), E = NestS.end(); I != E; ++I) {
+ const S &Ss = *I;
+ for (S::const_iterator SI = Ss.begin(), SE = Ss.end(); SI != SE; ++SI) {
+ printf("%d", *SI);
+ foo.const_g(SI);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-7]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto Ss : NestS)
+
+ for (Nested<S>::iterator I = NestS.begin(), E = NestS.end(); I != E; ++I) {
+ S &Ss = *I;
+ for (S::iterator SI = Ss.begin(), SE = Ss.end(); SI != SE; ++SI) {
+ printf("%d", *SI);
+ foo.g(SI);
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-7]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & Ss : NestS)
+
+}
+
+} // namespace Nesting
+
+namespace SingleIterator {
+
+void complexContainer() {
+ X Exes[5];
+ int Index = 0;
+
+ for (S::iterator I = Exes[Index].getS().begin(), E = Exes[Index].getS().end(); I != E; ++I) {
+ MutableVal K = *I;
+ MutableVal J = *I;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Exes[Index].getS())
+ // CHECK-FIXES-NEXT: MutableVal K = I;
+ // CHECK-FIXES-NEXT: MutableVal J = I;
+}
+
+void f() {
+ /// begin()/end() - based for loops here:
+ T Tt;
+ for (T::iterator It = Tt.begin(); It != Tt.end(); ++It) {
+ printf("I found %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : Tt)
+ // CHECK-FIXES-NEXT: printf("I found %d\n", It);
+
+ T *Pt;
+ for (T::iterator It = Pt->begin(); It != Pt->end(); ++It) {
+ printf("I found %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : *Pt)
+ // CHECK-FIXES-NEXT: printf("I found %d\n", It);
+
+ S Ss;
+ for (S::iterator It = Ss.begin(); It != Ss.end(); ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ S *Ps;
+ for (S::iterator It = Ps->begin(); It != Ps->end(); ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & P : *Ps)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", P.X);
+
+ for (S::iterator It = Ss.begin(); It != Ss.end(); ++It) {
+ printf("s has value %d\n", It->X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ for (S::iterator It = Ss.begin(); It != Ss.end(); ++It) {
+ It->X = 3;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: It.X = 3;
+
+ for (S::iterator It = Ss.begin(); It != Ss.end(); ++It) {
+ (*It).X = 3;
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: It.X = 3;
+
+ for (S::iterator It = Ss.begin(); It != Ss.end(); ++It) {
+ It->nonConstFun(4, 5);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Ss)
+ // CHECK-FIXES-NEXT: It.nonConstFun(4, 5);
+
+ U Uu;
+ for (U::iterator It = Uu.begin(); It != Uu.end(); ++It) {
+ printf("s has value %d\n", It->X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Uu)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ for (U::iterator It = Uu.begin(); It != Uu.end(); ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : Uu)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ U::iterator A;
+ for (U::iterator I = Uu.begin(); I != Uu.end(); ++I)
+ int K = A->X + I->X;
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & I : Uu)
+ // CHECK-FIXES-NEXT: int K = A->X + I.X;
+
+ dependent<int> V;
+ for (dependent<int>::iterator It = V.begin();
+ It != V.end(); ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);
+
+ for (dependent<int>::iterator It(V.begin());
+ It != V.end(); ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & It : V)
+ // CHECK-FIXES-NEXT: printf("Fibonacci number is %d\n", It);
+
+ doublyDependent<int, int> intmap;
+ for (doublyDependent<int, int>::iterator It = intmap.begin();
+ It != intmap.end(); ++It) {
+ printf("intmap[%d] = %d", It->first, It->second);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & It : intmap)
+ // CHECK-FIXES-NEXT: printf("intmap[%d] = %d", It.first, It.second);
+}
+
+void different_type() {
+ // Tests to verify the proper use of auto where the init variable type and the
+ // initializer type differ or are mostly the same except for const qualifiers.
+
+ // Ss.begin() returns a type 'iterator' which is just a non-const pointer and
+ // differs from const_iterator only on the const qualification.
+ S Ss;
+ for (S::const_iterator It = Ss.begin(); It != Ss.end(); ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto It : Ss)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", It.X);
+
+ S *Ps;
+ for (S::const_iterator It = Ps->begin(); It != Ps->end(); ++It) {
+ printf("s has value %d\n", (*It).X);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto P : *Ps)
+ // CHECK-FIXES-NEXT: printf("s has value %d\n", P.X);
+
+ // V.begin() returns a user-defined type 'iterator' which, since it's
+ // different from const_iterator, disqualifies these loops from
+ // transformation.
+ dependent<int> V;
+ for (dependent<int>::const_iterator It = V.begin(); It != V.end(); ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+
+ for (dependent<int>::const_iterator It(V.begin()); It != V.end(); ++It) {
+ printf("Fibonacci number is %d\n", *It);
+ }
+}
+
+} // namespace SingleIterator
+
+
+namespace Macros {
+
+#define TWO_PARAM(x, y) if (x == y) {}
+#define THREE_PARAM(x, y, z) if (x == y) {z;}
+
+const int N = 10;
+int Arr[N];
+
+void messing_with_macros() {
+ for (int I = 0; I < N; ++I) {
+ printf("Value: %d\n", Arr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: printf("Value: %d\n", I);
+
+ for (int I = 0; I < N; ++I) {
+ printf("Value: %d\n", CONT Arr[I]);
+ }
+
+ // Multiple macro arguments.
+ for (int I = 0; I < N; ++I) {
+ TWO_PARAM(Arr[I], Arr[I]);
+ THREE_PARAM(Arr[I], Arr[I], Arr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Arr)
+ // CHECK-FIXES-NEXT: TWO_PARAM(I, I);
+ // CHECK-FIXES-NEXT: THREE_PARAM(I, I, I);
+}
+
+} // namespace Macros
+
+namespace Templates {
+
+template <class Container>
+void set_union(Container &container) {
+ for (typename Container::const_iterator SI = container.begin(),
+ SE = container.end(); SI != SE; ++SI) {
+ (void) *SI;
+ }
+
+ S Ss;
+ for (S::iterator SI = Ss.begin(), SE = Ss.end(); SI != SE; ++SI)
+ (void) *SI;
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (auto & SI : Ss)
+}
+
+void template_instantiation() {
+ S Ss;
+ set_union(Ss);
+}
+
+} // namespace Templates
+
+namespace Lambdas {
+
+void capturesIndex() {
+ const int N = 10;
+ int Arr[N];
+ // FIXME: the next four loops could be convertible, if the capture list is
+ // also changed.
+
+ for (int I = 0; I < N; ++I)
+ auto F1 = [Arr, I]() { int R1 = Arr[I] + 1; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto F1 = [Arr, &I]() { int R1 = I + 1; };
+
+ for (int I = 0; I < N; ++I)
+ auto F2 = [Arr, &I]() { int R2 = Arr[I] + 3; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto F2 = [Arr, &I]() { int R2 = I + 3; };
+
+ // FIXME: alias don't work if the index is captured.
+ // Alias declared inside lambda (by value).
+ for (int I = 0; I < N; ++I)
+ auto F3 = [&Arr, I]() { int R3 = Arr[I]; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto F3 = [&Arr, &I]() { int R3 = I; };
+
+
+ for (int I = 0; I < N; ++I)
+ auto F4 = [&Arr, &I]() { int R4 = Arr[I]; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto F4 = [&Arr, &I]() { int R4 = I; };
+
+ // Alias declared inside lambda (by reference).
+ for (int I = 0; I < N; ++I)
+ auto F5 = [&Arr, I]() { int &R5 = Arr[I]; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Arr)
+ // CHECK-FIXES-NEXT: auto F5 = [&Arr, &I]() { int &R5 = I; };
+
+
+ for (int I = 0; I < N; ++I)
+ auto F6 = [&Arr, &I]() { int &R6 = Arr[I]; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Arr)
+ // CHECK-FIXES-NEXT: auto F6 = [&Arr, &I]() { int &R6 = I; };
+
+ for (int I = 0; I < N; ++I) {
+ auto F = [Arr, I](int k) {
+ printf("%d\n", Arr[I] + k);
+ };
+ F(Arr[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-6]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto F = [Arr, &I](int k)
+ // CHECK-FIXES-NEXT: printf("%d\n", I + k);
+ // CHECK-FIXES: F(I);
+}
+
+void implicitCapture() {
+ const int N = 10;
+ int Arr[N];
+ // Index is used, not convertible.
+ for (int I = 0; I < N; ++I) {
+ auto G1 = [&]() {
+ int R = Arr[I];
+ int J = I;
+ };
+ }
+
+ for (int I = 0; I < N; ++I) {
+ auto G2 = [=]() {
+ int R = Arr[I];
+ int J = I;
+ };
+ }
+
+ // Convertible.
+ for (int I = 0; I < N; ++I) {
+ auto G3 = [&]() {
+ int R3 = Arr[I];
+ int J3 = Arr[I] + R3;
+ };
+ }
+ // CHECK-MESSAGES: :[[@LINE-6]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto G3 = [&]()
+ // CHECK-FIXES-NEXT: int R3 = I;
+ // CHECK-FIXES-NEXT: int J3 = I + R3;
+
+ for (int I = 0; I < N; ++I) {
+ auto G4 = [=]() {
+ int R4 = Arr[I] + 5;
+ };
+ }
+ // CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto G4 = [=]()
+ // CHECK-FIXES-NEXT: int R4 = I + 5;
+
+ // Alias by value.
+ for (int I = 0; I < N; ++I) {
+ auto G5 = [&]() {
+ int R5 = Arr[I];
+ int J5 = 8 + R5;
+ };
+ }
+ // CHECK-MESSAGES: :[[@LINE-6]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int R5 : Arr)
+ // CHECK-FIXES-NEXT: auto G5 = [&]()
+ // CHECK-FIXES-NEXT: int J5 = 8 + R5;
+
+ // Alias by reference.
+ for (int I = 0; I < N; ++I) {
+ auto G6 = [&]() {
+ int &R6 = Arr[I];
+ int J6 = -1 + R6;
+ };
+ }
+ // CHECK-MESSAGES: :[[@LINE-6]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & R6 : Arr)
+ // CHECK-FIXES-NEXT: auto G6 = [&]()
+ // CHECK-FIXES-NEXT: int J6 = -1 + R6;
+}
+
+void iterators() {
+ dependent<int> Dep;
+
+ for (dependent<int>::iterator I = Dep.begin(), E = Dep.end(); I != E; ++I)
+ auto H1 = [&I]() { int R = *I; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Dep)
+ // CHECK-FIXES-NEXT: auto H1 = [&I]() { int R = I; };
+
+ for (dependent<int>::iterator I = Dep.begin(), E = Dep.end(); I != E; ++I)
+ auto H2 = [&]() { int R = *I + 2; };
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int & I : Dep)
+ // CHECK-FIXES-NEXT: auto H2 = [&]() { int R = I + 2; };
+
+ // FIXME: It doesn't work with const iterators.
+ for (dependent<int>::const_iterator I = Dep.begin(), E = Dep.end();
+ I != E; ++I)
+ auto H3 = [I]() { int R = *I; };
+
+ for (dependent<int>::const_iterator I = Dep.begin(), E = Dep.end();
+ I != E; ++I)
+ auto H4 = [&]() { int R = *I + 1; };
+
+ for (dependent<int>::const_iterator I = Dep.begin(), E = Dep.end();
+ I != E; ++I)
+ auto H5 = [=]() { int R = *I; };
+}
+
+void captureByValue() {
+ // When the index is captured by value, we should replace this by a capture
+ // by reference. This avoids extra copies.
+ // FIXME: this could change semantics on array or pseudoarray loops if the
+ // container is captured by copy.
+ const int N = 10;
+ int Arr[N];
+ dependent<int> Dep;
+
+ for (int I = 0; I < N; ++I) {
+ auto C1 = [&Arr, I]() { if (Arr[I] == 1); };
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Arr)
+ // CHECK-FIXES-NEXT: auto C1 = [&Arr, &I]() { if (I == 1); };
+
+ for (unsigned I = 0; I < Dep.size(); ++I) {
+ auto C2 = [&Dep, I]() { if (Dep[I] == 2); };
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Dep)
+ // CHECK-FIXES-NEXT: auto C2 = [&Dep, &I]() { if (I == 2); };
+}
+
+} // namespace Lambdas
+
+namespace InitLists {
+
+struct D { int Ii; };
+struct E { D Dd; };
+int g(int B);
+
+void f() {
+ const unsigned N = 3;
+ int Array[N];
+
+ // Subtrees of InitListExpr are visited twice. Test that we do not do repeated
+ // replacements.
+ for (unsigned I = 0; I < N; ++I) {
+ int A{ Array[I] };
+ int B{ g(Array[I]) };
+ int C{ g( { Array[I] } ) };
+ D Dd{ { g( { Array[I] } ) } };
+ E Ee{ { { g( { Array[I] } ) } } };
+ }
+ // CHECK-MESSAGES: :[[@LINE-7]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : Array)
+ // CHECK-FIXES-NEXT: int A{ I };
+ // CHECK-FIXES-NEXT: int B{ g(I) };
+ // CHECK-FIXES-NEXT: int C{ g( { I } ) };
+ // CHECK-FIXES-NEXT: D Dd{ { g( { I } ) } };
+ // CHECK-FIXES-NEXT: E Ee{ { { g( { I } ) } } };
+}
+
+} // namespace InitLists
+
+void bug28341() {
+ char v[5];
+ for(int i = 0; i < 5; ++i) {
+ unsigned char value = v[i];
+ if (value > 127)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for(unsigned char value : v)
+ // CHECK-FIXES-NEXT: if (value > 127)
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-lowercase.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-lowercase.cpp
new file mode 100644
index 0000000..c7bb221
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-lowercase.cpp
@@ -0,0 +1,41 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-loop-convert.NamingStyle, value: 'lower_case'}]}" \
+// RUN: -- -std=c++11 -I %S/Inputs/modernize-loop-convert
+
+#include "structures.h"
+
+const int n = 10;
+int arr[n];
+int nums[n];
+int nums_[n];
+
+void naming() {
+ for (int i = 0; i < n; ++i) {
+ printf("%d\n", arr[i]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead [modernize-loop-convert]
+ // CHECK-FIXES: for (int i : arr)
+ // CHECK-FIXES-NEXT: printf("%d\n", i);
+
+ for (int i = 0; i < n; ++i) {
+ printf("%d\n", nums[i]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int num : nums)
+ // CHECK-FIXES-NEXT: printf("%d\n", num);
+
+ for (int i = 0; i < n; ++i) {
+ printf("%d\n", nums_[i]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int num : nums_)
+ // CHECK-FIXES-NEXT: printf("%d\n", num);
+
+ int num = 0;
+ for (int i = 0; i < n; ++i) {
+ printf("%d\n", nums[i] + num);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int i : nums)
+ // CHECK-FIXES-NEXT: printf("%d\n", i + num);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-negative.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-negative.cpp
new file mode 100644
index 0000000..c038437
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-negative.cpp
@@ -0,0 +1,485 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t -- -- -std=c++11 -I %S/Inputs/modernize-loop-convert
+
+#include "structures.h"
+
+// CHECK-FIXES-NOT: for ({{.*[^:]:[^:].*}})
+// CHECK-MESSAGES-NOT: modernize-loop-convert
+
+namespace Negative {
+
+const int N = 6;
+int Arr[N] = {1, 2, 3, 4, 5, 6};
+int (*pArr)[N] = &Arr;
+int Sum = 0;
+
+// Checks for the Index start and end:
+void IndexStartAndEnd() {
+ for (int I = 0; I < N + 1; ++I)
+ Sum += Arr[I];
+
+ for (int I = 0; I < N - 1; ++I)
+ Sum += Arr[I];
+
+ for (int I = 1; I < N; ++I)
+ Sum += Arr[I];
+
+ for (int I = 1; I < N; ++I)
+ Sum += Arr[I];
+
+ for (int I = 0;; ++I)
+ Sum += (*pArr)[I];
+}
+
+// Checks for invalid increment steps:
+void increment() {
+ for (int I = 0; I < N; --I)
+ Sum += Arr[I];
+
+ for (int I = 0; I < N; I)
+ Sum += Arr[I];
+
+ for (int I = 0; I < N;)
+ Sum += Arr[I];
+
+ for (int I = 0; I < N; I += 2)
+ Sum++;
+}
+
+// Checks to make sure that the Index isn't used outside of the array:
+void IndexUse() {
+ for (int I = 0; I < N; ++I)
+ Arr[I] += 1 + I;
+}
+
+// Check for loops that don't mention arrays
+void noArray() {
+ for (int I = 0; I < N; ++I)
+ Sum += I;
+
+ for (int I = 0; I < N; ++I) {
+ }
+
+ for (int I = 0; I < N; ++I)
+ ;
+}
+
+// Checks for incorrect loop variables.
+void mixedVariables() {
+ int BadIndex;
+ for (int I = 0; BadIndex < N; ++I)
+ Sum += Arr[I];
+
+ for (int I = 0; I < N; ++BadIndex)
+ Sum += Arr[I];
+
+ for (int I = 0; BadIndex < N; ++BadIndex)
+ Sum += Arr[I];
+
+ for (int I = 0; BadIndex < N; ++BadIndex)
+ Sum += Arr[BadIndex];
+}
+
+// Checks for multiple arrays Indexed.
+void multipleArrays() {
+ int BadArr[N];
+
+ for (int I = 0; I < N; ++I)
+ Sum += Arr[I] + BadArr[I];
+
+ for (int I = 0; I < N; ++I) {
+ int K = BadArr[I];
+ Sum += Arr[I] + K;
+ }
+}
+
+}
+
+namespace NegativeIterator {
+
+S Ss;
+T Tt;
+U Tu;
+
+struct BadBeginEnd : T {
+ iterator notBegin();
+ iterator notEnd();
+};
+
+void notBeginOrEnd() {
+ BadBeginEnd Bad;
+ for (T::iterator I = Bad.notBegin(), E = Bad.end(); I != E; ++I)
+ int K = *I;
+
+ for (T::iterator I = Bad.begin(), E = Bad.notEnd(); I != E; ++I)
+ int K = *I;
+}
+
+void badLoopShapes() {
+ for (T::iterator I = Tt.begin(), E = Tt.end(), F = E; I != E; ++I)
+ int K = *I;
+
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E;)
+ int K = *I;
+
+ for (T::iterator I = Tt.begin(), E = Tt.end();; ++I)
+ int K = *I;
+
+ T::iterator OutsideI;
+ T::iterator OutsideE;
+
+ for (; OutsideI != OutsideE; ++OutsideI)
+ int K = *OutsideI;
+}
+
+void iteratorArrayMix() {
+ int Lower;
+ const int N = 6;
+ for (T::iterator I = Tt.begin(), E = Tt.end(); Lower < N; ++I)
+ int K = *I;
+
+ for (T::iterator I = Tt.begin(), E = Tt.end(); Lower < N; ++Lower)
+ int K = *I;
+}
+
+struct ExtraConstructor : T::iterator {
+ ExtraConstructor(T::iterator, int);
+ explicit ExtraConstructor(T::iterator);
+};
+
+void badConstructor() {
+ for (T::iterator I = ExtraConstructor(Tt.begin(), 0), E = Tt.end();
+ I != E; ++I)
+ int K = *I;
+ for (T::iterator I = ExtraConstructor(Tt.begin()), E = Tt.end(); I != E; ++I)
+ int K = *I;
+}
+
+void foo(S::iterator It) {}
+class Foo {public: void bar(S::iterator It); };
+Foo Fo;
+
+void iteratorUsed() {
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
+ foo(I);
+
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
+ Fo.bar(I);
+
+ S::iterator Ret;
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
+ Ret = I;
+}
+
+void iteratorMemberUsed() {
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
+ I.X = *I;
+
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
+ int K = I.X + *I;
+
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
+ int K = E.X + *I;
+}
+
+void iteratorMethodCalled() {
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
+ I.insert(3);
+
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
+ if (I != I)
+ int K = 3;
+}
+
+void iteratorOperatorCalled() {
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
+ int K = *(++I);
+
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
+ MutableVal K = *(++I);
+}
+
+void differentContainers() {
+ T Other;
+ for (T::iterator I = Tt.begin(), E = Other.end(); I != E; ++I)
+ int K = *I;
+
+ for (T::iterator I = Other.begin(), E = Tt.end(); I != E; ++I)
+ int K = *I;
+
+ S OtherS;
+ for (S::iterator I = Ss.begin(), E = OtherS.end(); I != E; ++I)
+ MutableVal K = *I;
+
+ for (S::iterator I = OtherS.begin(), E = Ss.end(); I != E; ++I)
+ MutableVal K = *I;
+}
+
+void wrongIterators() {
+ T::iterator Other;
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != Other; ++I)
+ int K = *I;
+}
+
+struct EvilArrow : U {
+ // Please, no one ever write code like this.
+ U *operator->();
+};
+
+void differentMemberAccessTypes() {
+ EvilArrow A;
+ for (EvilArrow::iterator I = A.begin(), E = A->end(); I != E; ++I)
+ Val K = *I;
+ for (EvilArrow::iterator I = A->begin(), E = A.end(); I != E; ++I)
+ Val K = *I;
+}
+
+void f(const T::iterator &It, int);
+void f(const T &It, int);
+void g(T &It, int);
+
+void iteratorPassedToFunction() {
+ for (T::iterator I = Tt.begin(), E = Tt.end(); I != E; ++I)
+ f(I, *I);
+}
+
+// FIXME: These tests can be removed if this tool ever does enough analysis to
+// decide that this is a safe transformation. Until then, we don't want it
+// applied.
+void iteratorDefinedOutside() {
+ T::iterator TheEnd = Tt.end();
+ for (T::iterator I = Tt.begin(); I != TheEnd; ++I)
+ int K = *I;
+
+ T::iterator TheBegin = Tt.begin();
+ for (T::iterator E = Tt.end(); TheBegin != E; ++TheBegin)
+ int K = *TheBegin;
+}
+
+} // namespace NegativeIterator
+
+namespace NegativePseudoArray {
+
+const int N = 6;
+dependent<int> V;
+dependent<int> *Pv;
+
+int Sum = 0;
+
+// Checks for the Index start and end:
+void IndexStartAndEnd() {
+ for (int I = 0; I < V.size() + 1; ++I)
+ Sum += V[I];
+
+ for (int I = 0; I < V.size() - 1; ++I)
+ Sum += V[I];
+
+ for (int I = 1; I < V.size(); ++I)
+ Sum += V[I];
+
+ for (int I = 1; I < V.size(); ++I)
+ Sum += V[I];
+
+ for (int I = 0;; ++I)
+ Sum += (*Pv)[I];
+}
+
+// Checks for invalid increment steps:
+void increment() {
+ for (int I = 0; I < V.size(); --I)
+ Sum += V[I];
+
+ for (int I = 0; I < V.size(); I)
+ Sum += V[I];
+
+ for (int I = 0; I < V.size();)
+ Sum += V[I];
+
+ for (int I = 0; I < V.size(); I += 2)
+ Sum++;
+}
+
+// Checks to make sure that the Index isn't used outside of the container:
+void IndexUse() {
+ for (int I = 0; I < V.size(); ++I)
+ V[I] += 1 + I;
+}
+
+// Checks for incorrect loop variables.
+void mixedVariables() {
+ int BadIndex;
+ for (int I = 0; BadIndex < V.size(); ++I)
+ Sum += V[I];
+
+ for (int I = 0; I < V.size(); ++BadIndex)
+ Sum += V[I];
+
+ for (int I = 0; BadIndex < V.size(); ++BadIndex)
+ Sum += V[I];
+
+ for (int I = 0; BadIndex < V.size(); ++BadIndex)
+ Sum += V[BadIndex];
+}
+
+// Checks for an array Indexed in addition to the container.
+void multipleArrays() {
+ int BadArr[N];
+
+ for (int I = 0; I < V.size(); ++I)
+ Sum += V[I] + BadArr[I];
+
+ for (int I = 0; I < V.size(); ++I)
+ Sum += BadArr[I];
+
+ for (int I = 0; I < V.size(); ++I) {
+ int K = BadArr[I];
+ Sum += K + 2;
+ }
+
+ for (int I = 0; I < V.size(); ++I) {
+ int K = BadArr[I];
+ Sum += V[I] + K;
+ }
+}
+
+// Checks for multiple containers being Indexed container.
+void multipleContainers() {
+ dependent<int> BadArr;
+
+ for (int I = 0; I < V.size(); ++I)
+ Sum += V[I] + BadArr[I];
+
+ for (int I = 0; I < V.size(); ++I)
+ Sum += BadArr[I];
+
+ for (int I = 0; I < V.size(); ++I) {
+ int K = BadArr[I];
+ Sum += K + 2;
+ }
+
+ for (int I = 0; I < V.size(); ++I) {
+ int K = BadArr[I];
+ Sum += V[I] + K;
+ }
+}
+
+// Check to make sure that dereferenced pointers-to-containers behave nicely.
+void derefContainer() {
+ // Note the dependent<T>::operator*() returns another dependent<T>.
+ // This test makes sure that we don't allow an arbitrary number of *'s.
+ for (int I = 0; I < Pv->size(); ++I)
+ Sum += (**Pv).at(I);
+
+ for (int I = 0; I < Pv->size(); ++I)
+ Sum += (**Pv)[I];
+}
+
+void wrongEnd() {
+ int Bad;
+ for (int I = 0, E = V.size(); I < Bad; ++I)
+ Sum += V[I];
+}
+
+// Checks to see that non-const member functions are not called on the container
+// object.
+// These could be conceivably allowed with a lower required confidence level.
+void memberFunctionCalled() {
+ for (int I = 0; I < V.size(); ++I) {
+ Sum += V[I];
+ V.foo();
+ }
+
+ for (int I = 0; I < V.size(); ++I) {
+ Sum += V[I];
+ dependent<int>::iterator It = V.begin();
+ }
+}
+
+} // namespace NegativePseudoArray
+
+namespace NegativeMultiEndCall {
+
+S Ss;
+T Tt;
+U Uu;
+
+void f(X);
+void f(S);
+void f(T);
+
+void complexContainer() {
+ X Xx;
+ for (S::iterator I = Xx.Ss.begin(), E = Xx.Ss.end(); I != E; ++I) {
+ f(Xx);
+ MutableVal K = *I;
+ }
+
+ for (T::iterator I = Xx.Tt.begin(), E = Xx.Tt.end(); I != E; ++I) {
+ f(Xx);
+ int K = *I;
+ }
+
+ for (S::iterator I = Xx.Ss.begin(), E = Xx.Ss.end(); I != E; ++I) {
+ f(Xx.Ss);
+ MutableVal K = *I;
+ }
+
+ for (T::iterator I = Xx.Tt.begin(), E = Xx.Tt.end(); I != E; ++I) {
+ f(Xx.Tt);
+ int K = *I;
+ }
+
+ for (S::iterator I = Xx.getS().begin(), E = Xx.getS().end(); I != E; ++I) {
+ f(Xx.getS());
+ MutableVal K = *I;
+ }
+
+ X Exes[5];
+ int Index = 0;
+
+ for (S::iterator I = Exes[Index].getS().begin(),
+ E = Exes[Index].getS().end();
+ I != E; ++I) {
+ Index++;
+ MutableVal K = *I;
+ }
+}
+
+} // namespace NegativeMultiEndCall
+
+namespace NoUsages {
+
+const int N = 6;
+int Arr[N] = {1, 2, 3, 4, 5, 6};
+S Ss;
+dependent<int> V;
+int Count = 0;
+
+void foo();
+
+void f() {
+ for (int I = 0; I < N; ++I) {}
+ for (int I = 0; I < N; ++I)
+ printf("Hello world\n");
+ for (int I = 0; I < N; ++I)
+ ++Count;
+ for (int I = 0; I < N; ++I)
+ foo();
+
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I) {}
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
+ printf("Hello world\n");
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
+ ++Count;
+ for (S::iterator I = Ss.begin(), E = Ss.end(); I != E; ++I)
+ foo();
+
+ for (int I = 0; I < V.size(); ++I) {}
+ for (int I = 0; I < V.size(); ++I)
+ printf("Hello world\n");
+ for (int I = 0; I < V.size(); ++I)
+ ++Count;
+ for (int I = 0; I < V.size(); ++I)
+ foo();
+}
+
+} // namespace NoUsages
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-uppercase.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-uppercase.cpp
new file mode 100644
index 0000000..4d1d5c2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert-uppercase.cpp
@@ -0,0 +1,41 @@
+// RUN: %check_clang_tidy %s modernize-loop-convert %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-loop-convert.NamingStyle, value: 'UPPER_CASE'}]}" \
+// RUN: -- -std=c++11 -I %S/Inputs/modernize-loop-convert
+
+#include "structures.h"
+
+const int N = 10;
+int ARR[N];
+int NUMS[N];
+int NUMS_[N];
+
+void naming() {
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", ARR[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead [modernize-loop-convert]
+ // CHECK-FIXES: for (int I : ARR)
+ // CHECK-FIXES-NEXT: printf("%d\n", I);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", NUMS[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int NUM : NUMS)
+ // CHECK-FIXES-NEXT: printf("%d\n", NUM);
+
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", NUMS_[I]);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int NUM : NUMS_)
+ // CHECK-FIXES-NEXT: printf("%d\n", NUM);
+
+ int NUM = 0;
+ for (int I = 0; I < N; ++I) {
+ printf("%d\n", NUMS[I] + NUM);
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+ // CHECK-FIXES: for (int I : NUMS)
+ // CHECK-FIXES-NEXT: printf("%d\n", I + NUM);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert.c
new file mode 100644
index 0000000..4c7d956
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-loop-convert.c
@@ -0,0 +1,12 @@
+// RUN: clang-tidy %s -checks=-*,modernize-loop-convert -- -std=c11 | count 0
+
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+
+int arr[6] = {1, 2, 3, 4, 5, 6};
+
+void f(void) {
+ for (int i = 0; i < 6; ++i) {
+ (void)arr[i];
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-shared-header.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-shared-header.cpp
new file mode 100644
index 0000000..21b07ee
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-shared-header.cpp
@@ -0,0 +1,17 @@
+// RUN: %check_clang_tidy %s modernize-make-shared %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: modernize-make-shared.MakeSmartPtrFunction, \
+// RUN: value: 'my::MakeShared'}, \
+// RUN: {key: modernize-make-shared.MakeSmartPtrFunctionHeader, \
+// RUN: value: 'make_shared_util.h'} \
+// RUN: ]}" \
+// RUN: -- -std=c++11 -I%S/Inputs/modernize-smart-ptr
+
+#include "shared_ptr.h"
+// CHECK-FIXES: #include "make_shared_util.h"
+
+void f() {
+ std::shared_ptr<int> P1 = std::shared_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use my::MakeShared instead
+ // CHECK-FIXES: std::shared_ptr<int> P1 = my::MakeShared<int>();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-shared.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-shared.cpp
new file mode 100644
index 0000000..ed4da99
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-shared.cpp
@@ -0,0 +1,286 @@
+// RUN: %check_clang_tidy %s modernize-make-shared %t -- -- -std=c++11 \
+// RUN: -I%S/Inputs/modernize-smart-ptr
+
+#include "shared_ptr.h"
+// CHECK-FIXES: #include <memory>
+
+struct Base {
+ Base();
+ Base(int, int);
+};
+
+struct Derived : public Base {
+ Derived();
+ Derived(int, int);
+};
+
+struct APair {
+ int a, b;
+};
+
+struct DPair {
+ DPair() : a(0), b(0) {}
+ DPair(int x, int y) : a(y), b(x) {}
+ int a, b;
+};
+
+struct Empty {};
+
+template <class T>
+using shared_ptr_ = std::shared_ptr<T>;
+
+void *operator new(__SIZE_TYPE__ Count, void *Ptr);
+
+int g(std::shared_ptr<int> P);
+
+std::shared_ptr<Base> getPointer() {
+ return std::shared_ptr<Base>(new Base);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use std::make_shared instead
+ // CHECK-FIXES: return std::make_shared<Base>();
+}
+
+void basic() {
+ std::shared_ptr<int> P1 = std::shared_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: std::shared_ptr<int> P1 = std::make_shared<int>();
+
+ P1.reset(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: P1 = std::make_shared<int>();
+
+ P1 = std::shared_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: P1 = std::make_shared<int>();
+
+ // Without parenthesis.
+ std::shared_ptr<int> P2 = std::shared_ptr<int>(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: std::shared_ptr<int> P2 = std::make_shared<int>();
+
+ P2.reset(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: P2 = std::make_shared<int>();
+
+ P2 = std::shared_ptr<int>(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_shared instead [modernize-make-shared]
+ // CHECK-FIXES: P2 = std::make_shared<int>();
+
+ // With auto.
+ auto P3 = std::shared_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_shared instead
+ // CHECK-FIXES: auto P3 = std::make_shared<int>();
+
+ {
+ // No std.
+ using namespace std;
+ shared_ptr<int> Q = shared_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use std::make_shared instead
+ // CHECK-FIXES: shared_ptr<int> Q = std::make_shared<int>();
+
+ Q = shared_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_shared instead
+ // CHECK-FIXES: Q = std::make_shared<int>();
+ }
+
+ std::shared_ptr<int> R(new int());
+
+ // Create the shared_ptr as a parameter to a function.
+ int T = g(std::shared_ptr<int>(new int()));
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_shared instead
+ // CHECK-FIXES: int T = g(std::make_shared<int>());
+
+ // Only replace if the type in the template is the same as the type returned
+ // by the new operator.
+ auto Pderived = std::shared_ptr<Base>(new Derived());
+
+ // OK to replace for reset and assign
+ Pderived.reset(new Derived());
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use std::make_shared instead
+ // CHECK-FIXES: Pderived = std::make_shared<Derived>();
+
+ Pderived = std::shared_ptr<Derived>(new Derived());
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use std::make_shared instead
+ // CHECK-FIXES: Pderived = std::make_shared<Derived>();
+
+ // FIXME: OK to replace if assigned to shared_ptr<Base>
+ Pderived = std::shared_ptr<Base>(new Derived());
+
+ // FIXME: OK to replace when auto is not used
+ std::shared_ptr<Base> PBase = std::shared_ptr<Base>(new Derived());
+
+ // The pointer is returned by the function, nothing to do.
+ std::shared_ptr<Base> RetPtr = getPointer();
+
+ // This emulates std::move.
+ std::shared_ptr<int> Move = static_cast<std::shared_ptr<int> &&>(P1);
+
+ // Placement arguments should not be removed.
+ int *PInt = new int;
+ std::shared_ptr<int> Placement = std::shared_ptr<int>(new (PInt) int{3});
+ Placement.reset(new (PInt) int{3});
+ Placement = std::shared_ptr<int>(new (PInt) int{3});
+}
+
+// Calling make_smart_ptr from within a member function of a type with a
+// private or protected constructor would be ill-formed.
+class Private {
+private:
+ Private(int z) {}
+
+public:
+ Private() {}
+ void create() {
+ auto callsPublic = std::shared_ptr<Private>(new Private);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_shared instead
+ // CHECK-FIXES: auto callsPublic = std::make_shared<Private>();
+ auto ptr = std::shared_ptr<Private>(new Private(42));
+ ptr.reset(new Private(42));
+ ptr = std::shared_ptr<Private>(new Private(42));
+ }
+
+ virtual ~Private();
+};
+
+class Protected {
+protected:
+ Protected() {}
+
+public:
+ Protected(int, int) {}
+ void create() {
+ auto callsPublic = std::shared_ptr<Protected>(new Protected(1, 2));
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_shared instead
+ // CHECK-FIXES: auto callsPublic = std::make_shared<Protected>(1, 2);
+ auto ptr = std::shared_ptr<Protected>(new Protected);
+ ptr.reset(new Protected);
+ ptr = std::shared_ptr<Protected>(new Protected);
+ }
+};
+
+void initialization(int T, Base b) {
+ // Test different kinds of initialization of the pointee.
+
+ // Direct initialization with parenthesis.
+ std::shared_ptr<DPair> PDir1 = std::shared_ptr<DPair>(new DPair(1, T));
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<DPair> PDir1 = std::make_shared<DPair>(1, T);
+ PDir1.reset(new DPair(1, T));
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_shared instead
+ // CHECK-FIXES: PDir1 = std::make_shared<DPair>(1, T);
+
+ // Direct initialization with braces.
+ std::shared_ptr<DPair> PDir2 = std::shared_ptr<DPair>(new DPair{2, T});
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<DPair> PDir2 = std::make_shared<DPair>(2, T);
+ PDir2.reset(new DPair{2, T});
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_shared instead
+ // CHECK-FIXES: PDir2 = std::make_shared<DPair>(2, T);
+
+ // Aggregate initialization.
+ std::shared_ptr<APair> PAggr = std::shared_ptr<APair>(new APair{T, 1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<APair> PAggr = std::make_shared<APair>(APair{T, 1});
+ PAggr.reset(new APair{T, 1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_shared instead
+ // CHECK-FIXES: std::make_shared<APair>(APair{T, 1});
+
+ // Test different kinds of initialization of the pointee, when the shared_ptr
+ // is initialized with braces.
+
+ // Direct initialization with parenthesis.
+ std::shared_ptr<DPair> PDir3 = std::shared_ptr<DPair>{new DPair(3, T)};
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<DPair> PDir3 = std::make_shared<DPair>(3, T);
+
+ // Direct initialization with braces.
+ std::shared_ptr<DPair> PDir4 = std::shared_ptr<DPair>{new DPair{4, T}};
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<DPair> PDir4 = std::make_shared<DPair>(4, T);
+
+ // Aggregate initialization.
+ std::shared_ptr<APair> PAggr2 = std::shared_ptr<APair>{new APair{T, 2}};
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<APair> PAggr2 = std::make_shared<APair>(APair{T, 2});
+
+ // Direct initialization with parenthesis, without arguments.
+ std::shared_ptr<DPair> PDir5 = std::shared_ptr<DPair>(new DPair());
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<DPair> PDir5 = std::make_shared<DPair>();
+
+ // Direct initialization with braces, without arguments.
+ std::shared_ptr<DPair> PDir6 = std::shared_ptr<DPair>(new DPair{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<DPair> PDir6 = std::make_shared<DPair>();
+
+ // Aggregate initialization without arguments.
+ std::shared_ptr<Empty> PEmpty = std::shared_ptr<Empty>(new Empty{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<Empty> PEmpty = std::make_shared<Empty>(Empty{});
+}
+
+void aliases() {
+ typedef std::shared_ptr<int> IntPtr;
+ IntPtr Typedef = IntPtr(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use std::make_shared instead
+ // CHECK-FIXES: IntPtr Typedef = std::make_shared<int>();
+
+ // We use 'bool' instead of '_Bool'.
+ typedef std::shared_ptr<bool> BoolPtr;
+ BoolPtr BoolType = BoolPtr(new bool);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use std::make_shared instead
+ // CHECK-FIXES: BoolPtr BoolType = std::make_shared<bool>();
+
+ // We use 'Base' instead of 'struct Base'.
+ typedef std::shared_ptr<Base> BasePtr;
+ BasePtr StructType = BasePtr(new Base);
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_shared instead
+// CHECK-FIXES: BasePtr StructType = std::make_shared<Base>();
+
+#define PTR shared_ptr<int>
+ std::shared_ptr<int> Macro = std::PTR(new int);
+// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use std::make_shared instead
+// CHECK-FIXES: std::shared_ptr<int> Macro = std::make_shared<int>();
+#undef PTR
+
+ std::shared_ptr<int> Using = shared_ptr_<int>(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use std::make_shared instead
+ // CHECK-FIXES: std::shared_ptr<int> Using = std::make_shared<int>();
+}
+
+void whitespaces() {
+ // clang-format off
+ auto Space = std::shared_ptr <int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use std::make_shared instead
+ // CHECK-FIXES: auto Space = std::make_shared<int>();
+
+ auto Spaces = std :: shared_ptr <int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use std::make_shared instead
+ // CHECK-FIXES: auto Spaces = std::make_shared<int>();
+ // clang-format on
+}
+
+void nesting() {
+ auto Nest = std::shared_ptr<std::shared_ptr<int>>(new std::shared_ptr<int>(new int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use std::make_shared instead
+ // CHECK-FIXES: auto Nest = std::make_shared<std::shared_ptr<int>>(new int);
+ Nest.reset(new std::shared_ptr<int>(new int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_shared instead
+ // CHECK-FIXES: Nest = std::make_shared<std::shared_ptr<int>>(new int);
+ Nest->reset(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_shared instead
+ // CHECK-FIXES: *Nest = std::make_shared<int>();
+}
+
+void reset() {
+ std::shared_ptr<int> P;
+ P.reset();
+ P.reset(nullptr);
+ P.reset(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use std::make_shared instead
+ // CHECK-FIXES: P = std::make_shared<int>();
+
+ auto Q = &P;
+ Q->reset(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_shared instead
+ // CHECK-FIXES: *Q = std::make_shared<int>();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique-cxx11.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique-cxx11.cpp
new file mode 100644
index 0000000..89beb08
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique-cxx11.cpp
@@ -0,0 +1,10 @@
+// RUN: %check_clang_tidy %s modernize-make-unique %t -- -- -std=c++11 \
+// RUN: -I%S/Inputs/modernize-smart-ptr
+
+#include "unique_ptr.h"
+// CHECK-FIXES: #include "unique_ptr.h"
+
+void f() {
+ auto my_ptr = std::unique_ptr<int>(new int(1));
+ // CHECK-FIXES: auto my_ptr = std::unique_ptr<int>(new int(1));
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique-cxx14.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique-cxx14.cpp
new file mode 100644
index 0000000..cd35f75
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique-cxx14.cpp
@@ -0,0 +1,11 @@
+// RUN: %check_clang_tidy %s modernize-make-unique %t -- -- -std=c++14 \
+// RUN: -I%S/Inputs/modernize-smart-ptr
+
+#include "unique_ptr.h"
+// CHECK-FIXES: #include <memory>
+
+void f() {
+ auto my_ptr = std::unique_ptr<int>(new int(1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use std::make_unique instead
+ // CHECK-FIXES: auto my_ptr = std::make_unique<int>(1);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique-header.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique-header.cpp
new file mode 100644
index 0000000..e6c2a61
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique-header.cpp
@@ -0,0 +1,17 @@
+// RUN: %check_clang_tidy %s modernize-make-unique %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: modernize-make-unique.MakeSmartPtrFunction, \
+// RUN: value: 'my::MakeUnique'}, \
+// RUN: {key: modernize-make-unique.MakeSmartPtrFunctionHeader, \
+// RUN: value: 'make_unique_util.h'} \
+// RUN: ]}" \
+// RUN: -- -std=c++11 -I%S/Inputs/modernize-smart-ptr
+
+#include "unique_ptr.h"
+// CHECK-FIXES: #include "make_unique_util.h"
+
+void f() {
+ std::unique_ptr<int> P1 = std::unique_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use my::MakeUnique instead
+ // CHECK-FIXES: std::unique_ptr<int> P1 = my::MakeUnique<int>();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique-macros.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique-macros.cpp
new file mode 100644
index 0000000..117a45c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique-macros.cpp
@@ -0,0 +1,28 @@
+// RUN: %check_clang_tidy %s modernize-make-unique %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-make-unique.IgnoreMacros, value: 0}]}" \
+// RUN: -- -std=c++14 -I%S/Inputs/modernize-smart-ptr
+
+#include "unique_ptr.h"
+
+class Foo {};
+class Bar {};
+#define DEFINE(...) __VA_ARGS__
+// CHECK-FIXES: {{^}}#define DEFINE(...) __VA_ARGS__{{$}}
+template<typename T>
+void g2(std::unique_ptr<Foo> *t) {
+ DEFINE(
+ // CHECK-FIXES: {{^ *}}DEFINE({{$}}
+ auto p = std::unique_ptr<Foo>(new Foo);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use std::make_unique instead
+ // CHECK-FIXES: {{^ *}}auto p = std::unique_ptr<Foo>(new Foo);{{$}}
+ t->reset(new Foo);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use std::make_unique instead
+ // CHECK-FIXES: {{^ *}}t->reset(new Foo);{{$}}
+ );
+ // CHECK-FIXES: {{^ *}});{{$}}
+}
+void macro() {
+ std::unique_ptr<Foo> *t;
+ g2<Bar>(t);
+}
+#undef DEFINE
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique.cpp
new file mode 100644
index 0000000..9685203
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-make-unique.cpp
@@ -0,0 +1,517 @@
+// RUN: %check_clang_tidy %s modernize-make-unique %t -- -- -std=c++14 \
+// RUN: -I%S/Inputs/modernize-smart-ptr
+
+#include "unique_ptr.h"
+#include "initializer_list.h"
+// CHECK-FIXES: #include <memory>
+
+struct Base {
+ Base();
+ Base(int, int);
+};
+
+struct Derived : public Base {
+ Derived();
+ Derived(int, int);
+};
+
+struct APair {
+ int a, b;
+};
+
+struct DPair {
+ DPair() : a(0), b(0) {}
+ DPair(int x, int y) : a(y), b(x) {}
+ int a, b;
+};
+
+template<typename T>
+struct MyVector {
+ MyVector(std::initializer_list<T>);
+};
+
+struct Empty {};
+
+struct E {
+ E(std::initializer_list<int>);
+ E();
+};
+
+struct F {
+ F(std::initializer_list<int>);
+ F();
+ int a;
+};
+
+struct G {
+ G(std::initializer_list<int>);
+ G(int);
+};
+
+struct H {
+ H(std::vector<int>);
+ H(std::vector<int> &, double);
+ H(MyVector<int>, int);
+};
+
+struct I {
+ I(G);
+};
+
+namespace {
+class Foo {};
+} // namespace
+
+namespace bar {
+class Bar {};
+} // namespace bar
+
+template <class T>
+using unique_ptr_ = std::unique_ptr<T>;
+
+void *operator new(__SIZE_TYPE__ Count, void *Ptr);
+
+int g(std::unique_ptr<int> P);
+
+std::unique_ptr<Base> getPointer() {
+ return std::unique_ptr<Base>(new Base);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use std::make_unique instead
+ // CHECK-FIXES: return std::make_unique<Base>();
+}
+
+void basic() {
+ std::unique_ptr<int> P1 = std::unique_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: std::unique_ptr<int> P1 = std::make_unique<int>();
+
+ P1.reset(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: P1 = std::make_unique<int>();
+
+ P1 = std::unique_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: P1 = std::make_unique<int>();
+
+ // Without parenthesis.
+ std::unique_ptr<int> P2 = std::unique_ptr<int>(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: std::unique_ptr<int> P2 = std::make_unique<int>();
+
+ P2.reset(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: P2 = std::make_unique<int>();
+
+ P2 = std::unique_ptr<int>(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_unique instead [modernize-make-unique]
+ // CHECK-FIXES: P2 = std::make_unique<int>();
+
+ // With auto.
+ auto P3 = std::unique_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_unique instead
+ // CHECK-FIXES: auto P3 = std::make_unique<int>();
+
+ {
+ // No std.
+ using namespace std;
+ unique_ptr<int> Q = unique_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use std::make_unique instead
+ // CHECK-FIXES: unique_ptr<int> Q = std::make_unique<int>();
+
+ Q = unique_ptr<int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_unique instead
+ // CHECK-FIXES: Q = std::make_unique<int>();
+ }
+
+ std::unique_ptr<int> R(new int());
+
+ // Create the unique_ptr as a parameter to a function.
+ int T = g(std::unique_ptr<int>(new int()));
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_unique instead
+ // CHECK-FIXES: int T = g(std::make_unique<int>());
+
+ // Only replace if the type in the template is the same as the type returned
+ // by the new operator.
+ auto Pderived = std::unique_ptr<Base>(new Derived());
+
+ // OK to replace for reset and assign
+ Pderived.reset(new Derived());
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use std::make_unique instead
+ // CHECK-FIXES: Pderived = std::make_unique<Derived>();
+
+ Pderived = std::unique_ptr<Derived>(new Derived());
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use std::make_unique instead
+ // CHECK-FIXES: Pderived = std::make_unique<Derived>();
+
+ // FIXME: OK to replace if assigned to unique_ptr<Base>
+ Pderived = std::unique_ptr<Base>(new Derived());
+
+ // FIXME: OK to replace when auto is not used
+ std::unique_ptr<Base> PBase = std::unique_ptr<Base>(new Derived());
+
+ // The pointer is returned by the function, nothing to do.
+ std::unique_ptr<Base> RetPtr = getPointer();
+
+ // This emulates std::move.
+ std::unique_ptr<int> Move = static_cast<std::unique_ptr<int> &&>(P1);
+
+ // Placement arguments should not be removed.
+ int *PInt = new int;
+ std::unique_ptr<int> Placement = std::unique_ptr<int>(new (PInt) int{3});
+ Placement.reset(new (PInt) int{3});
+ Placement = std::unique_ptr<int>(new (PInt) int{3});
+}
+
+// Calling make_smart_ptr from within a member function of a type with a
+// private or protected constructor would be ill-formed.
+class Private {
+private:
+ Private(int z) {}
+
+public:
+ Private() {}
+ void create() {
+ auto callsPublic = std::unique_ptr<Private>(new Private);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_unique instead
+ // CHECK-FIXES: auto callsPublic = std::make_unique<Private>();
+ auto ptr = std::unique_ptr<Private>(new Private(42));
+ ptr.reset(new Private(42));
+ ptr = std::unique_ptr<Private>(new Private(42));
+ }
+
+ virtual ~Private();
+};
+
+class Protected {
+protected:
+ Protected() {}
+
+public:
+ Protected(int, int) {}
+ void create() {
+ auto callsPublic = std::unique_ptr<Protected>(new Protected(1, 2));
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_unique instead
+ // CHECK-FIXES: auto callsPublic = std::make_unique<Protected>(1, 2);
+ auto ptr = std::unique_ptr<Protected>(new Protected);
+ ptr.reset(new Protected);
+ ptr = std::unique_ptr<Protected>(new Protected);
+ }
+};
+
+void initialization(int T, Base b) {
+ // Test different kinds of initialization of the pointee.
+
+ // Direct initialization with parenthesis.
+ std::unique_ptr<DPair> PDir1 = std::unique_ptr<DPair>(new DPair(1, T));
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<DPair> PDir1 = std::make_unique<DPair>(1, T);
+ PDir1.reset(new DPair(1, T));
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_unique instead
+ // CHECK-FIXES: PDir1 = std::make_unique<DPair>(1, T);
+
+ // Direct initialization with braces.
+ std::unique_ptr<DPair> PDir2 = std::unique_ptr<DPair>(new DPair{2, T});
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<DPair> PDir2 = std::make_unique<DPair>(2, T);
+ PDir2.reset(new DPair{2, T});
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_unique instead
+ // CHECK-FIXES: PDir2 = std::make_unique<DPair>(2, T);
+
+ // Aggregate initialization.
+ std::unique_ptr<APair> PAggr = std::unique_ptr<APair>(new APair{T, 1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<APair> PAggr = std::make_unique<APair>(APair{T, 1});
+ PAggr.reset(new APair{T, 1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_unique instead
+ // CHECK-FIXES: std::make_unique<APair>(APair{T, 1});
+
+ // Test different kinds of initialization of the pointee, when the unique_ptr
+ // is initialized with braces.
+
+ // Direct initialization with parenthesis.
+ std::unique_ptr<DPair> PDir3 = std::unique_ptr<DPair>{new DPair(3, T)};
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<DPair> PDir3 = std::make_unique<DPair>(3, T);
+
+ // Direct initialization with braces.
+ std::unique_ptr<DPair> PDir4 = std::unique_ptr<DPair>{new DPair{4, T}};
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<DPair> PDir4 = std::make_unique<DPair>(4, T);
+
+ // Aggregate initialization.
+ std::unique_ptr<APair> PAggr2 = std::unique_ptr<APair>{new APair{T, 2}};
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<APair> PAggr2 = std::make_unique<APair>(APair{T, 2});
+
+ // Direct initialization with parenthesis, without arguments.
+ std::unique_ptr<DPair> PDir5 = std::unique_ptr<DPair>(new DPair());
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<DPair> PDir5 = std::make_unique<DPair>();
+
+ // Direct initialization with braces, without arguments.
+ std::unique_ptr<DPair> PDir6 = std::unique_ptr<DPair>(new DPair{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<DPair> PDir6 = std::make_unique<DPair>();
+
+ // Aggregate initialization without arguments.
+ std::unique_ptr<Empty> PEmpty = std::unique_ptr<Empty>(new Empty{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<Empty> PEmpty = std::make_unique<Empty>(Empty{});
+
+ // Initialization with default constructor.
+ std::unique_ptr<E> PE1 = std::unique_ptr<E>(new E{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<E> PE1 = std::make_unique<E>();
+ PE1.reset(new E{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PE1 = std::make_unique<E>();
+
+ //============================================================================
+ // NOTE: For initlializer-list constructors, the check only gives warnings,
+ // and no fixes are generated.
+ //============================================================================
+
+ // Initialization with the initializer-list constructor.
+ std::unique_ptr<E> PE2 = std::unique_ptr<E>(new E{1, 2});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<E> PE2 = std::unique_ptr<E>(new E{1, 2});
+ PE2.reset(new E{1, 2});
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PE2.reset(new E{1, 2});
+
+ // Initialization with default constructor.
+ std::unique_ptr<F> PF1 = std::unique_ptr<F>(new F());
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<F> PF1 = std::make_unique<F>();
+ PF1.reset(new F());
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PF1 = std::make_unique<F>();
+
+ // Initialization with default constructor.
+ std::unique_ptr<F> PF2 = std::unique_ptr<F>(new F{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<F> PF2 = std::make_unique<F>();
+ PF2.reset(new F());
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PF2 = std::make_unique<F>();
+
+ // Initialization with the initializer-list constructor.
+ std::unique_ptr<F> PF3 = std::unique_ptr<F>(new F{1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<F> PF3 = std::unique_ptr<F>(new F{1});
+ PF3.reset(new F{1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PF3.reset(new F{1});
+
+ // Initialization with the initializer-list constructor.
+ std::unique_ptr<F> PF4 = std::unique_ptr<F>(new F{1, 2});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<F> PF4 = std::unique_ptr<F>(new F{1, 2});
+
+ // Initialization with the initializer-list constructor.
+ std::unique_ptr<F> PF5 = std::unique_ptr<F>(new F({1, 2}));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<F> PF5 = std::unique_ptr<F>(new F({1, 2}));
+
+ // Initialization with the initializer-list constructor as the default
+ // constructor is not present.
+ std::unique_ptr<G> PG1 = std::unique_ptr<G>(new G{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<G> PG1 = std::unique_ptr<G>(new G{});
+ PG1.reset(new G{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PG1.reset(new G{});
+
+ // Initialization with the initializer-list constructor.
+ std::unique_ptr<G> PG2 = std::unique_ptr<G>(new G{1});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<G> PG2 = std::unique_ptr<G>(new G{1});
+
+ // Initialization with the initializer-list constructor.
+ std::unique_ptr<G> PG3 = std::unique_ptr<G>(new G{1, 2});
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<G> PG3 = std::unique_ptr<G>(new G{1, 2});
+
+ std::unique_ptr<H> PH1 = std::unique_ptr<H>(new H({1, 2, 3}));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<H> PH1 = std::unique_ptr<H>(new H({1, 2, 3}));
+ PH1.reset(new H({1, 2, 3}));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PH1.reset(new H({1, 2, 3}));
+
+ std::unique_ptr<H> PH2 = std::unique_ptr<H>(new H({1, 2, 3}, 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<H> PH2 = std::unique_ptr<H>(new H({1, 2, 3}, 1));
+ PH2.reset(new H({1, 2, 3}, 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PH2.reset(new H({1, 2, 3}, 1));
+
+ std::unique_ptr<H> PH3 = std::unique_ptr<H>(new H({1, 2, 3}, 1.0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<H> PH3 = std::unique_ptr<H>(new H({1, 2, 3}, 1.0));
+ PH3.reset(new H({1, 2, 3}, 1.0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PH3.reset(new H({1, 2, 3}, 1.0));
+
+ std::unique_ptr<I> PI1 = std::unique_ptr<I>(new I(G({1, 2, 3})));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<I> PI1 = std::make_unique<I>(G({1, 2, 3}));
+ PI1.reset(new I(G({1, 2, 3})));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::make_unique instead
+ // CHECK-FIXES: PI1 = std::make_unique<I>(G({1, 2, 3}));
+
+ std::unique_ptr<Foo> FF = std::unique_ptr<Foo>(new Foo());
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning:
+ // CHECK-FIXES: std::unique_ptr<Foo> FF = std::make_unique<Foo>();
+ FF.reset(new Foo());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning:
+ // CHECK-FIXES: FF = std::make_unique<Foo>();
+
+ std::unique_ptr<bar::Bar> BB = std::unique_ptr<bar::Bar>(new bar::Bar());
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning:
+ // CHECK-FIXES: std::unique_ptr<bar::Bar> BB = std::make_unique<bar::Bar>();
+ BB.reset(new bar::Bar());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning:
+ // CHECK-FIXES: BB = std::make_unique<bar::Bar>();
+
+ std::unique_ptr<Foo[]> FFs;
+ FFs.reset(new Foo[5]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning:
+ // CHECK-FIXES: FFs = std::make_unique<Foo[]>(5);
+ FFs.reset(new Foo[5]());
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning:
+ // CHECK-FIXES: FFs = std::make_unique<Foo[]>(5);
+ const int Num = 1;
+ FFs.reset(new Foo[Num]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning:
+ // CHECK-FIXES: FFs = std::make_unique<Foo[]>(Num);
+ int Num2 = 1;
+ FFs.reset(new Foo[Num2]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning:
+ // CHECK-FIXES: FFs = std::make_unique<Foo[]>(Num2);
+
+ std::unique_ptr<int[]> FI;
+ FI.reset(new int[5]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning:
+ // CHECK-FIXES: FI = std::make_unique<int[]>(5);
+ FI.reset(new int[5]());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning:
+ // CHECK-FIXES: FI = std::make_unique<int[]>(5);
+ FI.reset(new int[Num]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning:
+ // CHECK-FIXES: FI = std::make_unique<int[]>(Num);
+ FI.reset(new int[Num2]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning:
+ // CHECK-FIXES: FI = std::make_unique<int[]>(Num2);
+}
+
+void aliases() {
+ typedef std::unique_ptr<int> IntPtr;
+ IntPtr Typedef = IntPtr(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use std::make_unique instead
+ // CHECK-FIXES: IntPtr Typedef = std::make_unique<int>();
+
+ // We use 'bool' instead of '_Bool'.
+ typedef std::unique_ptr<bool> BoolPtr;
+ BoolPtr BoolType = BoolPtr(new bool);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use std::make_unique instead
+ // CHECK-FIXES: BoolPtr BoolType = std::make_unique<bool>();
+
+ // We use 'Base' instead of 'struct Base'.
+ typedef std::unique_ptr<Base> BasePtr;
+ BasePtr StructType = BasePtr(new Base);
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use std::make_unique instead
+// CHECK-FIXES: BasePtr StructType = std::make_unique<Base>();
+
+#define PTR unique_ptr<int>
+ std::unique_ptr<int> Macro = std::PTR(new int);
+// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use std::make_unique instead
+// CHECK-FIXES: std::unique_ptr<int> Macro = std::make_unique<int>();
+#undef PTR
+
+ std::unique_ptr<int> Using = unique_ptr_<int>(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use std::make_unique instead
+ // CHECK-FIXES: std::unique_ptr<int> Using = std::make_unique<int>();
+}
+
+void whitespaces() {
+ // clang-format off
+ auto Space = std::unique_ptr <int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use std::make_unique instead
+ // CHECK-FIXES: auto Space = std::make_unique<int>();
+
+ auto Spaces = std :: unique_ptr <int>(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use std::make_unique instead
+ // CHECK-FIXES: auto Spaces = std::make_unique<int>();
+ // clang-format on
+}
+
+void nesting() {
+ auto Nest = std::unique_ptr<std::unique_ptr<int>>(new std::unique_ptr<int>(new int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use std::make_unique instead
+ // CHECK-FIXES: auto Nest = std::make_unique<std::unique_ptr<int>>(new int);
+ Nest.reset(new std::unique_ptr<int>(new int));
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use std::make_unique instead
+ // CHECK-FIXES: Nest = std::make_unique<std::unique_ptr<int>>(new int);
+ Nest->reset(new int);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use std::make_unique instead
+ // CHECK-FIXES: *Nest = std::make_unique<int>();
+}
+
+void reset() {
+ std::unique_ptr<int> P;
+ P.reset();
+ P.reset(nullptr);
+ P.reset(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use std::make_unique instead
+ // CHECK-FIXES: P = std::make_unique<int>();
+
+ auto Q = &P;
+ Q->reset(new int());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use std::make_unique instead
+ // CHECK-FIXES: *Q = std::make_unique<int>();
+}
+
+#define DEFINE(...) __VA_ARGS__
+template<typename T>
+void g2(std::unique_ptr<Foo> *t) {
+ DEFINE(auto p = std::unique_ptr<Foo>(new Foo); t->reset(new Foo););
+}
+void macro() {
+ std::unique_ptr<Foo> *t;
+ g2<bar::Bar>(t);
+}
+#undef DEFINE
+
+class UniqueFoo : public std::unique_ptr<Foo> {
+ public:
+ void foo() {
+ reset(new Foo);
+ this->reset(new Foo);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use std::make_unique instead
+ // CHECK-FIXES: *this = std::make_unique<Foo>();
+ (*this).reset(new Foo);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use std::make_unique instead
+ // CHECK-FIXES: (*this) = std::make_unique<Foo>();
+ }
+};
+
+// Ignore statements inside a template instantiation.
+template<typename T>
+void template_fun(T* t) {
+ std::unique_ptr<T> t2 = std::unique_ptr<T>(new T);
+ t2.reset(new T);
+}
+
+void invoke_template() {
+ Foo* foo;
+ template_fun(foo);
+}
+
+void no_fix_for_invalid_new_loc() {
+ // FIXME: Although the code is valid, the end location of `new struct Base` is
+ // invalid. Correct it once https://bugs.llvm.org/show_bug.cgi?id=35952 is
+ // fixed.
+ auto T = std::unique_ptr<Base>(new struct Base);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use std::make_unique instead
+ // CHECK-FIXES: auto T = std::unique_ptr<Base>(new struct Base);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-pass-by-value-header.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-pass-by-value-header.cpp
new file mode 100644
index 0000000..95ad623
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-pass-by-value-header.cpp
@@ -0,0 +1,8 @@
+// RUN: cp %S/Inputs/modernize-pass-by-value/header.h %T/pass-by-value-header.h
+// RUN: clang-tidy %s -checks='-*,modernize-pass-by-value' -header-filter='.*' -fix -- -std=c++11 -I %T | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not="{{warning|error}}:"
+// RUN: FileCheck -input-file=%T/pass-by-value-header.h %s -check-prefix=CHECK-FIXES
+
+#include "pass-by-value-header.h"
+// CHECK-MESSAGES: :8:5: warning: pass by value and use std::move [modernize-pass-by-value]
+// CHECK-FIXES: #include <utility>
+// CHECK-FIXES: A(ThreadId tid) : threadid(std::move(tid)) {}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-pass-by-value-macro-header.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-pass-by-value-macro-header.cpp
new file mode 100644
index 0000000..543b7e4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-pass-by-value-macro-header.cpp
@@ -0,0 +1,18 @@
+// RUN: %check_clang_tidy %s modernize-pass-by-value %t -- -- -std=c++11 -isystem %S/Inputs/Headers
+
+// CHECK-FIXES: #include <utility>
+
+#define HEADER <./a.h>
+#include HEADER
+
+struct A {
+ A(const A &) {}
+ A(A &&) {}
+};
+
+struct B {
+ B(const A &a) : a(a) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move [modernize-pass-by-value]
+// CHECK-FIXES: B(A a) : a(std::move(a)) {}
+ A a;
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-pass-by-value-multi-fixes.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-pass-by-value-multi-fixes.cpp
new file mode 100644
index 0000000..7980c30
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-pass-by-value-multi-fixes.cpp
@@ -0,0 +1,12 @@
+// RUN: cat %S/Inputs/modernize-pass-by-value/header-with-fix.h > %T/pass-by-value-header-with-fix.h
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: clang-tidy %t.cpp -checks='-*,modernize-pass-by-value' -header-filter='.*' -fix -- -std=c++11 -I %T | FileCheck %s -check-prefix=CHECK-MESSAGES -implicit-check-not="{{warning|error}}:"
+// RUN: FileCheck -input-file=%t.cpp %s -check-prefix=CHECK-FIXES
+// RUN: FileCheck -input-file=%T/pass-by-value-header-with-fix.h %s -check-prefix=CHECK-HEADER-FIXES
+
+#include "pass-by-value-header-with-fix.h"
+// CHECK-HEADER-FIXES: Foo(S s);
+Foo::Foo(const S &s) : s(s) {}
+// CHECK-MESSAGES: :9:10: warning: pass by value and use std::move [modernize-pass-by-value]
+// CHECK-FIXES: #include <utility>
+// CHECK-FIXES: Foo::Foo(S s) : s(std::move(s)) {}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-pass-by-value.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-pass-by-value.cpp
new file mode 100644
index 0000000..87e22ba
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-pass-by-value.cpp
@@ -0,0 +1,215 @@
+// RUN: %check_clang_tidy %s modernize-pass-by-value %t -- -- -std=c++11 -fno-delayed-template-parsing
+
+namespace {
+// POD types are trivially move constructible.
+struct POD {
+ int a, b, c;
+};
+
+struct Movable {
+ int a, b, c;
+ Movable() = default;
+ Movable(const Movable &) {}
+ Movable(Movable &&) {}
+};
+
+struct NotMovable {
+ NotMovable() = default;
+ NotMovable(const NotMovable &) = default;
+ NotMovable(NotMovable &&) = delete;
+ int a, b, c;
+};
+}
+
+struct A {
+ A(const Movable &M) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move [modernize-pass-by-value]
+ // CHECK-FIXES: A(Movable M) : M(std::move(M)) {}
+ Movable M;
+};
+
+// Test that we aren't modifying other things than a parameter.
+Movable GlobalObj;
+struct B {
+ B(const Movable &M) : M(GlobalObj) {}
+ // CHECK-FIXES: B(const Movable &M) : M(GlobalObj) {}
+ Movable M;
+};
+
+// Test that a parameter with more than one reference to it won't be changed.
+struct C {
+ // Tests extra-reference in body.
+ C(const Movable &M) : M(M) { this->i = M.a; }
+ // CHECK-FIXES: C(const Movable &M) : M(M) { this->i = M.a; }
+
+ // Tests extra-reference in init-list.
+ C(const Movable &M, int) : M(M), i(M.a) {}
+ // CHECK-FIXES: C(const Movable &M, int) : M(M), i(M.a) {}
+ Movable M;
+ int i;
+};
+
+// Test that both declaration and definition are updated.
+struct D {
+ D(const Movable &M);
+ // CHECK-FIXES: D(Movable M);
+ Movable M;
+};
+D::D(const Movable &M) : M(M) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move
+// CHECK-FIXES: D::D(Movable M) : M(std::move(M)) {}
+
+// Test with default parameter.
+struct E {
+ E(const Movable &M = Movable()) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
+ // CHECK-FIXES: E(Movable M = Movable()) : M(std::move(M)) {}
+ Movable M;
+};
+
+// Test with object that can't be moved.
+struct F {
+ F(const NotMovable &NM) : NM(NM) {}
+ // CHECK-FIXES: F(const NotMovable &NM) : NM(NM) {}
+ NotMovable NM;
+};
+
+// Test unnamed parameter in declaration.
+struct G {
+ G(const Movable &);
+ // CHECK-FIXES: G(Movable );
+ Movable M;
+};
+G::G(const Movable &M) : M(M) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move
+// CHECK-FIXES: G::G(Movable M) : M(std::move(M)) {}
+
+// Test parameter with and without qualifier.
+namespace ns_H {
+typedef ::Movable HMovable;
+}
+struct H {
+ H(const ns_H::HMovable &M);
+ // CHECK-FIXES: H(ns_H::HMovable M);
+ ns_H::HMovable M;
+};
+using namespace ns_H;
+H::H(const HMovable &M) : M(M) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: pass by value and use std::move
+// CHECK-FIXES: H(HMovable M) : M(std::move(M)) {}
+
+// Try messing up with macros.
+#define MOVABLE_PARAM(Name) const Movable & Name
+// CHECK-FIXES: #define MOVABLE_PARAM(Name) const Movable & Name
+struct I {
+ I(MOVABLE_PARAM(M)) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
+ // CHECK-FIXES: I(MOVABLE_PARAM(M)) : M(M) {}
+ Movable M;
+};
+#undef MOVABLE_PARAM
+
+// Test that templates aren't modified.
+template <typename T> struct J {
+ J(const T &M) : M(M) {}
+ // CHECK-FIXES: J(const T &M) : M(M) {}
+ T M;
+};
+J<Movable> j1(Movable());
+J<NotMovable> j2(NotMovable());
+
+struct K_Movable {
+ K_Movable() = default;
+ K_Movable(const K_Movable &) = default;
+ K_Movable(K_Movable &&o) { dummy = o.dummy; }
+ int dummy;
+};
+
+// Test with movable type with an user defined move constructor.
+struct K {
+ K(const K_Movable &M) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
+ // CHECK-FIXES: K(K_Movable M) : M(std::move(M)) {}
+ K_Movable M;
+};
+
+template <typename T> struct L {
+ L(const Movable &M) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
+ // CHECK-FIXES: L(Movable M) : M(std::move(M)) {}
+ Movable M;
+};
+L<int> l(Movable());
+
+// Test with a non-instantiated template class.
+template <typename T> struct N {
+ N(const Movable &M) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
+ // CHECK-FIXES: N(Movable M) : M(std::move(M)) {}
+
+ Movable M;
+ T A;
+};
+
+// Test with value parameter.
+struct O {
+ O(Movable M) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
+ // CHECK-FIXES: O(Movable M) : M(std::move(M)) {}
+ Movable M;
+};
+
+// Test with a const-value parameter.
+struct P {
+ P(const Movable M) : M(M) {}
+ // CHECK-FIXES: P(const Movable M) : M(M) {}
+ Movable M;
+};
+
+// Test with multiples parameters where some need to be changed and some don't.
+// need to.
+struct Q {
+ Q(const Movable &A, const Movable &B, const Movable &C, double D)
+ : A(A), B(B), C(C), D(D) {}
+ // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: pass by value and use std::move
+ // CHECK-MESSAGES: :[[@LINE-3]]:41: warning: pass by value and use std::move
+ // CHECK-FIXES: Q(const Movable &A, Movable B, Movable C, double D)
+ // CHECK-FIXES: : A(A), B(std::move(B)), C(std::move(C)), D(D) {}
+ const Movable &A;
+ Movable B;
+ Movable C;
+ double D;
+};
+
+// Test that value-parameters with a nested name specifier are left as-is.
+namespace ns_R {
+typedef ::Movable RMovable;
+}
+struct R {
+ R(ns_R::RMovable M) : M(M) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pass by value and use std::move
+ // CHECK-FIXES: R(ns_R::RMovable M) : M(std::move(M)) {}
+ ns_R::RMovable M;
+};
+
+// Test with rvalue parameter.
+struct S {
+ S(Movable &&M) : M(M) {}
+ // CHECK-FIXES: S(Movable &&M) : M(M) {}
+ Movable M;
+};
+
+template <typename T, int N> struct array { T A[N]; };
+
+// Test that types that are trivially copyable will not use std::move. This will
+// cause problems with performance-move-const-arg, as it will revert it.
+struct T {
+ T(array<int, 10> a) : a_(a) {}
+ // CHECK-FIXES: T(array<int, 10> a) : a_(a) {}
+ array<int, 10> a_;
+};
+
+struct U {
+ U(const POD &M) : M(M) {}
+ POD M;
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-raw-string-literal-delimiter.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-raw-string-literal-delimiter.cpp
new file mode 100644
index 0000000..1dd3e13
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-raw-string-literal-delimiter.cpp
@@ -0,0 +1,9 @@
+// RUN: %check_clang_tidy %s modernize-raw-string-literal %t -- -config='{CheckOptions: [{key: "modernize-raw-string-literal.DelimiterStem", value: "str"}, {key: modernize-raw-string-literal.ReplaceShorterLiterals, value: 1}]}' -- -std=c++11
+
+char const *const ContainsSentinel{"who\\ops)\""};
+// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const ContainsSentinel{R"str(who\ops)")str"};{{$}}
+
+//char const *const ContainsDelim{"whoops)\")lit\""};
+// CHECK-XMESSAGES: :[[@LINE-1]]:33: warning: {{.*}} can be written as a raw string literal
+// CHECK-XFIXES: {{^}}char const *const ContainsDelim{R"lit1(whoops)")lit")lit1"};{{$}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-raw-string-literal-replace-shorter.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-raw-string-literal-replace-shorter.cpp
new file mode 100644
index 0000000..673a8aa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-raw-string-literal-replace-shorter.cpp
@@ -0,0 +1,13 @@
+// RUN: %check_clang_tidy %s modernize-raw-string-literal %t
+
+// Don't replace these, because the raw literal would be longer.
+char const *const JustAQuote("quote:\'");
+char const *const NeedDelimiter("\":)\"");
+
+char const *const ManyQuotes("quotes:\'\'\'\'");
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const ManyQuotes(R"(quotes:'''')");{{$}}
+
+char const *const LongOctal("\042\072\051\042");
+// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const LongOctal(R"lit(":)")lit");{{$}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-raw-string-literal.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-raw-string-literal.cpp
new file mode 100644
index 0000000..b6d4995
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-raw-string-literal.cpp
@@ -0,0 +1,131 @@
+// RUN: %check_clang_tidy %s modernize-raw-string-literal %t -- -config="{CheckOptions: [{key: modernize-raw-string-literal.ReplaceShorterLiterals, value: 1}]}" -- -std=c++11
+
+char const *const BackSlash("goink\\frob");
+// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: escaped string literal can be written as a raw string literal [modernize-raw-string-literal]
+// CHECK-FIXES: {{^}}char const *const BackSlash(R"(goink\frob)");{{$}}
+
+char const *const PlainLiteral("plain literal");
+
+// Non-printable ASCII characters.
+char const *const Nul("goink\\\000");
+char const *const Soh("goink\\\001");
+char const *const Stx("goink\\\002");
+char const *const Etx("goink\\\003");
+char const *const Enq("goink\\\004");
+char const *const Ack("goink\\\005");
+char const *const Bell("goink\\\afrob");
+char const *const BackSpace("goink\\\bfrob");
+char const *const HorizontalTab("goink\\\tfrob");
+char const *const NewLine("goink\nfrob");
+char const *const VerticalTab("goink\\\vfrob");
+char const *const FormFeed("goink\\\ffrob");
+char const *const CarraigeReturn("goink\\\rfrob");
+char const *const So("goink\\\016");
+char const *const Si("goink\\\017");
+char const *const Dle("goink\\\020");
+char const *const Dc1("goink\\\021");
+char const *const Dc2("goink\\\022");
+char const *const Dc3("goink\\\023");
+char const *const Dc4("goink\\\024");
+char const *const Nak("goink\\\025");
+char const *const Syn("goink\\\026");
+char const *const Etb("goink\\\027");
+char const *const Can("goink\\\030");
+char const *const Em("goink\\\031");
+char const *const Sub("goink\\\032");
+char const *const Esc("goink\\\033");
+char const *const Fs("goink\\\034");
+char const *const Gs("goink\\\035");
+char const *const Rs("goink\\\036");
+char const *const Us("goink\\\037");
+char const *const HexNonPrintable("\\\x03");
+char const *const Delete("\\\177");
+char const *const MultibyteSnowman("\xE2\x98\x83");
+// CHECK-FIXES: {{^}}char const *const MultibyteSnowman("\xE2\x98\x83");{{$}}
+
+char const *const TrailingSpace("A line \\with space. \n");
+char const *const TrailingNewLine("A single \\line.\n");
+char const *const AlreadyRaw(R"(foobie\\bletch)");
+char const *const UTF8Literal(u8"foobie\\bletch");
+char const *const UTF8RawLiteral(u8R"(foobie\\bletch)");
+// TODO: enable these tests once all supported compilers
+// support char16_t and char32_t (VS2013 does not)
+// char16_t const *const UTF16Literal(u"foobie\\bletch");
+// char16_t const *const UTF16RawLiteral(uR"(foobie\\bletch)");
+// char32_t const *const UTF32Literal(U"foobie\\bletch");
+// char32_t const *const UTF32RawLiteral(UR"(foobie\\bletch)");
+wchar_t const *const WideLiteral(L"foobie\\bletch");
+wchar_t const *const WideRawLiteral(LR"(foobie\\bletch)");
+
+char const *const SingleQuote("goink\'frob");
+// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: {{.*}} can be written as a raw string literal
+// CHECK-XFIXES: {{^}}char const *const SingleQuote(R"(goink'frob)");{{$}}
+
+char const *const DoubleQuote("goink\"frob");
+// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const DoubleQuote(R"(goink"frob)");{{$}}
+
+char const *const QuestionMark("goink\?frob");
+// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const QuestionMark(R"(goink?frob)");{{$}}
+
+char const *const RegEx("goink\\(one|two\\)\\\\\\?.*\\nfrob");
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const RegEx(R"(goink\(one|two\)\\\?.*\nfrob)");{{$}}
+
+char const *const Path("C:\\Program Files\\Vendor\\Application\\Application.exe");
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const Path(R"(C:\Program Files\Vendor\Application\Application.exe)");{{$}}
+
+char const *const ContainsSentinel("who\\ops)\"");
+// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const ContainsSentinel(R"lit(who\ops)")lit");{{$}}
+
+char const *const ContainsDelim("whoops)\")lit\"");
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const ContainsDelim(R"lit1(whoops)")lit")lit1");{{$}}
+
+char const *const OctalPrintable("\100\\");
+// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const OctalPrintable(R"(@\)");{{$}}
+
+char const *const HexPrintable("\x40\\");
+// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: {{.*}} can be written as a raw string literal
+// CHECK-FIXES: {{^}}char const *const HexPrintable(R"(@\)");{{$}}
+
+char const *const prettyFunction(__PRETTY_FUNCTION__);
+char const *const function(__FUNCTION__);
+char const *const func(__func__);
+
+#define TRICK(arg_) #arg_
+char const *const MacroBody = TRICK(foo\\bar);
+
+#define HAT(rabbit_) #rabbit_ "foo\\bar"
+char const *const StringizedMacroArgument = HAT(foo\\bar);
+
+#define SUBST(lit_) lit_
+char const *const MacroArgument = SUBST("foo\\bar");
+// FIXME: We should be able to replace this string literal macro argument
+
+template <typename T>
+void fn(char const *const Arg) {
+ char const *const Str("foo\\bar");
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: {{.*}} can be written as a raw string literal
+ // CHECK-FIXES: {{^}} char const *const Str(R"(foo\bar)");{{$}}
+}
+
+template <>
+void fn<int>(char const *const Arg) {
+ char const *const Str("foo\\bar");
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: {{.*}} can be written as a raw string literal
+ // CHECK-FIXES: {{^}} char const *const Str(R"(foo\bar)");{{$}}
+}
+
+void callFn() {
+ fn<int>("foo\\bar");
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}} can be written as a raw string literal
+ // CHECK-FIXES: {{^}} fn<int>(R"(foo\bar)");{{$}}
+ fn<double>("foo\\bar");
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} can be written as a raw string literal
+ // CHECK-FIXES: {{^}} fn<double>(R"(foo\bar)");{{$}}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-redundant-void-arg-delayed.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-redundant-void-arg-delayed.cpp
new file mode 100644
index 0000000..dd88775
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-redundant-void-arg-delayed.cpp
@@ -0,0 +1,28 @@
+// RUN: %check_clang_tidy %s modernize-redundant-void-arg %t -- -- -fdelayed-template-parsing
+
+int foo(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
+// CHECK-FIXES: {{^}}int foo() {{{$}}
+ return 0;
+}
+
+template <class T>
+struct MyFoo {
+ int foo(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
+// CHECK-FIXES: {{^}} int foo() {{{$}}
+ return 0;
+ }
+};
+// Explicit instantiation.
+template class MyFoo<int>;
+
+template <class T>
+struct MyBar {
+ // This declaration isn't instantiated and won't be parsed 'delayed-template-parsing'.
+ int foo(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
+// CHECK-FIXES: {{^}} int foo() {{{$}}
+ return 0;
+ }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-redundant-void-arg.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-redundant-void-arg.c
new file mode 100644
index 0000000..fdaf375
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-redundant-void-arg.c
@@ -0,0 +1,58 @@
+// RUN: clang-tidy -checks=-*,modernize-redundant-void-arg %s -- -x c | count 0
+
+#define NULL 0
+
+extern int i;
+
+int foo2() {
+ return 0;
+}
+
+int j = 1;
+
+int foo(void) {
+ return 0;
+}
+
+typedef unsigned int my_uint;
+
+typedef void my_void;
+
+// A function taking void and returning a pointer to function taking void
+// and returning int.
+int (*returns_fn_void_int(void))(void);
+
+typedef int (*returns_fn_void_int_t(void))(void);
+
+int (*returns_fn_void_int(void))(void) {
+ return NULL;
+}
+
+// A function taking void and returning a pointer to a function taking void
+// and returning a pointer to a function taking void and returning void.
+void (*(*returns_fn_returns_fn_void_void(void))(void))(void);
+
+typedef void (*(*returns_fn_returns_fn_void_void_t(void))(void))(void);
+
+void (*(*returns_fn_returns_fn_void_void(void))(void))(void) {
+ return NULL;
+}
+
+void bar() {
+ int i;
+ int *pi = NULL;
+ void *pv = (void *) pi;
+ float f;
+ float *fi;
+ double d;
+ double *pd;
+}
+
+void (*f1)(void);
+void (*f2)(void) = NULL;
+void (*f3)(void) = bar;
+void (*fa)();
+void (*fb)() = NULL;
+void (*fc)() = bar;
+
+typedef void (function_ptr)(void);
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-redundant-void-arg.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-redundant-void-arg.cpp
new file mode 100644
index 0000000..ea4b75f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-redundant-void-arg.cpp
@@ -0,0 +1,447 @@
+// RUN: %check_clang_tidy %s modernize-redundant-void-arg %t
+
+#define NULL 0
+
+int foo();
+
+void bar();
+
+void bar2();
+
+extern "C" void ecfoo(void);
+
+extern "C" void ecfoo(void) {
+}
+
+extern int i;
+
+int j = 1;
+
+int foo(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
+// CHECK-FIXES: {{^}}int foo() {{{$}}
+ return 0;
+}
+
+typedef unsigned int my_uint;
+
+typedef void my_void;
+
+// A function taking void and returning a pointer to function taking void
+// and returning int.
+int (*returns_fn_void_int(void))(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: {{.*}} in function declaration
+// CHECK-MESSAGES: :[[@LINE-2]]:34: warning: {{.*}} in function declaration
+// CHECK-FIXES: {{^}}int (*returns_fn_void_int())();{{$}}
+
+typedef int (*returns_fn_void_int_t(void))(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: {{.*}} in typedef
+// CHECK-MESSAGES: :[[@LINE-2]]:44: warning: {{.*}} in typedef
+// CHECK-FIXES: {{^}}typedef int (*returns_fn_void_int_t())();{{$}}
+
+// Should work for type aliases as well as typedef.
+using returns_fn_void_int_t2 = int (*(void))(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:39: warning: {{.*}} in type alias
+// CHECK-MESSAGES: :[[@LINE-2]]:46: warning: {{.*}} in type alias
+// CHECK-FIXES: {{^}}using returns_fn_void_int_t2 = int (*())();{{$}}
+
+int (*returns_fn_void_int(void))(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: {{.*}} in function definition
+// CHECK-MESSAGES: :[[@LINE-2]]:34: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^}}int (*returns_fn_void_int())() {{{$}}
+ return nullptr;
+}
+
+// A function taking void and returning a pointer to a function taking void
+// and returning a pointer to a function taking void and returning void.
+void (*(*returns_fn_returns_fn_void_void(void))(void))(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:42: warning: {{.*}} in function declaration
+// CHECK-MESSAGES: :[[@LINE-2]]:49: warning: {{.*}} in function declaration
+// CHECK-MESSAGES: :[[@LINE-3]]:56: warning: {{.*}} in function declaration
+// CHECK-FIXES: {{^}}void (*(*returns_fn_returns_fn_void_void())())();{{$}}
+
+typedef void (*(*returns_fn_returns_fn_void_void_t(void))(void))(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:52: warning: {{.*}} in typedef
+// CHECK-MESSAGES: :[[@LINE-2]]:59: warning: {{.*}} in typedef
+// CHECK-MESSAGES: :[[@LINE-3]]:66: warning: {{.*}} in typedef
+// CHECK-FIXES: {{^}}typedef void (*(*returns_fn_returns_fn_void_void_t())())();{{$}}
+
+void (*(*returns_fn_returns_fn_void_void(void))(void))(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:42: warning: {{.*}} in function definition
+// CHECK-MESSAGES: :[[@LINE-2]]:49: warning: {{.*}} in function definition
+// CHECK-MESSAGES: :[[@LINE-3]]:56: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^}}void (*(*returns_fn_returns_fn_void_void())())() {{{$}}
+ return nullptr;
+}
+
+void bar(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^}}void bar() {{{$}}
+}
+
+void op_fn(int i) {
+}
+
+class gronk {
+public:
+ gronk();
+ ~gronk();
+
+ void foo();
+ void bar();
+ void bar2
+ ();
+ void operation(int i) { }
+
+private:
+ int m_i;
+ int *m_pi;
+ float m_f;
+ float *m_pf;
+ double m_d;
+ double *m_pd;
+
+ void (*f1)(void);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} in field declaration
+ // CHECK-FIXES: {{^ }}void (*f1)();{{$}}
+
+ void (*op)(int i);
+
+ void (gronk::*p1)(void);
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}} in field declaration
+ // CHECK-FIXES: {{^ }}void (gronk::*p1)();{{$}}
+
+ int (gronk::*p_mi);
+
+ void (gronk::*p2)(int);
+
+ void (*(*returns_fn_returns_fn_void_void(void))(void))(void);
+ // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: {{.*}} in function declaration
+ // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: {{.*}} in function declaration
+ // CHECK-MESSAGES: :[[@LINE-3]]:58: warning: {{.*}} in function declaration
+ // CHECK-FIXES: {{^}} void (*(*returns_fn_returns_fn_void_void())())();{{$}}
+
+ void (*(*(gronk::*returns_fn_returns_fn_void_void_mem)(void))(void))(void);
+ // CHECK-MESSAGES: :[[@LINE-1]]:58: warning: {{.*}} in field declaration
+ // CHECK-MESSAGES: :[[@LINE-2]]:65: warning: {{.*}} in field declaration
+ // CHECK-MESSAGES: :[[@LINE-3]]:72: warning: {{.*}} in field declaration
+ // CHECK-FIXES: {{^}} void (*(*(gronk::*returns_fn_returns_fn_void_void_mem)())())();{{$}}
+};
+
+int i;
+int *pi;
+void *pv = (void *) pi;
+float f;
+float *fi;
+double d;
+double *pd;
+
+void (*f1)(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}} in variable declaration
+// CHECK-FIXES: {{^}}void (*f1)();{{$}}
+
+void (*f2)(void) = nullptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (*f2)() = nullptr;{{$}}
+
+void (*f2b)(void)(nullptr);
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (*f2b)()(nullptr);{{$}}
+
+void (*f2c)(void){nullptr};
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (*f2c)(){nullptr};{{$}}
+
+void (*f2d)(void) = NULL;
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (*f2d)() = NULL;{{$}}
+
+void (*f2e)(void)(NULL);
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (*f2e)()(NULL);{{$}}
+
+void (*f2f)(void){NULL};
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (*f2f)(){NULL};{{$}}
+
+void (*f3)(void) = bar;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (*f3)() = bar;{{$}}
+
+void (*o1)(int i);
+void (*o2)(int i) = nullptr;
+void (*o3)(int i)(nullptr);
+void (*o4)(int i){nullptr};
+void (*o5)(int i) = NULL;
+void (*o6)(int i)(NULL);
+void (*o7)(int i){NULL};
+void (*o8)(int i) = op_fn;
+
+void (*fa)();
+
+void (*fb)() = nullptr;
+
+void (*fc)() = bar;
+
+typedef void (function_ptr)(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: {{.*}} in typedef
+// CHECK-FIXES: {{^}}typedef void (function_ptr)();{{$}}
+
+// intentionally not LLVM style to check preservation of whitesapce
+typedef void (function_ptr2)
+ (
+ void
+ );
+// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: {{.*}} in typedef
+// CHECK-FIXES: {{^typedef void \(function_ptr2\)$}}
+// CHECK-FIXES-NEXT: {{^ \($}}
+// CHECK-FIXES-NEXT: {{^ $}}
+// CHECK-FIXES-NEXT: {{^ \);$}}
+
+// intentionally not LLVM style to check preservation of whitesapce
+typedef
+void
+(
+*
+(
+*
+returns_fn_returns_fn_void_void_t2
+(
+void
+)
+)
+(
+void
+)
+)
+(
+void
+)
+;
+// CHECK-MESSAGES: :[[@LINE-11]]:1: warning: {{.*}} in typedef
+// CHECK-MESSAGES: :[[@LINE-8]]:1: warning: {{.*}} in typedef
+// CHECK-MESSAGES: :[[@LINE-5]]:1: warning: {{.*}} in typedef
+// CHECK-FIXES: {{^typedef$}}
+// CHECK-FIXES-NEXT: {{^void$}}
+// CHECK-FIXES-NEXT: {{^\($}}
+// CHECK-FIXES-NEXT: {{^\*$}}
+// CHECK-FIXES-NEXT: {{^\($}}
+// CHECK-FIXES-NEXT: {{^\*$}}
+// CHECK-FIXES-NEXT: {{^returns_fn_returns_fn_void_void_t2$}}
+// CHECK-FIXES-NEXT: {{^\($}}
+// CHECK-FIXES-NOT: {{[^ ]}}
+// CHECK-FIXES: {{^\)$}}
+// CHECK-FIXES-NEXT: {{^\)$}}
+// CHECK-FIXES-NEXT: {{^\($}}
+// CHECK-FIXES-NOT: {{[^ ]}}
+// CHECK-FIXES: {{^\)$}}
+// CHECK-FIXES-NEXT: {{^\)$}}
+// CHECK-FIXES-NEXT: {{^\($}}
+// CHECK-FIXES-NOT: {{[^ ]}}
+// CHECK-FIXES: {{^\)$}}
+// CHECK-FIXES-NEXT: {{^;$}}
+
+
+void (gronk::*p1)(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: {{.*}} in variable declaration
+// CHECK-FIXES: {{^}}void (gronk::*p1)();{{$}}
+
+void (gronk::*p2)(void) = &gronk::foo;
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: {{.*}} in variable declaration with initializer
+// CHECK-FIXES: {{^}}void (gronk::*p2)() = &gronk::foo;{{$}}
+
+typedef void (gronk::*member_function_ptr)(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:44: warning: {{.*}} in typedef
+// CHECK-FIXES: {{^}}typedef void (gronk::*member_function_ptr)();{{$}}
+
+// intentionally not LLVM style to check preservation of whitesapce
+typedef void (gronk::*member_function_ptr2)
+ (
+ void
+ );
+// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: {{.*}} in typedef
+// CHECK-FIXES: {{^typedef void \(gronk::\*member_function_ptr2\)$}}
+// CHECK-FIXES-NEXT: {{^ \($}}
+// CHECK-FIXES-NEXT: {{^ $}}
+// CHECK-FIXES-NEXT: {{^ \);$}}
+
+void gronk::foo() {
+ void (*f1)(void) = &::bar;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer
+ // CHECK-FIXES: {{^ }}void (*f1)() = &::bar;{{$}}
+
+ void (*f2)(void);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration
+ // CHECK-FIXES: {{^ }}void (*f2)();{{$}}
+
+ // intentionally not LLVM style to check preservation of whitesapce
+ void (*f3)
+ (
+ void
+ );
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: {{.*}} in variable declaration
+ // CHECK-FIXES: {{^ }}void (*f3){{$}}
+ // CHECK-FIXES-NEXT: {{^ \($}}
+ // CHECK-FIXES-NEXT: {{^ $}}
+ // CHECK-FIXES-NEXT: {{^ \);$}}
+}
+
+void gronk::bar(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^}}void gronk::bar() {{{$}}
+ void (gronk::*p3)(void) = &gronk::foo;
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}} in variable declaration with initializer
+ // CHECK-FIXES: {{^ }}void (gronk::*p3)() = &gronk::foo;{{$}}
+
+ void (gronk::*p4)(void);
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}} in variable declaration
+ // CHECK-FIXES: {{^ }}void (gronk::*p4)();{{$}}
+
+ // intentionally not LLVM style to check preservation of whitesapce
+ void (gronk::*p5)
+ (
+ void
+ );
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: {{.*}} in variable declaration
+ // CHECK-FIXES: {{^ }}void (gronk::*p5){{$}}
+ // CHECK-FIXES-NEXT: {{^ \($}}
+ // CHECK-FIXES-NExT: {{^ $}}
+ // CHECK-FIXES-NExT: {{^ \);$}}
+}
+
+// intentionally not LLVM style to check preservation of whitesapce
+void gronk::bar2
+ (
+ void
+ )
+// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^void gronk::bar2$}}
+// CHECK-FIXES-NEXT: {{^ \($}}
+// CHECK-FIXES-NEXT: {{^ $}}
+// CHECK-FIXES-NEXT: {{^ \)$}}
+{
+}
+
+gronk::gronk(void)
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^}}gronk::gronk(){{$}}
+ : f1(nullptr),
+ p1(nullptr) {
+}
+
+gronk::~gronk(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^}}gronk::~gronk() {{{$}}
+}
+
+class nutter {
+public:
+ nutter();
+};
+
+nutter::nutter(void) {
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} in function definition
+// CHECK-FIXES: {{^}}nutter::nutter() {{{$}}
+ void (*f3)(void) = static_cast<void (*)(void)>(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer
+ // CHECK-MESSAGES: :[[@LINE-2]]:43: warning: {{.*}} in named cast
+ // CHECK-FIXES: void (*f3)() = static_cast<void (*)()>(0);{{$}}
+
+ void (*f4)(void) = (void (*)(void)) 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer
+ // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: {{.*}} in cast expression
+ // CHECK-FIXES: void (*f4)() = (void (*)()) 0;{{$}}
+
+ void (*f5)(void) = reinterpret_cast<void (*)(void)>(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer
+ // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: {{.*}} in named cast
+ // CHECK-FIXES: void (*f5)() = reinterpret_cast<void (*)()>(0);{{$}}
+
+ // intentionally not LLVM style to check preservation of whitesapce
+ void (*f6)(void) = static_cast<void (*)
+ (
+ void
+ )>(0);
+ // CHECK-MESSAGES: :[[@LINE-4]]:14: warning: {{.*}} in variable declaration with initializer
+ // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: {{.*}} in named cast
+ // CHECK-FIXES: {{^ }}void (*f6)() = static_cast<void (*){{$}}
+ // CHECK-FIXES-NEXT: {{^ \($}}
+ // CHECK-FIXES-NEXT: {{^ $}}
+ // CHECK-FIXES-NEXT: {{^ }})>(0);{{$}}
+
+ // intentionally not LLVM style to check preservation of whitesapce
+ void (*f7)(void) = (void (*)
+ (
+ void
+ )) 0;
+ // CHECK-MESSAGES: :[[@LINE-4]]:14: warning: {{.*}} in variable declaration with initializer
+ // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: {{.*}} in cast expression
+ // CHECK-FIXES: {{^ }}void (*f7)() = (void (*){{$}}
+ // CHECK-FIXES-NEXT: {{^ \($}}
+ // CHECK-FIXES-NEXT: {{^ $}}
+ // CHECK-FIXES-NEXT: {{^ \)\) 0;$}}
+
+ // intentionally not LLVM style to check preservation of whitesapce
+ void (*f8)(void) = reinterpret_cast<void (*)
+ (
+ void
+ )>(0);
+ // CHECK-MESSAGES: :[[@LINE-4]]:14: warning: {{.*}} in variable declaration with initializer
+ // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: {{.*}} in named cast
+ // CHECK-FIXES: {{^ }}void (*f8)() = reinterpret_cast<void (*){{$}}
+ // CHECK-FIXES-NEXT: {{^ \($}}
+ // CHECK-FIXES-NEXT: {{^ $}}
+ // CHECK-FIXES-NEXT: {{^ \)>\(0\);$}}
+
+ void (*o1)(int) = static_cast<void (*)(int)>(0);
+ void (*o2)(int) = (void (*)(int)) 0;
+ void (*o3)(int) = reinterpret_cast<void (*)(int)>(0);
+}
+
+class generator {
+public:
+ int operator()(void) { return 1; }
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: {{.*}} in function definition
+ // CHECK-FIXES: {{^ }}int operator()() { return 1; }{{$}}
+};
+
+void test_lambda_functions() {
+ auto lamb_duh = [](void (*fn)(void)) { (*fn)(); };
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: {{.*}} in variable declaration
+ // CHECK-FIXES: {{^ }}auto lamb_duh = [](void (*fn)()) { (*fn)(); };{{$}}
+
+ auto lambda_generator = [](void) { return 1; };
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: {{.*}} in lambda expression
+ // CHECK-FIXES: {{^ }}auto lambda_generator = []() { return 1; };{{$}}
+
+ auto gen2 = []() { return 1; };
+
+ auto gen3 = []{ return 1; };
+
+ auto void_returner = [](void) -> void (*)(void) { return f1; };
+ // CHECK-MESSAGES: [[@LINE-1]]:27: warning: {{.*}} in lambda expression
+ // CHECK-MESSAGES: [[@LINE-2]]:45: warning: {{.*}} in lambda expression
+ // CHECK-FIXES: {{^ }}auto void_returner = []() -> void (*)() { return f1; };{{$}}
+}
+
+#define M(x) x
+
+M(void inmacro(void) {})
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} in function definition
+// CHECK-FIXES: M(void inmacro() {})
+
+#define F(A, B) \
+ struct F_##A##_##B { \
+ F_##A##_##B(void); \
+ }; \
+ F_##A##_##B::F_##A##_##B(void)
+
+F(Foo, Bar) {
+
+}
+
+struct DefinitionWithNoBody {
+ DefinitionWithNoBody(void) = delete;
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: {{.*}} in function definition
+ // CHECK-FIXES: DefinitionWithNoBody() = delete;
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-replace-auto-ptr.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-replace-auto-ptr.cpp
new file mode 100644
index 0000000..13405b2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-replace-auto-ptr.cpp
@@ -0,0 +1,304 @@
+// RUN: %check_clang_tidy %s modernize-replace-auto-ptr %t -- -- \
+// RUN: -std=c++11 -I %S/Inputs/modernize-replace-auto-ptr
+
+// CHECK-FIXES: #include <utility>
+
+#include "memory.h"
+
+// Instrumentation for auto_ptr_ref test.
+struct Base {};
+struct Derived : Base {};
+std::auto_ptr<Derived> create_derived_ptr();
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: auto_ptr is deprecated, use unique_ptr instead [modernize-replace-auto-ptr]
+// CHECK-FIXES: std::unique_ptr<Derived> create_derived_ptr();
+
+
+// Test function return values (declaration)
+std::auto_ptr<char> f_5();
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: auto_ptr is deprecated
+// CHECK-FIXES: std::unique_ptr<char> f_5()
+
+
+// Test function parameters.
+void f_6(std::auto_ptr<int>);
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: auto_ptr is deprecated
+// CHECK-FIXES: void f_6(std::unique_ptr<int>);
+void f_7(const std::auto_ptr<int> &);
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: auto_ptr is deprecated
+// CHECK-FIXES: void f_7(const std::unique_ptr<int> &);
+
+
+// Test on record type fields.
+struct A {
+ std::auto_ptr<int> field;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> field;
+
+ typedef std::auto_ptr<int> int_ptr_type;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: auto_ptr is deprecated
+ // CHECK-FIXES: typedef std::unique_ptr<int> int_ptr_type;
+};
+
+
+// FIXME: Test template WITH instantiation.
+template <typename T> struct B {
+ typedef typename std::auto_ptr<T> created_type;
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: auto_ptr is deprecated
+ // CHECK-FIXES: typedef typename std::unique_ptr<T> created_type;
+
+ created_type create() { return std::auto_ptr<T>(new T()); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: auto_ptr is deprecated
+ // CHECK-FIXES: created_type create() { return std::unique_ptr<T>(new T()); }
+};
+
+
+// Test 'using' in a namespace (declaration)
+namespace ns_1 {
+// Test multiple using declarations.
+ using std::auto_ptr;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: auto_ptr is deprecated
+ // CHECK-FIXES: using std::unique_ptr;
+ using std::auto_ptr;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: auto_ptr is deprecated
+ // CHECK-FIXES: using std::unique_ptr;
+}
+
+
+namespace ns_2 {
+template <typename T> struct auto_ptr {};
+}
+
+void f_1() {
+ std::auto_ptr<int> a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> a;
+
+ // Check that spaces aren't modified unnecessarily.
+ std:: auto_ptr <int> b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std:: unique_ptr <int> b;
+ std :: auto_ptr < char > c(new char());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std :: unique_ptr < char > c(new char());
+
+ // Test construction from a temporary.
+ std::auto_ptr<char> d = std::auto_ptr<char>();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<char> d = std::unique_ptr<char>();
+
+ typedef std::auto_ptr<int> int_ptr_t;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: auto_ptr is deprecated
+ // CHECK-FIXES: typedef std::unique_ptr<int> int_ptr_t;
+ int_ptr_t e(new int());
+
+ // Test pointers.
+ std::auto_ptr<int> *f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> *f;
+
+ // Test 'static' declarations.
+ static std::auto_ptr<int> g;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: auto_ptr is deprecated
+ // CHECK-FIXES: static std::unique_ptr<int> g;
+
+ // Test with cv-qualifiers.
+ const std::auto_ptr<int> h;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: auto_ptr is deprecated
+ // CHECK-FIXES: const std::unique_ptr<int> h;
+ volatile std::auto_ptr<int> i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: auto_ptr is deprecated
+ // CHECK-FIXES: volatile std::unique_ptr<int> i;
+ const volatile std::auto_ptr<int> j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: auto_ptr is deprecated
+ // CHECK-FIXES: const volatile std::unique_ptr<int> j;
+
+ // Test auto and initializer-list.
+ auto k = std::auto_ptr<int>{};
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: auto_ptr is deprecated
+ // CHECK-FIXES: auto k = std::unique_ptr<int>{};
+ std::auto_ptr<int> l{std::auto_ptr<int>()};
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-MESSAGES: :[[@LINE-2]]:29: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> l{std::unique_ptr<int>()};
+
+ // Test interlocked auto_ptr.
+ std::auto_ptr<std::auto_ptr<int> > m;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-MESSAGES: :[[@LINE-2]]:22: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<std::unique_ptr<int> > m;
+
+ // Test temporaries.
+ std::auto_ptr<char>();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<char>();
+
+ // Test void-specialization.
+ std::auto_ptr<void> n;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<void> n;
+
+ // Test template WITH instantiation (instantiation).
+ B<double> o;
+ std::auto_ptr<double> p(o.create());
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<double> p(o.create());
+
+ // Test 'using' in a namespace ("definition").
+ ns_1::auto_ptr<int> q;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: auto_ptr is deprecated
+ // CHECK-FIXES: ns_1::unique_ptr<int> q;
+
+ // Test construction with an 'auto_ptr_ref'.
+ std::auto_ptr<Base> r(create_derived_ptr());
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<Base> r(create_derived_ptr());
+}
+
+// Test without the nested name specifiers.
+void f_2() {
+ using namespace std;
+
+ auto_ptr<int> a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: auto_ptr is deprecated
+ // CHECK-FIXES: unique_ptr<int> a;
+}
+
+// Test using declaration.
+void f_3() {
+ using std::auto_ptr;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: auto_ptr is deprecated
+ // CHECK-FIXES: using std::unique_ptr;
+
+ auto_ptr<int> a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: auto_ptr is deprecated
+ // CHECK-FIXES: unique_ptr<int> a;
+}
+
+// Test messing-up with macros.
+void f_4() {
+#define MACRO_1 <char>
+ std::auto_ptr MACRO_1 p(new char());
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr MACRO_1 p(new char());
+#define MACRO_2 auto_ptr
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: auto_ptr is deprecated
+ // CHECK-FIXES: #define MACRO_2 unique_ptr
+ std::MACRO_2<int> q;
+#define MACRO_3(Type) std::auto_ptr<Type>
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: auto_ptr is deprecated
+ // CHECK-FIXES: #define MACRO_3(Type) std::unique_ptr<Type>
+ MACRO_3(float)r(new float());
+#define MACRO_4 std::auto_ptr
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: auto_ptr is deprecated
+ // CHECK-FIXES: #define MACRO_4 std::unique_ptr
+ using MACRO_4;
+#undef MACRO_1
+#undef MACRO_2
+#undef MACRO_3
+#undef MACRO_4
+}
+
+// Test function return values (definition).
+std::auto_ptr<char> f_5()
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<char> f_5()
+{
+ // Test constructor.
+ return std::auto_ptr<char>(new char());
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: auto_ptr is deprecated
+ // CHECK-FIXES: return std::unique_ptr<char>(new char());
+}
+
+// Test that non-std auto_ptr aren't replaced.
+void f_8() {
+ ns_2::auto_ptr<char> a;
+ using namespace ns_2;
+ auto_ptr<int> b;
+}
+
+// Fail to modify when the template is never instantiated.
+//
+// This might not be an issue. If it's never used it doesn't really matter if
+// it's changed or not. If it's a header and one of the source use it, then it
+// will still be changed.
+template <typename X>
+void f() {
+ std::auto_ptr<X> p;
+}
+
+// FIXME: Alias template could be replaced if a matcher existed.
+namespace std {
+template <typename T> using aaaaaaaa = auto_ptr<T>;
+}
+
+// We want to avoid replacing 'aaaaaaaa' by unique_ptr here. It's better to
+// change the type alias directly.
+std::aaaaaaaa<int> d;
+
+
+void takes_ownership_fn(std::auto_ptr<int> x);
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: auto_ptr is deprecated
+// CHECK-FIXES: void takes_ownership_fn(std::unique_ptr<int> x);
+
+std::auto_ptr<int> get_by_value();
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: auto_ptr is deprecated
+// CHECK-FIXES: std::unique_ptr<int> get_by_value();
+
+class Wrapper {
+ public:
+ std::auto_ptr<int> &get_wrapped();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+
+ private:
+ std::auto_ptr<int> wrapped;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+};
+
+void f() {
+ std::auto_ptr<int> a, b, c;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> a, b, c;
+ Wrapper wrapper_a, wrapper_b;
+
+ a = b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use std::move to transfer ownership
+ // CHECK-FIXES: a = std::move(b);
+
+ wrapper_a.get_wrapped() = wrapper_b.get_wrapped();
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use std::move to transfer ownership
+ // CHECK-FIXES: wrapper_a.get_wrapped() = std::move(wrapper_b.get_wrapped());
+
+ // Test that 'std::move()' is inserted when call to the
+ // copy-constructor are made.
+ takes_ownership_fn(c);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use std::move to transfer ownership
+ // CHECK-FIXES: takes_ownership_fn(std::move(c));
+ takes_ownership_fn(wrapper_a.get_wrapped());
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use std::move to transfer ownership
+ // CHECK-FIXES: takes_ownership_fn(std::move(wrapper_a.get_wrapped()));
+
+ std::auto_ptr<int> d[] = { std::auto_ptr<int>(new int(1)),
+ std::auto_ptr<int>(new int(2)) };
+ // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: auto_ptr is deprecated
+ // CHECK-MESSAGES: :[[@LINE-3]]:35: warning: auto_ptr is deprecated
+ // CHECK-MESSAGES: :[[@LINE-3]]:35: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> d[] = { std::unique_ptr<int>(new int(1)),
+ // CHECK-FIXES-NEXT: std::unique_ptr<int>(new int(2)) };
+ std::auto_ptr<int> e = d[0];
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-MESSAGES: :[[@LINE-2]]:26: warning: use std::move to transfer ownership
+ // CHECK: std::unique_ptr<int> e = std::move(d[0]);
+
+ // Test that std::move() is not used when assigning an rvalue
+ std::auto_ptr<int> f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> f;
+ f = std::auto_ptr<int>(new int(0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: auto_ptr is deprecated
+ // CHECK-NEXT: f = std::unique_ptr<int>(new int(0));
+
+ std::auto_ptr<int> g = get_by_value();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: auto_ptr is deprecated
+ // CHECK-FIXES: std::unique_ptr<int> g = get_by_value();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-replace-random-shuffle.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-replace-random-shuffle.cpp
new file mode 100644
index 0000000..019471e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-replace-random-shuffle.cpp
@@ -0,0 +1,57 @@
+// RUN: %check_clang_tidy %s modernize-replace-random-shuffle %t -- -- -std=c++11
+
+//CHECK-FIXES: #include <random>
+
+namespace std {
+template <typename T> struct vec_iterator {
+ T *ptr;
+ vec_iterator operator++(int);
+};
+
+template <typename T> struct vector {
+ typedef vec_iterator<T> iterator;
+
+ iterator begin();
+ iterator end();
+};
+
+template <typename FwIt>
+void random_shuffle(FwIt begin, FwIt end);
+
+template <typename FwIt, typename randomFunc>
+void random_shuffle(FwIt begin, FwIt end, randomFunc& randomfunc);
+
+template <typename FwIt>
+void shuffle(FwIt begin, FwIt end);
+} // namespace std
+
+// Random Func
+int myrandom (int i) { return i;}
+
+using namespace std;
+
+int main() {
+ std::vector<int> vec;
+
+ std::random_shuffle(vec.begin(), vec.end());
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'std::random_shuffle' has been removed in C++17; use 'std::shuffle' instead
+ // CHECK-FIXES: std::shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
+
+ std::shuffle(vec.begin(), vec.end());
+
+ random_shuffle(vec.begin(), vec.end());
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'std::random_shuffle' has been removed in C++17; use 'std::shuffle' instead
+ // CHECK-FIXES: shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
+
+ std::random_shuffle(vec.begin(), vec.end(), myrandom);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'std::random_shuffle' has been removed in C++17; use 'std::shuffle' and an alternative random mechanism instead
+ // CHECK-FIXES: std::shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
+
+ random_shuffle(vec.begin(), vec.end(), myrandom);
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'std::random_shuffle' has been removed in C++17; use 'std::shuffle' and an alternative random mechanism instead
+ // CHECK-FIXES: shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));
+
+ shuffle(vec.begin(), vec.end());
+
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-return-braced-init-list.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-return-braced-init-list.cpp
new file mode 100644
index 0000000..49a41ae
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-return-braced-init-list.cpp
@@ -0,0 +1,198 @@
+// RUN: %check_clang_tidy %s modernize-return-braced-init-list %t -- -- -std=c++14
+
+namespace std {
+typedef decltype(sizeof(int)) size_t;
+
+// libc++'s implementation
+template <class _E>
+class initializer_list {
+ const _E *__begin_;
+ size_t __size_;
+
+ initializer_list(const _E *__b, size_t __s)
+ : __begin_(__b),
+ __size_(__s) {}
+
+public:
+ typedef _E value_type;
+ typedef const _E &reference;
+ typedef const _E &const_reference;
+ typedef size_t size_type;
+
+ typedef const _E *iterator;
+ typedef const _E *const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const { return __size_; }
+ const _E *begin() const { return __begin_; }
+ const _E *end() const { return __begin_ + __size_; }
+};
+
+template <typename T>
+class vector {
+public:
+ vector(T) {}
+ vector(std::initializer_list<T>) {}
+};
+}
+
+class Bar {};
+
+Bar b0;
+
+class Foo {
+public:
+ Foo(Bar) {}
+ explicit Foo(Bar, unsigned int) {}
+ Foo(unsigned int) {}
+};
+
+class Baz {
+public:
+ Foo m() {
+ Bar bm;
+ return Foo(bm);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: avoid repeating the return type from the declaration; use a braced initializer list instead [modernize-return-braced-init-list]
+ // CHECK-FIXES: return {bm};
+ }
+};
+
+class Quux : public Foo {
+public:
+ Quux(Bar bar) : Foo(bar) {}
+ Quux(unsigned, unsigned, unsigned k = 0) : Foo(k) {}
+};
+
+Foo f() {
+ Bar b1;
+ return Foo(b1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+ // CHECK-FIXES: return {b1};
+}
+
+Foo f2() {
+ Bar b2;
+ return {b2};
+}
+
+auto f3() {
+ Bar b3;
+ return Foo(b3);
+}
+
+#define A(b) Foo(b)
+
+Foo f4() {
+ Bar b4;
+ return A(b4);
+}
+
+Foo f5() {
+ Bar b5;
+ return Quux(b5);
+}
+
+Foo f6() {
+ Bar b6;
+ return Foo(b6, 1);
+}
+
+std::vector<int> f7() {
+ int i7 = 1;
+ return std::vector<int>(i7);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+}
+
+Bar f8() {
+ return {};
+}
+
+Bar f9() {
+ return Bar();
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+}
+
+Bar f10() {
+ return Bar{};
+}
+
+Foo f11(Bar b11) {
+ return Foo(b11);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+ // CHECK-FIXES: return {b11};
+}
+
+Foo f12() {
+ return f11(Bar());
+}
+
+Foo f13() {
+ return Foo(Bar()); // 13
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+ // CHECK-FIXES: return {Bar()}; // 13
+}
+
+Foo f14() {
+ // FIXME: Type narrowing should not occur!
+ return Foo(-1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+ // CHECK-FIXES: return {-1};
+}
+
+Foo f15() {
+ return Foo(f10());
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+ // CHECK-FIXES: return {f10()};
+}
+
+Quux f16() {
+ return Quux(1, 2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+ // CHECK-FIXES: return {1, 2};
+}
+
+Quux f17() {
+ return Quux(1, 2, 3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
+ // CHECK-FIXES: return {1, 2, 3};
+}
+
+template <typename T>
+T f19() {
+ return T();
+}
+
+Bar i1 = f19<Bar>();
+Baz i2 = f19<Baz>();
+
+template <typename T>
+Foo f20(T t) {
+ return Foo(t);
+}
+
+Foo i3 = f20(b0);
+
+template <typename T>
+class BazT {
+public:
+ T m() {
+ Bar b;
+ return T(b);
+ }
+
+ Foo m2(T t) {
+ return Foo(t);
+ }
+};
+
+BazT<Foo> bazFoo;
+Foo i4 = bazFoo.m();
+Foo i5 = bazFoo.m2(b0);
+
+BazT<Quux> bazQuux;
+Foo i6 = bazQuux.m();
+Foo i7 = bazQuux.m2(b0);
+
+auto v1 = []() { return std::vector<int>({1, 2}); }();
+auto v2 = []() -> std::vector<int> { return std::vector<int>({1, 2}); }();
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-shrink-to-fit.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-shrink-to-fit.cpp
new file mode 100644
index 0000000..6993d30
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-shrink-to-fit.cpp
@@ -0,0 +1,87 @@
+// RUN: %check_clang_tidy %s modernize-shrink-to-fit %t
+
+namespace std {
+template <typename T> struct vector { void swap(vector &other); };
+}
+
+void f() {
+ std::vector<int> v;
+
+ std::vector<int>(v).swap(v);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should be used to reduce the capacity of a shrinkable container [modernize-shrink-to-fit]
+ // CHECK-FIXES: {{^ }}v.shrink_to_fit();{{$}}
+
+ std::vector<int> &vref = v;
+ std::vector<int>(vref).swap(vref);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}vref.shrink_to_fit();{{$}}
+
+ std::vector<int> *vptr = &v;
+ std::vector<int>(*vptr).swap(*vptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}vptr->shrink_to_fit();{{$}}
+}
+
+struct X {
+ std::vector<int> v;
+ void f() {
+ std::vector<int>(v).swap(v);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}v.shrink_to_fit();{{$}}
+
+ std::vector<int> *vptr = &v;
+ std::vector<int>(*vptr).swap(*vptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}vptr->shrink_to_fit();{{$}}
+ }
+};
+
+template <typename T> void g() {
+ std::vector<int> v;
+ std::vector<int>(v).swap(v);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}v.shrink_to_fit();{{$}}
+
+ std::vector<T> v2;
+ std::vector<T>(v2).swap(v2);
+ // CHECK-FIXES: {{^ }}std::vector<T>(v2).swap(v2);{{$}}
+}
+
+template <typename T> void g2() {
+ std::vector<int> v;
+ std::vector<int>(v).swap(v);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}v.shrink_to_fit();{{$}}
+
+ T v3;
+ T(v3).swap(v3);
+ // CHECK-FIXES: {{^ }}T(v3).swap(v3);{{$}}
+}
+
+#define COPY_AND_SWAP_INT_VEC(x) std::vector<int>(x).swap(x)
+// CHECK-FIXES: #define COPY_AND_SWAP_INT_VEC(x) std::vector<int>(x).swap(x)
+
+void h() {
+ g<int>();
+ g<double>();
+ g<bool>();
+ g2<std::vector<int>>();
+ std::vector<int> v;
+ COPY_AND_SWAP_INT_VEC(v);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}COPY_AND_SWAP_INT_VEC(v);{{$}}
+}
+
+void PR38315() {
+ typedef std::vector<int> Vector;
+ Vector v;
+ Vector(v).swap(v);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}v.shrink_to_fit();{{$}}
+
+ using Vector2 = std::vector<int>;
+ Vector2 v2;
+ Vector2(v2).swap(v2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the shrink_to_fit method should
+ // CHECK-FIXES: {{^ }}v2.shrink_to_fit();{{$}}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-unary-static-assert.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-unary-static-assert.cpp
new file mode 100644
index 0000000..fd39d5b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-unary-static-assert.cpp
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s modernize-unary-static-assert %t -- -- -std=c++1z
+
+#define FOO static_assert(sizeof(a) <= 15, "");
+#define MSG ""
+
+void f_textless(int a) {
+ static_assert(sizeof(a) <= 10, "");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use unary 'static_assert' when the string literal is an empty string [modernize-unary-static-assert]
+ // CHECK-FIXES: {{^}} static_assert(sizeof(a) <= 10 );{{$}}
+ static_assert(sizeof(a) <= 12, L"");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use unary 'static_assert' when
+ // CHECK-FIXES: {{^}} static_assert(sizeof(a) <= 12 );{{$}}
+ FOO
+ // CHECK-FIXES: {{^}} FOO{{$}}
+ static_assert(sizeof(a) <= 17, MSG);
+ // CHECK-FIXES: {{^}} static_assert(sizeof(a) <= 17, MSG);{{$}}
+}
+
+void f_with_tex(int a) {
+ static_assert(sizeof(a) <= 10, "Size of variable a is out of range!");
+}
+
+void f_unary(int a) { static_assert(sizeof(a) <= 10); }
+
+void f_incorrect_assert() { static_assert(""); }
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp
new file mode 100644
index 0000000..97b87b8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-cast-remove-stars.cpp
@@ -0,0 +1,233 @@
+// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: '1'} , {key: modernize-use-auto.MinTypeNameLength, value: '0'}]}" \
+// RUN: -- -std=c++11 -frtti
+
+struct A {
+ virtual ~A() {}
+};
+
+struct B : public A {};
+
+struct C {};
+
+void f_static_cast() {
+ long l = 1;
+ int i1 = static_cast<int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = static_cast<int>(l);
+
+ const int i2 = static_cast<int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto i2 = static_cast<int>(l);
+
+ long long ll = static_cast<long long>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ll = static_cast<long long>(l);
+ unsigned long long ull = static_cast<unsigned long long>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ull = static_cast<unsigned long long>(l);
+ unsigned int ui = static_cast<unsigned int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ui = static_cast<unsigned int>(l);
+ long double ld = static_cast<long double>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ld = static_cast<long double>(l);
+
+ A *a = new B();
+ B *b1 = static_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto b1 = static_cast<B *>(a);
+
+ B *const b2 = static_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto const b2 = static_cast<B *>(a);
+
+ const B *b3 = static_cast<const B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto b3 = static_cast<const B *>(a);
+
+ B &b4 = static_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b4 = static_cast<B &>(*a);
+
+ const B &b5 = static_cast<const B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto &b5 = static_cast<const B &>(*a);
+
+ B &b6 = static_cast<B &>(*a), &b7 = static_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b6 = static_cast<B &>(*a), &b7 = static_cast<B &>(*a);
+
+ // Don't warn when non-cast involved
+ long double cast = static_cast<long double>(l), noncast = 5;
+
+ // Don't warn when auto is already being used.
+ auto i3 = static_cast<int>(l);
+ auto *b8 = static_cast<B *>(a);
+ auto &b9 = static_cast<B &>(*a);
+}
+
+void f_dynamic_cast() {
+ A *a = new B();
+ B *b1 = dynamic_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto b1 = dynamic_cast<B *>(a);
+
+ B &b2 = dynamic_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b2 = dynamic_cast<B &>(*a);
+}
+
+void f_reinterpret_cast() {
+ auto *a = new A();
+ C *c1 = reinterpret_cast<C *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto c1 = reinterpret_cast<C *>(a);
+
+ C &c2 = reinterpret_cast<C &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &c2 = reinterpret_cast<C &>(*a);
+}
+
+void f_const_cast() {
+ const A *a1 = new A();
+ A *a2 = const_cast<A *>(a1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto a2 = const_cast<A *>(a1);
+ A &a3 = const_cast<A &>(*a1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &a3 = const_cast<A &>(*a1);
+}
+
+typedef unsigned char xmlChar;
+#define BAD_CAST (xmlChar *)
+
+#define XMLCHAR_CAST(x) (xmlChar *)(x)
+
+#define CAST_IN_MACRO(x) \
+ do { \
+ xmlChar *s = (xmlChar *)(x); \
+ } while (false);
+// CHECK-FIXES: xmlChar *s = (xmlChar *)(x);
+
+void f_cstyle_cast() {
+ auto *a = new A();
+ C *c1 = (C *)a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto c1 = (C *)a;
+
+ C &c2 = (C &)*a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &c2 = (C &)*a;
+
+ xmlChar *s = BAD_CAST "xml";
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto s = BAD_CAST "xml";
+ xmlChar *t = XMLCHAR_CAST("xml");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto t = XMLCHAR_CAST("xml");
+ CAST_IN_MACRO("xml");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+}
+
+void f_functional_cast() {
+ long l = 1;
+ int i1 = int(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = int(l);
+
+ B b;
+ A a = A(b);
+}
+
+class StringRef
+{
+public:
+ StringRef(const char *);
+ const char *begin() const;
+ const char *end() const;
+};
+
+template <typename T, typename U>
+T template_value_cast(const U &u);
+
+template <typename T, typename U>
+T *template_pointer_cast(U *u);
+
+template <typename T, typename U>
+T &template_reference_cast(U &u);
+
+template <typename T, typename U>
+const T *template_const_pointer_cast(const U *u);
+
+template <typename T, typename U>
+const T &template_const_reference_cast(const U &u);
+
+template <typename T>
+T template_value_get(StringRef s);
+
+struct S {
+ template <typename T>
+ const T *template_member_get();
+};
+
+template <typename T>
+T max(T t1, T t2);
+
+void f_template_cast()
+{
+ double d = 0;
+ int i1 = template_value_cast<int>(d);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = template_value_cast<int>(d);
+
+ A *a = new B();
+ B *b1 = template_value_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto b1 = template_value_cast<B *>(a);
+ B &b2 = template_value_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b2 = template_value_cast<B &>(*a);
+ B *b3 = template_pointer_cast<B>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto b3 = template_pointer_cast<B>(a);
+ B &b4 = template_reference_cast<B>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b4 = template_reference_cast<B>(*a);
+ const B *b5 = template_const_pointer_cast<B>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto b5 = template_const_pointer_cast<B>(a);
+ const B &b6 = template_const_reference_cast<B>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto &b6 = template_const_reference_cast<B>(*a);
+ B *b7 = template_value_get<B *>("foo");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto b7 = template_value_get<B *>("foo");
+ B *b8 = template_value_get<B *>("foo"), *b9 = template_value_get<B *>("bar");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto b8 = template_value_get<B *>("foo"), b9 = template_value_get<B *>("bar");
+
+ S s;
+ const B *b10 = s.template_member_get<B>();
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto b10 = s.template_member_get<B>();
+
+ // Don't warn when auto is already being used.
+ auto i2 = template_value_cast<int>(d);
+ auto *i3 = template_value_cast<int *>(d);
+ auto **i4 = template_value_cast<int **>(d);
+ auto &i5 = template_reference_cast<int>(d);
+
+ // Don't warn for implicit template arguments.
+ int i6 = max(i1, i2);
+
+ // Don't warn for mismatched var and initializer types.
+ A *a1 = template_value_cast<B *>(a);
+
+ // Don't warn for mismatched var types.
+ B *b11 = template_value_get<B *>("foo"), b12 = template_value_get<B>("bar");
+
+ // Don't warn for implicit variables.
+ for (auto &c : template_reference_cast<StringRef>(*a)) {
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-cast.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-cast.cpp
new file mode 100644
index 0000000..e07c9cb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-cast.cpp
@@ -0,0 +1,233 @@
+// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-auto.MinTypeNameLength, value: '0'}]}" \
+// RUN: -- -std=c++11 -I %S/Inputs/modernize-use-auto -frtti
+
+struct A {
+ virtual ~A() {}
+};
+
+struct B : public A {};
+
+struct C {};
+
+void f_static_cast() {
+ long l = 1;
+ int i1 = static_cast<int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = static_cast<int>(l);
+
+ const int i2 = static_cast<int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto i2 = static_cast<int>(l);
+
+ long long ll = static_cast<long long>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ll = static_cast<long long>(l);
+ unsigned long long ull = static_cast<unsigned long long>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ull = static_cast<unsigned long long>(l);
+ unsigned int ui = static_cast<unsigned int>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ui = static_cast<unsigned int>(l);
+ long double ld = static_cast<long double>(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto ld = static_cast<long double>(l);
+
+ A *a = new B();
+ B *b1 = static_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *b1 = static_cast<B *>(a);
+
+ B *const b2 = static_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *const b2 = static_cast<B *>(a);
+
+ const B *b3 = static_cast<const B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto *b3 = static_cast<const B *>(a);
+
+ B &b4 = static_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b4 = static_cast<B &>(*a);
+
+ const B &b5 = static_cast<const B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto &b5 = static_cast<const B &>(*a);
+
+ B &b6 = static_cast<B &>(*a), &b7 = static_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b6 = static_cast<B &>(*a), &b7 = static_cast<B &>(*a);
+
+ // Don't warn when non-cast involved
+ long double cast = static_cast<long double>(l), noncast = 5;
+
+ // Don't warn when auto is already being used.
+ auto i3 = static_cast<int>(l);
+ auto *b8 = static_cast<B *>(a);
+ auto &b9 = static_cast<B &>(*a);
+}
+
+void f_dynamic_cast() {
+ A *a = new B();
+ B *b1 = dynamic_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *b1 = dynamic_cast<B *>(a);
+
+ B &b2 = dynamic_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b2 = dynamic_cast<B &>(*a);
+}
+
+void f_reinterpret_cast() {
+ auto *a = new A();
+ C *c1 = reinterpret_cast<C *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *c1 = reinterpret_cast<C *>(a);
+
+ C &c2 = reinterpret_cast<C &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &c2 = reinterpret_cast<C &>(*a);
+}
+
+void f_const_cast() {
+ const A *a1 = new A();
+ A *a2 = const_cast<A *>(a1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *a2 = const_cast<A *>(a1);
+ A &a3 = const_cast<A &>(*a1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &a3 = const_cast<A &>(*a1);
+}
+
+typedef unsigned char xmlChar;
+#define BAD_CAST (xmlChar *)
+
+#define XMLCHAR_CAST(x) (xmlChar *)(x)
+
+#define CAST_IN_MACRO(x) \
+ do { \
+ xmlChar *s = (xmlChar *)(x); \
+ } while (false);
+// CHECK-FIXES: xmlChar *s = (xmlChar *)(x);
+
+void f_cstyle_cast() {
+ auto *a = new A();
+ C *c1 = (C *)a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *c1 = (C *)a;
+
+ C &c2 = (C &)*a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &c2 = (C &)*a;
+
+ xmlChar *s = BAD_CAST "xml";
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *s = BAD_CAST "xml";
+ xmlChar *t = XMLCHAR_CAST("xml");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *t = XMLCHAR_CAST("xml");
+ CAST_IN_MACRO("xml");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+}
+
+void f_functional_cast() {
+ long l = 1;
+ int i1 = int(l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = int(l);
+
+ B b;
+ A a = A(b);
+}
+
+class StringRef
+{
+public:
+ StringRef(const char *);
+ const char *begin() const;
+ const char *end() const;
+};
+
+template <typename T, typename U>
+T template_value_cast(const U &u);
+
+template <typename T, typename U>
+T *template_pointer_cast(U *u);
+
+template <typename T, typename U>
+T &template_reference_cast(U &u);
+
+template <typename T, typename U>
+const T *template_const_pointer_cast(const U *u);
+
+template <typename T, typename U>
+const T &template_const_reference_cast(const U &u);
+
+template <typename T>
+T template_value_get(StringRef s);
+
+struct S {
+ template <typename T>
+ const T *template_member_get();
+};
+
+template <typename T>
+T max(T t1, T t2);
+
+void f_template_cast()
+{
+ double d = 0;
+ int i1 = template_value_cast<int>(d);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto i1 = template_value_cast<int>(d);
+
+ A *a = new B();
+ B *b1 = template_value_cast<B *>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *b1 = template_value_cast<B *>(a);
+ B &b2 = template_value_cast<B &>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b2 = template_value_cast<B &>(*a);
+ B *b3 = template_pointer_cast<B>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *b3 = template_pointer_cast<B>(a);
+ B &b4 = template_reference_cast<B>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto &b4 = template_reference_cast<B>(*a);
+ const B *b5 = template_const_pointer_cast<B>(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto *b5 = template_const_pointer_cast<B>(a);
+ const B &b6 = template_const_reference_cast<B>(*a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto &b6 = template_const_reference_cast<B>(*a);
+ B *b7 = template_value_get<B *>("foo");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *b7 = template_value_get<B *>("foo");
+ B *b8 = template_value_get<B *>("foo"), *b9 = template_value_get<B *>("bar");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: auto *b8 = template_value_get<B *>("foo"), *b9 = template_value_get<B *>("bar");
+
+ S s;
+ const B *b10 = s.template_member_get<B>();
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use auto when initializing with a template cast to avoid duplicating the type name
+ // CHECK-FIXES: const auto *b10 = s.template_member_get<B>();
+
+ // Don't warn when auto is already being used.
+ auto i2 = template_value_cast<int>(d);
+ auto *i3 = template_value_cast<int *>(d);
+ auto **i4 = template_value_cast<int **>(d);
+ auto &i5 = template_reference_cast<int>(d);
+
+ // Don't warn for implicit template arguments.
+ int i6 = max(i1, i2);
+
+ // Don't warn for mismatched var and initializer types.
+ A *a1 = template_value_cast<B *>(a);
+
+ // Don't warn for mismatched var types.
+ B *b11 = template_value_get<B *>("foo"), b12 = template_value_get<B>("bar");
+
+ // Don't warn for implicit variables.
+ for (auto &c : template_reference_cast<StringRef>(*a)) {
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-iterator.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-iterator.cpp
new file mode 100644
index 0000000..98117fc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-iterator.cpp
@@ -0,0 +1,320 @@
+// RUN: %check_clang_tidy %s modernize-use-auto %t -- -- \
+// RUN: -std=c++11 -I %S/Inputs/modernize-use-auto
+
+#include "containers.h"
+
+void f_array() {
+ std::array<int, 4> C;
+ std::array<int, 4>::iterator ArrayI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators [modernize-use-auto]
+ // CHECK-FIXES: auto ArrayI1 = C.begin();
+
+ std::array<int, 5>::reverse_iterator ArrayI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto ArrayI2 = C.rbegin();
+
+ const std::array<int, 3> D;
+ std::array<int, 3>::const_iterator ArrayI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto ArrayI3 = D.begin();
+
+ std::array<int, 5>::const_reverse_iterator ArrayI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto ArrayI4 = D.rbegin();
+}
+
+void f_deque() {
+ std::deque<int> C;
+ std::deque<int>::iterator DequeI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto DequeI1 = C.begin();
+
+ std::deque<int>::reverse_iterator DequeI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto DequeI2 = C.rbegin();
+
+ const std::deque<int> D;
+ std::deque<int>::const_iterator DequeI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto DequeI3 = D.begin();
+
+ std::deque<int>::const_reverse_iterator DequeI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto DequeI4 = D.rbegin();
+}
+
+void f_forward_list() {
+ std::forward_list<int> C;
+ std::forward_list<int>::iterator FListI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto FListI1 = C.begin();
+
+ const std::forward_list<int> D;
+ std::forward_list<int>::const_iterator FListI2 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto FListI2 = D.begin();
+}
+
+void f_list() {
+ std::list<int> C;
+ std::list<int>::iterator ListI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto ListI1 = C.begin();
+ std::list<int>::reverse_iterator ListI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto ListI2 = C.rbegin();
+
+ const std::list<int> D;
+ std::list<int>::const_iterator ListI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto ListI3 = D.begin();
+ std::list<int>::const_reverse_iterator ListI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto ListI4 = D.rbegin();
+}
+
+void f_vector() {
+ std::vector<int> C;
+ std::vector<int>::iterator VecI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto VecI1 = C.begin();
+
+ std::vector<int>::reverse_iterator VecI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto VecI2 = C.rbegin();
+
+ const std::vector<int> D;
+ std::vector<int>::const_iterator VecI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto VecI3 = D.begin();
+
+ std::vector<int>::const_reverse_iterator VecI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto VecI4 = D.rbegin();
+}
+
+void f_map() {
+ std::map<int, int> C;
+ std::map<int, int>::iterator MapI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MapI1 = C.begin();
+
+ std::map<int, int>::reverse_iterator MapI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MapI2 = C.rbegin();
+
+ const std::map<int, int> D;
+ std::map<int, int>::const_iterator MapI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MapI3 = D.begin();
+
+ std::map<int, int>::const_reverse_iterator MapI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MapI4 = D.rbegin();
+}
+
+void f_multimap() {
+ std::multimap<int, int> C;
+ std::multimap<int, int>::iterator MMapI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MMapI1 = C.begin();
+
+ std::multimap<int, int>::reverse_iterator MMapI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MMapI2 = C.rbegin();
+
+ const std::multimap<int, int> D;
+ std::multimap<int, int>::const_iterator MMapI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MMapI3 = D.begin();
+
+ std::multimap<int, int>::const_reverse_iterator MMapI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MMapI4 = D.rbegin();
+}
+
+void f_set() {
+ std::set<int> C;
+ std::set<int>::iterator SetI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto SetI1 = C.begin();
+
+ std::set<int>::reverse_iterator SetI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto SetI2 = C.rbegin();
+
+ const std::set<int> D;
+ std::set<int>::const_iterator SetI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto SetI3 = D.begin();
+
+ std::set<int>::const_reverse_iterator SetI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto SetI4 = D.rbegin();
+}
+
+void f_multiset() {
+ std::multiset<int> C;
+ std::multiset<int>::iterator MSetI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MSetI1 = C.begin();
+
+ std::multiset<int>::reverse_iterator MSetI2 = C.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MSetI2 = C.rbegin();
+
+ const std::multiset<int> D;
+ std::multiset<int>::const_iterator MSetI3 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MSetI3 = D.begin();
+
+ std::multiset<int>::const_reverse_iterator MSetI4 = D.rbegin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto MSetI4 = D.rbegin();
+}
+
+void f_unordered_map() {
+ std::unordered_map<int, int> C;
+ std::unordered_map<int, int>::iterator UMapI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto UMapI1 = C.begin();
+
+ const std::unordered_map<int, int> D;
+ std::unordered_map<int, int>::const_iterator UMapI2 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto UMapI2 = D.begin();
+}
+
+void f_unordered_multimap() {
+ std::unordered_multimap<int, int> C;
+ std::unordered_multimap<int, int>::iterator UMMapI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto UMMapI1 = C.begin();
+
+ const std::unordered_multimap<int, int> D;
+ std::unordered_multimap<int, int>::const_iterator UMMapI2 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto UMMapI2 = D.begin();
+}
+
+void f_unordered_set() {
+ std::unordered_set<int> C;
+ std::unordered_set<int>::iterator USetI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto USetI1 = C.begin();
+
+ const std::unordered_set<int> D;
+ std::unordered_set<int>::const_iterator USetI2 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto USetI2 = D.begin();
+}
+
+void f_unordered_multiset() {
+ std::unordered_multiset<int> C;
+ std::unordered_multiset<int>::iterator UMSetI1 = C.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto UMSetI1 = C.begin();
+
+ const std::unordered_multiset<int> D;
+ std::unordered_multiset<int>::const_iterator UMSetI2 = D.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto UMSetI2 = D.begin();
+}
+
+typedef std::vector<int>::iterator int_iterator;
+
+std::vector<int> Vec;
+std::unordered_map<int, int> Map;
+
+void sugar() {
+ // Types with more sugar should work. Types with less should not.
+ int_iterator more_sugar = Vec.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto more_sugar = Vec.begin();
+}
+
+void initializer_list() {
+ // Initialization from initializer lists isn't allowed. Using 'auto' would
+ // result in std::initializer_list being deduced for the type.
+ std::unordered_map<int, int>::iterator I{Map.begin()};
+ std::unordered_map<int, int>::iterator I2 = {Map.begin()};
+}
+
+void construction() {
+ // Various forms of construction. Default constructors and constructors with
+ // all-default parameters shouldn't get transformed. Construction from other
+ // types is also not allowed.
+
+ std::unordered_map<int, int>::iterator copy(Map.begin());
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto copy(Map.begin());
+
+ std::unordered_map<int, int>::iterator def;
+ std::unordered_map<int, int>::const_iterator constI;
+
+ // Implicit conversion.
+ std::unordered_map<int, int>::const_iterator constI2 = def;
+ std::unordered_map<int, int>::const_iterator constI3(def);
+
+ // Explicit conversion
+ std::unordered_map<int, int>::const_iterator constI4
+ = std::unordered_map<int, int>::const_iterator(def);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto constI4
+ // CHECK-FIXES-NEXT: = std::unordered_map<int, int>::const_iterator(def);
+}
+
+void pointer_to_iterator() {
+ int_iterator I = Vec.begin();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto I = Vec.begin();
+
+ // Pointers and references to iterators are not transformed.
+ int_iterator *IPtr = &I;
+ int_iterator &IRef = I;
+}
+
+void loop() {
+ for (std::vector<int>::iterator I = Vec.begin(); I != Vec.end(); ++I) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use auto when declaring iterators
+ // CHECK-FIXES: for (auto I = Vec.begin(); I != Vec.end(); ++I)
+ }
+
+ for (int_iterator I = Vec.begin(), E = Vec.end(); I != E; ++I) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use auto when declaring iterators
+ // CHECK-FIXES: for (auto I = Vec.begin(), E = Vec.end(); I != E; ++I)
+ }
+
+ std::vector<std::vector<int>::iterator> IterVec;
+ for (std::vector<int>::iterator I : IterVec) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use auto when declaring iterators
+ // CHECK-FIXES: for (auto I : IterVec)
+ }
+}
+
+void cv_qualifiers() {
+ // Make sure references and cv qualifiers don't get removed (i.e. replaced
+ // with just 'auto').
+ const auto & I = Vec.begin();
+ auto && I2 = Vec.begin();
+}
+
+void cleanup() {
+ // Passing a string as an argument to introduce a temporary object that will
+ // create an expression with cleanups.
+ std::map<std::string, int> MapFind;
+ std::map<std::string, int>::iterator I = MapFind.find("foo");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto I = MapFind.find("foo");
+}
+
+void declaration_lists() {
+ // Declaration lists that match the declaration type with written no-list
+ // initializer are transformed.
+ std::vector<int>::iterator I = Vec.begin(), E = Vec.end();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when declaring iterators
+ // CHECK-FIXES: auto I = Vec.begin(), E = Vec.end();
+
+ // Declaration lists with non-initialized variables should not be transformed.
+ std::vector<int>::iterator J = Vec.begin(), K;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-min-type-name-length.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-min-type-name-length.cpp
new file mode 100644
index 0000000..1cd9158
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-min-type-name-length.cpp
@@ -0,0 +1,85 @@
+// RUN: %check_clang_tidy -check-suffix=0-0 %s modernize-use-auto %t -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 0}, {key: modernize-use-auto.MinTypeNameLength, value: 0}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=0-8 %s modernize-use-auto %t -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 0}, {key: modernize-use-auto.MinTypeNameLength, value: 8}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=1-0 %s modernize-use-auto %t -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 1}, {key: modernize-use-auto.MinTypeNameLength, value: 0}]}" -- --std=c++11 -frtti
+// RUN: %check_clang_tidy -check-suffix=1-8 %s modernize-use-auto %t -- -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: 1}, {key: modernize-use-auto.MinTypeNameLength, value: 8}]}" -- --std=c++11 -frtti
+
+template <class T> extern T foo();
+template <class T> struct P { explicit P(T t) : t_(t) {} T t_;};
+template <class T> P<T> *foo_ptr();
+template <class T> P<T> &foo_ref();
+
+int bar() {
+ {
+ // Lenth(long) = 4
+ long i = static_cast<long>(foo<long>());
+ // CHECK-FIXES-0-0: auto i = {{.*}}
+ // CHECK-FIXES-0-8: long i = {{.*}}
+ // CHECK-FIXES-1-0: auto i = {{.*}}
+ // CHECK-FIXES-1-8: long i = {{.*}}
+ const long ci = static_cast<long>(foo<const long>());
+ // CHECK-FIXES-0-0: auto ci = {{.*}}
+ // CHECK-FIXES-0-8: long ci = {{.*}}
+ // CHECK-FIXES-1-0: auto ci = {{.*}}
+ // CHECK-FIXES-1-8: long ci = {{.*}}
+ long *pi = static_cast<long *>(foo<long *>());
+ // CHECK-FIXES-0-0: auto *pi = {{.*}}
+ // CHECK-FIXES-0-8: long *pi = {{.*}}
+ // CHECK-FIXES-1-0: auto pi = {{.*}}
+ // CHECK-FIXES-1-8: long *pi = {{.*}}
+
+ // Length(long *) is still 5
+ long * pi2 = static_cast<long *>(foo<long *>());
+ // CHECK-FIXES-0-0: auto * pi2 = {{.*}}
+ // CHECK-FIXES-0-8: long * pi2 = {{.*}}
+ // CHECK-FIXES-1-0: auto pi2 = {{.*}}
+ // CHECK-FIXES-1-8: long * pi2 = {{.*}}
+
+ // Length(long **) = 6
+ long **ppi = static_cast<long **>(foo<long **>());
+ // CHECK-FIXES-0-0: auto **ppi = {{.*}}
+ // CHECK-FIXES-0-8: long **ppi = {{.*}}
+ // CHECK-FIXES-1-0: auto ppi = {{.*}}
+ // CHECK-FIXES-1-8: long **ppi = {{.*}}
+ }
+
+ {
+ // Lenth(long int) = 4 + 1 + 3 = 8
+ // Lenth(long int) is still 8
+ long int i = static_cast<long int>(foo<long int>());
+ // CHECK-FIXES-0-0: auto i = {{.*}}
+ // CHECK-FIXES-0-8: auto i = {{.*}}
+ // CHECK-FIXES-1-0: auto i = {{.*}}
+ // CHECK-FIXES-1-8: auto i = {{.*}}
+
+ long int *pi = static_cast<long int *>(foo<long int *>());
+ // CHECK-FIXES-0-0: auto *pi = {{.*}}
+ // CHECK-FIXES-0-8: auto *pi = {{.*}}
+ // CHECK-FIXES-1-0: auto pi = {{.*}}
+ // CHECK-FIXES-1-8: auto pi = {{.*}}
+ }
+
+ // Templates
+ {
+ // Length(P<long>) = 7
+ P<long>& i = static_cast<P<long>&>(foo_ref<long>());
+ // CHECK-FIXES-0-0: auto& i = {{.*}}
+ // CHECK-FIXES-0-8: P<long>& i = {{.*}}
+ // CHECK-FIXES-1-0: auto & i = {{.*}}
+ // CHECK-FIXES-1-8: P<long>& i = {{.*}}
+
+ // Length(P<long*>) = 8
+ P<long*>& pi = static_cast<P<long*> &>(foo_ref<long*>());
+ // CHECK-FIXES-0-0: auto& pi = {{.*}}
+ // CHECK-FIXES-0-8: auto& pi = {{.*}}
+ // CHECK-FIXES-1-0: auto & pi = {{.*}}
+ // CHECK-FIXES-1-8: auto & pi = {{.*}}
+
+ P<long>* pi2 = static_cast<P<long>*>(foo_ptr<long>());
+ // CHECK-FIXES-0-0: auto* pi2 = {{.*}}
+ // CHECK-FIXES-0-8: P<long>* pi2 = {{.*}}
+ // CHECK-FIXES-1-0: auto pi2 = {{.*}}
+ // CHECK-FIXES-1-8: auto pi2 = {{.*}}
+ }
+
+ return 1;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-new-remove-stars.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-new-remove-stars.cpp
new file mode 100644
index 0000000..00e3c89
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-new-remove-stars.cpp
@@ -0,0 +1,106 @@
+// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-auto.RemoveStars, value: '1'}, {key: modernize-use-auto.MinTypeNameLength, value: '0'}]}" \
+// RUN: -- -std=c++11
+
+class MyType {};
+
+class MyDerivedType : public MyType {};
+
+// FIXME: the replacement sometimes results in two consecutive spaces after
+// the word 'auto' (due to the presence of spaces at both sides of '*').
+void auto_new() {
+ MyType *a_new = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto a_new = new MyType();
+
+ static MyType *a_static = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new
+ // CHECK-FIXES: static auto a_static = new MyType();
+
+ MyType *derived = new MyDerivedType();
+
+ void *vd = new MyType();
+
+ // CV-qualifier tests.
+ //
+ // NOTE : the form "type const" is expected here because of a deficiency in
+ // TypeLoc where CV qualifiers are not considered part of the type location
+ // info. That is, all that is being replaced in each case is "MyType *" and
+ // not "MyType * const".
+ static MyType * const d_static = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new
+ // CHECK-FIXES: static auto const d_static = new MyType();
+
+ MyType * const a_const = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto const a_const = new MyType();
+
+ MyType * volatile vol = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto volatile vol = new MyType();
+
+ struct SType {} *stype = new SType;
+
+ int (**func)(int, int) = new (int(*[5])(int,int));
+
+ int *array = new int[5];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto array = new int[5];
+
+ MyType *ptr(new MyType);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto ptr(new MyType);
+
+ MyType *ptr2{new MyType};
+
+ {
+ // Test for declaration lists.
+ MyType *a = new MyType(), *b = new MyType(), *c = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto a = new MyType(), b = new MyType(), c = new MyType();
+
+ // Non-initialized declaration should not be transformed.
+ MyType *d = new MyType(), *e;
+
+ MyType **f = new MyType*(), **g = new MyType*();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto f = new MyType*(), g = new MyType*();
+
+ // Mismatching types in declaration lists should not be transformed.
+ MyType *h = new MyType(), **i = new MyType*();
+
+ // '*' shouldn't be removed in case of mismatching types with multiple
+ // declarations.
+ MyType *j = new MyType(), *k = new MyType(), **l = new MyType*();
+ }
+
+ {
+ // Test for typedefs.
+ typedef int * int_p;
+ // CHECK-FIXES: typedef int * int_p;
+
+ int_p a = new int;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto a = new int;
+ int_p *b = new int*;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto b = new int*;
+
+ // Test for typedefs in declarations lists.
+ int_p c = new int, d = new int;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto c = new int, d = new int;
+
+ // Different types should not be transformed.
+ int_p e = new int, *f = new int_p;
+
+ int_p *g = new int*, *h = new int_p;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto g = new int*, h = new int_p;
+ }
+
+ // Don't warn when 'auto' is already being used.
+ auto aut = new MyType();
+ auto *paut = new MyType();
+ const auto *pcaut = new MyType();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-new.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-new.cpp
new file mode 100644
index 0000000..3c872c9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-auto-new.cpp
@@ -0,0 +1,110 @@
+// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-auto.MinTypeNameLength, value: '0'}]}" \
+// RUN: -- -std=c++11 -frtti
+
+class MyType {};
+
+class MyDerivedType : public MyType {};
+
+// FIXME: the replacement sometimes results in two consecutive spaces after
+// the word 'auto' (due to the presence of spaces at both sides of '*').
+void auto_new() {
+ MyType *a_new = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *a_new = new MyType();
+
+ static MyType *a_static = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new
+ // CHECK-FIXES: static auto *a_static = new MyType();
+
+ long long *ll = new long long();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *ll = new long long();
+
+ MyType *derived = new MyDerivedType();
+
+ void *vd = new MyType();
+
+ // CV-qualifier tests.
+ //
+ // NOTE : the form "type const" is expected here because of a deficiency in
+ // TypeLoc where CV qualifiers are not considered part of the type location
+ // info. That is, all that is being replaced in each case is "MyType *" and
+ // not "MyType * const".
+ static MyType * const d_static = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use auto when initializing with new
+ // CHECK-FIXES: static auto * const d_static = new MyType();
+
+ MyType * const a_const = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto * const a_const = new MyType();
+
+ MyType * volatile vol = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto * volatile vol = new MyType();
+
+ struct SType {} *stype = new SType;
+
+ int (**func)(int, int) = new (int(*[5])(int,int));
+
+ int *array = new int[5];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *array = new int[5];
+
+ MyType *ptr(new MyType);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *ptr(new MyType);
+
+ MyType *ptr2{new MyType};
+
+ {
+ // Test for declaration lists.
+ MyType *a = new MyType(), *b = new MyType(), *c = new MyType();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *a = new MyType(), *b = new MyType(), *c = new MyType();
+
+ // Non-initialized declaration should not be transformed.
+ MyType *d = new MyType(), *e;
+
+ MyType **f = new MyType*(), **g = new MyType*();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto **f = new MyType*(), **g = new MyType*();
+
+ // Mismatching types in declaration lists should not be transformed.
+ MyType *h = new MyType(), **i = new MyType*();
+
+ // '*' shouldn't be removed in case of mismatching types with multiple
+ // declarations.
+ MyType *j = new MyType(), *k = new MyType(), **l = new MyType*();
+ }
+
+ {
+ // Test for typedefs.
+ typedef int * int_p;
+ // CHECK-FIXES: typedef int * int_p;
+
+ int_p a = new int;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto a = new int;
+ int_p *b = new int*;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *b = new int*;
+
+ // Test for typedefs in declarations lists.
+ int_p c = new int, d = new int;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto c = new int, d = new int;
+
+ // Different types should not be transformed.
+ int_p e = new int, *f = new int_p;
+
+ int_p *g = new int*, *h = new int_p;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use auto when initializing with new
+ // CHECK-FIXES: auto *g = new int*, *h = new int_p;
+ }
+
+ // Don't warn when 'auto' is already being used.
+ auto aut = new MyType();
+ auto *paut = new MyType();
+ const auto *pcaut = new MyType();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-bool-literals-ignore-macros.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-bool-literals-ignore-macros.cpp
new file mode 100644
index 0000000..cf8f72c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-bool-literals-ignore-macros.cpp
@@ -0,0 +1,148 @@
+// RUN: %check_clang_tidy %s modernize-use-bool-literals %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: modernize-use-bool-literals.IgnoreMacros, \
+// RUN: value: 1}]}" \
+// RUN: -- -std=c++11
+
+bool IntToTrue = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: converting integer literal to bool, use bool literal instead [modernize-use-bool-literals]
+// CHECK-FIXES: {{^}}bool IntToTrue = true;{{$}}
+
+bool IntToFalse(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: converting integer literal to bool
+// CHECK-FIXES: {{^}}bool IntToFalse(false);{{$}}
+
+bool LongLongToTrue{0x1LL};
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: converting integer literal to bool
+// CHECK-FIXES: {{^}}bool LongLongToTrue{true};{{$}}
+
+bool ExplicitCStyleIntToFalse = (bool)0;
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: converting integer literal to bool
+// CHECK-FIXES: {{^}}bool ExplicitCStyleIntToFalse = false;{{$}}
+
+bool ExplicitFunctionalIntToFalse = bool(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: converting integer literal to bool
+// CHECK-FIXES: {{^}}bool ExplicitFunctionalIntToFalse = false;{{$}}
+
+bool ExplicitStaticIntToFalse = static_cast<bool>(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: converting integer literal to bool
+// CHECK-FIXES: {{^}}bool ExplicitStaticIntToFalse = false;{{$}}
+
+#define TRUE_MACRO 1
+// CHECK-FIXES: {{^}}#define TRUE_MACRO 1{{$}}
+
+bool MacroIntToTrue = TRUE_MACRO;
+// CHECK-FIXES: {{^}}bool MacroIntToTrue = TRUE_MACRO;{{$}}
+
+#define FALSE_MACRO bool(0)
+// CHECK-FIXES: {{^}}#define FALSE_MACRO bool(0){{$}}
+
+bool TrueBool = true; // OK
+
+bool FalseBool = bool(FALSE_MACRO);
+// CHECK-FIXES: {{^}}bool FalseBool = bool(FALSE_MACRO);{{$}}
+
+void boolFunction(bool bar) {
+
+}
+
+char Character = 0; // OK
+
+unsigned long long LongInteger = 1; // OK
+
+#define MACRO_DEPENDENT_CAST(x) static_cast<bool>(x)
+// CHECK-FIXES: {{^}}#define MACRO_DEPENDENT_CAST(x) static_cast<bool>(x){{$}}
+
+bool MacroDependentBool = MACRO_DEPENDENT_CAST(0);
+// CHECK-FIXES: {{^}}bool MacroDependentBool = MACRO_DEPENDENT_CAST(0);{{$}}
+
+bool ManyMacrosDependent = MACRO_DEPENDENT_CAST(FALSE_MACRO);
+// CHECK-FIXES: {{^}}bool ManyMacrosDependent = MACRO_DEPENDENT_CAST(FALSE_MACRO);{{$}}
+
+class FooClass {
+ public:
+ FooClass() : JustBool(0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}FooClass() : JustBool(false) {}{{$}}
+ FooClass(int) : JustBool{0} {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}FooClass(int) : JustBool{false} {}{{$}}
+ private:
+ bool JustBool;
+ bool BoolWithBraces{0};
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}bool BoolWithBraces{false};{{$}}
+ bool BoolFromInt = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}bool BoolFromInt = false;{{$}}
+ bool SimpleBool = true; // OK
+};
+
+template<typename type>
+void templateFunction(type) {
+ type TemplateType = 0;
+ // CHECK-FIXES: {{^ *}}type TemplateType = 0;{{$}}
+}
+
+template<int c>
+void valueDependentTemplateFunction() {
+ bool Boolean = c;
+ // CHECK-FIXES: {{^ *}}bool Boolean = c;{{$}}
+}
+
+template<typename type>
+void anotherTemplateFunction(type) {
+ bool JustBool = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}bool JustBool = false;{{$}}
+}
+
+int main() {
+ boolFunction(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}boolFunction(true);{{$}}
+
+ boolFunction(false);
+
+ templateFunction(0);
+
+ templateFunction(false);
+
+ valueDependentTemplateFunction<1>();
+
+ anotherTemplateFunction(1);
+
+ IntToTrue = 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}IntToTrue = true;{{$}}
+}
+
+static int Value = 1;
+
+bool Function1() {
+ bool Result = Value == 1 ? 1 : 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: converting integer literal to bool
+ // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}bool Result = Value == 1 ? true : false;{{$}}
+ return Result;
+}
+
+bool Function2() {
+ return Value == 1 ? 1 : 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: converting integer literal to bool
+ // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}return Value == 1 ? true : false;{{$}}
+}
+
+void foo() {
+ bool Result;
+ Result = Value == 1 ? true : 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}Result = Value == 1 ? true : false;{{$}}
+ Result = Value == 1 ? false : bool(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}Result = Value == 1 ? false : false;{{$}}
+ Result = Value == 1 ? (bool)0 : false;
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}Result = Value == 1 ? false : false;{{$}}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-bool-literals.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-bool-literals.cpp
new file mode 100644
index 0000000..f2ab9ce
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-bool-literals.cpp
@@ -0,0 +1,152 @@
+// RUN: %check_clang_tidy %s modernize-use-bool-literals %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: modernize-use-bool-literals.IgnoreMacros, \
+// RUN: value: 0}]}" \
+// RUN: -- -std=c++11
+
+bool IntToTrue = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: converting integer literal to bool, use bool literal instead [modernize-use-bool-literals]
+// CHECK-FIXES: {{^}}bool IntToTrue = true;{{$}}
+
+bool IntToFalse(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: converting integer literal to bool
+// CHECK-FIXES: {{^}}bool IntToFalse(false);{{$}}
+
+bool LongLongToTrue{0x1LL};
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: converting integer literal to bool
+// CHECK-FIXES: {{^}}bool LongLongToTrue{true};{{$}}
+
+bool ExplicitCStyleIntToFalse = (bool)0;
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: converting integer literal to bool
+// CHECK-FIXES: {{^}}bool ExplicitCStyleIntToFalse = false;{{$}}
+
+bool ExplicitFunctionalIntToFalse = bool(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: converting integer literal to bool
+// CHECK-FIXES: {{^}}bool ExplicitFunctionalIntToFalse = false;{{$}}
+
+bool ExplicitStaticIntToFalse = static_cast<bool>(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: converting integer literal to bool
+// CHECK-FIXES: {{^}}bool ExplicitStaticIntToFalse = false;{{$}}
+
+#define TRUE_MACRO 1
+// CHECK-FIXES: {{^}}#define TRUE_MACRO 1{{$}}
+
+bool MacroIntToTrue = TRUE_MACRO;
+// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: converting integer literal to bool
+// CHECK-FIXES: {{^}}bool MacroIntToTrue = TRUE_MACRO;{{$}}
+
+#define FALSE_MACRO bool(0)
+// CHECK-FIXES: {{^}}#define FALSE_MACRO bool(0){{$}}
+
+bool TrueBool = true; // OK
+
+bool FalseBool = bool(FALSE_MACRO);
+// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: converting integer literal to bool
+// CHECK-FIXES: {{^}}bool FalseBool = bool(FALSE_MACRO);{{$}}
+
+void boolFunction(bool bar) {
+
+}
+
+char Character = 0; // OK
+
+unsigned long long LongInteger = 1; // OK
+
+#define MACRO_DEPENDENT_CAST(x) static_cast<bool>(x)
+// CHECK-FIXES: {{^}}#define MACRO_DEPENDENT_CAST(x) static_cast<bool>(x){{$}}
+
+bool MacroDependentBool = MACRO_DEPENDENT_CAST(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: converting integer literal to bool
+// CHECK-FIXES: {{^}}bool MacroDependentBool = MACRO_DEPENDENT_CAST(0);{{$}}
+
+bool ManyMacrosDependent = MACRO_DEPENDENT_CAST(FALSE_MACRO);
+// CHECK-MESSAGES: :[[@LINE-1]]:49: warning: converting integer literal to bool
+// CHECK-FIXES: {{^}}bool ManyMacrosDependent = MACRO_DEPENDENT_CAST(FALSE_MACRO);{{$}}
+
+class FooClass {
+ public:
+ FooClass() : JustBool(0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}FooClass() : JustBool(false) {}{{$}}
+ FooClass(int) : JustBool{0} {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}FooClass(int) : JustBool{false} {}{{$}}
+ private:
+ bool JustBool;
+ bool BoolWithBraces{0};
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}bool BoolWithBraces{false};{{$}}
+ bool BoolFromInt = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}bool BoolFromInt = false;{{$}}
+ bool SimpleBool = true; // OK
+};
+
+template<typename type>
+void templateFunction(type) {
+ type TemplateType = 0;
+ // CHECK-FIXES: {{^ *}}type TemplateType = 0;{{$}}
+}
+
+template<int c>
+void valueDependentTemplateFunction() {
+ bool Boolean = c;
+ // CHECK-FIXES: {{^ *}}bool Boolean = c;{{$}}
+}
+
+template<typename type>
+void anotherTemplateFunction(type) {
+ bool JustBool = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}bool JustBool = false;{{$}}
+}
+
+int main() {
+ boolFunction(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}boolFunction(true);{{$}}
+
+ boolFunction(false);
+
+ templateFunction(0);
+
+ templateFunction(false);
+
+ valueDependentTemplateFunction<1>();
+
+ anotherTemplateFunction(1);
+
+ IntToTrue = 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}IntToTrue = true;{{$}}
+}
+
+static int Value = 1;
+
+bool Function1() {
+ bool Result = Value == 1 ? 1 : 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: converting integer literal to bool
+ // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}bool Result = Value == 1 ? true : false;{{$}}
+ return Result;
+}
+
+bool Function2() {
+ return Value == 1 ? 1 : 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: converting integer literal to bool
+ // CHECK-MESSAGES: :[[@LINE-2]]:27: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}return Value == 1 ? true : false;{{$}}
+}
+
+void foo() {
+ bool Result;
+ Result = Value == 1 ? true : 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}Result = Value == 1 ? true : false;{{$}}
+ Result = Value == 1 ? false : bool(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}Result = Value == 1 ? false : false;{{$}}
+ Result = Value == 1 ? (bool)0 : false;
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: converting integer literal to bool
+ // CHECK-FIXES: {{^ *}}Result = Value == 1 ? false : false;{{$}}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-default-member-init-assignment.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-default-member-init-assignment.cpp
new file mode 100644
index 0000000..fdc0db1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-default-member-init-assignment.cpp
@@ -0,0 +1,184 @@
+// RUN: %check_clang_tidy %s modernize-use-default-member-init %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-default-member-init.UseAssignment, value: 1}]}" -- -std=c++11
+
+struct S {
+};
+
+struct PositiveValueChar {
+ PositiveValueChar() : c0(), c1()/*, c2(), c3()*/ {}
+ // CHECK-FIXES: PositiveValueChar() {}
+ const char c0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use default member initializer for 'c0' [modernize-use-default-member-init]
+ // CHECK-FIXES: const char c0 = '\0';
+ wchar_t c1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use default member initializer for 'c1'
+ // CHECK-FIXES: wchar_t c1 = L'\0';
+ // FIXME: char16_t c2;
+ // C HECK-MESSAGES: :[[@LINE-1]]:12: warning: use default member initializer for 'c2'
+ // C HECK-FIXES: char16_t c2 = u'\0';
+ // FIXME: char32_t c3;
+ // C HECK-MESSAGES: :[[@LINE-1]]:12: warning: use default member initializer for 'c3'
+ // C HECK-FIXES: char32_t c3 = U'\0';
+};
+
+struct PositiveChar {
+ PositiveChar() : d('a') {}
+ // CHECK-FIXES: PositiveChar() {}
+ char d;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'd'
+ // CHECK-FIXES: char d = 'a';
+};
+
+struct PositiveValueInt {
+ PositiveValueInt() : i() {}
+ // CHECK-FIXES: PositiveValueInt() {}
+ const int i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use default member initializer for 'i'
+ // CHECK-FIXES: const int i = 0;
+};
+
+struct PositiveInt {
+ PositiveInt() : j(1) {}
+ // CHECK-FIXES: PositiveInt() {}
+ int j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'j'
+ // CHECK-FIXES: int j = 1;
+};
+
+struct PositiveUnaryMinusInt {
+ PositiveUnaryMinusInt() : j(-1) {}
+ // CHECK-FIXES: PositiveUnaryMinusInt() {}
+ int j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'j'
+ // CHECK-FIXES: int j = -1;
+};
+
+struct PositiveUnaryPlusInt {
+ PositiveUnaryPlusInt() : j(+1) {}
+ // CHECK-FIXES: PositiveUnaryPlusInt() {}
+ int j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'j'
+ // CHECK-FIXES: int j = +1;
+};
+
+struct PositiveValueComplexInt {
+ PositiveValueComplexInt() : i() {}
+ // CHECK-FIXES: PositiveValueComplexInt() {}
+ _Complex int i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use default member initializer for 'i'
+ // CHECK-FIXES: _Complex int i = 0;
+};
+
+struct PositiveValueFloat {
+ PositiveValueFloat() : f() {}
+ // CHECK-FIXES: PositiveValueFloat() {}
+ float f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use default member initializer for 'f'
+ // CHECK-FIXES: float f = 0.0f;
+};
+
+struct PositiveValueDouble {
+ PositiveValueDouble() : d() {}
+ // CHECK-FIXES: PositiveValueDouble() {}
+ double d;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'd'
+ // CHECK-FIXES: double d = 0.0;
+};
+
+struct PositiveDouble {
+ PositiveDouble() : f(2.5463e43) {}
+ // CHECK-FIXES: PositiveDouble() {}
+ double f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'f'
+ // CHECK-FIXES: double f = 2.5463e43;
+};
+
+struct PositiveValueComplexFloat {
+ PositiveValueComplexFloat() : f() {}
+ // CHECK-FIXES: PositiveValueComplexFloat() {}
+ _Complex float f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use default member initializer for 'f'
+ // CHECK-FIXES: _Complex float f = 0.0f;
+};
+
+struct PositiveValueComplexDouble {
+ PositiveValueComplexDouble() : f() {}
+ // CHECK-FIXES: PositiveValueComplexDouble() {}
+ _Complex double f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use default member initializer for 'f'
+ // CHECK-FIXES: _Complex double f = 0.0;
+};
+
+struct PositiveUnaryMinusDouble {
+ PositiveUnaryMinusDouble() : f(-2.5463e43) {}
+ // CHECK-FIXES: PositiveUnaryMinusDouble() {}
+ double f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'f'
+ // CHECK-FIXES: double f = -2.5463e43;
+};
+
+struct PositiveUnaryPlusDouble {
+ PositiveUnaryPlusDouble() : f(+2.5463e43) {}
+ // CHECK-FIXES: PositiveUnaryPlusDouble() {}
+ double f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'f'
+ // CHECK-FIXES: double f = +2.5463e43;
+};
+
+struct PositiveValueBool {
+ PositiveValueBool() : b() {}
+ // CHECK-FIXES: PositiveValueBool() {}
+ bool b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'b'
+ // CHECK-FIXES: bool b = false;
+};
+
+struct PositiveBool {
+ PositiveBool() : a(true) {}
+ // CHECK-FIXES: PositiveBool() {}
+ bool a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'a'
+ // CHECK-FIXES: bool a = true;
+};
+
+struct PositiveValuePointer {
+ PositiveValuePointer() : p() {}
+ // CHECK-FIXES: PositiveValuePointer() {}
+ int *p;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'p'
+ // CHECK-FIXES: int *p = nullptr;
+};
+
+struct PositiveNullPointer {
+ PositiveNullPointer() : q(nullptr) {}
+ // CHECK-FIXES: PositiveNullPointer() {}
+ int *q;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'q'
+ // CHECK-FIXES: int *q = nullptr;
+};
+
+enum Enum { Foo };
+struct PositiveEnum {
+ PositiveEnum() : e(Foo) {}
+ // CHECK-FIXES: PositiveEnum() {}
+ Enum e;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'e'
+ // CHECK-FIXES: Enum e = Foo;
+};
+
+struct PositiveString {
+ PositiveString() : s("foo") {}
+ // CHECK-FIXES: PositiveString() {}
+ const char *s;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use default member initializer for 's'
+ // CHECK-FIXES: const char *s = "foo";
+};
+
+template <typename T>
+struct NegativeTemplate {
+ NegativeTemplate() : t() {}
+ T t;
+};
+
+NegativeTemplate<int> nti;
+NegativeTemplate<double> ntd;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-default-member-init-bitfield.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-default-member-init-bitfield.cpp
new file mode 100644
index 0000000..1ff08f9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-default-member-init-bitfield.cpp
@@ -0,0 +1,10 @@
+// RUN: %check_clang_tidy %s modernize-use-default-member-init %t -- -- -std=c++2a
+
+struct PositiveBitField
+{
+ PositiveBitField() : i(6) {}
+ // CHECK-FIXES: PositiveBitField() {}
+ int i : 5;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'i' [modernize-use-default-member-init]
+ // CHECK-FIXES: int i : 5{6};
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-default-member-init-macros.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-default-member-init-macros.cpp
new file mode 100644
index 0000000..5b366b5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-default-member-init-macros.cpp
@@ -0,0 +1,18 @@
+// RUN: %check_clang_tidy %s modernize-use-default-member-init %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-default-member-init.IgnoreMacros, value: 0}]}" \
+// RUN: -- -std=c++11
+
+#define MACRO() \
+ struct S { \
+ void *P; \
+ S() : P(nullptr) {} \
+ };
+
+MACRO();
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use default member initializer for 'P'
+
+struct S2 {
+ void *P;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use default member initializer for 'P'
+ S2() : P(nullptr) {}
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-default-member-init.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-default-member-init.cpp
new file mode 100644
index 0000000..0ed65df
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-default-member-init.cpp
@@ -0,0 +1,401 @@
+// RUN: %check_clang_tidy %s modernize-use-default-member-init %t -- -- -std=c++11
+
+struct S {
+};
+
+struct PositiveValueChar {
+ PositiveValueChar() : c0(), c1()/*, c2(), c3()*/ {}
+ // CHECK-FIXES: PositiveValueChar() {}
+ const char c0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use default member initializer for 'c0' [modernize-use-default-member-init]
+ // CHECK-FIXES: const char c0{};
+ wchar_t c1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use default member initializer for 'c1'
+ // CHECK-FIXES: wchar_t c1{};
+ // FIXME: char16_t c2;
+ // C HECK-MESSAGES: :[[@LINE-1]]:12: warning: use default member initializer for 'c2'
+ // C HECK-FIXES: char16_t c2{};
+ // FIXME: char32_t c3;
+ // C HECK-MESSAGES: :[[@LINE-1]]:12: warning: use default member initializer for 'c3'
+ // C HECK-FIXES: char32_t c3{};
+};
+
+struct PositiveChar {
+ PositiveChar() : d('a') {}
+ // CHECK-FIXES: PositiveChar() {}
+ char d;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'd'
+ // CHECK-FIXES: char d{'a'};
+};
+
+struct PositiveValueInt {
+ PositiveValueInt() : i() {}
+ // CHECK-FIXES: PositiveValueInt() {}
+ const int i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use default member initializer for 'i'
+ // CHECK-FIXES: const int i{};
+};
+
+struct PositiveInt {
+ PositiveInt() : j(1) {}
+ // CHECK-FIXES: PositiveInt() {}
+ int j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'j'
+ // CHECK-FIXES: int j{1};
+};
+
+struct PositiveUnaryMinusInt {
+ PositiveUnaryMinusInt() : j(-1) {}
+ // CHECK-FIXES: PositiveUnaryMinusInt() {}
+ int j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'j'
+ // CHECK-FIXES: int j{-1};
+};
+
+struct PositiveUnaryPlusInt {
+ PositiveUnaryPlusInt() : j(+1) {}
+ // CHECK-FIXES: PositiveUnaryPlusInt() {}
+ int j;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'j'
+ // CHECK-FIXES: int j{+1};
+};
+
+struct PositiveValueComplexInt {
+ PositiveValueComplexInt() : i() {}
+ // CHECK-FIXES: PositiveValueComplexInt() {}
+ _Complex int i;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use default member initializer for 'i'
+ // CHECK-FIXES: _Complex int i{};
+};
+
+struct PositiveValueFloat {
+ PositiveValueFloat() : f() {}
+ // CHECK-FIXES: PositiveValueFloat() {}
+ float f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use default member initializer for 'f'
+ // CHECK-FIXES: float f{};
+};
+
+struct PositiveValueDouble {
+ PositiveValueDouble() : d() {}
+ // CHECK-FIXES: PositiveValueDouble() {}
+ double d;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'd'
+ // CHECK-FIXES: double d{};
+};
+
+struct PositiveDouble {
+ PositiveDouble() : f(2.5463e43) {}
+ // CHECK-FIXES: PositiveDouble() {}
+ double f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'f'
+ // CHECK-FIXES: double f{2.5463e43};
+};
+
+struct PositiveValueComplexFloat {
+ PositiveValueComplexFloat() : f() {}
+ // CHECK-FIXES: PositiveValueComplexFloat() {}
+ _Complex float f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use default member initializer for 'f'
+ // CHECK-FIXES: _Complex float f{};
+};
+
+struct PositiveValueComplexDouble {
+ PositiveValueComplexDouble() : f() {}
+ // CHECK-FIXES: PositiveValueComplexDouble() {}
+ _Complex double f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use default member initializer for 'f'
+ // CHECK-FIXES: _Complex double f{};
+};
+
+struct PositiveUnaryMinusDouble {
+ PositiveUnaryMinusDouble() : f(-2.5463e43) {}
+ // CHECK-FIXES: PositiveUnaryMinusDouble() {}
+ double f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'f'
+ // CHECK-FIXES: double f{-2.5463e43};
+};
+
+struct PositiveUnaryPlusDouble {
+ PositiveUnaryPlusDouble() : f(+2.5463e43) {}
+ // CHECK-FIXES: PositiveUnaryPlusDouble() {}
+ double f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'f'
+ // CHECK-FIXES: double f{+2.5463e43};
+};
+
+struct PositiveValueBool {
+ PositiveValueBool() : b() {}
+ // CHECK-FIXES: PositiveValueBool() {}
+ bool b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'b'
+ // CHECK-FIXES: bool b{};
+};
+
+struct PositiveBool {
+ PositiveBool() : a(true) {}
+ // CHECK-FIXES: PositiveBool() {}
+ bool a;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'a'
+ // CHECK-FIXES: bool a{true};
+};
+
+struct PositiveValuePointer {
+ PositiveValuePointer() : p() {}
+ // CHECK-FIXES: PositiveValuePointer() {}
+ int *p;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'p'
+ // CHECK-FIXES: int *p{};
+};
+
+struct PositiveNullPointer {
+ PositiveNullPointer() : q(nullptr) {}
+ // CHECK-FIXES: PositiveNullPointer() {}
+ int *q;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'q'
+ // CHECK-FIXES: int *q{nullptr};
+};
+
+enum Enum { Foo, Bar };
+struct PositiveEnum {
+ PositiveEnum() : e(Foo) {}
+ // CHECK-FIXES: PositiveEnum() {}
+ Enum e;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'e'
+ // CHECK-FIXES: Enum e{Foo};
+};
+
+struct PositiveString {
+ PositiveString() : s("foo") {}
+ // CHECK-FIXES: PositiveString() {}
+ const char *s;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use default member initializer for 's'
+ // CHECK-FIXES: const char *s{"foo"};
+};
+
+struct PositiveStruct {
+ PositiveStruct() : s(7) {}
+ // CHECK-FIXES: PositiveStruct() {}
+ struct {
+ int s;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use default member initializer for 's'
+ // CHECK-FIXES: int s{7};
+ };
+};
+
+template <typename T>
+struct NegativeTemplate {
+ NegativeTemplate() : t() {}
+ T t;
+};
+
+NegativeTemplate<int> nti;
+NegativeTemplate<double> ntd;
+
+struct NegativeDefaultMember {
+ NegativeDefaultMember() {}
+ int i = 2;
+};
+
+struct NegativeClass : S {
+ NegativeClass() : s() {}
+ S s;
+};
+
+struct NegativeBase : S {
+ NegativeBase() : S() {}
+};
+
+struct NegativeDefaultOtherMember{
+ NegativeDefaultOtherMember() : i(3) {}
+ int i = 4;
+};
+
+struct NegativeUnion {
+ NegativeUnion() : d(5.0) {}
+ union {
+ int i;
+ double d;
+ };
+};
+
+struct NegativeBitField
+{
+ NegativeBitField() : i(6) {}
+ int i : 5;
+};
+
+struct NegativeNotDefaultInt
+{
+ NegativeNotDefaultInt(int) : i(7) {}
+ int i;
+};
+
+struct NegativeDefaultArg
+{
+ NegativeDefaultArg(int i = 4) : i(i) {}
+ int i;
+};
+
+struct ExistingChar {
+ ExistingChar(short) : e1(), e2(), e3(), e4() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: member initializer for 'e1' is redundant [modernize-use-default-member-init]
+ // CHECK-MESSAGES: :[[@LINE-2]]:31: warning: member initializer for 'e2' is redundant
+ // CHECK-MESSAGES: :[[@LINE-3]]:37: warning: member initializer for 'e3' is redundant
+ // CHECK-FIXES: ExistingChar(short) : e4() {}
+ ExistingChar(int) : e1(0), e2(0), e3(0), e4(0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: member initializer for 'e1' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:30: warning: member initializer for 'e2' is redundant
+ // CHECK-MESSAGES: :[[@LINE-3]]:37: warning: member initializer for 'e3' is redundant
+ // CHECK-FIXES: ExistingChar(int) : e4(0) {}
+ ExistingChar(long) : e1('\0'), e2('\0'), e3('\0'), e4('\0') {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: member initializer for 'e1' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: member initializer for 'e2' is redundant
+ // CHECK-MESSAGES: :[[@LINE-3]]:44: warning: member initializer for 'e3' is redundant
+ // CHECK-FIXES: ExistingChar(long) : e4('\0') {}
+ ExistingChar(char) : e1('a'), e2('a'), e3('a'), e4('a') {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:51: warning: member initializer for 'e4' is redundant
+ // CHECK-FIXES: ExistingChar(char) : e1('a'), e2('a'), e3('a') {}
+ char e1{};
+ char e2 = 0;
+ char e3 = '\0';
+ char e4 = 'a';
+};
+
+struct ExistingInt {
+ ExistingInt(short) : e1(), e2(), e3(), e4(), e5(), e6() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: member initializer for 'e1' is redundant [modernize-use-default-member-init]
+ // CHECK-MESSAGES: :[[@LINE-2]]:30: warning: member initializer for 'e2' is redundant
+ // CHECK-FIXES: ExistingInt(short) : e3(), e4(), e5(), e6() {}
+ ExistingInt(int) : e1(0), e2(0), e3(0), e4(0), e5(0), e6(0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: member initializer for 'e1' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:29: warning: member initializer for 'e2' is redundant
+ // CHECK-FIXES: ExistingInt(int) : e3(0), e4(0), e5(0), e6(0) {}
+ ExistingInt(long) : e1(5), e2(5), e3(5), e4(5), e5(5), e6(5) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: member initializer for 'e3' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:44: warning: member initializer for 'e4' is redundant
+ // CHECK-MESSAGES: :[[@LINE-3]]:58: warning: member initializer for 'e6' is redundant
+ // CHECK-FIXES: ExistingInt(long) : e1(5), e2(5), e5(5) {}
+ ExistingInt(char) : e1(-5), e2(-5), e3(-5), e4(-5), e5(-5), e6(-5) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:55: warning: member initializer for 'e5' is redundant
+ // CHECK-FIXES: ExistingInt(char) : e1(-5), e2(-5), e3(-5), e4(-5), e6(-5) {}
+ int e1{};
+ int e2 = 0;
+ int e3 = {5};
+ int e4 = 5;
+ int e5 = -5;
+ int e6 = +5;
+};
+
+struct ExistingDouble {
+ ExistingDouble(short) : e1(), e2(), e3(), e4(), e5() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: member initializer for 'e1' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:33: warning: member initializer for 'e2' is redundant
+ // CHECK-FIXES: ExistingDouble(short) : e3(), e4(), e5() {}
+ ExistingDouble(int) : e1(0.0), e2(0.0), e3(0.0), e4(0.0), e5(0.0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: member initializer for 'e1' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: member initializer for 'e2' is redundant
+ // CHECK-FIXES: ExistingDouble(int) : e3(0.0), e4(0.0), e5(0.0) {}
+ ExistingDouble(long) : e1(5.0), e2(5.0), e3(5.0), e4(5.0), e5(5.0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: member initializer for 'e3' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:62: warning: member initializer for 'e5' is redundant
+ // CHECK-FIXES: ExistingDouble(long) : e1(5.0), e2(5.0), e4(5.0) {}
+ ExistingDouble(char) : e1(-5.0), e2(-5.0), e3(-5.0), e4(-5.0), e5(-5.0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:56: warning: member initializer for 'e4' is redundant
+ // CHECK-FIXES: ExistingDouble(char) : e1(-5.0), e2(-5.0), e3(-5.0), e5(-5.0) {}
+ double e1{};
+ double e2 = 0.0;
+ double e3 = 5.0;
+ double e4 = -5.0;
+ double e5 = +5.0;
+};
+
+struct ExistingBool {
+ ExistingBool(short) : e1(), e2(), e3() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: member initializer for 'e1' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:31: warning: member initializer for 'e2' is redundant
+ // CHECK-FIXES: ExistingBool(short) : e3() {}
+ ExistingBool(int) : e1(false), e2(false), e3(false) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: member initializer for 'e1' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: member initializer for 'e2' is redundant
+ // CHECK-FIXES: ExistingBool(int) : e3(false) {}
+ ExistingBool(long) : e1(true), e2(true), e3(true) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: member initializer for 'e3' is redundant
+ // CHECK-FIXES: ExistingBool(long) : e1(true), e2(true) {}
+ bool e1{};
+ bool e2 = false;
+ bool e3 = true;
+};
+
+struct ExistingEnum {
+ ExistingEnum(short) : e1(Foo), e2(Foo) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: member initializer for 'e1' is redundant
+ // CHECK-FIXES: ExistingEnum(short) : e2(Foo) {}
+ ExistingEnum(int) : e1(Bar), e2(Bar) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: member initializer for 'e2' is redundant
+ // CHECK-FIXES: ExistingEnum(int) : e1(Bar) {}
+ Enum e1 = Foo;
+ Enum e2{Bar};
+};
+
+struct ExistingPointer {
+ ExistingPointer(short) : e1(), e2(), e3(), e4() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: member initializer for 'e1' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: member initializer for 'e2' is redundant
+ // CHECK-MESSAGES: :[[@LINE-3]]:40: warning: member initializer for 'e3' is redundant
+ // CHECK-FIXES: ExistingPointer(short) : e4() {}
+ ExistingPointer(int) : e1(0), e2(0), e3(0), e4(&e1) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: member initializer for 'e1' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:33: warning: member initializer for 'e2' is redundant
+ // CHECK-MESSAGES: :[[@LINE-3]]:40: warning: member initializer for 'e3' is redundant
+ // CHECK-FIXES: ExistingPointer(int) : e4(&e1) {}
+ ExistingPointer(long) : e1(nullptr), e2(nullptr), e3(nullptr), e4(&e2) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: member initializer for 'e1' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:40: warning: member initializer for 'e2' is redundant
+ // CHECK-MESSAGES: :[[@LINE-3]]:53: warning: member initializer for 'e3' is redundant
+ // CHECK-FIXES: ExistingPointer(long) : e4(&e2) {}
+ int *e1{};
+ int *e2 = 0;
+ int *e3 = nullptr;
+ int **e4 = &e1;
+};
+
+struct ExistingString {
+ ExistingString(short) : e1(), e2(), e3(), e4() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: member initializer for 'e1' is redundant [modernize-use-default-member-init]
+ // CHECK-MESSAGES: :[[@LINE-2]]:33: warning: member initializer for 'e2' is redundant
+ // CHECK-FIXES: ExistingString(short) : e3(), e4() {}
+ ExistingString(int) : e1(0), e2(0), e3(0), e4(0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: member initializer for 'e1' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: member initializer for 'e2' is redundant
+ // CHECK-FIXES: ExistingString(int) : e3(0), e4(0) {}
+ ExistingString(long) : e1(nullptr), e2(nullptr), e3(nullptr), e4(nullptr) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: member initializer for 'e1' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:39: warning: member initializer for 'e2' is redundant
+ // CHECK-FIXES: ExistingString(long) : e3(nullptr), e4(nullptr) {}
+ ExistingString(char) : e1("foo"), e2("foo"), e3("foo"), e4("foo") {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:48: warning: member initializer for 'e3' is redundant
+ // CHECK-FIXES: ExistingString(char) : e1("foo"), e2("foo"), e4("foo") {}
+ const char *e1{};
+ const char *e2 = nullptr;
+ const char *e3 = "foo";
+ const char *e4 = "bar";
+};
+
+template <typename T>
+struct NegativeTemplateExisting {
+ NegativeTemplateExisting(int) : t(0) {}
+ T t{};
+};
+
+NegativeTemplateExisting<int> ntei(0);
+NegativeTemplateExisting<double> nted(0);
+
+// This resulted in a warning by default.
+#define MACRO() \
+ struct MacroS { \
+ void *P; \
+ MacroS() : P(nullptr) {} \
+ };
+
+MACRO();
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-emplace-ignore-implicit-constructors.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-emplace-ignore-implicit-constructors.cpp
new file mode 100644
index 0000000..2f6b37f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-emplace-ignore-implicit-constructors.cpp
@@ -0,0 +1,123 @@
+// RUN: %check_clang_tidy %s modernize-use-emplace %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: modernize-use-emplace.IgnoreImplicitConstructors, \
+// RUN: value: 1}] \
+// RUN: }" -- -std=c++11
+
+namespace std {
+template <typename>
+class initializer_list
+{
+public:
+ initializer_list() noexcept {}
+};
+
+template <typename T>
+class vector {
+public:
+ vector() = default;
+ vector(initializer_list<T>) {}
+
+ void push_back(const T &) {}
+ void push_back(T &&) {}
+
+ template <typename... Args>
+ void emplace_back(Args &&... args){};
+ ~vector();
+};
+
+} // namespace std
+
+void testInts() {
+ std::vector<int> v;
+ v.push_back(42);
+ v.push_back(int(42));
+ v.push_back(int{42});
+ v.push_back(42.0);
+ int z;
+ v.push_back(z);
+}
+
+struct Something {
+ Something(int a, int b = 41) {}
+ Something() {}
+ void push_back(Something);
+ int getInt() { return 42; }
+};
+
+struct Convertable {
+ operator Something() { return Something{}; }
+};
+
+struct Zoz {
+ Zoz(Something, int = 42) {}
+};
+
+Zoz getZoz(Something s) { return Zoz(s); }
+
+void test_Something() {
+ std::vector<Something> v;
+
+ v.push_back(Something(1, 2));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back instead of push_back [modernize-use-emplace]
+ // CHECK-FIXES: v.emplace_back(1, 2);
+
+ v.push_back(Something{1, 2});
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(1, 2);
+
+ v.push_back(Something());
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back();
+
+ v.push_back(Something{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back();
+
+ Something Different;
+ v.push_back(Something(Different.getInt(), 42));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(Different.getInt(), 42);
+
+ v.push_back(Different.getInt());
+ v.push_back(42);
+
+ Something temporary(42, 42);
+ temporary.push_back(temporary);
+ v.push_back(temporary);
+
+ v.push_back(Convertable());
+ v.push_back(Convertable{});
+ Convertable s;
+ v.push_back(s);
+}
+
+template <typename ElemType>
+void dependOnElem() {
+ std::vector<ElemType> v;
+ v.push_back(ElemType(42));
+}
+
+template <typename ContainerType>
+void dependOnContainer() {
+ ContainerType v;
+ v.push_back(Something(42));
+}
+
+void callDependent() {
+ dependOnElem<Something>();
+ dependOnContainer<std::vector<Something>>();
+}
+
+void test2() {
+ std::vector<Zoz> v;
+ v.push_back(Zoz(Something(21, 37)));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(Something(21, 37));
+
+ v.push_back(Zoz(Something(21, 37), 42));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(Something(21, 37), 42);
+
+ v.push_back(getZoz(Something(1, 2)));
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-emplace.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-emplace.cpp
new file mode 100644
index 0000000..c03d024
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-emplace.cpp
@@ -0,0 +1,607 @@
+// RUN: %check_clang_tidy %s modernize-use-emplace %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: modernize-use-emplace.ContainersWithPushBack, \
+// RUN: value: '::std::vector; ::std::list; ::std::deque; llvm::LikeASmallVector'}, \
+// RUN: {key: modernize-use-emplace.TupleTypes, \
+// RUN: value: '::std::pair; std::tuple; ::test::Single'}, \
+// RUN: {key: modernize-use-emplace.TupleMakeFunctions, \
+// RUN: value: '::std::make_pair; ::std::make_tuple; ::test::MakeSingle'}] \
+// RUN: }" -- -std=c++11
+
+namespace std {
+template <typename>
+class initializer_list
+{
+public:
+ initializer_list() noexcept {}
+};
+
+template <typename T>
+class vector {
+public:
+ vector() = default;
+ vector(initializer_list<T>) {}
+
+ void push_back(const T &) {}
+ void push_back(T &&) {}
+
+ template <typename... Args>
+ void emplace_back(Args &&... args){};
+ ~vector();
+};
+template <typename T>
+class list {
+public:
+ void push_back(const T &) {}
+ void push_back(T &&) {}
+
+ template <typename... Args>
+ void emplace_back(Args &&... args){};
+ ~list();
+};
+
+template <typename T>
+class deque {
+public:
+ void push_back(const T &) {}
+ void push_back(T &&) {}
+
+ template <typename... Args>
+ void emplace_back(Args &&... args){};
+ ~deque();
+};
+
+template <typename T> struct remove_reference { using type = T; };
+template <typename T> struct remove_reference<T &> { using type = T; };
+template <typename T> struct remove_reference<T &&> { using type = T; };
+
+template <typename T1, typename T2> class pair {
+public:
+ pair() = default;
+ pair(const pair &) = default;
+ pair(pair &&) = default;
+
+ pair(const T1 &, const T2 &) {}
+ pair(T1 &&, T2 &&) {}
+
+ template <typename U1, typename U2> pair(const pair<U1, U2> &){};
+ template <typename U1, typename U2> pair(pair<U1, U2> &&){};
+};
+
+template <typename T1, typename T2>
+pair<typename remove_reference<T1>::type, typename remove_reference<T2>::type>
+make_pair(T1 &&, T2 &&) {
+ return {};
+};
+
+template <typename... Ts> class tuple {
+public:
+ tuple() = default;
+ tuple(const tuple &) = default;
+ tuple(tuple &&) = default;
+
+ tuple(const Ts &...) {}
+ tuple(Ts &&...) {}
+
+ template <typename... Us> tuple(const tuple<Us...> &){};
+ template <typename... Us> tuple(tuple<Us...> &&) {}
+
+ template <typename U1, typename U2> tuple(const pair<U1, U2> &) {
+ static_assert(sizeof...(Ts) == 2, "Wrong tuple size");
+ };
+ template <typename U1, typename U2> tuple(pair<U1, U2> &&) {
+ static_assert(sizeof...(Ts) == 2, "Wrong tuple size");
+ };
+};
+
+template <typename... Ts>
+tuple<typename remove_reference<Ts>::type...> make_tuple(Ts &&...) {
+ return {};
+}
+
+template <typename T>
+class unique_ptr {
+public:
+ explicit unique_ptr(T *) {}
+ ~unique_ptr();
+};
+} // namespace std
+
+namespace llvm {
+template <typename T>
+class LikeASmallVector {
+public:
+ void push_back(const T &) {}
+ void push_back(T &&) {}
+
+ template <typename... Args>
+ void emplace_back(Args &&... args){};
+};
+
+} // llvm
+
+void testInts() {
+ std::vector<int> v;
+ v.push_back(42);
+ v.push_back(int(42));
+ v.push_back(int{42});
+ v.push_back(42.0);
+ int z;
+ v.push_back(z);
+}
+
+struct Something {
+ Something(int a, int b = 41) {}
+ Something() {}
+ void push_back(Something);
+ int getInt() { return 42; }
+};
+
+struct Convertable {
+ operator Something() { return Something{}; }
+};
+
+struct Zoz {
+ Zoz(Something, int = 42) {}
+};
+
+Zoz getZoz(Something s) { return Zoz(s); }
+
+void test_Something() {
+ std::vector<Something> v;
+
+ v.push_back(Something(1, 2));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back instead of push_back [modernize-use-emplace]
+ // CHECK-FIXES: v.emplace_back(1, 2);
+
+ v.push_back(Something{1, 2});
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(1, 2);
+
+ v.push_back(Something());
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back();
+
+ v.push_back(Something{});
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back();
+
+ Something Different;
+ v.push_back(Something(Different.getInt(), 42));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(Different.getInt(), 42);
+
+ v.push_back(Different.getInt());
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(Different.getInt());
+
+ v.push_back(42);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(42);
+
+ Something temporary(42, 42);
+ temporary.push_back(temporary);
+ v.push_back(temporary);
+
+ v.push_back(Convertable());
+ v.push_back(Convertable{});
+ Convertable s;
+ v.push_back(s);
+}
+
+template <typename ElemType>
+void dependOnElem() {
+ std::vector<ElemType> v;
+ v.push_back(ElemType(42));
+}
+
+template <typename ContainerType>
+void dependOnContainer() {
+ ContainerType v;
+ v.push_back(Something(42));
+}
+
+void callDependent() {
+ dependOnElem<Something>();
+ dependOnContainer<std::vector<Something>>();
+}
+
+void test2() {
+ std::vector<Zoz> v;
+ v.push_back(Zoz(Something(21, 37)));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(Something(21, 37));
+
+ v.push_back(Zoz(Something(21, 37), 42));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(Something(21, 37), 42);
+
+ v.push_back(getZoz(Something(1, 2)));
+}
+
+struct GetPair {
+ std::pair<int, long> getPair();
+};
+void testPair() {
+ std::vector<std::pair<int, int>> v;
+ v.push_back(std::pair<int, int>(1, 2));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(1, 2);
+
+ GetPair g;
+ v.push_back(g.getPair());
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(g.getPair());
+
+ std::vector<std::pair<Something, Zoz>> v2;
+ v2.push_back(std::pair<Something, Zoz>(Something(42, 42), Zoz(Something(21, 37))));
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use emplace_back
+ // CHECK-FIXES: v2.emplace_back(Something(42, 42), Zoz(Something(21, 37)));
+}
+
+void testTuple() {
+ std::vector<std::tuple<bool, char, int>> v;
+ v.push_back(std::tuple<bool, char, int>(false, 'x', 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(false, 'x', 1);
+
+ v.push_back(std::tuple<bool, char, int>{false, 'y', 2});
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(false, 'y', 2);
+
+ v.push_back({true, 'z', 3});
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(true, 'z', 3);
+
+ std::vector<std::tuple<int, bool>> x;
+ x.push_back(std::make_pair(1, false));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: x.emplace_back(1, false);
+
+ x.push_back(std::make_pair(2LL, 1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: x.emplace_back(2LL, 1);
+}
+
+struct Base {
+ Base(int, int *, int = 42);
+};
+
+struct Derived : Base {
+ Derived(int *, Something) : Base(42, nullptr) {}
+};
+
+void testDerived() {
+ std::vector<Base> v;
+ v.push_back(Derived(nullptr, Something{}));
+}
+
+void testNewExpr() {
+ std::vector<Derived> v;
+ v.push_back(Derived(new int, Something{}));
+}
+
+void testSpaces() {
+ std::vector<Something> v;
+
+ // clang-format off
+
+ v.push_back(Something(1, //arg1
+ 2 // arg2
+ ) // Something
+ );
+ // CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(1, //arg1
+ // CHECK-FIXES: 2 // arg2
+ // CHECK-FIXES: // Something
+ // CHECK-FIXES: );
+
+ v.push_back( Something (1, 2) );
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(1, 2 );
+
+ v.push_back( Something {1, 2} );
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(1, 2 );
+
+ v.push_back( Something {} );
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back( );
+
+ v.push_back(
+ Something(1, 2) );
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(1, 2 );
+
+ std::vector<Base> v2;
+ v2.push_back(
+ Base(42, nullptr));
+ // CHECK-MESSAGES: :[[@LINE-2]]:6: warning: use emplace_back
+ // CHECK-FIXES: v2.emplace_back(42, nullptr);
+
+ // clang-format on
+}
+
+void testPointers() {
+ std::vector<int *> v;
+ v.push_back(new int(5));
+
+ std::vector<std::unique_ptr<int>> v2;
+ v2.push_back(std::unique_ptr<int>(new int(42)));
+ // This call can't be replaced with emplace_back.
+ // If emplacement will fail (not enough memory to add to vector)
+ // we will have leak of int because unique_ptr won't be constructed
+ // (and destructed) as in push_back case.
+
+ auto *ptr = new int;
+ v2.push_back(std::unique_ptr<int>(ptr));
+ // Same here
+}
+
+void testMakePair() {
+ std::vector<std::pair<int, int>> v;
+ v.push_back(std::make_pair(1, 2));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(1, 2);
+
+ v.push_back(std::make_pair(42LL, 13));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(42LL, 13);
+
+ v.push_back(std::make_pair<char, char>(0, 3));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(std::make_pair<char, char>(0, 3));
+ //
+ // Even though the call above could be turned into v.emplace_back(0, 3),
+ // we don't eliminate the make_pair call here, because of the explicit
+ // template parameters provided. make_pair's arguments can be convertible
+ // to its explicitly provided template parameter, but not to the pair's
+ // element type. The examples below illustrate the problem.
+ struct D {
+ D(...) {}
+ operator char() const { return 0; }
+ };
+ v.push_back(std::make_pair<D, int>(Something(), 2));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(std::make_pair<D, int>(Something(), 2));
+
+ struct X {
+ X(std::pair<int, int>) {}
+ };
+ std::vector<X> x;
+ x.push_back(std::make_pair(1, 2));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: x.emplace_back(std::make_pair(1, 2));
+ // make_pair cannot be removed here, as X is not constructible with two ints.
+
+ struct Y {
+ Y(std::pair<int, int>&&) {}
+ };
+ std::vector<Y> y;
+ y.push_back(std::make_pair(2, 3));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: y.emplace_back(std::make_pair(2, 3));
+ // make_pair cannot be removed here, as Y is not constructible with two ints.
+}
+
+void testMakeTuple() {
+ std::vector<std::tuple<int, bool, char>> v;
+ v.push_back(std::make_tuple(1, true, 'v'));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(1, true, 'v');
+
+ v.push_back(std::make_tuple(2ULL, 1, 0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(2ULL, 1, 0);
+
+ v.push_back(std::make_tuple<long long, int, int>(3LL, 1, 0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(std::make_tuple<long long, int, int>(3LL, 1, 0));
+ // make_tuple is not removed when there are explicit template
+ // arguments provided.
+}
+
+namespace test {
+template <typename T> struct Single {
+ Single() = default;
+ Single(const Single &) = default;
+ Single(Single &&) = default;
+
+ Single(const T &) {}
+ Single(T &&) {}
+
+ template <typename U> Single(const Single<U> &) {}
+ template <typename U> Single(Single<U> &&) {}
+
+ template <typename U> Single(const std::tuple<U> &) {}
+ template <typename U> Single(std::tuple<U> &&) {}
+};
+
+template <typename T>
+Single<typename std::remove_reference<T>::type> MakeSingle(T &&) {
+ return {};
+}
+} // namespace test
+
+void testOtherTuples() {
+ std::vector<test::Single<int>> v;
+ v.push_back(test::Single<int>(1));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(1);
+
+ v.push_back({2});
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(2);
+
+ v.push_back(test::MakeSingle(3));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(3);
+
+ v.push_back(test::MakeSingle<long long>(4));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(test::MakeSingle<long long>(4));
+ // We don't remove make functions with explicit template parameters.
+
+ v.push_back(test::MakeSingle(5LL));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(5LL);
+
+ v.push_back(std::make_tuple(6));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(6);
+
+ v.push_back(std::make_tuple(7LL));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(7LL);
+}
+
+void testOtherContainers() {
+ std::list<Something> l;
+ l.push_back(Something(42, 41));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: l.emplace_back(42, 41);
+
+ std::deque<Something> d;
+ d.push_back(Something(42));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: d.emplace_back(42);
+
+ llvm::LikeASmallVector<Something> ls;
+ ls.push_back(Something(42));
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use emplace_back
+ // CHECK-FIXES: ls.emplace_back(42);
+}
+
+class IntWrapper {
+public:
+ IntWrapper(int x) : value(x) {}
+ IntWrapper operator+(const IntWrapper other) const {
+ return IntWrapper(value + other.value);
+ }
+
+private:
+ int value;
+};
+
+void testMultipleOpsInPushBack() {
+ std::vector<IntWrapper> v;
+ v.push_back(IntWrapper(42) + IntWrapper(27));
+}
+
+// Macro tests.
+#define PUSH_BACK_WHOLE(c, x) c.push_back(x)
+#define PUSH_BACK_NAME push_back
+#define PUSH_BACK_ARG(x) (x)
+#define SOME_OBJ Something(10)
+#define MILLION 3
+#define SOME_WEIRD_PUSH(v) v.push_back(Something(
+#define OPEN (
+#define CLOSE )
+void macroTest() {
+ std::vector<Something> v;
+ Something s;
+
+ PUSH_BACK_WHOLE(v, Something(5, 6));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use emplace_back
+
+ v.PUSH_BACK_NAME(Something(5));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+
+ v.push_back PUSH_BACK_ARG(Something(5, 6));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+
+ v.push_back(SOME_OBJ);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+
+ v.push_back(Something(MILLION));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(MILLION);
+
+ // clang-format off
+ v.push_back( Something OPEN 3 CLOSE );
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // clang-format on
+ PUSH_BACK_WHOLE(s, Something(1));
+}
+
+struct A {
+ int value1, value2;
+};
+
+struct B {
+ B(A) {}
+};
+
+struct C {
+ int value1, value2, value3;
+};
+
+void testAggregation() {
+ // This should not be noticed or fixed; after the correction, the code won't
+ // compile.
+
+ std::vector<A> v;
+ v.push_back(A({1, 2}));
+
+ std::vector<B> vb;
+ vb.push_back(B({10, 42}));
+}
+
+struct Bitfield {
+ unsigned bitfield : 1;
+ unsigned notBitfield;
+};
+
+void testBitfields() {
+ std::vector<Something> v;
+ Bitfield b;
+ v.push_back(Something(42, b.bitfield));
+ v.push_back(Something(b.bitfield));
+
+ v.push_back(Something(42, b.notBitfield));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(42, b.notBitfield);
+ int var;
+ v.push_back(Something(42, var));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(42, var);
+}
+
+class PrivateCtor {
+ PrivateCtor(int z);
+
+public:
+ void doStuff() {
+ std::vector<PrivateCtor> v;
+ // This should not change it because emplace back doesn't have permission.
+ // Check currently doesn't support friend declarations because pretty much
+ // nobody would want to be friend with std::vector :(.
+ v.push_back(PrivateCtor(42));
+ }
+};
+
+struct WithDtor {
+ WithDtor(int) {}
+ ~WithDtor();
+};
+
+void testWithDtor() {
+ std::vector<WithDtor> v;
+
+ v.push_back(WithDtor(42));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use emplace_back
+ // CHECK-FIXES: v.emplace_back(42);
+}
+
+void testInitializerList() {
+ std::vector<std::vector<int>> v;
+ v.push_back(std::vector<int>({1}));
+ // Test against the bug reported in PR32896.
+
+ v.push_back({{2}});
+
+ using PairIntVector = std::pair<int, std::vector<int>>;
+ std::vector<PairIntVector> x;
+ x.push_back(PairIntVector(3, {4}));
+ x.push_back({5, {6}});
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-default-copy.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-default-copy.cpp
new file mode 100644
index 0000000..39a864d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-default-copy.cpp
@@ -0,0 +1,507 @@
+// RUN: %check_clang_tidy %s modernize-use-equals-default %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-equals-default.IgnoreMacros, value: 0}]}" \
+// RUN: -- -std=c++11 -fno-delayed-template-parsing -fexceptions
+
+// Out of line definition.
+struct OL {
+ OL(const OL &);
+ OL &operator=(const OL &);
+ int Field;
+};
+OL::OL(const OL &Other) : Field(Other.Field) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default' to define a trivial copy constructor [modernize-use-equals-default]
+// CHECK-FIXES: OL::OL(const OL &Other) = default;
+OL &OL::operator=(const OL &Other) {
+ Field = Other.Field;
+ return *this;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:9: warning: use '= default' to define a trivial copy-assignment operator [modernize-use-equals-default]
+// CHECK-FIXES: OL &OL::operator=(const OL &Other) = default;
+
+// Inline.
+struct IL {
+ IL(const IL &Other) : Field(Other.Field) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: IL(const IL &Other) = default;
+ IL &operator=(const IL &Other) {
+ Field = Other.Field;
+ return *this;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use '= default'
+ // CHECK-FIXES: IL &operator=(const IL &Other) = default;
+ int Field;
+};
+
+// Wrong type.
+struct WT {
+ WT(const IL &Other) {}
+ WT &operator=(const IL &);
+};
+WT &WT::operator=(const IL &Other) { return *this; }
+
+// Qualifiers.
+struct Qual {
+ Qual(const Qual &Other) : Field(Other.Field), Volatile(Other.Volatile),
+ Mutable(Other.Mutable), Reference(Other.Reference),
+ Const(Other.Const) {}
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use '= default'
+ // CHECK-FIXES: Qual(const Qual &Other)
+ // CHECK-FIXES: = default;
+
+ int Field;
+ volatile char Volatile;
+ mutable bool Mutable;
+ const OL &Reference; // This makes this class non-assignable.
+ const IL Const; // This also makes this class non-assignable.
+ static int Static;
+};
+
+// Wrong init arguments.
+struct WI {
+ WI(const WI &Other) : Field1(Other.Field1), Field2(Other.Field1) {}
+ WI &operator=(const WI &);
+ int Field1, Field2;
+};
+WI &WI::operator=(const WI &Other) {
+ Field1 = Other.Field1;
+ Field2 = Other.Field1;
+ return *this;
+}
+
+// Missing field.
+struct MF {
+ MF(const MF &Other) : Field1(Other.Field1), Field2(Other.Field2) {}
+ MF &operator=(const MF &);
+ int Field1, Field2, Field3;
+};
+MF &MF::operator=(const MF &Other) {
+ Field1 = Other.Field1;
+ Field2 = Other.Field2;
+ return *this;
+}
+
+struct Comments {
+ Comments(const Comments &Other)
+ /* don't delete */ : /* this comment */ Field(Other.Field) {}
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
+ // CHECK-FIXES: /* don't delete */ = default;
+ int Field;
+};
+
+struct MoreComments {
+ MoreComments(const MoreComments &Other) /* this comment is OK */
+ : Field(Other.Field) {}
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
+ // CHECK-FIXES: MoreComments(const MoreComments &Other) /* this comment is OK */
+ // CHECK-FIXES-NEXT: = default;
+ int Field;
+};
+
+struct ColonInComment {
+ ColonInComment(const ColonInComment &Other) /* : */ : Field(Other.Field) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: ColonInComment(const ColonInComment &Other) /* : */ = default;
+ int Field;
+};
+
+// No members or bases (in particular, no colon).
+struct Empty {
+ Empty(const Empty &Other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: Empty(const Empty &Other) = default;
+ Empty &operator=(const Empty &);
+};
+Empty &Empty::operator=(const Empty &Other) { return *this; }
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use '= default'
+// CHECK-FIXES: Empty &Empty::operator=(const Empty &Other) = default;
+
+// Bit fields.
+struct BF {
+ BF() = default;
+ BF(const BF &Other) : Field1(Other.Field1), Field2(Other.Field2), Field3(Other.Field3),
+ Field4(Other.Field4) {}
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
+ // CHECK-FIXES: BF(const BF &Other) {{$}}
+ // CHECK-FIXES: = default;
+ BF &operator=(const BF &);
+
+ unsigned Field1 : 3;
+ int : 7;
+ char Field2 : 6;
+ int : 0;
+ int Field3 : 24;
+ unsigned char Field4;
+};
+BF &BF::operator=(const BF &Other) {
+ Field1 = Other.Field1;
+ Field2 = Other.Field2;
+ Field3 = Other.Field3;
+ Field4 = Other.Field4;
+ return *this;
+}
+// CHECK-MESSAGES: :[[@LINE-7]]:9: warning: use '= default'
+// CHECK-FIXES: BF &BF::operator=(const BF &Other) = default;
+
+// Base classes.
+struct BC : IL, OL, BF {
+ BC(const BC &Other) : IL(Other), OL(Other), BF(Other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: BC(const BC &Other) = default;
+ BC &operator=(const BC &Other);
+};
+BC &BC::operator=(const BC &Other) {
+ IL::operator=(Other);
+ OL::operator=(Other);
+ BF::operator=(Other);
+ return *this;
+}
+// CHECK-MESSAGES: :[[@LINE-6]]:9: warning: use '= default'
+// CHECK-FIXES: BC &BC::operator=(const BC &Other) = default;
+
+// Base classes with member.
+struct BCWM : IL, OL {
+ BCWM(const BCWM &Other) : IL(Other), OL(Other), Bf(Other.Bf) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: BCWM(const BCWM &Other) = default;
+ BCWM &operator=(const BCWM &);
+ BF Bf;
+};
+BCWM &BCWM::operator=(const BCWM &Other) {
+ IL::operator=(Other);
+ OL::operator=(Other);
+ Bf = Other.Bf;
+ return *this;
+}
+// CHECK-MESSAGES: :[[@LINE-6]]:13: warning: use '= default'
+// CHECK-FIXES: BCWM &BCWM::operator=(const BCWM &Other) = default;
+
+// Missing base class.
+struct MBC : IL, OL, BF {
+ MBC(const MBC &Other) : IL(Other), OL(Other) {}
+ MBC &operator=(const MBC &);
+};
+MBC &MBC::operator=(const MBC &Other) {
+ IL::operator=(Other);
+ OL::operator=(Other);
+ return *this;
+}
+
+// Base classes, incorrect parameter.
+struct BCIP : BCWM, BF {
+ BCIP(const BCIP &Other) : BCWM(Other), BF(Other.Bf) {}
+ BCIP &operator=(const BCIP &);
+};
+BCIP &BCIP::operator=(const BCIP &Other) {
+ BCWM::operator=(Other);
+ BF::operator=(Other.Bf);
+ return *this;
+}
+
+// Virtual base classes.
+struct VA : virtual OL {};
+struct VB : virtual OL {};
+struct VBC : VA, VB, virtual OL {
+ // OL is the first thing that is going to be initialized, despite the fact
+ // that it is the last in the list of bases, because it is virtual and there
+ // is a virtual OL at the beginning of VA (which is the same).
+ VBC(const VBC &Other) : OL(Other), VA(Other), VB(Other) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: VBC(const VBC &Other) = default;
+ VBC &operator=(const VBC &Other);
+};
+VBC &VBC::operator=(const VBC &Other) {
+ OL::operator=(Other);
+ VA::operator=(Other);
+ VB::operator=(Other);
+ return *this;
+}
+// CHECK-MESSAGES: :[[@LINE-6]]:11: warning: use '= default'
+// CHECK-FIXES: VBC &VBC::operator=(const VBC &Other) = default;
+
+// Indirect base.
+struct IB : VBC {
+ IB(const IB &Other) : OL(Other), VBC(Other) {}
+ IB &operator=(const IB &);
+};
+IB &IB::operator=(const IB &Other) {
+ OL::operator=(Other);
+ VBC::operator=(Other);
+ return *this;
+}
+
+// Class template.
+template <class T>
+struct Template {
+ Template() = default;
+ Template(const Template &Other) : Field(Other.Field) {}
+ Template &operator=(const Template &Other);
+ void foo(const T &t);
+ int Field;
+};
+template <class T>
+Template<T> &Template<T>::operator=(const Template<T> &Other) {
+ Field = Other.Field;
+ return *this;
+}
+Template<int> T1;
+
+// Dependent types.
+template <class T>
+struct DT1 {
+ DT1() = default;
+ DT1(const DT1 &Other) : Field(Other.Field) {}
+ DT1 &operator=(const DT1 &);
+ T Field;
+};
+template <class T>
+DT1<T> &DT1<T>::operator=(const DT1<T> &Other) {
+ Field = Other.Field;
+ return *this;
+}
+DT1<int> Dt1;
+
+template <class T>
+struct DT2 {
+ DT2() = default;
+ DT2(const DT2 &Other) : Field(Other.Field), Dependent(Other.Dependent) {}
+ DT2 &operator=(const DT2 &);
+ T Field;
+ typename T::TT Dependent;
+};
+template <class T>
+DT2<T> &DT2<T>::operator=(const DT2<T> &Other) {
+ Field = Other.Field;
+ Dependent = Other.Dependent;
+ return *this;
+}
+struct T {
+ typedef int TT;
+};
+DT2<T> Dt2;
+
+// Default arguments.
+struct DA {
+ DA(int Int);
+ DA(const DA &Other = DA(0)) : Field1(Other.Field1), Field2(Other.Field2) {}
+ DA &operator=(const DA &);
+ int Field1;
+ char Field2;
+};
+// Overloaded operator= cannot have a default argument.
+DA &DA::operator=(const DA &Other) {
+ Field1 = Other.Field1;
+ Field2 = Other.Field2;
+ return *this;
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:9: warning: use '= default'
+// CHECK-FIXES: DA &DA::operator=(const DA &Other) = default;
+
+struct DA2 {
+ // Can be used as copy-constructor but cannot be explicitly defaulted.
+ DA2(const DA &Other, int Def = 0) {}
+};
+
+// Default initialization.
+struct DI {
+ DI(const DI &Other) : Field1(Other.Field1), Field2(Other.Field2) {}
+ int Field1;
+ int Field2 = 0;
+ int Fiedl3;
+};
+
+// Statement inside body.
+void foo();
+struct SIB {
+ SIB(const SIB &Other) : Field(Other.Field) { foo(); }
+ SIB &operator=(const SIB &);
+ int Field;
+};
+SIB &SIB::operator=(const SIB &Other) {
+ Field = Other.Field;
+ foo();
+ return *this;
+}
+
+// Comment inside body.
+struct CIB {
+ CIB(const CIB &Other) : Field(Other.Field) { /* Don't erase this */
+ }
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
+ CIB &operator=(const CIB &);
+ int Field;
+};
+CIB &CIB::operator=(const CIB &Other) {
+ Field = Other.Field;
+ // FIXME: don't erase this comment.
+ return *this;
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:11: warning: use '= default'
+// CHECK-FIXES: CIB &CIB::operator=(const CIB &Other) = default;
+
+// Take non-const reference as argument.
+struct NCRef {
+ NCRef(NCRef &Other) : Field1(Other.Field1), Field2(Other.Field2) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: NCRef(NCRef &Other) = default;
+ NCRef &operator=(NCRef &);
+ int Field1, Field2;
+};
+NCRef &NCRef::operator=(NCRef &Other) {
+ Field1 = Other.Field1;
+ Field2 = Other.Field2;
+ return *this;
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:15: warning: use '= default'
+// CHECK-FIXES: NCRef &NCRef::operator=(NCRef &Other) = default;
+
+// Already defaulted.
+struct IAD {
+ IAD(const IAD &Other) = default;
+ IAD &operator=(const IAD &Other) = default;
+};
+
+struct OAD {
+ OAD(const OAD &Other);
+ OAD &operator=(const OAD &);
+};
+OAD::OAD(const OAD &Other) = default;
+OAD &OAD::operator=(const OAD &Other) = default;
+
+// Deleted.
+struct ID {
+ ID(const ID &Other) = delete;
+ ID &operator=(const ID &Other) = delete;
+};
+
+// Non-reference parameter.
+struct NRef {
+ NRef &operator=(NRef Other);
+ int Field1;
+};
+NRef &NRef::operator=(NRef Other) {
+ Field1 = Other.Field1;
+ return *this;
+}
+
+// RValue reference parameter.
+struct RVR {
+ RVR(RVR &&Other) {}
+ RVR &operator=(RVR &&);
+};
+RVR &RVR::operator=(RVR &&Other) { return *this; }
+
+// Similar function.
+struct SF {
+ SF &foo(const SF &);
+ int Field1;
+};
+SF &SF::foo(const SF &Other) {
+ Field1 = Other.Field1;
+ return *this;
+}
+
+// No return.
+struct NR {
+ NR &operator=(const NR &);
+};
+NR &NR::operator=(const NR &Other) {}
+
+// Return misplaced.
+struct RM {
+ RM &operator=(const RM &);
+ int Field;
+};
+RM &RM::operator=(const RM &Other) {
+ return *this;
+ Field = Other.Field;
+}
+
+// Wrong return value.
+struct WRV {
+ WRV &operator=(WRV &);
+};
+WRV &WRV::operator=(WRV &Other) {
+ return Other;
+}
+
+// Wrong return type.
+struct WRT : IL {
+ IL &operator=(const WRT &);
+};
+IL &WRT::operator=(const WRT &Other) {
+ return *this;
+}
+
+// Try-catch.
+struct ITC {
+ ITC(const ITC &Other)
+ try : Field(Other.Field) {
+ } catch (...) {
+ }
+ ITC &operator=(const ITC &Other) try {
+ Field = Other.Field;
+ } catch (...) {
+ }
+ int Field;
+};
+
+struct OTC {
+ OTC(const OTC &);
+ OTC &operator=(const OTC &);
+ int Field;
+};
+OTC::OTC(const OTC &Other) try : Field(Other.Field) {
+} catch (...) {
+}
+OTC &OTC::operator=(const OTC &Other) try {
+ Field = Other.Field;
+} catch (...) {
+}
+
+// FIXME: the check is not able to detect exception specification.
+// noexcept(true).
+struct NET {
+ // This is the default.
+ //NET(const NET &Other) noexcept {}
+ NET &operator=(const NET &Other) noexcept;
+};
+//NET &NET::operator=(const NET &Other) noexcept { return *this; }
+
+// noexcept(false).
+struct NEF {
+ // This is the default.
+ //NEF(const NEF &Other) noexcept(false) {}
+ NEF &operator=(const NEF &Other) noexcept(false);
+};
+//NEF &NEF::operator=(const NEF &Other) noexcept(false) { return *this; }
+
+#define STRUCT_WITH_COPY_CONSTRUCT(_base, _type) \
+ struct _type { \
+ _type(const _type &v) : value(v.value) {} \
+ _base value; \
+ };
+
+STRUCT_WITH_COPY_CONSTRUCT(unsigned char, Hex8CopyConstruct)
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial copy constructor
+// CHECK-MESSAGES: :[[@LINE-6]]:44: note:
+
+#define STRUCT_WITH_COPY_ASSIGN(_base, _type) \
+ struct _type { \
+ _type &operator=(const _type &rhs) { \
+ value = rhs.value; \
+ return *this; \
+ } \
+ _base value; \
+ };
+
+STRUCT_WITH_COPY_ASSIGN(unsigned char, Hex8CopyAssign)
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial copy-assignment operator
+// CHECK-MESSAGES: :[[@LINE-9]]:40: note:
+
+// Use of braces
+struct UOB{
+ UOB(const UOB &Other):j{Other.j}{}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' to define a trivial copy constructor [modernize-use-equals-default]
+ // CHECK-FIXES: UOB(const UOB &Other)= default;
+ int j;
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-default-delayed.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-default-delayed.cpp
new file mode 100644
index 0000000..953d88a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-default-delayed.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-tidy %s -checks=-*,modernize-use-equals-default -- -std=c++11 -fdelayed-template-parsing -fexceptions | count 0
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+
+template <typename Ty>
+struct S {
+ S<Ty>& operator=(const S<Ty>&) { return *this; }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-default-macros.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-default-macros.cpp
new file mode 100644
index 0000000..2277a86
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-default-macros.cpp
@@ -0,0 +1,13 @@
+// RUN: %check_clang_tidy %s modernize-use-equals-default %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-equals-default.IgnoreMacros, value: 0}]}" \
+// RUN: -- -std=c++11
+
+#define STRUCT_WITH_DEFAULT(_base, _type) \
+ struct _type { \
+ _type() {} \
+ _base value; \
+ };
+
+STRUCT_WITH_DEFAULT(unsigned char, InMacro)
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial default constructor
+// CHECK-MESSAGES: :[[@LINE-6]]:13: note:
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-default.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-default.cpp
new file mode 100644
index 0000000..8fa15ff
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-default.cpp
@@ -0,0 +1,207 @@
+// RUN: %check_clang_tidy %s modernize-use-equals-default %t -- -- -std=c++11 -fno-delayed-template-parsing -fexceptions
+
+// Out of line definition.
+class OL {
+public:
+ OL();
+ ~OL();
+};
+
+OL::OL() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default' to define a trivial default constructor [modernize-use-equals-default]
+// CHECK-FIXES: OL::OL() = default;
+OL::~OL() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default' to define a trivial destructor [modernize-use-equals-default]
+// CHECK-FIXES: OL::~OL() = default;
+
+// Inline definitions.
+class IL {
+public:
+ IL() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: IL() = default;
+ ~IL() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: ~IL() = default;
+};
+
+// Non-empty body.
+void f();
+class NE {
+public:
+ NE() { f(); }
+ ~NE() { f(); }
+};
+
+// Initializer or arguments.
+class IA {
+public:
+ // Constructor with initializer.
+ IA() : Field(5) {}
+ // Constructor with arguments.
+ IA(int Arg1, int Arg2) {}
+ int Field;
+};
+
+// Default member initializer
+class DMI {
+public:
+ DMI() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: DMI() = default;
+ int Field = 5;
+};
+
+// Class member
+class CM {
+public:
+ CM() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: CM() = default;
+ OL o;
+};
+
+// Private constructor/destructor.
+class Priv {
+ Priv() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: Priv() = default;
+ ~Priv() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: ~Priv() = default;
+};
+
+// struct.
+struct ST {
+ ST() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: ST() = default;
+ ~ST() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: ST() = default;
+};
+
+// Deleted constructor/destructor.
+class Del {
+public:
+ Del() = delete;
+ ~Del() = delete;
+};
+
+// Do not remove other keywords.
+class KW {
+public:
+ explicit KW() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use '= default'
+ // CHECK-FIXES: explicit KW() = default;
+ virtual ~KW() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use '= default'
+ // CHECK-FIXES: virtual ~KW() = default;
+};
+
+// Nested class.
+struct N {
+ struct NN {
+ NN() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default'
+ // CHECK-FIXES: NN() = default;
+ ~NN() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default'
+ // CHECK-FIXES: ~NN() = default;
+ };
+ int Int;
+};
+
+// Class template.
+template <class T>
+class Temp {
+public:
+ Temp() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: Temp() = default;
+ ~Temp() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: ~Temp() = default;
+};
+
+// Class template out of line with explicit instantiation.
+template <class T>
+class TempODef {
+public:
+ TempODef();
+ ~TempODef();
+};
+
+template <class T>
+TempODef<T>::TempODef() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use '= default'
+// CHECK-FIXES: TempODef<T>::TempODef() = default;
+template <class T>
+TempODef<T>::~TempODef() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use '= default'
+// CHECK-FIXES: TempODef<T>::~TempODef() = default;
+
+template class TempODef<int>;
+template class TempODef<double>;
+
+// Non user-provided constructor/destructor.
+struct Imp {
+ int Int;
+};
+void g() {
+ Imp *PtrImp = new Imp();
+ PtrImp->~Imp();
+ delete PtrImp;
+}
+
+// Already using default.
+struct IDef {
+ IDef() = default;
+ ~IDef() = default;
+};
+struct ODef {
+ ODef();
+ ~ODef();
+};
+ODef::ODef() = default;
+ODef::~ODef() = default;
+
+// Delegating constructor and overriden destructor.
+struct DC : KW {
+ DC() : KW() {}
+ ~DC() override {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
+ // CHECK-FIXES: ~DC() override = default;
+};
+
+struct Comments {
+ Comments() {
+ // Don't erase comments inside the body.
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use '= default'
+ ~Comments() {
+ // Don't erase comments inside the body.
+ }
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use '= default'
+};
+
+// Try-catch.
+struct ITC {
+ ITC() try {} catch(...) {}
+ ~ITC() try {} catch(...) {}
+};
+
+struct OTC {
+ OTC();
+ ~OTC();
+};
+OTC::OTC() try {} catch(...) {}
+OTC::~OTC() try {} catch(...) {}
+
+#define STRUCT_WITH_DEFAULT(_base, _type) \
+ struct _type { \
+ _type() {} \
+ _base value; \
+ };
+
+STRUCT_WITH_DEFAULT(unsigned char, InMacro)
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-delete.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-delete.cpp
new file mode 100644
index 0000000..6ab2ae4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-equals-delete.cpp
@@ -0,0 +1,187 @@
+// RUN: %check_clang_tidy %s modernize-use-equals-delete %t
+
+struct PositivePrivate {
+private:
+ PositivePrivate();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositivePrivate() = delete;
+ PositivePrivate(const PositivePrivate &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositivePrivate(const PositivePrivate &) = delete;
+ PositivePrivate &operator=(const PositivePrivate &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositivePrivate &operator=(const PositivePrivate &) = delete;
+ PositivePrivate(PositivePrivate &&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositivePrivate(PositivePrivate &&) = delete;
+ PositivePrivate &operator=(PositivePrivate &&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositivePrivate &operator=(PositivePrivate &&) = delete;
+ ~PositivePrivate();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: ~PositivePrivate() = delete;
+};
+
+template<typename T>
+struct PositivePrivateTemplate {
+private:
+ PositivePrivateTemplate();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositivePrivateTemplate() = delete;
+ PositivePrivateTemplate(const PositivePrivateTemplate &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositivePrivateTemplate(const PositivePrivateTemplate &) = delete;
+ PositivePrivateTemplate &operator=(const PositivePrivateTemplate &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositivePrivateTemplate &operator=(const PositivePrivateTemplate &) = delete;
+ PositivePrivateTemplate(PositivePrivateTemplate &&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositivePrivateTemplate(PositivePrivateTemplate &&) = delete;
+ PositivePrivateTemplate &operator=(PositivePrivateTemplate &&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositivePrivateTemplate &operator=(PositivePrivateTemplate &&) = delete;
+ ~PositivePrivateTemplate();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: ~PositivePrivateTemplate() = delete;
+};
+
+template struct PositivePrivateTemplate<int>;
+template struct PositivePrivateTemplate<char>;
+
+struct NegativePublic {
+ NegativePublic(const NegativePublic &);
+};
+
+struct NegativeProtected {
+protected:
+ NegativeProtected(const NegativeProtected &);
+};
+
+struct PositiveInlineMember {
+ int foo() { return 0; }
+
+private:
+ PositiveInlineMember(const PositiveInlineMember &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositiveInlineMember(const PositiveInlineMember &) = delete;
+};
+
+struct PositiveOutOfLineMember {
+ int foo();
+
+private:
+ PositiveOutOfLineMember(const PositiveOutOfLineMember &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositiveOutOfLineMember(const PositiveOutOfLineMember &) = delete;
+};
+
+int PositiveOutOfLineMember::foo() { return 0; }
+
+struct PositiveAbstractMember {
+ virtual int foo() = 0;
+
+private:
+ PositiveAbstractMember(const PositiveAbstractMember &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositiveAbstractMember(const PositiveAbstractMember &) = delete;
+};
+
+struct NegativeMemberNotImpl {
+ int foo();
+
+private:
+ NegativeMemberNotImpl(const NegativeMemberNotImpl &);
+};
+
+struct NegativeStaticMemberNotImpl {
+ static int foo();
+
+private:
+ NegativeStaticMemberNotImpl(const NegativeStaticMemberNotImpl &);
+};
+
+struct NegativeInline {
+private:
+ NegativeInline(const NegativeInline &) {}
+};
+
+struct NegativeOutOfLine {
+private:
+ NegativeOutOfLine(const NegativeOutOfLine &);
+};
+
+NegativeOutOfLine::NegativeOutOfLine(const NegativeOutOfLine &) {}
+
+struct NegativeConstructNotImpl {
+ NegativeConstructNotImpl();
+
+private:
+ NegativeConstructNotImpl(const NegativeConstructNotImpl &);
+};
+
+struct PositiveDefaultedConstruct {
+ PositiveDefaultedConstruct() = default;
+
+private:
+ PositiveDefaultedConstruct(const PositiveDefaultedConstruct &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositiveDefaultedConstruct(const PositiveDefaultedConstruct &) = delete;
+};
+
+struct PositiveDeletedConstruct {
+ PositiveDeletedConstruct() = delete;
+
+private:
+ PositiveDeletedConstruct(const PositiveDeletedConstruct &);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= delete' to prohibit calling of a special member function [modernize-use-equals-delete]
+ // CHECK-FIXES: PositiveDeletedConstruct(const PositiveDeletedConstruct &) = delete;
+};
+
+struct NegativeDefaulted {
+private:
+ NegativeDefaulted(const NegativeDefaulted &) = default;
+};
+
+struct PrivateDeleted {
+private:
+ PrivateDeleted(const PrivateDeleted &) = delete;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: deleted member function should be public [modernize-use-equals-delete]
+};
+
+struct ProtectedDeleted {
+protected:
+ ProtectedDeleted(const ProtectedDeleted &) = delete;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: deleted member function should be public [modernize-use-equals-delete]
+};
+
+struct PublicDeleted {
+public:
+ PublicDeleted(const PublicDeleted &) = delete;
+};
+
+#define M1 \
+ struct PrivateDeletedMacro { \
+ private: \
+ PrivateDeletedMacro(const PrivateDeletedMacro &) = delete; \
+ }; \
+ struct ProtectedDeletedMacro { \
+ protected: \
+ ProtectedDeletedMacro(const ProtectedDeletedMacro &) = delete; \
+ }
+
+M1;
+
+#define DISALLOW_COPY_AND_ASSIGN(name) \
+ name(const name &) = delete; \
+ void operator=(const name &) = delete
+
+struct PrivateDeletedMacro2 {
+private:
+ DISALLOW_COPY_AND_ASSIGN(PrivateDeletedMacro2);
+};
+
+struct ProtectedDeletedMacro2 {
+protected:
+ DISALLOW_COPY_AND_ASSIGN(ProtectedDeletedMacro2);
+};
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-noexcept-macro.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-noexcept-macro.cpp
new file mode 100644
index 0000000..3948b66
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-noexcept-macro.cpp
@@ -0,0 +1,36 @@
+// RUN: %check_clang_tidy %s modernize-use-noexcept %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-noexcept.ReplacementString, value: 'NOEXCEPT'}]}" \
+// RUN: -- -std=c++11 -fexceptions
+
+// Example definition of NOEXCEPT -- simplified test to see if noexcept is supported.
+#if (__has_feature(cxx_noexcept))
+#define NOEXCEPT noexcept
+#else
+#define NOEXCEPT throw()
+#endif
+
+void bar() throw() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: dynamic exception specification 'throw()' is deprecated; consider using 'NOEXCEPT' instead [modernize-use-noexcept]
+// CHECK-FIXES: void bar() NOEXCEPT {}
+
+// Should not trigger a FixItHint, since macros only support noexcept, and this
+// case throws.
+class A {};
+class B {};
+void foobar() throw(A, B);
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: dynamic exception specification 'throw(A, B)' is deprecated; consider removing it instead [modernize-use-noexcept]
+
+// Should not trigger a replacement.
+void foo() noexcept(true);
+
+struct Z {
+ void operator delete(void *ptr) throw();
+ void operator delete[](void *ptr) throw(int);
+ ~Z() throw(int) {}
+};
+// CHECK-MESSAGES: :[[@LINE-4]]:35: warning: dynamic exception specification 'throw()' is deprecated; consider using 'NOEXCEPT' instead [modernize-use-noexcept]
+// CHECK-MESSAGES: :[[@LINE-4]]:37: warning: dynamic exception specification 'throw(int)' is deprecated; consider removing it instead [modernize-use-noexcept]
+// CHECK-MESSAGES: :[[@LINE-4]]:8: warning: dynamic exception specification 'throw(int)' is deprecated; consider removing it instead [modernize-use-noexcept]
+// CHECK-FIXES: void operator delete(void *ptr) NOEXCEPT;
+// CHECK-FIXES: void operator delete[](void *ptr) throw(int);
+// CHECK-FIXES: ~Z() throw(int) {}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-noexcept-opt.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-noexcept-opt.cpp
new file mode 100644
index 0000000..85a83c8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-noexcept-opt.cpp
@@ -0,0 +1,88 @@
+// RUN: %check_clang_tidy %s modernize-use-noexcept %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-noexcept.UseNoexceptFalse, value: 0}]}" \
+// RUN: -- -std=c++11 -fexceptions
+
+class A {};
+class B {};
+
+void foo() throw();
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-FIXES: void foo() noexcept;
+
+void bar() throw(...);
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: dynamic exception specification 'throw(...)' is deprecated; consider removing it instead [modernize-use-noexcept]
+// CHECK-FIXES: void bar() ;
+
+void k() throw(int(int));
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: dynamic exception specification 'throw(int(int))' is deprecated; consider removing it instead [modernize-use-noexcept]
+// CHECK-FIXES: void k() ;
+
+void foobar() throw(A, B)
+{}
+// CHECK-MESSAGES: :[[@LINE-2]]:15: warning: dynamic exception specification 'throw(A, B)' is deprecated; consider removing it instead [modernize-use-noexcept]
+// CHECK-FIXES: void foobar()
+
+void baz(int = (throw A(), 0)) throw(A, B) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: dynamic exception specification 'throw(A, B)' is deprecated; consider removing it instead [modernize-use-noexcept]
+// CHECK-FIXES: void baz(int = (throw A(), 0)) {}
+
+void g(void (*fp)(void) throw());
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-FIXES: void g(void (*fp)(void) noexcept);
+
+void f(void (*fp)(void) throw(int)) throw(char);
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: dynamic exception specification 'throw(int)' is deprecated; consider removing it instead [modernize-use-noexcept]
+// CHECK-MESSAGES: :[[@LINE-2]]:37: warning: dynamic exception specification 'throw(char)' is deprecated; consider removing it instead [modernize-use-noexcept]
+// CHECK-FIXES: void f(void (*fp)(void) ) ;
+
+#define THROW throw
+void h(void (*fp)(void) THROW(int)) THROW(char);
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: dynamic exception specification 'THROW(int)' is deprecated; consider removing it instead [modernize-use-noexcept]
+// CHECK-MESSAGES: :[[@LINE-2]]:37: warning: dynamic exception specification 'THROW(char)' is deprecated; consider removing it instead [modernize-use-noexcept]
+// CHECK-FIXES: void h(void (*fp)(void) ) ;
+
+void j() throw(int(int) throw(void(void) throw(int)));
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: dynamic exception specification 'throw(int(int) throw(void(void) throw(int)))' is deprecated; consider removing it instead [modernize-use-noexcept]
+// CHECK-FIXES: void j() ;
+
+class Y {
+ Y() throw() = default;
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:7: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-FIXES: Y() noexcept = default;
+
+struct Z {
+ void operator delete(void *ptr) throw();
+ void operator delete[](void *ptr) throw(int);
+ ~Z() throw(int) {}
+};
+// CHECK-MESSAGES: :[[@LINE-4]]:35: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-MESSAGES: :[[@LINE-4]]:37: warning: dynamic exception specification 'throw(int)' is deprecated; consider using 'noexcept(false)' instead [modernize-use-noexcept]
+// CHECK-MESSAGES: :[[@LINE-4]]:8: warning: dynamic exception specification 'throw(int)' is deprecated; consider using 'noexcept(false)' instead [modernize-use-noexcept]
+// CHECK-FIXES: void operator delete(void *ptr) noexcept;
+// CHECK-FIXES: void operator delete[](void *ptr) noexcept(false);
+// CHECK-FIXES: ~Z() noexcept(false) {}
+
+struct S {
+ void f() throw();
+};
+void f(void (S::*)() throw());
+// CHECK-MESSAGES: :[[@LINE-3]]:12: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-MESSAGES: :[[@LINE-2]]:22: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-FIXES: void f() noexcept;
+// CHECK-FIXES: void f(void (S::*)() noexcept);
+
+typedef void (*fp)(void (*fp2)(int) throw());
+// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-FIXES: typedef void (*fp)(void (*fp2)(int) noexcept);
+
+// Should not trigger a replacement.
+void titi() noexcept {}
+void toto() noexcept(true) {}
+
+// Should not trigger a replacement.
+void bad()
+#if !__has_feature(cxx_noexcept)
+ throw()
+#endif
+ ;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-noexcept.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-noexcept.cpp
new file mode 100644
index 0000000..58c764a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-noexcept.cpp
@@ -0,0 +1,104 @@
+// RUN: %check_clang_tidy %s modernize-use-noexcept %t -- \
+// RUN: -- -std=c++11 -fexceptions
+
+class A {};
+class B {};
+
+void foo() throw();
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-FIXES: void foo() noexcept;
+
+template <typename T>
+void foo() throw();
+void footest() { foo<int>(); foo<double>(); }
+// CHECK-MESSAGES: :[[@LINE-2]]:12: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-FIXES: void foo() noexcept;
+
+void bar() throw(...);
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: dynamic exception specification 'throw(...)' is deprecated; consider using 'noexcept(false)' instead [modernize-use-noexcept]
+// CHECK-FIXES: void bar() noexcept(false);
+
+void k() throw(int(int));
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: dynamic exception specification 'throw(int(int))' is deprecated; consider using 'noexcept(false)' instead [modernize-use-noexcept]
+// CHECK-FIXES: void k() noexcept(false);
+
+void foobar() throw(A, B)
+{}
+// CHECK-MESSAGES: :[[@LINE-2]]:15: warning: dynamic exception specification 'throw(A, B)' is deprecated; consider using 'noexcept(false)' instead [modernize-use-noexcept]
+// CHECK-FIXES: void foobar() noexcept(false)
+
+void baz(int = (throw A(), 0)) throw(A, B) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: dynamic exception specification 'throw(A, B)' is deprecated; consider using 'noexcept(false)' instead [modernize-use-noexcept]
+// CHECK-FIXES: void baz(int = (throw A(), 0)) noexcept(false) {}
+
+void g(void (*fp)(void) throw());
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-FIXES: void g(void (*fp)(void) noexcept);
+
+void f(void (*fp)(void) throw(int)) throw(char);
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: dynamic exception specification 'throw(int)' is deprecated; consider using 'noexcept(false)' instead [modernize-use-noexcept]
+// CHECK-MESSAGES: :[[@LINE-2]]:37: warning: dynamic exception specification 'throw(char)' is deprecated; consider using 'noexcept(false)' instead [modernize-use-noexcept]
+// CHECK-FIXES: void f(void (*fp)(void) noexcept(false)) noexcept(false);
+
+#define THROW throw
+void h(void (*fp)(void) THROW(int)) THROW(char);
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: dynamic exception specification 'THROW(int)' is deprecated; consider using 'noexcept(false)' instead [modernize-use-noexcept]
+// CHECK-MESSAGES: :[[@LINE-2]]:37: warning: dynamic exception specification 'THROW(char)' is deprecated; consider using 'noexcept(false)' instead [modernize-use-noexcept]
+// CHECK-FIXES: void h(void (*fp)(void) noexcept(false)) noexcept(false);
+
+void j() throw(int(int) throw(void(void) throw(int)));
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: dynamic exception specification 'throw(int(int) throw(void(void) throw(int)))' is deprecated; consider using 'noexcept(false)' instead [modernize-use-noexcept]
+// CHECK-FIXES: void j() noexcept(false);
+
+class Y {
+ Y() throw() = default;
+};
+// CHECK-MESSAGES: :[[@LINE-2]]:7: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-FIXES: Y() noexcept = default;
+
+struct Z {
+ void operator delete(void *ptr) throw();
+ void operator delete[](void *ptr) throw(int);
+ ~Z() throw(int) {}
+};
+// CHECK-MESSAGES: :[[@LINE-4]]:35: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-MESSAGES: :[[@LINE-4]]:37: warning: dynamic exception specification 'throw(int)' is deprecated; consider using 'noexcept(false)' instead [modernize-use-noexcept]
+// CHECK-MESSAGES: :[[@LINE-4]]:8: warning: dynamic exception specification 'throw(int)' is deprecated; consider using 'noexcept(false)' instead [modernize-use-noexcept]
+// CHECK-FIXES: void operator delete(void *ptr) noexcept;
+// CHECK-FIXES: void operator delete[](void *ptr) noexcept(false);
+// CHECK-FIXES: ~Z() noexcept(false) {}
+
+struct S {
+ void f() throw();
+};
+void f(void (S::*)() throw());
+// CHECK-MESSAGES: :[[@LINE-3]]:12: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-MESSAGES: :[[@LINE-2]]:22: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-FIXES: void f() noexcept;
+// CHECK-FIXES: void f(void (S::*)() noexcept);
+
+template <typename T>
+struct ST {
+ void foo() throw();
+};
+template <typename T>
+void ft(void (ST<T>::*)() throw());
+// CHECK-MESSAGES: :[[@LINE-4]]:14: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-MESSAGES: :[[@LINE-2]]:27: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-FIXES: void foo() noexcept;
+// CHECK-FIXES: void ft(void (ST<T>::*)() noexcept);
+
+typedef void (*fp)(void (*fp2)(int) throw());
+// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: dynamic exception specification 'throw()' is deprecated; consider using 'noexcept' instead [modernize-use-noexcept]
+// CHECK-FIXES: typedef void (*fp)(void (*fp2)(int) noexcept);
+
+// Should not trigger a replacement.
+void titi() noexcept {}
+void toto() noexcept(true) {}
+
+// Should not trigger a replacement.
+void bad()
+#if !__has_feature(cxx_noexcept)
+ throw()
+#endif
+ ;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-nullptr-basic.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-nullptr-basic.cpp
new file mode 100644
index 0000000..7a953a7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-nullptr-basic.cpp
@@ -0,0 +1,361 @@
+// RUN: %check_clang_tidy %s modernize-use-nullptr %t -- -- \
+// RUN: -std=c++98 -Wno-non-literal-null-conversion
+//
+// Some parts of the test (e.g. assignment of `const int` to `int *`) fail in
+// C++11, so we need to run the test in C++98 mode.
+
+const unsigned int g_null = 0;
+#define NULL 0
+
+void test_assignment() {
+ int *p1 = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr [modernize-use-nullptr]
+ // CHECK-FIXES: int *p1 = nullptr;
+ p1 = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr
+ // CHECK-FIXES: p1 = nullptr;
+
+ int *p2 = NULL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
+ // CHECK-FIXES: int *p2 = nullptr;
+
+ p2 = p1;
+ // CHECK-FIXES: p2 = p1;
+
+ const int null = 0;
+ int *p3 = null;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
+ // CHECK-FIXES: int *p3 = nullptr;
+
+ p3 = NULL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr
+ // CHECK-FIXES: p3 = nullptr;
+
+ int *p4 = p3;
+ // CHECK-FIXES: int *p4 = p3;
+
+ p4 = null;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr
+ // CHECK-FIXES: p4 = nullptr;
+
+ int i1 = 0;
+
+ int i2 = NULL;
+
+ int i3 = null;
+
+ int *p5, *p6, *p7;
+ p5 = p6 = p7 = NULL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr
+ // CHECK-FIXES: p5 = p6 = p7 = nullptr;
+}
+
+struct Foo {
+ Foo(int *p = NULL) : m_p1(p) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr
+ // CHECK-FIXES: Foo(int *p = nullptr) : m_p1(p) {}
+
+ void bar(int *p = 0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use nullptr
+ // CHECK-FIXES: void bar(int *p = nullptr) {}
+
+ void baz(int i = 0) {}
+
+ int *m_p1;
+ static int *m_p2;
+};
+
+int *Foo::m_p2 = NULL;
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr
+// CHECK-FIXES: int *Foo::m_p2 = nullptr;
+
+template <typename T>
+struct Bar {
+ Bar(T *p) : m_p(p) {
+ m_p = static_cast<T*>(NULL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use nullptr
+ // CHECK-FIXES: m_p = static_cast<T*>(nullptr);
+
+ m_p = static_cast<T*>(reinterpret_cast<int*>((void*)NULL));
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use nullptr
+ // CHECK-FIXES: m_p = static_cast<T*>(nullptr);
+
+ m_p = static_cast<T*>(p ? p : static_cast<void*>(g_null));
+ // CHECK-MESSAGES: :[[@LINE-1]]:54: warning: use nullptr
+ // CHECK-FIXES: m_p = static_cast<T*>(p ? p : static_cast<void*>(nullptr));
+
+ T *p2 = static_cast<T*>(reinterpret_cast<int*>((void*)NULL));
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use nullptr
+ // CHECK-FIXES: T *p2 = static_cast<T*>(nullptr);
+
+ m_p = NULL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use nullptr
+ // CHECK-FIXES: m_p = nullptr;
+
+ int i = static_cast<int>(0.f);
+ T *i2 = static_cast<int>(0.f);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
+ // CHECK-FIXES: T *i2 = nullptr;
+ }
+
+ T *m_p;
+};
+
+struct Baz {
+ Baz() : i(0) {}
+ int i;
+};
+
+void test_cxx_cases() {
+ Foo f(g_null);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr
+ // CHECK-FIXES: Foo f(nullptr);
+
+ f.bar(NULL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr
+ // CHECK-FIXES: f.bar(nullptr);
+
+ f.baz(g_null);
+
+ f.m_p1 = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr
+ // CHECK-FIXES: f.m_p1 = nullptr;
+
+ Bar<int> b(g_null);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use nullptr
+ // CHECK-FIXES: Bar<int> b(nullptr);
+
+ Baz b2;
+ int Baz::*memptr(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use nullptr
+ // CHECK-FIXES: int Baz::*memptr(nullptr);
+
+ memptr = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr
+ // CHECK-FIXES: memptr = nullptr;
+}
+
+void test_function_default_param1(void *p = 0);
+// CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use nullptr
+// CHECK-FIXES: void test_function_default_param1(void *p = nullptr);
+
+void test_function_default_param2(void *p = NULL);
+// CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use nullptr
+// CHECK-FIXES: void test_function_default_param2(void *p = nullptr);
+
+void test_function_default_param3(void *p = g_null);
+// CHECK-MESSAGES: :[[@LINE-1]]:45: warning: use nullptr
+// CHECK-FIXES: void test_function_default_param3(void *p = nullptr);
+
+void test_function(int *p) {}
+
+void test_function_no_ptr_param(int i) {}
+
+void test_function_call() {
+ test_function(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr
+ // CHECK-FIXES: test_function(nullptr);
+
+ test_function(NULL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr
+ // CHECK-FIXES: test_function(nullptr);
+
+ test_function(g_null);
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr
+ // CHECK-FIXES: test_function(nullptr);
+
+ test_function_no_ptr_param(0);
+}
+
+char *test_function_return1() {
+ return 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
+ // CHECK-FIXES: return nullptr;
+}
+
+void *test_function_return2() {
+ return NULL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
+ // CHECK-FIXES: return nullptr;
+}
+
+long *test_function_return3() {
+ return g_null;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
+ // CHECK-FIXES: return nullptr;
+}
+
+int test_function_return4() {
+ return 0;
+}
+
+int test_function_return5() {
+ return NULL;
+}
+
+int test_function_return6() {
+ return g_null;
+}
+
+int *test_function_return_cast1() {
+ return(int)0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr
+ // CHECK-FIXES: return nullptr;
+}
+
+int *test_function_return_cast2() {
+#define RET return
+ RET(int)0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use nullptr
+ // CHECK-FIXES: RET nullptr;
+#undef RET
+}
+
+// Test parentheses expressions resulting in a nullptr.
+int *test_parentheses_expression1() {
+ return(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
+ // CHECK-FIXES: return(nullptr);
+}
+
+int *test_parentheses_expression2() {
+ return(int(0.f));
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr
+ // CHECK-FIXES: return(nullptr);
+}
+
+int *test_nested_parentheses_expression() {
+ return((((0))));
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
+ // CHECK-FIXES: return((((nullptr))));
+}
+
+void *test_parentheses_explicit_cast() {
+ return(static_cast<void*>(0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use nullptr
+ // CHECK-FIXES: return(static_cast<void*>(nullptr));
+}
+
+void *test_parentheses_explicit_cast_sequence1() {
+ return(static_cast<void*>(static_cast<int*>((void*)NULL)));
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use nullptr
+ // CHECK-FIXES: return(static_cast<void*>(nullptr));
+}
+
+void *test_parentheses_explicit_cast_sequence2() {
+ return(static_cast<void*>(reinterpret_cast<int*>((float*)int(0.f))));
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use nullptr
+ // CHECK-FIXES: return(static_cast<void*>(nullptr));
+}
+
+// Test explicit cast expressions resulting in nullptr.
+struct Bam {
+ Bam(int *a) {}
+ Bam(float *a) {}
+ Bam operator=(int *a) { return Bam(a); }
+ Bam operator=(float *a) { return Bam(a); }
+};
+
+void ambiguous_function(int *a) {}
+void ambiguous_function(float *a) {}
+void const_ambiguous_function(const int *p) {}
+void const_ambiguous_function(const float *p) {}
+
+void test_explicit_cast_ambiguous1() {
+ ambiguous_function((int*)0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use nullptr
+ // CHECK-FIXES: ambiguous_function((int*)nullptr);
+}
+
+void test_explicit_cast_ambiguous2() {
+ ambiguous_function((int*)(0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use nullptr
+ // CHECK-FIXES: ambiguous_function((int*)nullptr);
+}
+
+void test_explicit_cast_ambiguous3() {
+ ambiguous_function(static_cast<int*>(reinterpret_cast<int*>((float*)0)));
+ // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: use nullptr
+ // CHECK-FIXES: ambiguous_function(static_cast<int*>(nullptr));
+}
+
+Bam test_explicit_cast_ambiguous4() {
+ return(((int*)(0)));
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr
+ // CHECK-FIXES: return(((int*)nullptr));
+}
+
+void test_explicit_cast_ambiguous5() {
+ // Test for ambiguous overloaded constructors.
+ Bam k((int*)(0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use nullptr
+ // CHECK-FIXES: Bam k((int*)nullptr);
+
+ // Test for ambiguous overloaded operators.
+ k = (int*)0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr
+ // CHECK-FIXES: k = (int*)nullptr;
+}
+
+void test_const_pointers_abiguous() {
+ const_ambiguous_function((int*)0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: use nullptr
+ // CHECK-FIXES: const_ambiguous_function((int*)nullptr);
+}
+
+// Test where the implicit cast to null is surrounded by another implict cast
+// with possible explict casts in-between.
+void test_const_pointers() {
+ const int *const_p1 = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr
+ // CHECK-FIXES: const int *const_p1 = nullptr;
+ const int *const_p2 = NULL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr
+ // CHECK-FIXES: const int *const_p2 = nullptr;
+ const int *const_p3 = (int)0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr
+ // CHECK-FIXES: const int *const_p3 = nullptr;
+ const int *const_p4 = (int)0.0f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr
+ // CHECK-FIXES: const int *const_p4 = nullptr;
+ const int *const_p5 = (int*)0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: use nullptr
+ // CHECK-FIXES: const int *const_p5 = (int*)nullptr;
+ int *t;
+ const int *const_p6 = static_cast<int*>(t ? t : static_cast<int*>(0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:69: warning: use nullptr
+ // CHECK-FIXES: const int *const_p6 = static_cast<int*>(t ? t : static_cast<int*>(nullptr));
+}
+
+void test_nested_implicit_cast_expr() {
+ int func0(void*, void*);
+ int func1(int, void*, void*);
+
+ (double)func1(0, 0, 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use nullptr
+ // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: use nullptr
+ // CHECK-FIXES: (double)func1(0, nullptr, nullptr);
+ (double)func1(func0(0, 0), 0, 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use nullptr
+ // CHECK-MESSAGES: :[[@LINE-2]]:26: warning: use nullptr
+ // CHECK-MESSAGES: :[[@LINE-3]]:30: warning: use nullptr
+ // CHECK-MESSAGES: :[[@LINE-4]]:33: warning: use nullptr
+ // CHECK-FIXES: (double)func1(func0(nullptr, nullptr), nullptr, nullptr);
+}
+
+// FIXME: currently, the check doesn't work as it should with templates.
+template<typename T>
+class A {
+ public:
+ A(T *p = NULL) {}
+
+ void f() {
+ Ptr = NULL;
+ }
+ T *Ptr;
+};
+
+template<typename T>
+T *f2(T *a = NULL) {
+ return a ? a : NULL;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-nullptr.c b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-nullptr.c
new file mode 100644
index 0000000..c2ccbbd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-nullptr.c
@@ -0,0 +1,10 @@
+// RUN: clang-tidy %s -checks=-*,modernize-use-nullptr -- | count 0
+
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+
+#define NULL 0
+void f(void) {
+ char *str = NULL; // ok
+ (void)str;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-nullptr.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-nullptr.cpp
new file mode 100644
index 0000000..878c114
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-nullptr.cpp
@@ -0,0 +1,305 @@
+// RUN: %check_clang_tidy %s modernize-use-nullptr %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-nullptr.NullMacros, value: 'MY_NULL,NULL'}]}" \
+// RUN: -- -std=c++11
+
+#define NULL 0
+
+namespace std {
+
+typedef decltype(nullptr) nullptr_t;
+
+} // namespace std
+
+// Just to make sure make_null() could have side effects.
+void external();
+
+std::nullptr_t make_null() {
+ external();
+ return nullptr;
+}
+
+void func() {
+ void *CallTest = make_null();
+
+ int var = 1;
+ void *CommaTest = (var+=2, make_null());
+
+ int *CastTest = static_cast<int*>(make_null());
+}
+
+void dummy(int*) {}
+void side_effect() {}
+
+#define MACRO_EXPANSION_HAS_NULL \
+ void foo() { \
+ dummy(0); \
+ dummy(NULL); \
+ side_effect(); \
+ }
+
+MACRO_EXPANSION_HAS_NULL;
+#undef MACRO_EXPANSION_HAS_NULL
+
+
+void test_macro_expansion1() {
+#define MACRO_EXPANSION_HAS_NULL \
+ dummy(NULL); \
+ side_effect();
+
+ MACRO_EXPANSION_HAS_NULL;
+
+#undef MACRO_EXPANSION_HAS_NULL
+}
+
+// Test macro expansion with cast sequence, PR15572.
+void test_macro_expansion2() {
+#define MACRO_EXPANSION_HAS_NULL \
+ dummy((int*)0); \
+ side_effect();
+
+ MACRO_EXPANSION_HAS_NULL;
+
+#undef MACRO_EXPANSION_HAS_NULL
+}
+
+void test_macro_expansion3() {
+#define MACRO_EXPANSION_HAS_NULL \
+ dummy(NULL); \
+ side_effect();
+
+#define OUTER_MACRO \
+ MACRO_EXPANSION_HAS_NULL; \
+ side_effect();
+
+ OUTER_MACRO;
+
+#undef OUTER_MACRO
+#undef MACRO_EXPANSION_HAS_NULL
+}
+
+void test_macro_expansion4() {
+#define MY_NULL NULL
+ int *p = MY_NULL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr [modernize-use-nullptr]
+ // CHECK-FIXES: int *p = nullptr;
+#undef MY_NULL
+}
+
+#define IS_EQ(x, y) if (x != y) return;
+void test_macro_args() {
+ int i = 0;
+ int *Ptr;
+
+ IS_EQ(static_cast<int*>(0), Ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use nullptr
+ // CHECK-FIXES: IS_EQ(static_cast<int*>(nullptr), Ptr);
+
+ IS_EQ(0, Ptr); // literal
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr
+ // CHECK-FIXES: IS_EQ(nullptr, Ptr);
+
+ IS_EQ(NULL, Ptr); // macro
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr
+ // CHECK-FIXES: IS_EQ(nullptr, Ptr);
+
+ // These are ok since the null literal is not spelled within a macro.
+#define myassert(x) if (!(x)) return;
+ myassert(0 == Ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr
+ // CHECK-FIXES: myassert(nullptr == Ptr);
+
+ myassert(NULL == Ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use nullptr
+ // CHECK-FIXES: myassert(nullptr == Ptr);
+
+ // These are bad as the null literal is buried in a macro.
+#define BLAH(X) myassert(0 == (X));
+#define BLAH2(X) myassert(NULL == (X));
+ BLAH(Ptr);
+ BLAH2(Ptr);
+
+ // Same as above but testing extra macro expansion.
+#define EXPECT_NULL(X) IS_EQ(0, X);
+#define EXPECT_NULL2(X) IS_EQ(NULL, X);
+ EXPECT_NULL(Ptr);
+ EXPECT_NULL2(Ptr);
+
+ // Almost the same as above but now null literal is not in a macro so ok
+ // to transform.
+#define EQUALS_PTR(X) IS_EQ(X, Ptr);
+ EQUALS_PTR(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use nullptr
+ // CHECK-FIXES: EQUALS_PTR(nullptr);
+ EQUALS_PTR(NULL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use nullptr
+ // CHECK-FIXES: EQUALS_PTR(nullptr);
+
+ // Same as above but testing extra macro expansion.
+#define EQUALS_PTR_I(X) EQUALS_PTR(X)
+ EQUALS_PTR_I(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr
+ // CHECK-FIXES: EQUALS_PTR_I(nullptr);
+ EQUALS_PTR_I(NULL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr
+ // CHECK-FIXES: EQUALS_PTR_I(nullptr);
+
+ // Ok since null literal not within macro. However, now testing macro
+ // used as arg to another macro.
+#define decorate(EXPR) side_effect(); EXPR;
+ decorate(IS_EQ(NULL, Ptr));
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr
+ // CHECK-FIXES: decorate(IS_EQ(nullptr, Ptr));
+ decorate(IS_EQ(0, Ptr));
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr
+ // CHECK-FIXES: decorate(IS_EQ(nullptr, Ptr));
+
+ // This macro causes a NullToPointer cast to happen where 0 is assigned to z
+ // but the 0 literal cannot be replaced because it is also used as an
+ // integer in the comparison.
+#define INT_AND_PTR_USE(X) do { int *z = X; if (X == 4) break; } while(false)
+ INT_AND_PTR_USE(0);
+
+ // Both uses of X in this case result in NullToPointer casts so replacement
+ // is possible.
+#define PTR_AND_PTR_USE(X) do { int *z = X; if (X != z) break; } while(false)
+ PTR_AND_PTR_USE(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr
+ // CHECK-FIXES: PTR_AND_PTR_USE(nullptr);
+ PTR_AND_PTR_USE(NULL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr
+ // CHECK-FIXES: PTR_AND_PTR_USE(nullptr);
+
+#define OPTIONAL_CODE(...) __VA_ARGS__
+#define NOT_NULL dummy(0)
+#define CALL(X) X
+ OPTIONAL_CODE(NOT_NULL);
+ CALL(NOT_NULL);
+
+#define ENTRY(X) {X}
+ struct A {
+ int *Ptr;
+ } a[2] = {ENTRY(0), {0}};
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr
+ // CHECK-MESSAGES: :[[@LINE-2]]:24: warning: use nullptr
+ // CHECK-FIXES: a[2] = {ENTRY(nullptr), {nullptr}};
+#undef ENTRY
+
+#define assert1(expr) (expr) ? 0 : 1
+#define assert2 assert1
+ int *p;
+ assert2(p == 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr
+ // CHECK-FIXES: assert2(p == nullptr);
+ assert2(p == NULL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr
+ // CHECK-FIXES: assert2(p == nullptr);
+#undef assert2
+#undef assert1
+
+#define ASSERT_EQ(a, b) a == b
+#define ASSERT_NULL(x) ASSERT_EQ(static_cast<void *>(NULL), x)
+ int *pp;
+ ASSERT_NULL(pp);
+ ASSERT_NULL(NULL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use nullptr
+ // CHECK-FIXES: ASSERT_NULL(nullptr);
+#undef ASSERT_NULL
+#undef ASSERT_EQ
+}
+
+// One of the ancestor of the cast is a NestedNameSpecifierLoc.
+class NoDef;
+char function(NoDef *p);
+#define F(x) (sizeof(function(x)) == 1)
+template<class T, T t>
+class C {};
+C<bool, F(0)> c;
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use nullptr
+// CHECK-FIXES: C<bool, F(nullptr)> c;
+#undef F
+
+// Test default argument expression.
+struct D {
+ explicit D(void *t, int *c = NULL) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: use nullptr
+ // CHECK-FIXES: explicit D(void *t, int *c = nullptr) {}
+};
+
+void test_default_argument() {
+ D(nullptr);
+}
+
+// Test on two neighbour CXXDefaultArgExprs nodes.
+typedef unsigned long long uint64;
+struct ZZ {
+ explicit ZZ(uint64, const uint64* = NULL) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:39: warning: use nullptr
+// CHECK-FIXES: explicit ZZ(uint64, const uint64* = nullptr) {}
+ operator bool() { return true; }
+};
+
+uint64 Hash(uint64 seed = 0) { return 0; }
+
+void f() {
+ bool a;
+ a = ZZ(Hash());
+}
+
+// Test on ignoring substituted template types.
+template<typename T>
+class TemplateClass {
+ public:
+ explicit TemplateClass(int a, T default_value = 0) {}
+
+ void h(T *default_value = 0) {}
+
+ void f(int* p = 0) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use nullptr
+// CHECK-FIXES: void f(int* p = nullptr) {}
+};
+
+void IgnoreSubstTemplateType() {
+ TemplateClass<int*> a(1);
+}
+
+// Test on casting nullptr.
+struct G {
+ explicit G(bool, const char * = NULL) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use nullptr
+ // CHECK-FIXES: explicit G(bool, const char * = nullptr) {}
+};
+bool g(const char*);
+void test_cast_nullptr() {
+ G(g(nullptr));
+ G(g((nullptr)));
+ G(g(static_cast<char*>(nullptr)));
+ G(g(static_cast<const char*>(nullptr)));
+}
+
+// Test on recognizing multiple NULLs.
+class H {
+public:
+ H(bool);
+};
+
+#define T(expression) H(expression);
+bool h(int *, int *, int * = nullptr);
+void test_multiple_nulls() {
+ T(h(NULL, NULL));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use nullptr
+// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: use nullptr
+// CHECK-FIXES: T(h(nullptr, nullptr));
+ T(h(NULL, nullptr));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use nullptr
+// CHECK-FIXES: T(h(nullptr, nullptr));
+ T(h(nullptr, NULL));
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use nullptr
+// CHECK-FIXES: T(h(nullptr, nullptr));
+ T(h(nullptr, nullptr));
+ T(h(NULL, NULL, NULL));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use nullptr
+// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: use nullptr
+// CHECK-MESSAGES: :[[@LINE-3]]:19: warning: use nullptr
+// CHECK-FIXES: T(h(nullptr, nullptr, nullptr));
+}
+#undef T
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-override-cxx98.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-override-cxx98.cpp
new file mode 100644
index 0000000..bc162d6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-override-cxx98.cpp
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy %s modernize-use-override %t -- -- -std=c++98
+
+struct Base {
+ virtual ~Base() {}
+ virtual void a();
+ virtual void b();
+};
+
+struct SimpleCases : public Base {
+public:
+ virtual ~SimpleCases();
+ // CHECK-FIXES: {{^}} virtual ~SimpleCases();
+
+ void a();
+ // CHECK-FIXES: {{^}} void a();
+
+ virtual void b();
+ // CHECK-FIXES: {{^}} virtual void b();
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-override-ms.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-override-ms.cpp
new file mode 100644
index 0000000..0cee917
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-override-ms.cpp
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s modernize-use-override %t -- -- -fms-extensions -std=c++11
+
+// This test is designed to test ms-extension __declspec(dllexport) attributes.
+#define EXPORT __declspec(dllexport)
+
+class Base {
+ virtual EXPORT void a();
+};
+
+class EXPORT InheritedBase {
+ virtual void a();
+};
+
+class Derived : public Base {
+ virtual EXPORT void a();
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: prefer using 'override' or (rarely) 'final' instead of 'virtual' [modernize-use-override]
+ // CHECK-FIXES: {{^}} EXPORT void a() override;
+};
+
+class EXPORT InheritedDerived : public InheritedBase {
+ virtual void a();
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using 'override' or (rarely) 'final' instead of 'virtual' [modernize-use-override]
+ // CHECK-FIXES: {{^}} void a() override;
+};
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-override.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-override.cpp
new file mode 100644
index 0000000..24aafe5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-override.cpp
@@ -0,0 +1,318 @@
+// RUN: %check_clang_tidy %s modernize-use-override %t -- -- -std=c++11 -fexceptions
+
+#define ABSTRACT = 0
+
+#define OVERRIDE override
+#define VIRTUAL virtual
+#define NOT_VIRTUAL
+#define NOT_OVERRIDE
+
+#define MUST_USE_RESULT __attribute__((warn_unused_result))
+#define UNUSED __attribute__((unused))
+
+struct MUST_USE_RESULT MustUseResultObject {};
+
+struct IntPair {
+ int First, Second;
+};
+
+struct Base {
+ virtual ~Base() {}
+ virtual void a();
+ virtual void b();
+ virtual void c();
+ virtual void d();
+ virtual void d2();
+ virtual void e() = 0;
+ virtual void f() = 0;
+ virtual void f2() const = 0;
+ virtual void g() = 0;
+
+ virtual void j() const;
+ virtual MustUseResultObject k();
+ virtual bool l() MUST_USE_RESULT UNUSED;
+ virtual bool n() MUST_USE_RESULT UNUSED;
+
+ virtual void m();
+ virtual void m2();
+ virtual void o() __attribute__((unused));
+
+ virtual void r() &;
+ virtual void rr() &&;
+
+ virtual void cv() const volatile;
+ virtual void cv2() const volatile;
+
+ virtual void ne() noexcept(false);
+ virtual void t() throw();
+
+ virtual void il(IntPair);
+};
+
+struct SimpleCases : public Base {
+public:
+ virtual ~SimpleCases();
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: prefer using 'override' or (rarely) 'final' instead of 'virtual' [modernize-use-override]
+ // CHECK-FIXES: {{^}} ~SimpleCases() override;
+
+ void a();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: annotate this
+ // CHECK-FIXES: {{^}} void a() override;
+
+ void b() override;
+ // CHECK-MESSAGES-NOT: warning:
+ // CHECK-FIXES: {{^}} void b() override;
+
+ virtual void c();
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void c() override;
+
+ virtual void d() override;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'virtual' is redundant since the function is already declared 'override'
+ // CHECK-FIXES: {{^}} void d() override;
+
+ virtual void d2() final;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'virtual' is redundant since the function is already declared 'final'
+ // CHECK-FIXES: {{^}} void d2() final;
+
+ virtual void e() = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void e() override = 0;
+
+ virtual void f()=0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void f() override =0;
+
+ virtual void f2() const=0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void f2() const override =0;
+
+ virtual void g() ABSTRACT;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void g() override ABSTRACT;
+
+ virtual void j() const;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void j() const override;
+
+ virtual MustUseResultObject k(); // Has an implicit attribute.
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: prefer using
+ // CHECK-FIXES: {{^}} MustUseResultObject k() override;
+
+ virtual bool l() MUST_USE_RESULT UNUSED;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} bool l() override MUST_USE_RESULT UNUSED;
+
+ virtual bool n() UNUSED MUST_USE_RESULT;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} bool n() override UNUSED MUST_USE_RESULT;
+
+ void m() override final;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: 'override' is redundant since the function is already declared 'final'
+ // CHECK-FIXES: {{^}} void m() final;
+
+ virtual void m2() override final;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'virtual' and 'override' are redundant since the function is already declared 'final'
+ // CHECK-FIXES: {{^}} void m2() final;
+
+ virtual void o() __attribute__((unused));
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void o() override __attribute__((unused));
+
+ virtual void ne() noexcept(false);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void ne() noexcept(false) override;
+
+ virtual void t() throw();
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void t() throw() override;
+};
+
+// CHECK-MESSAGES-NOT: warning:
+
+void SimpleCases::c() {}
+// CHECK-FIXES: {{^}}void SimpleCases::c() {}
+
+SimpleCases::~SimpleCases() {}
+// CHECK-FIXES: {{^}}SimpleCases::~SimpleCases() {}
+
+struct DefaultedDestructor : public Base {
+ DefaultedDestructor() {}
+ virtual ~DefaultedDestructor() = default;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: prefer using
+ // CHECK-FIXES: {{^}} ~DefaultedDestructor() override = default;
+};
+
+struct FinalSpecified : public Base {
+public:
+ virtual ~FinalSpecified() final;
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: 'virtual' is redundant since the function is already declared 'final'
+ // CHECK-FIXES: {{^}} ~FinalSpecified() final;
+
+ void b() final;
+ // CHECK-MESSAGES-NOT: warning:
+ // CHECK-FIXES: {{^}} void b() final;
+
+ virtual void d() final;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'virtual' is redundant
+ // CHECK-FIXES: {{^}} void d() final;
+
+ virtual void e() final = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'virtual' is redundant
+ // CHECK-FIXES: {{^}} void e() final = 0;
+
+ virtual void j() const final;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'virtual' is redundant
+ // CHECK-FIXES: {{^}} void j() const final;
+
+ virtual bool l() final MUST_USE_RESULT UNUSED;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'virtual' is redundant
+ // CHECK-FIXES: {{^}} bool l() final MUST_USE_RESULT UNUSED;
+};
+
+struct InlineDefinitions : public Base {
+public:
+ virtual ~InlineDefinitions() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: prefer using
+ // CHECK-FIXES: {{^}} ~InlineDefinitions() override {}
+
+ void a() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: annotate this
+ // CHECK-FIXES: {{^}} void a() override {}
+
+ void b() override {}
+ // CHECK-MESSAGES-NOT: warning:
+ // CHECK-FIXES: {{^}} void b() override {}
+
+ virtual void c()
+ {}
+ // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void c() override
+
+ virtual void d() override {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'virtual' is redundant
+ // CHECK-FIXES: {{^}} void d() override {}
+
+ virtual void j() const
+ {}
+ // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void j() const override
+
+ virtual MustUseResultObject k() {} // Has an implicit attribute.
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: prefer using
+ // CHECK-FIXES: {{^}} MustUseResultObject k() override {}
+
+ virtual bool l() MUST_USE_RESULT UNUSED {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} bool l() override MUST_USE_RESULT UNUSED {}
+
+ virtual void r() &
+ {}
+ // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void r() & override
+
+ virtual void rr() &&
+ {}
+ // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void rr() && override
+
+ virtual void cv() const volatile
+ {}
+ // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void cv() const volatile override
+
+ virtual void cv2() const volatile // some comment
+ {}
+ // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void cv2() const volatile override // some comment
+};
+
+struct DefaultArguments : public Base {
+ // Tests for default arguments (with initializer lists).
+ // Make sure the override fix is placed after the argument list.
+ void il(IntPair p = {1, (2 + (3))}) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: annotate this
+ // CHECK-FIXES: {{^}} void il(IntPair p = {1, (2 + (3))}) override {}
+};
+
+struct Macros : public Base {
+ // Tests for 'virtual' and 'override' being defined through macros. Basically
+ // give up for now.
+ NOT_VIRTUAL void a() NOT_OVERRIDE;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: annotate this
+ // CHECK-FIXES: {{^}} NOT_VIRTUAL void a() override NOT_OVERRIDE;
+
+ VIRTUAL void b() NOT_OVERRIDE;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} VIRTUAL void b() override NOT_OVERRIDE;
+
+ NOT_VIRTUAL void c() OVERRIDE;
+ // CHECK-MESSAGES-NOT: warning:
+ // CHECK-FIXES: {{^}} NOT_VIRTUAL void c() OVERRIDE;
+
+ VIRTUAL void d() OVERRIDE;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'virtual' is redundant
+ // CHECK-FIXES: {{^}} VIRTUAL void d() OVERRIDE;
+
+#define FUNC(return_type, name) return_type name()
+ FUNC(void, e);
+ // CHECK-FIXES: {{^}} FUNC(void, e);
+
+#define F virtual void f();
+ F
+ // CHECK-FIXES: {{^}} F
+
+ VIRTUAL void g() OVERRIDE final;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: 'virtual' and 'override' are redundant
+ // CHECK-FIXES: {{^}} VIRTUAL void g() final;
+};
+
+// Tests for templates.
+template <typename T> struct TemplateBase {
+ virtual void f(T t);
+};
+
+template <typename T> struct DerivedFromTemplate : public TemplateBase<T> {
+ virtual void f(T t);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void f(T t) override;
+};
+void f() { DerivedFromTemplate<int>().f(2); }
+
+template <class C>
+struct UnusedMemberInstantiation : public C {
+ virtual ~UnusedMemberInstantiation() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: prefer using
+ // CHECK-FIXES: {{^}} ~UnusedMemberInstantiation() override {}
+};
+struct IntantiateWithoutUse : public UnusedMemberInstantiation<Base> {};
+
+struct Base2 {
+ virtual ~Base2() {}
+ virtual void a();
+};
+
+// The OverrideAttr isn't propagated to specializations in all cases. Make sure
+// we don't add "override" a second time.
+template <int I>
+struct MembersOfSpecializations : public Base2 {
+ void a() override;
+ // CHECK-MESSAGES-NOT: warning:
+ // CHECK-FIXES: {{^}} void a() override;
+};
+template <> void MembersOfSpecializations<3>::a() {}
+void ff() { MembersOfSpecializations<3>().a(); };
+
+// In case try statement is used as a method body,
+// make sure that override fix is placed before try keyword.
+struct TryStmtAsBody : public Base {
+ void a() try
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: annotate this
+ // CHECK-FIXES: {{^}} void a() override try
+ { b(); } catch(...) { c(); }
+
+ virtual void d() try
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
+ // CHECK-FIXES: {{^}} void d() override try
+ { e(); } catch(...) { f(); }
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-transparent-functors.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-transparent-functors.cpp
new file mode 100644
index 0000000..b700f54
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-transparent-functors.cpp
@@ -0,0 +1,107 @@
+// RUN: %check_clang_tidy %s modernize-use-transparent-functors %t -- -- -std=c++14
+
+namespace std {
+template<class T>
+struct remove_reference;
+
+template <class T>
+constexpr T &&forward(typename std::remove_reference<T>::type &t);
+
+template <class T>
+constexpr T &&forward(typename std::remove_reference<T>::type &&t);
+
+template <typename T = void>
+struct plus {
+ constexpr T operator()(const T &Lhs, const T &Rhs) const;
+};
+
+template <>
+struct plus<void> {
+ template <typename T, typename U>
+ constexpr auto operator()(T &&Lhs, U &&Rhs) const ->
+ decltype(forward<T>(Lhs) + forward<U>(Rhs));
+};
+
+template <typename T = void>
+struct less {
+ constexpr bool operator()(const T &Lhs, const T &Rhs) const;
+};
+
+template <>
+struct less<void> {
+ template <typename T, typename U>
+ constexpr bool operator()(T &&Lhs, U &&Rhs) const;
+};
+
+template <typename T = void>
+struct logical_not {
+ constexpr bool operator()(const T &Arg) const;
+};
+
+template <>
+struct logical_not<void> {
+ template <typename T>
+ constexpr bool operator()(T &&Arg) const;
+};
+
+template <typename T>
+class allocator;
+
+template <
+ class Key,
+ class Compare = std::less<>,
+ class Allocator = std::allocator<Key>>
+class set {};
+
+template <
+ class Key,
+ class Compare = std::less<Key>,
+ class Allocator = std::allocator<Key>>
+class set2 {};
+
+template <class InputIt, class UnaryPredicate>
+InputIt find_if(InputIt first, InputIt last,
+ UnaryPredicate p);
+
+template <class RandomIt, class Compare>
+void sort(RandomIt first, RandomIt last, Compare comp);
+
+class iterator {};
+class string {};
+}
+
+int main() {
+ using std::set;
+ using std::less;
+ std::set<int, std::less<int>> s;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: prefer transparent functors 'less<>' [modernize-use-transparent-functors]
+ // CHECK-FIXES: {{^}} std::set<int, std::less<>> s;{{$}}
+ set<int, std::less<int>> s2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: prefer transparent functors
+ // CHECK-FIXES: {{^}} set<int, std::less<>> s2;{{$}}
+ set<int, less<int>> s3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: prefer transparent functors
+ // CHECK-FIXES: {{^}} set<int, less<>> s3;{{$}}
+ std::set<int, std::less<>> s4;
+ std::set<char *, std::less<std::string>> s5;
+ std::set<set<int, less<int>>, std::less<>> s6;
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: prefer transparent functors
+ // CHECK-FIXES: {{^}} std::set<set<int, less<>>, std::less<>> s6;{{$}}
+ std::iterator begin, end;
+ sort(begin, end, std::less<int>());
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: prefer transparent functors
+ std::sort(begin, end, std::less<>());
+ find_if(begin, end, std::logical_not<bool>());
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: prefer transparent functors
+ std::find_if(begin, end, std::logical_not<>());
+ using my_set = std::set<int, std::less<int>>;
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: prefer transparent functors
+ // CHECK-FIXES: {{^}} using my_set = std::set<int, std::less<>>;{{$}}
+ using my_set2 = std::set<char*, std::less<std::string>>;
+ using my_less = std::less<std::string>;
+ find_if(begin, end, my_less());
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: prefer transparent functors
+ std::set2<int> control;
+}
+
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-uncaught-exceptions.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-uncaught-exceptions.cpp
new file mode 100644
index 0000000..e6bae2b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-uncaught-exceptions.cpp
@@ -0,0 +1,79 @@
+// RUN: %check_clang_tidy %s modernize-use-uncaught-exceptions %t -- -- -std=c++1z
+#define MACRO std::uncaught_exception
+// CHECK-FIXES: #define MACRO std::uncaught_exception
+
+bool uncaught_exception() {
+ return 0;
+}
+
+namespace std {
+ bool uncaught_exception() {
+ return false;
+ }
+
+ int uncaught_exceptions() {
+ return 0;
+ }
+}
+
+template <typename T>
+bool doSomething(T t) {
+ return t();
+ // CHECK-FIXES: return t();
+}
+
+template <bool (*T)()>
+bool doSomething2() {
+ return T();
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead
+ // CHECK-FIXES: return T();
+}
+
+void no_warn() {
+
+ uncaught_exception();
+ // CHECK-FIXES: uncaught_exception();
+
+ doSomething(uncaught_exception);
+ // CHECK-FIXES: doSomething(uncaught_exception);
+}
+
+void warn() {
+
+ std::uncaught_exception();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead
+ // CHECK-FIXES: std::uncaught_exceptions();
+
+ using std::uncaught_exception;
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead
+ // CHECK-FIXES: using std::uncaught_exceptions;
+
+ uncaught_exception();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead
+ // CHECK-FIXES: uncaught_exceptions();
+
+ bool b{uncaught_exception()};
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead
+ // CHECK-FIXES: bool b{std::uncaught_exceptions() > 0};
+
+ MACRO();
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead
+ // CHECK-FIXES: MACRO();
+
+ doSomething(std::uncaught_exception);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead
+ // CHECK-FIXES: doSomething(std::uncaught_exception);
+
+ doSomething(uncaught_exception);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead
+ // CHECK-FIXES: doSomething(uncaught_exception);
+
+ bool (*foo)();
+ foo = &uncaught_exception;
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead
+ // CHECK-FIXES: foo = &uncaught_exception;
+
+ doSomething2<uncaught_exception>();
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: 'std::uncaught_exception' is deprecated, use 'std::uncaught_exceptions' instead
+ // CHECK-FIXES: doSomething2<uncaught_exception>();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-using-macros.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-using-macros.cpp
new file mode 100644
index 0000000..5d88d1d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-using-macros.cpp
@@ -0,0 +1,23 @@
+// RUN: %check_clang_tidy %s modernize-use-using %t -- \
+// RUN: -config="{CheckOptions: [{key: modernize-use-using.IgnoreMacros, value: 0}]}" \
+// RUN: -- -std=c++11
+
+#define CODE typedef int INT
+
+CODE;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: #define CODE typedef int INT
+// CHECK-FIXES: CODE;
+
+struct Foo;
+#define Bar Baz
+typedef Foo Bar;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: #define Bar Baz
+// CHECK-FIXES: using Baz = Foo;
+
+#define TYPEDEF typedef
+TYPEDEF Foo Bak;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: #define TYPEDEF typedef
+// CHECK-FIXES: TYPEDEF Foo Bak;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-using.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
new file mode 100644
index 0000000..e8f4958
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/modernize-use-using.cpp
@@ -0,0 +1,164 @@
+// RUN: %check_clang_tidy %s modernize-use-using %t
+
+typedef int Type;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using]
+// CHECK-FIXES: using Type = int;
+
+typedef long LL;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using LL = long;
+
+typedef int Bla;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Bla = int;
+
+typedef Bla Bla2;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Bla2 = Bla;
+
+typedef void (*type)(int, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using type = void (*)(int, int);
+
+typedef void (*type2)();
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using type2 = void (*)();
+
+class Class {
+ typedef long long Type;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
+ // CHECK-FIXES: using Type = long long;
+};
+
+typedef void (Class::*MyPtrType)(Bla) const;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using MyPtrType = void (Class::*)(Bla)[[ATTR:( __attribute__\(\(thiscall\)\))?]] const;
+
+class Iterable {
+public:
+ class Iterator {};
+};
+
+template <typename T>
+class Test {
+ typedef typename T::iterator Iter;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
+ // CHECK-FIXES: using Iter = typename T::iterator;
+};
+
+using balba = long long;
+
+union A {};
+
+typedef void (A::*PtrType)(int, int) const;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PtrType = void (A::*)(int, int)[[ATTR]] const;
+
+typedef Class some_class;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using some_class = Class;
+
+typedef Class Cclass;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Cclass = Class;
+
+typedef Cclass cclass2;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using cclass2 = Cclass;
+
+class cclass {};
+
+typedef void (cclass::*MyPtrType3)(Bla);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using MyPtrType3 = void (cclass::*)(Bla)[[ATTR]];
+
+using my_class = int;
+
+typedef Test<my_class *> another;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using another = Test<my_class *>;
+
+typedef int* PInt;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using PInt = int *;
+
+typedef int bla1, bla2, bla3;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef int bla1, bla2, bla3;
+
+#define CODE typedef int INT
+
+CODE;
+// CHECK-FIXES: #define CODE typedef int INT
+// CHECK-FIXES: CODE;
+
+struct Foo;
+#define Bar Baz
+typedef Foo Bar;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: #define Bar Baz
+// CHECK-FIXES: using Baz = Foo;
+
+#define TYPEDEF typedef
+TYPEDEF Foo Bak;
+// CHECK-FIXES: #define TYPEDEF typedef
+// CHECK-FIXES: TYPEDEF Foo Bak;
+
+#define FOO Foo
+typedef FOO Bam;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: #define FOO Foo
+// CHECK-FIXES: using Bam = Foo;
+
+typedef struct Foo Bap;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Bap = struct Foo;
+
+struct Foo typedef Bap2;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Bap2 = struct Foo;
+
+Foo typedef Bap3;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Bap3 = Foo;
+
+typedef struct Unknown Baq;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Baq = struct Unknown;
+
+struct Unknown2 typedef Baw;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Baw = struct Unknown2;
+
+int typedef Bax;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using Bax = int;
+
+typedef struct Q1 { int a; } S1;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef struct Q1 { int a; } S1;
+typedef struct { int b; } S2;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef struct { int b; } S2;
+struct Q2 { int c; } typedef S3;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: struct Q2 { int c; } typedef S3;
+struct { int d; } typedef S4;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: struct { int d; } typedef S4;
+
+namespace my_space {
+ class my_cclass {};
+ typedef my_cclass FuncType;
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using FuncType = my_cclass;
+}
+
+#define lol 4
+typedef unsigned Map[lol];
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: typedef unsigned Map[lol];
+
+typedef void (*fun_type)();
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
+// CHECK-FIXES: using fun_type = void (*)();
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/mpi-buffer-deref.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/mpi-buffer-deref.cpp
new file mode 100644
index 0000000..67304d2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/mpi-buffer-deref.cpp
@@ -0,0 +1,50 @@
+// RUN: %check_clang_tidy %s mpi-buffer-deref %t -- -- -I %S/Inputs/mpi-type-mismatch
+
+#include "mpimock.h"
+
+void negativeTests() {
+ char *buf;
+ MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer is insufficiently dereferenced: pointer->pointer [mpi-buffer-deref]
+
+ unsigned **buf2;
+ MPI_Send(buf2, 1, MPI_UNSIGNED, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer is insufficiently dereferenced: pointer->pointer
+
+ short buf3[1][1];
+ MPI_Send(buf3, 1, MPI_SHORT, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer is insufficiently dereferenced: array->array
+
+ long double _Complex *buf4[1];
+ MPI_Send(buf4, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer is insufficiently dereferenced: pointer->array
+
+ std::complex<float> *buf5[1][1];
+ MPI_Send(&buf5, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer is insufficiently dereferenced: pointer->array->array->pointer
+}
+
+void positiveTests() {
+ char buf;
+ MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+
+ unsigned *buf2;
+ MPI_Send(buf2, 1, MPI_UNSIGNED, 0, 0, MPI_COMM_WORLD);
+
+ short buf3[1][1];
+ MPI_Send(buf3[0], 1, MPI_SHORT, 0, 0, MPI_COMM_WORLD);
+
+ long double _Complex *buf4[1];
+ MPI_Send(*buf4, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+
+ long double _Complex buf5[1];
+ MPI_Send(buf5, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+
+ std::complex<float> *buf6[1][1];
+ MPI_Send(*buf6[0], 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+
+ // Referencing an array with '&' is valid, as this also points to the
+ // beginning of the array.
+ long double _Complex buf7[1];
+ MPI_Send(&buf7, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/mpi-type-mismatch.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/mpi-type-mismatch.cpp
new file mode 100644
index 0000000..5e230b8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/mpi-type-mismatch.cpp
@@ -0,0 +1,255 @@
+// RUN: %check_clang_tidy %s mpi-type-mismatch %t -- -- -I %S/Inputs/mpi-type-mismatch
+
+#include "mpimock.h"
+
+void charNegativeTest() {
+ int buf;
+ MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'int' does not match the MPI datatype 'MPI_CHAR'
+
+ short buf2;
+ MPI_Send(&buf2, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'short' does not match the MPI datatype 'MPI_CHAR'
+
+ long buf3;
+ MPI_Send(&buf3, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'long' does not match the MPI datatype 'MPI_CHAR'
+
+ int8_t buf4;
+ MPI_Send(&buf4, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'int8_t' does not match the MPI datatype 'MPI_CHAR'
+
+ uint16_t buf5;
+ MPI_Send(&buf5, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint16_t' does not match the MPI datatype 'MPI_CHAR'
+
+ long double _Complex buf6;
+ MPI_Send(&buf6, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'long double _Complex' does not match the MPI datatype 'MPI_CHAR'
+
+ std::complex<float> buf7;
+ MPI_Send(&buf7, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'complex<float>' does not match the MPI datatype 'MPI_CHAR'
+}
+
+void intNegativeTest() {
+ unsigned char buf;
+ MPI_Send(&buf, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned char' does not match the MPI datatype 'MPI_INT'
+
+ unsigned buf2;
+ MPI_Send(&buf2, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned int' does not match the MPI datatype 'MPI_INT'
+
+ short buf3;
+ MPI_Send(&buf3, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'short' does not match the MPI datatype 'MPI_INT'
+
+ long buf4;
+ MPI_Send(&buf4, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'long' does not match the MPI datatype 'MPI_INT'
+
+ int8_t buf5;
+ MPI_Send(&buf5, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'int8_t' does not match the MPI datatype 'MPI_INT'
+
+ uint16_t buf6;
+ MPI_Send(&buf6, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint16_t' does not match the MPI datatype 'MPI_INT'
+
+ long double _Complex buf7;
+ MPI_Send(&buf7, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'long double _Complex' does not match the MPI datatype 'MPI_INT'
+
+ std::complex<float> buf8;
+ MPI_Send(&buf8, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'complex<float>' does not match the MPI datatype 'MPI_INT'
+}
+
+void longNegativeTest() {
+ char buf;
+ MPI_Send(&buf, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'char' does not match the MPI datatype 'MPI_LONG'
+
+ unsigned buf2;
+ MPI_Send(&buf2, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned int' does not match the MPI datatype 'MPI_LONG'
+
+ unsigned short buf3;
+ MPI_Send(&buf3, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned short' does not match the MPI datatype 'MPI_LONG'
+
+ unsigned long buf4;
+ MPI_Send(&buf4, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned long' does not match the MPI datatype 'MPI_LONG'
+
+ int8_t buf5;
+ MPI_Send(&buf5, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'int8_t' does not match the MPI datatype 'MPI_LONG'
+
+ uint16_t buf6;
+ MPI_Send(&buf6, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint16_t' does not match the MPI datatype 'MPI_LONG'
+
+ long double _Complex buf7;
+ MPI_Send(&buf7, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'long double _Complex' does not match the MPI datatype 'MPI_LONG'
+
+ std::complex<float> buf8;
+ MPI_Send(&buf8, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'complex<float>' does not match the MPI datatype 'MPI_LONG'
+}
+
+void int8_tNegativeTest() {
+ char buf;
+ MPI_Send(&buf, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'char' does not match the MPI datatype 'MPI_INT8_T'
+
+ unsigned buf2;
+ MPI_Send(&buf2, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned int' does not match the MPI datatype 'MPI_INT8_T'
+
+ short buf3;
+ MPI_Send(&buf3, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'short' does not match the MPI datatype 'MPI_INT8_T'
+
+ unsigned long buf4;
+ MPI_Send(&buf4, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned long' does not match the MPI datatype 'MPI_INT8_T'
+
+ uint8_t buf5;
+ MPI_Send(&buf5, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint8_t' does not match the MPI datatype 'MPI_INT8_T'
+
+ uint16_t buf6;
+ MPI_Send(&buf6, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint16_t' does not match the MPI datatype 'MPI_INT8_T'
+
+ long double _Complex buf7;
+ MPI_Send(&buf7, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'long double _Complex' does not match the MPI datatype 'MPI_INT8_T'
+
+ std::complex<float> buf8;
+ MPI_Send(&buf8, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'complex<float>' does not match the MPI datatype 'MPI_INT8_T'
+}
+
+void complex_c_long_double_complexNegativeTest() {
+ char buf;
+ MPI_Send(&buf, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'char' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+
+ unsigned buf2;
+ MPI_Send(&buf2, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned int' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+
+ short buf3;
+ MPI_Send(&buf3, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'short' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+
+ unsigned long buf4;
+ MPI_Send(&buf4, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned long' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+
+ uint8_t buf5;
+ MPI_Send(&buf5, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint8_t' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+
+ uint16_t buf6;
+ MPI_Send(&buf6, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint16_t' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+
+ double _Complex buf7;
+ MPI_Send(&buf7, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'double _Complex' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+
+ std::complex<float> buf8;
+ MPI_Send(&buf8, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'complex<float>' does not match the MPI datatype 'MPI_C_LONG_DOUBLE_COMPLEX'
+}
+
+void complex_cxx_float_complexNegativeTest() {
+ char buf;
+ MPI_Send(&buf, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'char' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+
+ unsigned buf2;
+ MPI_Send(&buf2, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned int' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+
+ short buf3;
+ MPI_Send(&buf3, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'short' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+
+ unsigned long buf4;
+ MPI_Send(&buf4, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'unsigned long' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+
+ uint8_t buf5;
+ MPI_Send(&buf5, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint8_t' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+
+ uint16_t buf6;
+ MPI_Send(&buf6, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'uint16_t' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+
+ double _Complex buf7;
+ MPI_Send(&buf7, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'double _Complex' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+
+ std::complex<double> buf8;
+ MPI_Send(&buf8, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer type 'complex<double>' does not match the MPI datatype 'MPI_CXX_FLOAT_COMPLEX'
+}
+
+void skippedTypesTests() {
+ // typedefs, user defined MPI and nullptr types are skipped
+ typedef char CHAR;
+ CHAR buf;
+ MPI_Send(&buf, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+
+ typedef unsigned UNSIGNED;
+ UNSIGNED buf2;
+ MPI_Send(&buf2, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+
+#define _MPI_LONG MPI_LONG
+ int buf3;
+ MPI_Send(&buf3, 1, _MPI_LONG, 0, 0, MPI_COMM_WORLD);
+
+#define _MPI_CXX_FLOAT_COMPLEX MPI_CXX_FLOAT_COMPLEX
+ short buf4;
+ MPI_Send(&buf4, 1, _MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+
+ MPI_Send(NULL, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+}
+
+void positiveTests() {
+ char buf;
+ MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+
+ int buf2;
+ MPI_Send(&buf2, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
+
+ long buf3;
+ MPI_Send(&buf3, 1, MPI_LONG, 0, 0, MPI_COMM_WORLD);
+
+ int8_t buf4;
+ MPI_Send(&buf4, 1, MPI_INT8_T, 0, 0, MPI_COMM_WORLD);
+
+ long double _Complex buf5;
+ MPI_Send(&buf5, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+
+ std::complex<float> buf6;
+ MPI_Send(&buf6, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+
+ uint8_t buf7;
+ MPI_Send(&buf7, 1, MPI_UINT8_T, 0, 0, MPI_COMM_WORLD);
+
+ uint16_t buf8;
+ MPI_Send(&buf8, 1, MPI_UINT16_T, 0, 0, MPI_COMM_WORLD);
+
+ // On some systems like PPC or ARM, 'char' is unsigned by default which is why
+ // distinct signedness for the buffer and MPI type is tolerated.
+ unsigned char buf9;
+ MPI_Send(&buf9, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/nolint.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/nolint.cpp
new file mode 100644
index 0000000..893e819
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/nolint.cpp
@@ -0,0 +1,49 @@
+// RUN: %check_clang_tidy %s google-explicit-constructor,clang-diagnostic-unused-variable,clang-analyzer-core.UndefinedBinaryOperatorResult %t -- -extra-arg=-Wunused-variable -- -I%S/Inputs/nolint
+
+#include "trigger_warning.h"
+void I(int& Out) {
+ int In;
+ A1(In, Out);
+}
+// CHECK-MESSAGES-NOT: trigger_warning.h:{{.*}} warning
+// CHECK-MESSAGES-NOT: :[[@LINE-4]]:{{.*}} note
+
+class A { A(int i); };
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: single-argument constructors must be marked explicit
+
+class B { B(int i); }; // NOLINT
+
+class C { C(int i); }; // NOLINT(for-some-other-check)
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: single-argument constructors must be marked explicit
+
+class C1 { C1(int i); }; // NOLINT(*)
+
+class C2 { C2(int i); }; // NOLINT(not-closed-bracket-is-treated-as-skip-all
+
+class C3 { C3(int i); }; // NOLINT(google-explicit-constructor)
+
+class C4 { C4(int i); }; // NOLINT(some-check, google-explicit-constructor)
+
+class C5 { C5(int i); }; // NOLINT without-brackets-skip-all, another-check
+
+void f() {
+ int i;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: unused variable 'i' [clang-diagnostic-unused-variable]
+ int j; // NOLINT
+}
+
+#define MACRO(X) class X { X(int i); };
+MACRO(D)
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: single-argument constructors must be marked explicit
+MACRO(E) // NOLINT
+
+#define MACRO_NOARG class F { F(int i); };
+MACRO_NOARG // NOLINT
+
+#define MACRO_NOLINT class G { G(int i); }; // NOLINT
+MACRO_NOLINT
+
+#define DOUBLE_MACRO MACRO(H) // NOLINT
+DOUBLE_MACRO
+
+// CHECK-MESSAGES: Suppressed 12 warnings (12 NOLINT)
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/nolintnextline.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/nolintnextline.cpp
new file mode 100644
index 0000000..a97928a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/nolintnextline.cpp
@@ -0,0 +1,49 @@
+class A { A(int i); };
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: single-argument constructors must be marked explicit
+
+// NOLINTNEXTLINE
+class B { B(int i); };
+
+// NOLINTNEXTLINE(for-some-other-check)
+class C { C(int i); };
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: single-argument constructors must be marked explicit
+
+// NOLINTNEXTLINE(*)
+class C1 { C1(int i); };
+
+// NOLINTNEXTLINE(not-closed-bracket-is-treated-as-skip-all
+class C2 { C2(int i); };
+
+// NOLINTNEXTLINE(google-explicit-constructor)
+class C3 { C3(int i); };
+
+// NOLINTNEXTLINE(some-check, google-explicit-constructor)
+class C4 { C4(int i); };
+
+// NOLINTNEXTLINE without-brackets-skip-all, another-check
+class C5 { C5(int i); };
+
+
+// NOLINTNEXTLINE
+
+class D { D(int i); };
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: single-argument constructors must be marked explicit
+
+// NOLINTNEXTLINE
+//
+class E { E(int i); };
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: single-argument constructors must be marked explicit
+
+#define MACRO(X) class X { X(int i); };
+MACRO(F)
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: single-argument constructors must be marked explicit
+// NOLINTNEXTLINE
+MACRO(G)
+
+#define MACRO_NOARG class H { H(int i); };
+// NOLINTNEXTLINE
+MACRO_NOARG
+
+// CHECK-MESSAGES: Suppressed 8 warnings (8 NOLINT)
+
+// RUN: %check_clang_tidy %s google-explicit-constructor %t --
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/nonstandard-file-extension.test b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/nonstandard-file-extension.test
new file mode 100644
index 0000000..4cb4d11
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/nonstandard-file-extension.test
@@ -0,0 +1,6 @@
+// RUN: %check_clang_tidy -assume-filename=const-cast.cpp %s cppcoreguidelines-pro-type-const-cast %t
+
+const int *i;
+int *j;
+void f() { j = const_cast<int *>(i); }
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: do not use const_cast [cppcoreguidelines-pro-type-const-cast]
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-arc-and-properties.m b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-arc-and-properties.m
new file mode 100644
index 0000000..7fbd796
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-arc-and-properties.m
@@ -0,0 +1,21 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-semicolon %t
+
+// This test checks if Objective-C 2.0 (@properties) and
+// Automatic Reference Counting (ARC) are enabled for .m files
+// checked via check_clang_tidy.py.
+
+#if !__has_feature(objc_arc)
+#error Objective-C ARC not enabled as expected
+#endif
+
+@interface Foo
+@property (nonatomic, assign) int shouldDoStuff;
+- (void)nop;
+@end
+
+void fail(Foo *f)
+{
+ if(f.shouldDoStuff); [f nop];
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: potentially unintended semicolon [bugprone-suspicious-semicolon]
+ // CHECK-FIXES: if(f.shouldDoStuff) [f nop];
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-avoid-nserror-init.m b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-avoid-nserror-init.m
new file mode 100644
index 0000000..7794077
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-avoid-nserror-init.m
@@ -0,0 +1,12 @@
+// RUN: %check_clang_tidy %s objc-avoid-nserror-init %t
+@interface NSError
++ (instancetype)alloc;
+- (instancetype)init;
+@end
+
+@implementation foo
+- (void)bar {
+ NSError *error = [[NSError alloc] init];
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use errorWithDomain:code:userInfo: or initWithDomain:code:userInfo: to create a new NSError [objc-avoid-nserror-init]
+}
+@end
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-avoid-spinlock.m b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-avoid-spinlock.m
new file mode 100644
index 0000000..f9f05cb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-avoid-spinlock.m
@@ -0,0 +1,15 @@
+// RUN: %check_clang_tidy %s objc-avoid-spinlock %t
+
+typedef int OSSpinLock;
+
+@implementation Foo
+- (void)f {
+ int i = 1;
+ OSSpinlockLock(&i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use os_unfair_lock_lock() or dispatch queue APIs instead of the deprecated OSSpinLock [objc-avoid-spinlock]
+ OSSpinlockTry(&i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use os_unfair_lock_lock() or dispatch queue APIs instead of the deprecated OSSpinLock [objc-avoid-spinlock]
+ OSSpinlockUnlock(&i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use os_unfair_lock_lock() or dispatch queue APIs instead of the deprecated OSSpinLock [objc-avoid-spinlock]
+}
+@end
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-forbidden-subclassing-custom.m b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-forbidden-subclassing-custom.m
new file mode 100644
index 0000000..59e6a88
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-forbidden-subclassing-custom.m
@@ -0,0 +1,39 @@
+// RUN: %check_clang_tidy %s objc-forbidden-subclassing %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: objc-forbidden-subclassing.ClassNames, value: "Foo;Quux"}]}' \
+// RUN: --
+
+@interface UIImagePickerController
+@end
+
+// Make sure custom config options replace (not add to) the default list.
+@interface Waldo : UIImagePickerController
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: Objective-C interface 'Waldo' subclasses 'UIImagePickerController', which is not intended to be subclassed [objc-forbidden-subclassing]
+@end
+
+@interface Foo
+@end
+
+@interface Bar : Foo
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: Objective-C interface 'Bar' subclasses 'Foo', which is not intended to be subclassed [objc-forbidden-subclassing]
+@end
+
+// Check subclasses of subclasses.
+@interface Baz : Bar
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: Objective-C interface 'Baz' subclasses 'Foo', which is not intended to be subclassed [objc-forbidden-subclassing]
+@end
+
+@interface Quux
+@end
+
+// Check that more than one forbidden superclass can be specified.
+@interface Xyzzy : Quux
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: Objective-C interface 'Xyzzy' subclasses 'Quux', which is not intended to be subclassed [objc-forbidden-subclassing]
+@end
+
+@interface Plugh
+@end
+
+@interface Corge : Plugh
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: Objective-C interface 'Corge' subclasses 'Plugh', which is not intended to be subclassed [objc-forbidden-subclassing]
+@end
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-forbidden-subclassing.m b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-forbidden-subclassing.m
new file mode 100644
index 0000000..3ad38bf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-forbidden-subclassing.m
@@ -0,0 +1,21 @@
+// RUN: %check_clang_tidy %s objc-forbidden-subclassing %t
+
+@interface UIImagePickerController
+@end
+
+@interface Foo : UIImagePickerController
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: Objective-C interface 'Foo' subclasses 'UIImagePickerController', which is not intended to be subclassed [objc-forbidden-subclassing]
+@end
+
+// Check subclasses of subclasses.
+@interface Bar : Foo
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: Objective-C interface 'Bar' subclasses 'UIImagePickerController', which is not intended to be subclassed [objc-forbidden-subclassing]
+@end
+
+@interface Baz
+@end
+
+// Make sure innocent subclasses aren't caught by the check.
+@interface Blech : Baz
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:12: warning: Objective-C interface 'Blech' subclasses 'Baz', which is not intended to be subclassed [objc-forbidden-subclassing]
+@end
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-no-arc-or-properties.m b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-no-arc-or-properties.m
new file mode 100644
index 0000000..c1e73ed
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-no-arc-or-properties.m
@@ -0,0 +1,29 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-semicolon %t -- -- -fno-objc-arc -fobjc-abi-version=1
+
+// This test ensures check_clang_tidy.py allows disabling Objective-C ARC and
+// Objective-C 2.0 via passing arguments after -- on the command line.
+//
+// (We could include a test which doesn't pass any arguments after --
+// to check if ARC and ObjC 2.0 are disabled by default, but that test
+// could change behavior based on the default Objective-C runtime for
+// the platform, which would make this test flaky.)
+
+#if __has_feature(objc_arc)
+#error Objective-C ARC unexpectedly enabled even with -fno-objc-arc
+#endif
+
+#ifdef __OBJC2__
+#error Objective-C 2.0 unexpectedly enabled even with -fobjc-abi-version=1
+#endif
+
+@interface Foo
+- (int)shouldDoStuff;
+- (void)nop;
+@end
+
+void fail(Foo *f)
+{
+ if([f shouldDoStuff]); [f nop];
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: potentially unintended semicolon [bugprone-suspicious-semicolon]
+ // CHECK-FIXES: if([f shouldDoStuff]) [f nop];
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-property-declaration-additional.m b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-property-declaration-additional.m
new file mode 100644
index 0000000..bf836fa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-property-declaration-additional.m
@@ -0,0 +1,15 @@
+// RUN: %check_clang_tidy %s objc-property-declaration %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: objc-property-declaration.Acronyms, value: "ABC;TGIF"}]}' \
+// RUN: --
+@class NSString;
+
+@interface Foo
+@property(assign, nonatomic) int AbcNotRealPrefix;
+// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: property name 'AbcNotRealPrefix' not using lowerCamelCase style or not prefixed in a category, according to the Apple Coding Guidelines [objc-property-declaration]
+// CHECK-FIXES: @property(assign, nonatomic) int abcNotRealPrefix;
+@property(assign, nonatomic) int ABCCustomPrefix;
+@property(strong, nonatomic) NSString *ABC_custom_prefix;
+// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: property name 'ABC_custom_prefix' not using lowerCamelCase style or not prefixed in a category, according to the Apple Coding Guidelines [objc-property-declaration]
+@property(assign, nonatomic) int GIFShouldIncludeStandardAcronym;
+@end
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-property-declaration-custom.m b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-property-declaration-custom.m
new file mode 100644
index 0000000..68374ec
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-property-declaration-custom.m
@@ -0,0 +1,18 @@
+// RUN: %check_clang_tidy %s objc-property-declaration %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: objc-property-declaration.Acronyms, value: "ABC;TGIF"}, \
+// RUN: {key: objc-property-declaration.IncludeDefaultAcronyms, value: 0}]}' \
+// RUN: --
+@class NSString;
+
+@interface Foo
+@property(assign, nonatomic) int AbcNotRealPrefix;
+// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: property name 'AbcNotRealPrefix' not using lowerCamelCase style or not prefixed in a category, according to the Apple Coding Guidelines [objc-property-declaration]
+// CHECK-FIXES: @property(assign, nonatomic) int abcNotRealPrefix;
+@property(assign, nonatomic) int ABCCustomPrefix;
+@property(strong, nonatomic) NSString *ABC_custom_prefix;
+// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: property name 'ABC_custom_prefix' not using lowerCamelCase style or not prefixed in a category, according to the Apple Coding Guidelines [objc-property-declaration]
+@property(assign, nonatomic) int GIFIgnoreStandardAcronym;
+// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: property name 'GIFIgnoreStandardAcronym' not using lowerCamelCase style or not prefixed in a category, according to the Apple Coding Guidelines [objc-property-declaration]
+@property(strong, nonatomic) NSString *TGIF;
+@end
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-property-declaration.m b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-property-declaration.m
new file mode 100644
index 0000000..7f70784
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/objc-property-declaration.m
@@ -0,0 +1,46 @@
+// RUN: %check_clang_tidy %s objc-property-declaration %t
+@class NSData;
+@class NSString;
+@class UIViewController;
+
+@interface Foo
+@property(assign, nonatomic) int NotCamelCase;
+// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: property name 'NotCamelCase' not using lowerCamelCase style or not prefixed in a category, according to the Apple Coding Guidelines [objc-property-declaration]
+// CHECK-FIXES: @property(assign, nonatomic) int notCamelCase;
+@property(assign, nonatomic) int camelCase;
+@property(strong, nonatomic) NSString *URLString;
+@property(strong, nonatomic) NSString *bundleID;
+@property(strong, nonatomic) NSData *RGBABytes;
+@property(strong, nonatomic) UIViewController *notificationsVC;
+@property(strong, nonatomic) NSString *URL_string;
+// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: property name 'URL_string' not using lowerCamelCase style or not prefixed in a category, according to the Apple Coding Guidelines [objc-property-declaration]
+@property(strong, nonatomic) NSString *supportURLsCamelCase;
+@property(strong, nonatomic) NSString *supportURLCamelCase;
+@property(strong, nonatomic) NSString *VCsPluralToAdd;
+@property(assign, nonatomic) int centerX;
+@property(assign, nonatomic) int enable2GBackgroundFetch;
+@property(assign, nonatomic) int shouldUseCFPreferences;
+@property(assign, nonatomic) int enableGLAcceleration;
+@property(assign, nonatomic) int ID;
+@property(assign, nonatomic) int hasADog;
+@end
+
+@interface Foo (Bar)
+@property(assign, nonatomic) int abc_NotCamelCase;
+// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: property name 'abc_NotCamelCase' not using lowerCamelCase style or not prefixed in a category, according to the Apple Coding Guidelines [objc-property-declaration]
+@property(assign, nonatomic) int abCD_camelCase;
+// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: property name 'abCD_camelCase' not using lowerCamelCase style or not prefixed in a category, according to the Apple Coding Guidelines [objc-property-declaration]
+// CHECK-FIXES: @property(assign, nonatomic) int abcd_camelCase;
+@property(assign, nonatomic) int abCD_NotCamelCase;
+// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: property name 'abCD_NotCamelCase' not using lowerCamelCase style or not prefixed in a category, according to the Apple Coding Guidelines [objc-property-declaration]
+// CHECK-FIXES: @property(assign, nonatomic) int abcd_notCamelCase;
+@property(assign, nonatomic) int wrongFormat_;
+// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: property name 'wrongFormat_' not using lowerCamelCase style or not prefixed in a category, according to the Apple Coding Guidelines [objc-property-declaration]
+@property(strong, nonatomic) NSString *URLStr;
+@property(assign, nonatomic) int abc_camelCase;
+@end
+
+@interface Foo ()
+@property(assign, nonatomic) int abc_inClassExtension;
+// CHECK-MESSAGES: :[[@LINE-1]]:34: warning: property name 'abc_inClassExtension' not using lowerCamelCase style or not prefixed in a category, according to the Apple Coding Guidelines [objc-property-declaration]
+@end
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/overlapping.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/overlapping.cpp
new file mode 100644
index 0000000..f970a13
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/overlapping.cpp
@@ -0,0 +1,10 @@
+// RUN: clang-tidy -checks=-*,llvm-include-order -header-filter=.* %s \
+// RUN: -- -isystem %S/Inputs/Headers -I %S/Inputs/overlapping | \
+// RUN: not grep "note: this fix will not be applied because it overlaps with another fix"
+
+#include <s.h>
+#include "o.h"
+
+// Test that clang-tidy takes into account in which file we are doing the
+// replacements to determine if they overlap or not. In the file "o.h" there is
+// a similar error at the same file offset, but they do not overlap.
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-faster-string-find.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-faster-string-find.cpp
new file mode 100644
index 0000000..b36e323
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-faster-string-find.cpp
@@ -0,0 +1,110 @@
+// RUN: %check_clang_tidy %s performance-faster-string-find %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: performance-faster-string-find.StringLikeClasses, \
+// RUN: value: 'std::basic_string; ::llvm::StringRef;'}]}" --
+
+namespace std {
+template <typename Char>
+struct basic_string {
+ int find(const Char *, int = 0) const;
+ int find(const Char *, int, int) const;
+ int rfind(const Char *) const;
+ int find_first_of(const Char *) const;
+ int find_first_not_of(const Char *) const;
+ int find_last_of(const Char *) const;
+ int find_last_not_of(const Char *) const;
+};
+
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+} // namespace std
+
+namespace llvm {
+struct StringRef {
+ int find(const char *) const;
+};
+} // namespace llvm
+
+struct NotStringRef {
+ int find(const char *);
+};
+
+void StringFind() {
+ std::string Str;
+
+ Str.find("a");
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal consisting of a single character; consider using the more effective overload accepting a character [performance-faster-string-find]
+ // CHECK-FIXES: Str.find('a');
+
+ // Works with the pos argument.
+ Str.find("a", 1);
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: 'find' called with a string literal
+ // CHECK-FIXES: Str.find('a', 1);
+
+ // Doens't work with strings smaller or larger than 1 char.
+ Str.find("");
+ Str.find("ab");
+
+ // Doesn't do anything with the 3 argument overload.
+ Str.find("a", 1, 1);
+
+ // Other methods that can also be replaced
+ Str.rfind("a");
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'rfind' called with a string literal
+ // CHECK-FIXES: Str.rfind('a');
+ Str.find_first_of("a");
+ // CHECK-MESSAGES: [[@LINE-1]]:21: warning: 'find_first_of' called with a string
+ // CHECK-FIXES: Str.find_first_of('a');
+ Str.find_first_not_of("a");
+ // CHECK-MESSAGES: [[@LINE-1]]:25: warning: 'find_first_not_of' called with a
+ // CHECK-FIXES: Str.find_first_not_of('a');
+ Str.find_last_of("a");
+ // CHECK-MESSAGES: [[@LINE-1]]:20: warning: 'find_last_of' called with a string
+ // CHECK-FIXES: Str.find_last_of('a');
+ Str.find_last_not_of("a");
+ // CHECK-MESSAGES: [[@LINE-1]]:24: warning: 'find_last_not_of' called with a
+ // CHECK-FIXES: Str.find_last_not_of('a');
+
+ // std::wstring should work.
+ std::wstring WStr;
+ WStr.find(L"n");
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'find' called with a string literal
+ // CHECK-FIXES: Str.find(L'n');
+ // Even with unicode that fits in one wide char.
+ WStr.find(L"\x3A9");
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: 'find' called with a string literal
+ // CHECK-FIXES: Str.find(L'\x3A9');
+
+ // Also with other types, but only if it was specified in the options.
+ llvm::StringRef sr;
+ sr.find("x");
+ // CHECK-MESSAGES: [[@LINE-1]]:11: warning: 'find' called with a string literal
+ // CHECK-FIXES: sr.find('x');
+ NotStringRef nsr;
+ nsr.find("x");
+}
+
+
+template <typename T>
+int FindTemplateDependant(T value) {
+ return value.find("A");
+}
+template <typename T>
+int FindTemplateNotDependant(T pos) {
+ return std::string().find("A", pos);
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: 'find' called with a string literal
+ // CHECK-FIXES: return std::string().find('A', pos);
+}
+
+int FindStr() {
+ return FindTemplateDependant(std::string()) + FindTemplateNotDependant(1);
+}
+
+#define STR_MACRO(str) str.find("A")
+#define POS_MACRO(pos) std::string().find("A",pos)
+
+int Macros() {
+ return STR_MACRO(std::string()) + POS_MACRO(1);
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: 'find' called with a string literal
+ // CHECK-MESSAGES: [[@LINE-2]]:37: warning: 'find' called with a string literal
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-for-range-copy-warn-on-all-auto-copies.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-for-range-copy-warn-on-all-auto-copies.cpp
new file mode 100644
index 0000000..75655a6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-for-range-copy-warn-on-all-auto-copies.cpp
@@ -0,0 +1,39 @@
+// RUN: %check_clang_tidy %s performance-for-range-copy %t -config="{CheckOptions: [{key: "performance-for-range-copy.WarnOnAllAutoCopies", value: 1}]}" -- -std=c++11
+
+template <typename T>
+struct Iterator {
+ void operator++() {}
+ const T& operator*() {
+ static T* TT = new T();
+ return *TT;
+ }
+ bool operator!=(const Iterator &) { return false; }
+};
+template <typename T>
+struct View {
+ T begin() { return T(); }
+ T begin() const { return T(); }
+ T end() { return T(); }
+ T end() const { return T(); }
+};
+
+struct S {
+ S();
+ S(const S &);
+ ~S();
+ S &operator=(const S &);
+};
+
+void NegativeLoopVariableNotAuto() {
+ for (S S1 : View<Iterator<S>>()) {
+ S* S2 = &S1;
+ }
+}
+
+void PositiveTriggeredForAutoLoopVariable() {
+ for (auto S1 : View<Iterator<S>>()) {
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: the loop variable's type is not a reference type; this creates a copy in each iteration; consider making this a reference [performance-for-range-copy]
+ // CHECK-FIXES: for (const auto& S1 : View<Iterator<S>>()) {
+ S* S2 = &S1;
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-for-range-copy.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-for-range-copy.cpp
new file mode 100644
index 0000000..1c77996
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-for-range-copy.cpp
@@ -0,0 +1,262 @@
+// RUN: %check_clang_tidy %s performance-for-range-copy %t -- -- -std=c++11 -fno-delayed-template-parsing
+
+namespace std {
+
+template <typename _Tp>
+struct remove_reference { typedef _Tp type; };
+
+template <typename _Tp>
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) {
+ return static_cast<typename std::remove_reference<_Tp>::type &&>(__t);
+}
+
+} // std
+
+template <typename T>
+struct Iterator {
+ void operator++() {}
+ const T& operator*() {
+ static T* TT = new T();
+ return *TT;
+ }
+ bool operator!=(const Iterator &) { return false; }
+ typedef const T& const_reference;
+};
+template <typename T>
+struct View {
+ T begin() { return T(); }
+ T begin() const { return T(); }
+ T end() { return T(); }
+ T end() const { return T(); }
+ typedef typename T::const_reference const_reference;
+};
+
+struct ConstructorConvertible {
+};
+
+struct S {
+ S();
+ S(const S &);
+ S(const ConstructorConvertible&) {}
+ ~S();
+ S &operator=(const S &);
+};
+
+struct Convertible {
+ operator S() const {
+ return S();
+ }
+};
+
+void negativeConstReference() {
+ for (const S &S1 : View<Iterator<S>>()) {
+ }
+}
+
+void negativeUserDefinedConversion() {
+ Convertible C[0];
+ for (const S &S1 : C) {
+ }
+}
+
+void negativeImplicitConstructorConversion() {
+ ConstructorConvertible C[0];
+ for (const S &S1 : C) {
+ }
+}
+
+template <typename T>
+void uninstantiated() {
+ for (const S S1 : View<Iterator<S>>()) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not a reference type; this creates a copy in each iteration; consider making this a reference [performance-for-range-copy]
+ // CHECK-FIXES: {{^}} for (const S& S1 : View<Iterator<S>>()) {}
+
+ // Don't warn on dependent types.
+ for (const T t1 : View<Iterator<T>>()) {
+ }
+}
+
+template <typename T>
+void instantiated() {
+ for (const S S2 : View<Iterator<S>>()) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}
+ // CHECK-FIXES: {{^}} for (const S& S2 : View<Iterator<S>>()) {}
+
+ for (const T T2 : View<Iterator<T>>()) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}
+ // CHECK-FIXES: {{^}} for (const T& T2 : View<Iterator<T>>()) {}
+}
+
+template <typename T>
+void instantiatedNegativeTypedefConstReference() {
+ for (typename T::const_reference T2 : T()) {
+ S S1 = T2;
+ }
+}
+
+void f() {
+ instantiated<int>();
+ instantiated<S>();
+ instantiatedNegativeTypedefConstReference<View<Iterator<S>>>();
+}
+
+struct Mutable {
+ Mutable() {}
+ Mutable(const Mutable &) = default;
+ Mutable(const Mutable &, const Mutable &) {}
+ void setBool(bool B) {}
+ bool constMethod() const {
+ return true;
+ }
+ Mutable& operator[](int I) {
+ return *this;
+ }
+ bool operator==(const Mutable &Other) const {
+ return true;
+ }
+ ~Mutable() {}
+};
+
+struct Point {
+ ~Point() {}
+ int x, y;
+};
+
+Mutable& operator<<(Mutable &Out, bool B) {
+ Out.setBool(B);
+ return Out;
+}
+
+bool operator!=(const Mutable& M1, const Mutable& M2) {
+ return false;
+}
+
+void use(const Mutable &M);
+void use(int I);
+void useTwice(const Mutable &M1, const Mutable &M2);
+void useByValue(Mutable M);
+void useByConstValue(const Mutable M);
+void mutate(Mutable *M);
+void mutate(Mutable &M);
+void onceConstOnceMutated(const Mutable &M1, Mutable &M2);
+
+void negativeVariableIsMutated() {
+ for (auto M : View<Iterator<Mutable>>()) {
+ mutate(M);
+ }
+ for (auto M : View<Iterator<Mutable>>()) {
+ mutate(&M);
+ }
+ for (auto M : View<Iterator<Mutable>>()) {
+ M.setBool(true);
+ }
+}
+
+void negativeOnceConstOnceMutated() {
+ for (auto M : View<Iterator<Mutable>>()) {
+ onceConstOnceMutated(M, M);
+ }
+}
+
+void negativeVarIsMoved() {
+ for (auto M : View<Iterator<Mutable>>()) {
+ auto Moved = std::move(M);
+ }
+}
+
+void negativeNonConstOperatorIsInvoked() {
+ for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {
+ auto& N = NonConstOperatorInvokee[0];
+ }
+}
+
+void negativeNonConstNonMemberOperatorInvoked() {
+ for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {
+ NonConstOperatorInvokee << true;
+ }
+}
+
+void negativeConstCheapToCopy() {
+ for (const int I : View<Iterator<int>>()) {
+ }
+}
+
+void negativeConstCheapToCopyTypedef() {
+ typedef const int ConstInt;
+ for (ConstInt C : View<Iterator<ConstInt>>()) {
+ }
+}
+
+void negativeCheapToCopy() {
+ for (int I : View<Iterator<int>>()) {
+ use(I);
+ }
+}
+
+void negativeCheapToCopyTypedef() {
+ typedef int Int;
+ for (Int I : View<Iterator<Int>>()) {
+ use(I);
+ }
+}
+
+void positiveOnlyConstMethodInvoked() {
+ for (auto M : View<Iterator<Mutable>>()) {
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
+ // CHECK-FIXES: for (const auto& M : View<Iterator<Mutable>>()) {
+ M.constMethod();
+ }
+}
+
+void positiveOnlyUsedAsConstArguments() {
+ for (auto UsedAsConst : View<Iterator<Mutable>>()) {
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
+ // CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Mutable>>()) {
+ use(UsedAsConst);
+ useTwice(UsedAsConst, UsedAsConst);
+ useByValue(UsedAsConst);
+ useByConstValue(UsedAsConst);
+ }
+}
+
+void positiveOnlyAccessedFieldAsConst() {
+ for (auto UsedAsConst : View<Iterator<Point>>()) {
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
+ // CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Point>>()) {
+ use(UsedAsConst.x);
+ use(UsedAsConst.y);
+ }
+}
+
+void positiveOnlyUsedInCopyConstructor() {
+ for (auto A : View<Iterator<Mutable>>()) {
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
+ // CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {
+ Mutable Copy = A;
+ Mutable Copy2(A);
+ }
+}
+
+void positiveTwoConstConstructorArgs() {
+ for (auto A : View<Iterator<Mutable>>()) {
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
+ // CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {
+ Mutable Copy(A, A);
+ }
+}
+
+void PositiveConstMemberOperatorInvoked() {
+ for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
+ // CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {
+ bool result = ConstOperatorInvokee == Mutable();
+ }
+}
+
+void PositiveConstNonMemberOperatorInvoked() {
+ for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {
+ // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
+ // CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {
+ bool result = ConstOperatorInvokee != Mutable();
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-implicit-conversion-in-loop.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-implicit-conversion-in-loop.cpp
new file mode 100644
index 0000000..72f9e52
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-implicit-conversion-in-loop.cpp
@@ -0,0 +1,197 @@
+// RUN: %check_clang_tidy %s performance-implicit-conversion-in-loop %t
+
+// ---------- Classes used in the tests ----------
+
+// Iterator returning by value.
+template <typename T>
+struct Iterator {
+ void operator++();
+ T operator*();
+ bool operator!=(const Iterator& other);
+};
+
+// Iterator returning by reference.
+template <typename T>
+struct RefIterator {
+ void operator++();
+ T& operator*();
+ bool operator!=(const RefIterator& other);
+};
+
+// The template argument is an iterator type, and a view is an object you can
+// run a for loop on.
+template <typename T>
+struct View {
+ T begin();
+ T end();
+};
+
+// With this class, the implicit conversion is a call to the (implicit)
+// constructor of the class.
+template <typename T>
+class ImplicitWrapper {
+ public:
+ // Implicit!
+ ImplicitWrapper(const T& t);
+};
+
+// With this class, the implicit conversion is a call to the conversion
+// operators of SimpleClass and ComplexClass.
+template <typename T>
+class OperatorWrapper {
+ public:
+ OperatorWrapper() = delete;
+};
+
+struct SimpleClass {
+ int foo;
+ operator OperatorWrapper<SimpleClass>();
+};
+
+// The materialize expression is not the same when the class has a destructor,
+// so we make sure we cover that case too.
+class ComplexClass {
+ public:
+ ComplexClass();
+ ~ComplexClass();
+ operator OperatorWrapper<ComplexClass>();
+};
+
+typedef View<Iterator<SimpleClass>> SimpleView;
+typedef View<RefIterator<SimpleClass>> SimpleRefView;
+typedef View<Iterator<ComplexClass>> ComplexView;
+typedef View<RefIterator<ComplexClass>> ComplexRefView;
+
+// ---------- The test themselves ----------
+// For each test we do, in the same order, const ref, non const ref, const
+// value, non const value.
+
+void SimpleClassIterator() {
+ for (const SimpleClass& foo : SimpleView()) {}
+ // This line does not compile because a temporary cannot be assigned to a non
+ // const reference.
+ // for (SimpleClass& foo : SimpleView()) {}
+ for (const SimpleClass foo : SimpleView()) {}
+ for (SimpleClass foo : SimpleView()) {}
+}
+
+void SimpleClassRefIterator() {
+ for (const SimpleClass& foo : SimpleRefView()) {}
+ for (SimpleClass& foo : SimpleRefView()) {}
+ for (const SimpleClass foo : SimpleRefView()) {}
+ for (SimpleClass foo : SimpleRefView()) {}
+}
+
+void ComplexClassIterator() {
+ for (const ComplexClass& foo : ComplexView()) {}
+ // for (ComplexClass& foo : ComplexView()) {}
+ for (const ComplexClass foo : ComplexView()) {}
+ for (ComplexClass foo : ComplexView()) {}
+}
+
+void ComplexClassRefIterator() {
+ for (const ComplexClass& foo : ComplexRefView()) {}
+ for (ComplexClass& foo : ComplexRefView()) {}
+ for (const ComplexClass foo : ComplexRefView()) {}
+ for (ComplexClass foo : ComplexRefView()) {}
+}
+
+void ImplicitSimpleClassIterator() {
+ for (const ImplicitWrapper<SimpleClass>& foo : SimpleView()) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the loop variable 'foo' is different from the one returned by the iterator and generates an implicit conversion; you can either change the type to the matching one ('const SimpleClass &' but 'const auto&' is always a valid option) or remove the reference to make it explicit that you are creating a new value [performance-implicit-conversion-in-loop]
+ // for (ImplicitWrapper<SimpleClass>& foo : SimpleView()) {}
+ for (const ImplicitWrapper<SimpleClass> foo : SimpleView()) {}
+ for (ImplicitWrapper<SimpleClass> foo : SimpleView()) {}
+}
+
+void ImplicitSimpleClassRefIterator() {
+ for (const ImplicitWrapper<SimpleClass>& foo : SimpleRefView()) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}}
+ // for (ImplicitWrapper<SimpleClass>& foo : SimpleRefView()) {}
+ for (const ImplicitWrapper<SimpleClass> foo : SimpleRefView()) {}
+ for (ImplicitWrapper<SimpleClass> foo : SimpleRefView()) {}
+}
+
+void ImplicitSimpleClassArray() {
+ SimpleClass array[5];
+ for (const ImplicitWrapper<SimpleClass>& foo : array) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}}
+ // for (ImplicitWrapper<SimpleClass>& foo : array) {}
+ for (const ImplicitWrapper<SimpleClass> foo : array) {}
+ for (ImplicitWrapper<SimpleClass> foo : array) {}
+}
+
+void ImplicitComplexClassIterator() {
+ for (const ImplicitWrapper<ComplexClass>& foo : ComplexView()) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}}
+ // for (ImplicitWrapper<ComplexClass>& foo : ComplexView()) {}
+ for (const ImplicitWrapper<ComplexClass> foo : ComplexView()) {}
+ for (ImplicitWrapper<ComplexClass> foo : ComplexView()) {}
+}
+
+void ImplicitComplexClassRefIterator() {
+ ComplexClass array[5];
+ for (const ImplicitWrapper<ComplexClass>& foo : array) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}}
+ // for (ImplicitWrapper<ComplexClass>& foo : array) {}
+ for (const ImplicitWrapper<ComplexClass> foo : array) {}
+ for (ImplicitWrapper<ComplexClass> foo : array) {}
+}
+
+void ImplicitComplexClassArray() {
+ for (const ImplicitWrapper<ComplexClass>& foo : ComplexRefView()) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}}
+ // for (ImplicitWrapper<ComplexClass>& foo : ComplexRefView()) {}
+ for (const ImplicitWrapper<ComplexClass> foo : ComplexRefView()) {}
+ for (ImplicitWrapper<ComplexClass> foo : ComplexRefView()) {}
+}
+
+void OperatorSimpleClassIterator() {
+ for (const OperatorWrapper<SimpleClass>& foo : SimpleView()) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}}
+ // for (OperatorWrapper<SimpleClass>& foo : SimpleView()) {}
+ for (const OperatorWrapper<SimpleClass> foo : SimpleView()) {}
+ for (OperatorWrapper<SimpleClass> foo : SimpleView()) {}
+}
+
+void OperatorSimpleClassRefIterator() {
+ for (const OperatorWrapper<SimpleClass>& foo : SimpleRefView()) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}}
+ // for (OperatorWrapper<SimpleClass>& foo : SimpleRefView()) {}
+ for (const OperatorWrapper<SimpleClass> foo : SimpleRefView()) {}
+ for (OperatorWrapper<SimpleClass> foo : SimpleRefView()) {}
+}
+
+void OperatorSimpleClassArray() {
+ SimpleClass array[5];
+ for (const OperatorWrapper<SimpleClass>& foo : array) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}}
+ // for (OperatorWrapper<SimpleClass>& foo : array) {}
+ for (const OperatorWrapper<SimpleClass> foo : array) {}
+ for (OperatorWrapper<SimpleClass> foo : array) {}
+}
+
+void OperatorComplexClassIterator() {
+ for (const OperatorWrapper<ComplexClass>& foo : ComplexView()) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}}
+ // for (OperatorWrapper<ComplexClass>& foo : ComplexView()) {}
+ for (const OperatorWrapper<ComplexClass> foo : ComplexView()) {}
+ for (OperatorWrapper<ComplexClass> foo : ComplexView()) {}
+}
+
+void OperatorComplexClassRefIterator() {
+ for (const OperatorWrapper<ComplexClass>& foo : ComplexRefView()) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}}
+ // for (OperatorWrapper<ComplexClass>& foo : ComplexRefView()) {}
+ for (const OperatorWrapper<ComplexClass> foo : ComplexRefView()) {}
+ for (OperatorWrapper<ComplexClass> foo : ComplexRefView()) {}
+}
+
+void OperatorComplexClassArray() {
+ ComplexClass array[5];
+ for (const OperatorWrapper<ComplexClass>& foo : array) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}}
+ // for (OperatorWrapper<ComplexClass>& foo : array) {}
+ for (const OperatorWrapper<ComplexClass> foo : array) {}
+ for (OperatorWrapper<ComplexClass> foo : array) {}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-inefficient-algorithm.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-inefficient-algorithm.cpp
new file mode 100644
index 0000000..19a6701
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-inefficient-algorithm.cpp
@@ -0,0 +1,166 @@
+// RUN: %check_clang_tidy %s performance-inefficient-algorithm %t
+
+namespace std {
+template <typename T> struct less {
+ bool operator()(const T &lhs, const T &rhs) { return lhs < rhs; }
+};
+
+template <typename T> struct greater {
+ bool operator()(const T &lhs, const T &rhs) { return lhs > rhs; }
+};
+
+struct iterator_type {};
+
+template <typename K, typename Cmp = less<K>> struct set {
+ typedef iterator_type iterator;
+ iterator find(const K &k);
+ unsigned count(const K &k);
+
+ iterator begin();
+ iterator end();
+ iterator begin() const;
+ iterator end() const;
+};
+
+struct other_iterator_type {};
+
+template <typename K, typename V, typename Cmp = less<K>> struct map {
+ typedef other_iterator_type iterator;
+ iterator find(const K &k);
+ unsigned count(const K &k);
+
+ iterator begin();
+ iterator end();
+ iterator begin() const;
+ iterator end() const;
+};
+
+template <typename K, typename V> struct multimap : map<K, V> {};
+template <typename K> struct unordered_set : set<K> {};
+template <typename K, typename V> struct unordered_map : map<K, V> {};
+template <typename K> struct unordered_multiset : set<K> {};
+template <typename K, typename V> struct unordered_multimap : map<K, V> {};
+
+template <typename K, typename Cmp = less<K>> struct multiset : set<K, Cmp> {};
+
+template <typename FwIt, typename K>
+FwIt find(FwIt, FwIt end, const K &) { return end; }
+
+template <typename FwIt, typename K, typename Cmp>
+FwIt find(FwIt, FwIt end, const K &, Cmp) { return end; }
+
+template <typename FwIt, typename Pred>
+FwIt find_if(FwIt, FwIt end, Pred) { return end; }
+
+template <typename FwIt, typename K>
+unsigned count(FwIt, FwIt, const K &) { return 0; }
+
+template <typename FwIt, typename K>
+FwIt lower_bound(FwIt, FwIt end, const K &) { return end; }
+
+template <typename FwIt, typename K, typename Ord>
+FwIt lower_bound(FwIt, FwIt end, const K &, Ord) { return end; }
+}
+
+#define FIND_IN_SET(x) find(x.begin(), x.end(), 10)
+// CHECK-FIXES: #define FIND_IN_SET(x) find(x.begin(), x.end(), 10)
+
+template <typename T> void f(const T &t) {
+ std::set<int> s;
+ find(s.begin(), s.end(), 46);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this STL algorithm call should be
+ // CHECK-FIXES: {{^ }}s.find(46);{{$}}
+
+ find(t.begin(), t.end(), 46);
+ // CHECK-FIXES: {{^ }}find(t.begin(), t.end(), 46);{{$}}
+}
+
+int main() {
+ std::set<int> s;
+ auto it = std::find(s.begin(), s.end(), 43);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: this STL algorithm call should be replaced with a container method [performance-inefficient-algorithm]
+ // CHECK-FIXES: {{^ }}auto it = s.find(43);{{$}}
+ auto c = count(s.begin(), s.end(), 43);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: this STL algorithm call should be
+ // CHECK-FIXES: {{^ }}auto c = s.count(43);{{$}}
+
+#define SECOND(x, y, z) y
+ SECOND(q,std::count(s.begin(), s.end(), 22),w);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: this STL algorithm call should be
+ // CHECK-FIXES: {{^ }}SECOND(q,s.count(22),w);{{$}}
+
+ it = find_if(s.begin(), s.end(), [](int) { return false; });
+
+ std::multiset<int> ms;
+ find(ms.begin(), ms.end(), 46);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this STL algorithm call should be
+ // CHECK-FIXES: {{^ }}ms.find(46);{{$}}
+
+ const std::multiset<int> &msref = ms;
+ find(msref.begin(), msref.end(), 46);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this STL algorithm call should be
+ // CHECK-FIXES: {{^ }}msref.find(46);{{$}}
+
+ std::multiset<int> *msptr = &ms;
+ find(msptr->begin(), msptr->end(), 46);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this STL algorithm call should be
+ // CHECK-FIXES: {{^ }}msptr->find(46);{{$}}
+
+ it = std::find(s.begin(), s.end(), 43, std::greater<int>());
+ // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: different comparers used in the algorithm and the container [performance-inefficient-algorithm]
+
+ FIND_IN_SET(s);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this STL algorithm call should be
+ // CHECK-FIXES: {{^ }}FIND_IN_SET(s);{{$}}
+
+ f(s);
+
+ std::unordered_set<int> us;
+ lower_bound(us.begin(), us.end(), 10);
+ // CHECK-FIXES: {{^ }}lower_bound(us.begin(), us.end(), 10);{{$}}
+ find(us.begin(), us.end(), 10);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this STL algorithm call should be
+ // CHECK-FIXES: {{^ }}us.find(10);{{$}}
+
+ std::unordered_multiset<int> ums;
+ find(ums.begin(), ums.end(), 10);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this STL algorithm call should be
+ // CHECK-FIXES: {{^ }}ums.find(10);{{$}}
+
+ std::map<int, int> intmap;
+ find(intmap.begin(), intmap.end(), 46);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this STL algorithm call should be
+ // CHECK-FIXES: {{^ }}find(intmap.begin(), intmap.end(), 46);{{$}}
+
+ std::multimap<int, int> intmmap;
+ find(intmmap.begin(), intmmap.end(), 46);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this STL algorithm call should be
+ // CHECK-FIXES: {{^ }}find(intmmap.begin(), intmmap.end(), 46);{{$}}
+
+ std::unordered_map<int, int> umap;
+ find(umap.begin(), umap.end(), 46);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this STL algorithm call should be
+ // CHECK-FIXES: {{^ }}find(umap.begin(), umap.end(), 46);{{$}}
+
+ std::unordered_multimap<int, int> ummap;
+ find(ummap.begin(), ummap.end(), 46);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this STL algorithm call should be
+ // CHECK-FIXES: {{^ }}find(ummap.begin(), ummap.end(), 46);{{$}}
+}
+
+struct Value {
+ int value;
+};
+
+struct Ordering {
+ bool operator()(const Value &lhs, const Value &rhs) const {
+ return lhs.value < rhs.value;
+ }
+ bool operator()(int lhs, const Value &rhs) const { return lhs < rhs.value; }
+};
+
+void g(std::set<Value, Ordering> container, int value) {
+ lower_bound(container.begin(), container.end(), value, Ordering());
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this STL algorithm call should be
+ // CHECK-FIXES: {{^ }}lower_bound(container.begin(), container.end(), value, Ordering());{{$}}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-inefficient-string-concatenation.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-inefficient-string-concatenation.cpp
new file mode 100644
index 0000000..1dbd56b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-inefficient-string-concatenation.cpp
@@ -0,0 +1,48 @@
+// RUN: %check_clang_tidy %s performance-inefficient-string-concatenation %t
+
+namespace std {
+template <typename T>
+class basic_string {
+public:
+ basic_string() {}
+ ~basic_string() {}
+ basic_string<T> *operator+=(const basic_string<T> &) {}
+ friend basic_string<T> operator+(const basic_string<T> &, const basic_string<T> &) {}
+};
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+}
+
+void f(std::string) {}
+std::string g(std::string) {}
+
+int main() {
+ std::string mystr1, mystr2;
+ std::wstring mywstr1, mywstr2;
+ auto myautostr1 = mystr1;
+ auto myautostr2 = mystr2;
+
+ for (int i = 0; i < 10; ++i) {
+ f(mystr1 + mystr2 + mystr1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: string concatenation results in allocation of unnecessary temporary strings; consider using 'operator+=' or 'string::append()' instead
+ mystr1 = mystr1 + mystr2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: string concatenation
+ mystr1 = mystr2 + mystr2 + mystr2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: string concatenation
+ mystr1 = mystr2 + mystr1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: string concatenation
+ mywstr1 = mywstr2 + mywstr1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: string concatenation
+ mywstr1 = mywstr2 + mywstr2 + mywstr2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: string concatenation
+ myautostr1 = myautostr1 + myautostr2;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: string concatenation
+
+ mywstr1 = mywstr2 + mywstr2;
+ mystr1 = mystr2 + mystr2;
+ mystr1 += mystr2;
+ f(mystr2 + mystr1);
+ mystr1 = g(mystr1);
+ }
+ return 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-inefficient-vector-operation.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-inefficient-vector-operation.cpp
new file mode 100644
index 0000000..a04f66e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-inefficient-vector-operation.cpp
@@ -0,0 +1,277 @@
+// RUN: %check_clang_tidy %s performance-inefficient-vector-operation %t -- -format-style=llvm -- --std=c++11
+
+namespace std {
+
+typedef int size_t;
+
+template<class E> class initializer_list {
+public:
+ using value_type = E;
+ using reference = E&;
+ using const_reference = const E&;
+ using size_type = size_t;
+ using iterator = const E*;
+ using const_iterator = const E*;
+ initializer_list();
+ size_t size() const; // number of elements
+ const E* begin() const; // first element
+ const E* end() const; // one past the last element
+};
+
+// initializer list range access
+template<class E> const E* begin(initializer_list<E> il);
+template<class E> const E* end(initializer_list<E> il);
+
+template <class T>
+class vector {
+ public:
+ typedef T* iterator;
+ typedef const T* const_iterator;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef size_t size_type;
+
+ explicit vector();
+ explicit vector(size_type n);
+
+ void push_back(const T& val);
+
+ template <class... Args> void emplace_back(Args &&... args);
+
+ void reserve(size_t n);
+ void resize(size_t n);
+
+ size_t size();
+ const_reference operator[] (size_type) const;
+ reference operator[] (size_type);
+
+ const_iterator begin() const;
+ const_iterator end() const;
+};
+} // namespace std
+
+class Foo {
+ public:
+ explicit Foo(int);
+};
+
+class Bar {
+ public:
+ Bar(int);
+};
+
+int Op(int);
+
+void f(std::vector<int>& t) {
+ {
+ std::vector<int> v0;
+ // CHECK-FIXES: v0.reserve(10);
+ for (int i = 0; i < 10; ++i)
+ v0.push_back(i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside a loop; consider pre-allocating the vector capacity before the loop
+ }
+ {
+ std::vector<int> v1;
+ // CHECK-FIXES: v1.reserve(10);
+ for (int i = 0; i < 10; i++)
+ v1.push_back(i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
+ }
+ {
+ std::vector<int> v2;
+ // CHECK-FIXES: v2.reserve(10);
+ for (int i = 0; i < 10; ++i)
+ v2.push_back(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
+ }
+ {
+ std::vector<int> v3;
+ // CHECK-FIXES: v3.reserve(5);
+ for (int i = 0; i < 5; ++i) {
+ v3.push_back(i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
+ }
+ // CHECK-FIXES-NOT: v3.reserve(10);
+ for (int i = 0; i < 10; ++i) {
+ // No fix for this loop as we encounter the prior loops.
+ v3.push_back(i);
+ }
+ }
+ {
+ std::vector<int> v4;
+ std::vector<int> v5;
+ v5.reserve(3);
+ // CHECK-FIXES: v4.reserve(10);
+ for (int i = 0; i < 10; ++i)
+ v4.push_back(i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
+ }
+ {
+ std::vector<int> v6;
+ // CHECK-FIXES: v6.reserve(t.size());
+ for (std::size_t i = 0; i < t.size(); ++i) {
+ v6.push_back(t[i]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
+ }
+ }
+ {
+ std::vector<int> v7;
+ // CHECK-FIXES: v7.reserve(t.size() - 1);
+ for (std::size_t i = 0; i < t.size() - 1; ++i) {
+ v7.push_back(t[i]);
+ } // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
+ }
+ {
+ std::vector<int> v8;
+ // CHECK-FIXES: v8.reserve(t.size());
+ for (const auto &e : t) {
+ v8.push_back(e);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
+ }
+ }
+ {
+ std::vector<int> v9;
+ // CHECK-FIXES: v9.reserve(t.size());
+ for (const auto &e : t) {
+ v9.push_back(Op(e));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
+ }
+ }
+ {
+ std::vector<Foo> v10;
+ // CHECK-FIXES: v10.reserve(t.size());
+ for (const auto &e : t) {
+ v10.push_back(Foo(e));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
+ }
+ }
+ {
+ std::vector<Bar> v11;
+ // CHECK-FIXES: v11.reserve(t.size());
+ for (const auto &e : t) {
+ v11.push_back(e);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called
+ }
+ }
+ {
+ std::vector<Foo> v12;
+ // CHECK-FIXES: v12.reserve(t.size());
+ for (const auto &e : t) {
+ v12.emplace_back(e);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'emplace_back' is called
+ }
+ }
+
+ // ---- Non-fixed Cases ----
+ {
+ std::vector<int> z0;
+ z0.reserve(20);
+ // CHECK-FIXES-NOT: z0.reserve(10);
+ // There is a "reserve" call already.
+ for (int i = 0; i < 10; ++i) {
+ z0.push_back(i);
+ }
+ }
+ {
+ std::vector<int> z1;
+ z1.reserve(5);
+ // CHECK-FIXES-NOT: z1.reserve(10);
+ // There is a "reserve" call already.
+ for (int i = 0; i < 10; ++i) {
+ z1.push_back(i);
+ }
+ }
+ {
+ std::vector<int> z2;
+ z2.resize(5);
+ // CHECK-FIXES-NOT: z2.reserve(10);
+ // There is a ref usage of v before the loop.
+ for (int i = 0; i < 10; ++i) {
+ z2.push_back(i);
+ }
+ }
+ {
+ std::vector<int> z3;
+ z3.push_back(0);
+ // CHECK-FIXES-NOT: z3.reserve(10);
+ // There is a ref usage of v before the loop.
+ for (int i = 0; i < 10; ++i) {
+ z3.push_back(i);
+ }
+ }
+ {
+ std::vector<int> z4;
+ f(z4);
+ // CHECK-FIXES-NOT: z4.reserve(10);
+ // There is a ref usage of z4 before the loop.
+ for (int i = 0; i < 10; ++i) {
+ z4.push_back(i);
+ }
+ }
+ {
+ std::vector<int> z5(20);
+ // CHECK-FIXES-NOT: z5.reserve(10);
+ // z5 is not constructed with default constructor.
+ for (int i = 0; i < 10; ++i) {
+ z5.push_back(i);
+ }
+ }
+ {
+ std::vector<int> z6;
+ // CHECK-FIXES-NOT: z6.reserve(10);
+ // For-loop is not started with 0.
+ for (int i = 1; i < 10; ++i) {
+ z6.push_back(i);
+ }
+ }
+ {
+ std::vector<int> z7;
+ // CHECK-FIXES-NOT: z7.reserve(t.size());
+ // z7 isn't referenced in for-loop body.
+ for (std::size_t i = 0; i < t.size(); ++i) {
+ t.push_back(i);
+ }
+ }
+ {
+ std::vector<int> z8;
+ int k;
+ // CHECK-FIXES-NOT: z8.reserve(10);
+ // For-loop isn't a fixable loop.
+ for (std::size_t i = 0; k < 10; ++i) {
+ z8.push_back(t[i]);
+ }
+ }
+ {
+ std::vector<int> z9;
+ // CHECK-FIXES-NOT: z9.reserve(i + 1);
+ // The loop end expression refers to the loop variable i.
+ for (int i = 0; i < i + 1; i++)
+ z9.push_back(i);
+ }
+ {
+ std::vector<int> z10;
+ int k;
+ // CHECK-FIXES-NOT: z10.reserve(10);
+ // For-loop isn't a fixable loop.
+ for (std::size_t i = 0; i < 10; ++k) {
+ z10.push_back(t[i]);
+ }
+ }
+ {
+ std::vector<int> z11;
+ // initializer_list should not trigger the check.
+ for (int e : {1, 2, 3, 4, 5}) {
+ z11.push_back(e);
+ }
+ }
+ {
+ std::vector<int> z12;
+ std::vector<int>* z13 = &t;
+ // We only support detecting the range init expression which references
+ // container directly.
+ // Complex range init expressions like `*z13` is not supported.
+ for (const auto &e : *z13) {
+ z12.push_back(e);
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-move-const-arg-trivially-copyable.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-move-const-arg-trivially-copyable.cpp
new file mode 100644
index 0000000..ea0c2fc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-move-const-arg-trivially-copyable.cpp
@@ -0,0 +1,98 @@
+// RUN: %check_clang_tidy %s performance-move-const-arg %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: performance-move-const-arg.CheckTriviallyCopyableMove, value: 0}]}' \
+// RUN: -- -std=c++14
+
+namespace std {
+
+template <typename> struct remove_reference;
+template <typename _Tp> struct remove_reference { typedef _Tp type; };
+template <typename _Tp> struct remove_reference<_Tp &> { typedef _Tp type; };
+template <typename _Tp> struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template <typename _Tp>
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) {
+ return static_cast<typename std::remove_reference<_Tp>::type &&>(__t);
+}
+
+template <typename _Tp>
+constexpr _Tp &&
+forward(typename remove_reference<_Tp>::type &__t) noexcept {
+ return static_cast<_Tp &&>(__t);
+}
+
+} // namespace std
+
+class NoMoveSemantics {
+ public:
+ NoMoveSemantics();
+ NoMoveSemantics(const NoMoveSemantics &);
+
+ NoMoveSemantics &operator=(const NoMoveSemantics &);
+};
+
+void callByConstRef(const NoMoveSemantics &);
+void callByConstRef(int i, const NoMoveSemantics &);
+
+void moveToConstReferencePositives() {
+ NoMoveSemantics obj;
+
+ // Basic case. It is here just to have a single "detected and fixed" case.
+ callByConstRef(std::move(obj));
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as a const reference argument; no move will actually happen [performance-move-const-arg]
+ // CHECK-FIXES: callByConstRef(obj);
+}
+
+struct TriviallyCopyable {
+ int i;
+};
+
+void f(TriviallyCopyable) {}
+
+void g() {
+ TriviallyCopyable obj;
+ f(std::move(obj));
+}
+
+class MoveSemantics {
+ public:
+ MoveSemantics();
+ MoveSemantics(MoveSemantics &&);
+
+ MoveSemantics &operator=(MoveSemantics &&);
+};
+
+void fmovable(MoveSemantics);
+
+void lambda1() {
+ auto f = [](MoveSemantics m) {
+ fmovable(std::move(m));
+ };
+ f(MoveSemantics());
+}
+
+template<class T> struct function {};
+
+template<typename Result, typename... Args>
+class function<Result(Args...)> {
+public:
+ function() = default;
+ void operator()(Args... args) const {
+ fmovable(std::forward<Args>(args)...);
+ }
+};
+
+void functionInvocation() {
+ function<void(MoveSemantics)> callback;
+ MoveSemantics m;
+ callback(std::move(m));
+}
+
+void lambda2() {
+ function<void(MoveSemantics)> callback;
+
+ auto f = [callback = std::move(callback)](MoveSemantics m) mutable {
+ callback(std::move(m));
+ };
+ f(MoveSemantics());
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-move-const-arg.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-move-const-arg.cpp
new file mode 100644
index 0000000..06ed6e0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-move-const-arg.cpp
@@ -0,0 +1,248 @@
+// RUN: %check_clang_tidy %s performance-move-const-arg %t
+
+namespace std {
+template <typename>
+struct remove_reference;
+
+template <typename _Tp>
+struct remove_reference {
+ typedef _Tp type;
+};
+
+template <typename _Tp>
+struct remove_reference<_Tp &> {
+ typedef _Tp type;
+};
+
+template <typename _Tp>
+struct remove_reference<_Tp &&> {
+ typedef _Tp type;
+};
+
+template <typename _Tp>
+constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) {
+ return static_cast<typename std::remove_reference<_Tp>::type &&>(__t);
+}
+
+template <typename _Tp>
+constexpr _Tp &&
+forward(typename remove_reference<_Tp>::type &__t) noexcept {
+ return static_cast<_Tp &&>(__t);
+}
+
+} // namespace std
+
+class A {
+public:
+ A() {}
+ A(const A &rhs) {}
+ A(A &&rhs) {}
+};
+
+struct TriviallyCopyable {
+ int i;
+};
+
+void f(TriviallyCopyable) {}
+
+void g() {
+ TriviallyCopyable obj;
+ f(std::move(obj));
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: std::move of the variable 'obj' of the trivially-copyable type 'TriviallyCopyable' has no effect; remove std::move() [performance-move-const-arg]
+ // CHECK-FIXES: f(obj);
+}
+
+int f1() {
+ return std::move(42);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the expression of the trivially-copyable type 'int' has no effect; remove std::move() [performance-move-const-arg]
+ // CHECK-FIXES: return 42;
+}
+
+int f2(int x2) {
+ return std::move(x2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the variable 'x2' of the trivially-copyable type 'int'
+ // CHECK-FIXES: return x2;
+}
+
+int *f3(int *x3) {
+ return std::move(x3);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the variable 'x3' of the trivially-copyable type 'int *'
+ // CHECK-FIXES: return x3;
+}
+
+A f4(A x4) { return std::move(x4); }
+
+A f5(const A x5) {
+ return std::move(x5);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the const variable 'x5' has no effect; remove std::move() or make the variable non-const [performance-move-const-arg]
+ // CHECK-FIXES: return x5;
+}
+
+template <typename T>
+T f6(const T x6) {
+ return std::move(x6);
+}
+
+void f7() { int a = f6(10); }
+
+#define M1(x) x
+void f8() {
+ const A a;
+ M1(A b = std::move(a);)
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: std::move of the const variable 'a' has no effect; remove std::move() or make the variable non-const
+ // CHECK-FIXES: M1(A b = a;)
+}
+
+#define M2(x) std::move(x)
+int f9() { return M2(1); }
+
+template <typename T>
+T f10(const int x10) {
+ return std::move(x10);
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the const variable 'x10' of the trivially-copyable type 'const int' has no effect; remove std::move() [performance-move-const-arg]
+ // CHECK-FIXES: return x10;
+}
+void f11() {
+ f10<int>(1);
+ f10<double>(1);
+}
+
+class NoMoveSemantics {
+public:
+ NoMoveSemantics();
+ NoMoveSemantics(const NoMoveSemantics &);
+
+ NoMoveSemantics &operator=(const NoMoveSemantics &);
+};
+
+void callByConstRef(const NoMoveSemantics &);
+void callByConstRef(int i, const NoMoveSemantics &);
+
+void moveToConstReferencePositives() {
+ NoMoveSemantics obj;
+
+ // Basic case.
+ callByConstRef(std::move(obj));
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as
+ // CHECK-FIXES: callByConstRef(obj);
+
+ // Also works for second argument.
+ callByConstRef(1, std::move(obj));
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: passing result of std::move() as
+ // CHECK-FIXES: callByConstRef(1, obj);
+
+ // Works if std::move() applied to a temporary.
+ callByConstRef(std::move(NoMoveSemantics()));
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing result of std::move() as
+ // CHECK-FIXES: callByConstRef(NoMoveSemantics());
+
+ // Works if calling a copy constructor.
+ NoMoveSemantics other(std::move(obj));
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: passing result of std::move() as
+ // CHECK-FIXES: NoMoveSemantics other(obj);
+
+ // Works if calling assignment operator.
+ other = std::move(obj);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing result of std::move() as
+ // CHECK-FIXES: other = obj;
+}
+
+class MoveSemantics {
+public:
+ MoveSemantics();
+ MoveSemantics(MoveSemantics &&);
+
+ MoveSemantics &operator=(MoveSemantics &&);
+};
+
+void callByValue(MoveSemantics);
+
+void callByRValueRef(MoveSemantics &&);
+
+template <class T>
+void templateFunction(T obj) {
+ T other = std::move(obj);
+}
+
+#define M3(T, obj) \
+ do { \
+ T other = std::move(obj); \
+ } while (true)
+
+#define CALL(func) (func)()
+
+void moveToConstReferenceNegatives() {
+ // No warning when actual move takes place.
+ MoveSemantics move_semantics;
+ callByValue(std::move(move_semantics));
+ callByRValueRef(std::move(move_semantics));
+ MoveSemantics other(std::move(move_semantics));
+ other = std::move(move_semantics);
+
+ // No warning if std::move() not used.
+ NoMoveSemantics no_move_semantics;
+ callByConstRef(no_move_semantics);
+
+ // No warning if instantiating a template.
+ templateFunction(no_move_semantics);
+
+ // No warning inside of macro expansions.
+ M3(NoMoveSemantics, no_move_semantics);
+
+ // No warning inside of macro expansion, even if the macro expansion is inside
+ // a lambda that is, in turn, an argument to a macro.
+ CALL([no_move_semantics] { M3(NoMoveSemantics, no_move_semantics); });
+
+ auto lambda = [] {};
+ auto lambda2 = std::move(lambda);
+}
+
+class MoveOnly {
+public:
+ MoveOnly(const MoveOnly &other) = delete;
+ MoveOnly &operator=(const MoveOnly &other) = delete;
+ MoveOnly(MoveOnly &&other) = default;
+ MoveOnly &operator=(MoveOnly &&other) = default;
+};
+template <class T>
+void Q(T);
+void moveOnlyNegatives(MoveOnly val) {
+ Q(std::move(val));
+}
+
+void fmovable(MoveSemantics);
+
+void lambda1() {
+ auto f = [](MoveSemantics m) {
+ fmovable(std::move(m));
+ };
+ f(MoveSemantics());
+}
+
+template<class T> struct function {};
+
+template<typename Result, typename... Args>
+class function<Result(Args...)> {
+public:
+ function() = default;
+ void operator()(Args... args) const {
+ fmovable(std::forward<Args>(args)...);
+ }
+};
+
+void functionInvocation() {
+ function<void(MoveSemantics)> callback;
+ MoveSemantics m;
+ callback(std::move(m));
+}
+
+void lambda2() {
+ function<void(MoveSemantics)> callback;
+
+ auto f = [callback = std::move(callback)](MoveSemantics m) mutable {
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: std::move of the variable 'callback' of the trivially-copyable type 'function<void (MoveSemantics)>' has no effect; remove std::move()
+ // CHECK-FIXES: auto f = [callback = callback](MoveSemantics m) mutable {
+ callback(std::move(m));
+ };
+ f(MoveSemantics());
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-move-constructor-init.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-move-constructor-init.cpp
new file mode 100644
index 0000000..c9ed346
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-move-constructor-init.cpp
@@ -0,0 +1,154 @@
+// RUN: %check_clang_tidy %s performance-move-constructor-init,modernize-pass-by-value %t -- \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: modernize-pass-by-value.ValuesOnly, value: 1}]}' \
+// RUN: -- -std=c++11 -isystem %S/Inputs/Headers
+
+#include <s.h>
+
+// CHECK-FIXES: #include <utility>
+
+template <class T> struct remove_reference {typedef T type;};
+template <class T> struct remove_reference<T&> {typedef T type;};
+template <class T> struct remove_reference<T&&> {typedef T type;};
+
+template <typename T>
+typename remove_reference<T>::type&& move(T&& arg) {
+ return static_cast<typename remove_reference<T>::type&&>(arg);
+}
+
+struct C {
+ C() = default;
+ C(const C&) = default;
+};
+
+struct B {
+ B() {}
+ B(const B&) {}
+ B(B &&) {}
+};
+
+struct D : B {
+ D() : B() {}
+ D(const D &RHS) : B(RHS) {}
+ // CHECK-MESSAGES: :[[@LINE+3]]:16: warning: move constructor initializes base class by calling a copy constructor [performance-move-constructor-init]
+ // CHECK-MESSAGES: 26:3: note: copy constructor being called
+ // CHECK-MESSAGES: 27:3: note: candidate move constructor here
+ D(D &&RHS) : B(RHS) {}
+};
+
+struct E : B {
+ E() : B() {}
+ E(const E &RHS) : B(RHS) {}
+ E(E &&RHS) : B(move(RHS)) {} // ok
+};
+
+struct F {
+ C M;
+
+ F(F &&) : M(C()) {} // ok
+};
+
+struct G {
+ G() = default;
+ G(const G&) = default;
+ G(G&&) = delete;
+};
+
+struct H : G {
+ H() = default;
+ H(const H&) = default;
+ H(H &&RHS) : G(RHS) {} // ok
+};
+
+struct I {
+ I(const I &) = default; // suppresses move constructor creation
+};
+
+struct J : I {
+ J(J &&RHS) : I(RHS) {} // ok
+};
+
+struct K {}; // Has implicit copy and move constructors, is trivially copyable
+struct L : K {
+ L(L &&RHS) : K(RHS) {} // ok
+};
+
+struct M {
+ B Mem;
+ // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: move constructor initializes class member by calling a copy constructor [performance-move-constructor-init]
+ M(M &&RHS) : Mem(RHS.Mem) {}
+};
+
+struct N {
+ B Mem;
+ N(N &&RHS) : Mem(move(RHS.Mem)) {}
+};
+
+struct O {
+ O(O&& other) : b(other.b) {} // ok
+ const B b;
+};
+
+struct P {
+ P(O&& other) : b(other.b) {} // ok
+ B b;
+};
+
+struct Movable {
+ Movable(Movable &&) = default;
+ Movable(const Movable &) = default;
+ Movable &operator=(const Movable &) = default;
+ ~Movable() {}
+};
+
+struct TriviallyCopyable {
+ TriviallyCopyable() = default;
+ TriviallyCopyable(TriviallyCopyable &&) = default;
+ TriviallyCopyable(const TriviallyCopyable &) = default;
+};
+
+struct Positive {
+ Positive(Movable M) : M_(M) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: pass by value and use std::move [modernize-pass-by-value]
+ // CHECK-FIXES: Positive(Movable M) : M_(std::move(M)) {}
+ Movable M_;
+};
+
+struct NegativeMultipleInitializerReferences {
+ NegativeMultipleInitializerReferences(Movable M) : M_(M), n_(M) {}
+ Movable M_;
+ Movable n_;
+};
+
+struct NegativeReferencedInConstructorBody {
+ NegativeReferencedInConstructorBody(Movable M) : M_(M) { M_ = M; }
+ Movable M_;
+};
+
+struct NegativeParamTriviallyCopyable {
+ NegativeParamTriviallyCopyable(TriviallyCopyable T) : T_(T) {}
+ NegativeParamTriviallyCopyable(int I) : I_(I) {}
+
+ TriviallyCopyable T_;
+ int I_;
+};
+
+struct NegativeNotPassedByValue {
+ // This const ref constructor isn't warned about because the ValuesOnly option is set.
+ NegativeNotPassedByValue(const Movable &M) : M_(M) {}
+ NegativeNotPassedByValue(const Movable M) : M_(M) {}
+ NegativeNotPassedByValue(Movable &M) : M_(M) {}
+ NegativeNotPassedByValue(Movable *M) : M_(*M) {}
+ NegativeNotPassedByValue(const Movable *M) : M_(*M) {}
+ Movable M_;
+};
+
+struct Immovable {
+ Immovable(const Immovable &) = default;
+ Immovable(Immovable &&) = delete;
+};
+
+struct NegativeImmovableParameter {
+ NegativeImmovableParameter(Immovable I) : I_(I) {}
+ Immovable I_;
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-noexcept-move-constructor.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-noexcept-move-constructor.cpp
new file mode 100644
index 0000000..70d7065
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-noexcept-move-constructor.cpp
@@ -0,0 +1,54 @@
+// RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t
+
+class A {
+ A(A &&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
+ A &operator=(A &&);
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should
+};
+
+struct B {
+ static constexpr bool kFalse = false;
+ B(B &&) noexcept(kFalse);
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
+};
+
+class OK {};
+
+void f() {
+ OK a;
+ a = OK();
+}
+
+class OK1 {
+public:
+ OK1();
+ OK1(const OK1 &);
+ OK1(OK1 &&) noexcept;
+ OK1 &operator=(OK1 &&) noexcept;
+ void f();
+ void g() noexcept;
+};
+
+class OK2 {
+ static constexpr bool kTrue = true;
+
+public:
+ OK2(OK2 &&) noexcept(true) {}
+ OK2 &operator=(OK2 &&) noexcept(kTrue) { return *this; }
+};
+
+struct OK3 {
+ OK3(OK3 &&) noexcept(false) {}
+ OK3 &operator=(OK3 &&) = delete;
+};
+
+struct OK4 {
+ OK4(OK4 &&) noexcept = default;
+ OK4 &operator=(OK4 &&) noexcept = default;
+};
+
+struct OK5 {
+ OK5(OK5 &&) noexcept(true) = default;
+ OK5 &operator=(OK5 &&) noexcept(true) = default;
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-type-promotion-in-math-fn.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-type-promotion-in-math-fn.cpp
new file mode 100644
index 0000000..b2da7cc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-type-promotion-in-math-fn.cpp
@@ -0,0 +1,316 @@
+// RUN: %check_clang_tidy %s performance-type-promotion-in-math-fn %t
+
+// CHECK-FIXES: #include <cmath>
+
+double acos(double);
+double acosh(double);
+double asin(double);
+double asinh(double);
+double atan2(double, double);
+double atan(double);
+double atanh(double);
+double cbrt(double);
+double ceil(double);
+double copysign(double, double);
+double cos(double);
+double cosh(double);
+double erfc(double);
+double erf(double);
+double exp2(double);
+double exp(double);
+double expm1(double);
+double fabs(double);
+double fdim(double, double);
+double floor(double);
+double fma(double, double, double);
+double fmax(double, double);
+double fmin(double, double);
+double fmod(double, double);
+double frexp(double, int *);
+double hypot(double, double);
+double ilogb(double);
+double ldexp(double, double);
+double lgamma(double);
+long long llrint(double);
+double log10(double);
+double log1p(double);
+double log2(double);
+double logb(double);
+double log(double);
+long lrint(double);
+double modf(double);
+double nearbyint(double);
+double nextafter(double, double);
+double nexttoward(double, long double);
+double pow(double, double);
+double remainder(double, double);
+double remquo(double, double, int *);
+double rint(double);
+double round(double);
+double scalbln(double, long);
+double scalbn(double, int);
+double sin(double);
+double sinh(double);
+double sqrt(double);
+double tan(double);
+double tanh(double);
+double tgamma(double);
+double trunc(double);
+long long llround(double);
+long lround(double);
+
+void check_all_fns() {
+ float a, b, c;
+ int i;
+ long l;
+ int *int_ptr;
+
+ acos(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'acos' promotes float to double [performance-type-promotion-in-math-fn]
+ // CHECK-FIXES: {{^}} std::acos(a);{{$}}
+ acosh(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'acosh'
+ // CHECK-FIXES: {{^}} std::acosh(a);{{$}}
+ asin(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'asin'
+ // CHECK-FIXES: {{^}} std::asin(a);{{$}}
+ asinh(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'asinh'
+ // CHECK-FIXES: {{^}} std::asinh(a);{{$}}
+ atan2(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'atan2'
+ // CHECK-FIXES: {{^}} std::atan2(a, b);{{$}}
+ atan(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'atan'
+ // CHECK-FIXES: {{^}} std::atan(a);{{$}}
+ atanh(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'atanh'
+ // CHECK-FIXES: {{^}} std::atanh(a);{{$}}
+ cbrt(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'cbrt'
+ // CHECK-FIXES: {{^}} std::cbrt(a);{{$}}
+ ceil(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'ceil'
+ // CHECK-FIXES: {{^}} std::ceil(a);{{$}}
+ copysign(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'copysign'
+ // CHECK-FIXES: {{^}} std::copysign(a, b);{{$}}
+ cos(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'cos'
+ // CHECK-FIXES: {{^}} std::cos(a);{{$}}
+ cosh(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'cosh'
+ // CHECK-FIXES: {{^}} std::cosh(a);{{$}}
+ erf(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'erf'
+ // CHECK-FIXES: {{^}} std::erf(a);{{$}}
+ erfc(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'erfc'
+ // CHECK-FIXES: {{^}} std::erfc(a);{{$}}
+ exp2(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'exp2'
+ // CHECK-FIXES: {{^}} std::exp2(a);{{$}}
+ exp(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'exp'
+ // CHECK-FIXES: {{^}} std::exp(a);{{$}}
+ expm1(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'expm1'
+ // CHECK-FIXES: {{^}} std::expm1(a);{{$}}
+ fabs(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'fabs'
+ // CHECK-FIXES: {{^}} std::fabs(a);{{$}}
+ fdim(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'fdim'
+ // CHECK-FIXES: {{^}} std::fdim(a, b);{{$}}
+ floor(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'floor'
+ // CHECK-FIXES: {{^}} std::floor(a);{{$}}
+ fma(a, b, c);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'fma'
+ // CHECK-FIXES: {{^}} std::fma(a, b, c);{{$}}
+ fmax(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'fmax'
+ // CHECK-FIXES: {{^}} std::fmax(a, b);{{$}}
+ fmin(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'fmin'
+ // CHECK-FIXES: {{^}} std::fmin(a, b);{{$}}
+ fmod(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'fmod'
+ // CHECK-FIXES: {{^}} std::fmod(a, b);{{$}}
+ frexp(a, int_ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'frexp'
+ // CHECK-FIXES: {{^}} std::frexp(a, int_ptr);{{$}}
+ hypot(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'hypot'
+ // CHECK-FIXES: {{^}} std::hypot(a, b);{{$}}
+ ilogb(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'ilogb'
+ // CHECK-FIXES: {{^}} std::ilogb(a);{{$}}
+ ldexp(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'ldexp'
+ // CHECK-FIXES: {{^}} std::ldexp(a, b);{{$}}
+ lgamma(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'lgamma'
+ // CHECK-FIXES: {{^}} std::lgamma(a);{{$}}
+ llrint(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'llrint'
+ // CHECK-FIXES: {{^}} std::llrint(a);{{$}}
+ llround(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'llround'
+ // CHECK-FIXES: {{^}} std::llround(a);{{$}}
+ log10(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'log10'
+ // CHECK-FIXES: {{^}} std::log10(a);{{$}}
+ log1p(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'log1p'
+ // CHECK-FIXES: {{^}} std::log1p(a);{{$}}
+ log2(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'log2'
+ // CHECK-FIXES: {{^}} std::log2(a);{{$}}
+ log(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'log'
+ // CHECK-FIXES: {{^}} std::log(a);{{$}}
+ logb(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'logb'
+ // CHECK-FIXES: {{^}} std::logb(a);{{$}}
+ lrint(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'lrint'
+ // CHECK-FIXES: {{^}} std::lrint(a);{{$}}
+ lround(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'lround'
+ // CHECK-FIXES: {{^}} std::lround(a);{{$}}
+ nearbyint(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'nearbyint'
+ // CHECK-FIXES: {{^}} std::nearbyint(a);{{$}}
+ nextafter(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'nextafter'
+ // CHECK-FIXES: {{^}} std::nextafter(a, b);{{$}}
+ nexttoward(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'nexttoward'
+ // CHECK-FIXES: {{^}} std::nexttoward(a, b);{{$}}
+ pow(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'pow'
+ // CHECK-FIXES: {{^}} std::pow(a, b);{{$}}
+ remainder(a, b);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'remainder'
+ // CHECK-FIXES: {{^}} std::remainder(a, b);{{$}}
+ remquo(a, b, int_ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'remquo'
+ // CHECK-FIXES: {{^}} std::remquo(a, b, int_ptr);{{$}}
+ rint(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'rint'
+ // CHECK-FIXES: {{^}} std::rint(a);{{$}}
+ round(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'round'
+ // CHECK-FIXES: {{^}} std::round(a);{{$}}
+ scalbln(a, l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'scalbln'
+ // CHECK-FIXES: {{^}} std::scalbln(a, l);{{$}}
+ scalbn(a, i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'scalbn'
+ // CHECK-FIXES: {{^}} std::scalbn(a, i);{{$}}
+ sin(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'sin'
+ // CHECK-FIXES: {{^}} std::sin(a);{{$}}
+ sinh(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'sinh'
+ // CHECK-FIXES: {{^}} std::sinh(a);{{$}}
+ sqrt(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'sqrt'
+ // CHECK-FIXES: {{^}} std::sqrt(a);{{$}}
+ tan(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'tan'
+ // CHECK-FIXES: {{^}} std::tan(a);{{$}}
+ tanh(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'tanh'
+ // CHECK-FIXES: {{^}} std::tanh(a);{{$}}
+ tgamma(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'tgamma'
+ // CHECK-FIXES: {{^}} std::tgamma(a);{{$}}
+ trunc(a);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'trunc'
+ // CHECK-FIXES: {{^}} std::trunc(a);{{$}}
+}
+
+// nexttoward/nexttowardf are weird -- the second param is always long double.
+// So we warn if the first arg is a float, regardless of what the second arg is.
+void check_nexttoward() {
+ nexttoward(0.f, 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'nexttoward'
+ // CHECK-FIXES: {{^}} std::nexttoward(0.f, 0);{{$}}
+ nexttoward(0.f, 0l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'nexttoward'
+ // CHECK-FIXES: {{^}} std::nexttoward(0.f, 0l);{{$}}
+ nexttoward(0.f, 0.f);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'nexttoward'
+ // CHECK-FIXES: {{^}} std::nexttoward(0.f, 0.f);{{$}}
+ nexttoward(0.f, 0.);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'nexttoward'
+ // CHECK-FIXES: {{^}} std::nexttoward(0.f, 0.);{{$}}
+
+ // No warnings for these.
+ nexttoward(0., 0);
+ nexttoward(0., 0.f);
+ nexttoward(0., 0.);
+}
+
+// The second parameter to scalbn and scalbnf is an int, so we don't care what
+// type you pass as that argument; we warn iff the first argument is a float.
+void check_scalbn() {
+ scalbn(0.f, 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'scalbn'
+ // CHECK-FIXES: {{^}} std::scalbn(0.f, 0);{{$}}
+ scalbn(0.f, static_cast<char>(0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'scalbn'
+ // CHECK-FIXES: {{^}} std::scalbn(0.f, static_cast<char>(0));{{$}}
+
+ // No warnings for these.
+ scalbn(0., 0);
+ scalbn(0., static_cast<char>(0));
+}
+
+// scalbln/scalblnf are like scalbn/scalbnf except their second arg is a long.
+// Again, doesn't matter what we pass for the second arg; we warn iff the first
+// arg is a float.
+void check_scalbln() {
+ scalbln(0.f, 0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'scalbln'
+ // CHECK-FIXES: {{^}} std::scalbln(0.f, 0);{{$}}
+ scalbln(0.f, 0l);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: call to 'scalbln'
+ // CHECK-FIXES: {{^}} std::scalbln(0.f, 0l);{{$}}
+
+ // No warnings for these.
+ scalbln(0., 0);
+ scalbln(0., 0l);
+}
+
+float cosf(float);
+double foo(double); // not a math.h function
+float cos(float); // not a math.h function (wrong signature)
+double cos(double, double); // not a math.h function (wrong signature)
+
+namespace std {
+void cos(float);
+} // namespace std
+
+void check_no_warnings() {
+ foo(0.); // no warning because not a math.h function.
+
+ sin(0); // no warning because arg is an int
+ cos(0.); // no warning because arg is a double
+ std::cos(0.f); // no warning because not ::cos.
+ cosf(0.f); // no warning; we expect this to take a float
+ cos(0.f); // does not match the expected signature of ::cos
+ cos(0.f, 0.f); // does not match the expected signature of ::cos
+
+ // No warnings because all args are not floats.
+ remainder(0., 0.f);
+ remainder(0.f, 0.);
+ remainder(0, 0.f);
+ remainder(0.f, 0);
+ fma(0.f, 0.f, 0);
+ fma(0.f, 0.f, 0.);
+ fma(0.f, 0., 0.f);
+ fma(0., 0.f, 0.f);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-copy-initialization.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-copy-initialization.cpp
new file mode 100644
index 0000000..50dcfd8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-copy-initialization.cpp
@@ -0,0 +1,389 @@
+// RUN: %check_clang_tidy %s performance-unnecessary-copy-initialization %t
+
+struct ExpensiveToCopyType {
+ ExpensiveToCopyType();
+ virtual ~ExpensiveToCopyType();
+ const ExpensiveToCopyType &reference() const;
+ void nonConstMethod();
+ bool constMethod() const;
+};
+
+struct TrivialToCopyType {
+ const TrivialToCopyType &reference() const;
+};
+
+struct WeirdCopyCtorType {
+ WeirdCopyCtorType();
+ WeirdCopyCtorType(const WeirdCopyCtorType &w, bool oh_yes = true);
+
+ void nonConstMethod();
+ bool constMethod() const;
+};
+
+ExpensiveToCopyType global_expensive_to_copy_type;
+
+const ExpensiveToCopyType &ExpensiveTypeReference();
+const TrivialToCopyType &TrivialTypeReference();
+
+void mutate(ExpensiveToCopyType &);
+void mutate(ExpensiveToCopyType *);
+void useAsConstPointer(const ExpensiveToCopyType *);
+void useAsConstReference(const ExpensiveToCopyType &);
+void useByValue(ExpensiveToCopyType);
+
+void PositiveFunctionCall() {
+ const auto AutoAssigned = ExpensiveTypeReference();
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' is copy-constructed from a const reference; consider making it a const reference [performance-unnecessary-copy-initialization]
+ // CHECK-FIXES: const auto& AutoAssigned = ExpensiveTypeReference();
+ const auto AutoCopyConstructed(ExpensiveTypeReference());
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed'
+ // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveTypeReference());
+ const ExpensiveToCopyType VarAssigned = ExpensiveTypeReference();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned'
+ // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveTypeReference();
+ const ExpensiveToCopyType VarCopyConstructed(ExpensiveTypeReference());
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed'
+ // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveTypeReference());
+}
+
+void PositiveMethodCallConstReferenceParam(const ExpensiveToCopyType &Obj) {
+ const auto AutoAssigned = Obj.reference();
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned'
+ // CHECK-FIXES: const auto& AutoAssigned = Obj.reference();
+ const auto AutoCopyConstructed(Obj.reference());
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed'
+ // CHECK-FIXES: const auto& AutoCopyConstructed(Obj.reference());
+ const ExpensiveToCopyType VarAssigned = Obj.reference();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned'
+ // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj.reference();
+ const ExpensiveToCopyType VarCopyConstructed(Obj.reference());
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed'
+ // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj.reference());
+}
+
+void PositiveMethodCallConstParam(const ExpensiveToCopyType Obj) {
+ const auto AutoAssigned = Obj.reference();
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned'
+ // CHECK-FIXES: const auto& AutoAssigned = Obj.reference();
+ const auto AutoCopyConstructed(Obj.reference());
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed'
+ // CHECK-FIXES: const auto& AutoCopyConstructed(Obj.reference());
+ const ExpensiveToCopyType VarAssigned = Obj.reference();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned'
+ // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj.reference();
+ const ExpensiveToCopyType VarCopyConstructed(Obj.reference());
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed'
+ // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj.reference());
+}
+
+void PositiveMethodCallConstPointerParam(const ExpensiveToCopyType *const Obj) {
+ const auto AutoAssigned = Obj->reference();
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned'
+ // CHECK-FIXES: const auto& AutoAssigned = Obj->reference();
+ const auto AutoCopyConstructed(Obj->reference());
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed'
+ // CHECK-FIXES: const auto& AutoCopyConstructed(Obj->reference());
+ const ExpensiveToCopyType VarAssigned = Obj->reference();
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned'
+ // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj->reference();
+ const ExpensiveToCopyType VarCopyConstructed(Obj->reference());
+ // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed'
+ // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj->reference());
+}
+
+void PositiveLocalConstValue() {
+ const ExpensiveToCopyType Obj;
+ const auto UnnecessaryCopy = Obj.reference();
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy'
+ // CHECK-FIXES: const auto& UnnecessaryCopy = Obj.reference();
+}
+
+void PositiveLocalConstRef() {
+ const ExpensiveToCopyType Obj;
+ const ExpensiveToCopyType &ConstReference = Obj.reference();
+ const auto UnnecessaryCopy = ConstReference.reference();
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy'
+ // CHECK-FIXES: const auto& UnnecessaryCopy = ConstReference.reference();
+}
+
+void PositiveLocalConstPointer() {
+ const ExpensiveToCopyType Obj;
+ const ExpensiveToCopyType *const ConstPointer = &Obj;
+ const auto UnnecessaryCopy = ConstPointer->reference();
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy'
+ // CHECK-FIXES: const auto& UnnecessaryCopy = ConstPointer->reference();
+}
+
+void NegativeFunctionCallTrivialType() {
+ const auto AutoAssigned = TrivialTypeReference();
+ const auto AutoCopyConstructed(TrivialTypeReference());
+ const TrivialToCopyType VarAssigned = TrivialTypeReference();
+ const TrivialToCopyType VarCopyConstructed(TrivialTypeReference());
+}
+
+void NegativeStaticLocalVar(const ExpensiveToCopyType &Obj) {
+ static const auto StaticVar = Obj.reference();
+}
+
+void PositiveFunctionCallExpensiveTypeNonConstVariable() {
+ auto AutoAssigned = ExpensiveTypeReference();
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'AutoAssigned' is copy-constructed from a const reference but is only used as const reference; consider making it a const reference [performance-unnecessary-copy-initialization]
+ // CHECK-FIXES: const auto& AutoAssigned = ExpensiveTypeReference();
+ auto AutoCopyConstructed(ExpensiveTypeReference());
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'AutoCopyConstructed'
+ // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveTypeReference());
+ ExpensiveToCopyType VarAssigned = ExpensiveTypeReference();
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable 'VarAssigned'
+ // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveTypeReference();
+ ExpensiveToCopyType VarCopyConstructed(ExpensiveTypeReference());
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable 'VarCopyConstructed'
+ // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveTypeReference());
+}
+
+void positiveNonConstVarInCodeBlock(const ExpensiveToCopyType &Obj) {
+ {
+ auto Assigned = Obj.reference();
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: the variable 'Assigned'
+ // CHECK-FIXES: const auto& Assigned = Obj.reference();
+ Assigned.reference();
+ useAsConstReference(Assigned);
+ useByValue(Assigned);
+ }
+}
+
+void negativeNonConstVarWithNonConstUse(const ExpensiveToCopyType &Obj) {
+ {
+ auto NonConstInvoked = Obj.reference();
+ // CHECK-FIXES: auto NonConstInvoked = Obj.reference();
+ NonConstInvoked.nonConstMethod();
+ }
+ {
+ auto Reassigned = Obj.reference();
+ // CHECK-FIXES: auto Reassigned = Obj.reference();
+ Reassigned = ExpensiveToCopyType();
+ }
+ {
+ auto MutatedByReference = Obj.reference();
+ // CHECK-FIXES: auto MutatedByReference = Obj.reference();
+ mutate(MutatedByReference);
+ }
+ {
+ auto MutatedByPointer = Obj.reference();
+ // CHECK-FIXES: auto MutatedByPointer = Obj.reference();
+ mutate(&MutatedByPointer);
+ }
+}
+
+void PositiveMethodCallNonConstRefNotModified(ExpensiveToCopyType &Obj) {
+ const auto AutoAssigned = Obj.reference();
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned'
+ // CHECK-FIXES: const auto& AutoAssigned = Obj.reference();
+}
+
+void NegativeMethodCallNonConstRefIsModified(ExpensiveToCopyType &Obj) {
+ const auto AutoAssigned = Obj.reference();
+ const auto AutoCopyConstructed(Obj.reference());
+ const ExpensiveToCopyType VarAssigned = Obj.reference();
+ const ExpensiveToCopyType VarCopyConstructed(Obj.reference());
+ mutate(&Obj);
+}
+
+void PositiveMethodCallNonConstNotModified(ExpensiveToCopyType Obj) {
+ const auto AutoAssigned = Obj.reference();
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned'
+ // CHECK-FIXES: const auto& AutoAssigned = Obj.reference();
+}
+
+void NegativeMethodCallNonConstValueArgumentIsModified(ExpensiveToCopyType Obj) {
+ Obj.nonConstMethod();
+ const auto AutoAssigned = Obj.reference();
+}
+
+void PositiveMethodCallNonConstPointerNotModified(ExpensiveToCopyType *const Obj) {
+ const auto AutoAssigned = Obj->reference();
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned'
+ // CHECK-FIXES: const auto& AutoAssigned = Obj->reference();
+ Obj->constMethod();
+}
+
+void NegativeMethodCallNonConstPointerIsModified(ExpensiveToCopyType *const Obj) {
+ const auto AutoAssigned = Obj->reference();
+ const auto AutoCopyConstructed(Obj->reference());
+ const ExpensiveToCopyType VarAssigned = Obj->reference();
+ const ExpensiveToCopyType VarCopyConstructed(Obj->reference());
+ mutate(Obj);
+}
+
+void PositiveLocalVarIsNotModified() {
+ ExpensiveToCopyType LocalVar;
+ const auto AutoAssigned = LocalVar.reference();
+ // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned'
+ // CHECK-FIXES: const auto& AutoAssigned = LocalVar.reference();
+}
+
+void NegativeLocalVarIsModified() {
+ ExpensiveToCopyType Obj;
+ const auto AutoAssigned = Obj.reference();
+ Obj = AutoAssigned;
+}
+
+struct NegativeConstructor {
+ NegativeConstructor(const ExpensiveToCopyType &Obj) : Obj(Obj) {}
+ ExpensiveToCopyType Obj;
+};
+
+#define UNNECESSARY_COPY_INIT_IN_MACRO_BODY(TYPE) \
+ void functionWith##TYPE(const TYPE &T) { \
+ auto AssignedInMacro = T.reference(); \
+ } \
+// Ensure fix is not applied.
+// CHECK-FIXES: auto AssignedInMacro = T.reference();
+
+UNNECESSARY_COPY_INIT_IN_MACRO_BODY(ExpensiveToCopyType)
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: the variable 'AssignedInMacro' is copy-constructed
+
+#define UNNECESSARY_COPY_INIT_IN_MACRO_ARGUMENT(ARGUMENT) ARGUMENT
+
+void PositiveMacroArgument(const ExpensiveToCopyType &Obj) {
+ UNNECESSARY_COPY_INIT_IN_MACRO_ARGUMENT(auto CopyInMacroArg = Obj.reference());
+ // CHECK-MESSAGES: [[@LINE-1]]:48: warning: the variable 'CopyInMacroArg' is copy-constructed
+ // Ensure fix is not applied.
+ // CHECK-FIXES: auto CopyInMacroArg = Obj.reference()
+}
+
+void PositiveLocalCopyConstMethodInvoked() {
+ ExpensiveToCopyType orig;
+ ExpensiveToCopyType copy_1 = orig;
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_1' of the variable 'orig' is never modified; consider avoiding the copy [performance-unnecessary-copy-initialization]
+ // CHECK-FIXES: const ExpensiveToCopyType& copy_1 = orig;
+ copy_1.constMethod();
+ orig.constMethod();
+}
+
+void PositiveLocalCopyUsingExplicitCopyCtor() {
+ ExpensiveToCopyType orig;
+ ExpensiveToCopyType copy_2(orig);
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_2'
+ // CHECK-FIXES: const ExpensiveToCopyType& copy_2(orig);
+ copy_2.constMethod();
+ orig.constMethod();
+}
+
+void PositiveLocalCopyCopyIsArgument(const ExpensiveToCopyType &orig) {
+ ExpensiveToCopyType copy_3 = orig;
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_3'
+ // CHECK-FIXES: const ExpensiveToCopyType& copy_3 = orig;
+ copy_3.constMethod();
+}
+
+void PositiveLocalCopyUsedAsConstRef() {
+ ExpensiveToCopyType orig;
+ ExpensiveToCopyType copy_4 = orig;
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_4'
+ // CHECK-FIXES: const ExpensiveToCopyType& copy_4 = orig;
+ useAsConstReference(orig);
+}
+
+void PositiveLocalCopyTwice() {
+ ExpensiveToCopyType orig;
+ ExpensiveToCopyType copy_5 = orig;
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_5'
+ // CHECK-FIXES: const ExpensiveToCopyType& copy_5 = orig;
+ ExpensiveToCopyType copy_6 = copy_5;
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_6'
+ // CHECK-FIXES: const ExpensiveToCopyType& copy_6 = copy_5;
+ copy_5.constMethod();
+ copy_6.constMethod();
+ orig.constMethod();
+}
+
+
+void PositiveLocalCopyWeirdCopy() {
+ WeirdCopyCtorType orig;
+ WeirdCopyCtorType weird_1(orig);
+ // CHECK-MESSAGES: [[@LINE-1]]:21: warning: local copy 'weird_1'
+ // CHECK-FIXES: const WeirdCopyCtorType& weird_1(orig);
+ weird_1.constMethod();
+
+ WeirdCopyCtorType weird_2 = orig;
+ // CHECK-MESSAGES: [[@LINE-1]]:21: warning: local copy 'weird_2'
+ // CHECK-FIXES: const WeirdCopyCtorType& weird_2 = orig;
+ weird_2.constMethod();
+}
+
+void NegativeLocalCopySimpleTypes() {
+ int i1 = 0;
+ int i2 = i1;
+}
+
+void NegativeLocalCopyCopyIsModified() {
+ ExpensiveToCopyType orig;
+ ExpensiveToCopyType neg_copy_1 = orig;
+ neg_copy_1.nonConstMethod();
+}
+
+void NegativeLocalCopyOriginalIsModified() {
+ ExpensiveToCopyType orig;
+ ExpensiveToCopyType neg_copy_2 = orig;
+ orig.nonConstMethod();
+}
+
+void NegativeLocalCopyUsedAsRefArg() {
+ ExpensiveToCopyType orig;
+ ExpensiveToCopyType neg_copy_3 = orig;
+ mutate(neg_copy_3);
+}
+
+void NegativeLocalCopyUsedAsPointerArg() {
+ ExpensiveToCopyType orig;
+ ExpensiveToCopyType neg_copy_4 = orig;
+ mutate(&neg_copy_4);
+}
+
+void NegativeLocalCopyCopyFromGlobal() {
+ ExpensiveToCopyType neg_copy_5 = global_expensive_to_copy_type;
+}
+
+void NegativeLocalCopyCopyToStatic() {
+ ExpensiveToCopyType orig;
+ static ExpensiveToCopyType neg_copy_6 = orig;
+}
+
+void NegativeLocalCopyNonConstInForLoop() {
+ ExpensiveToCopyType orig;
+ for (ExpensiveToCopyType neg_copy_7 = orig; orig.constMethod();
+ orig.nonConstMethod()) {
+ orig.constMethod();
+ }
+}
+
+void NegativeLocalCopyWeirdNonCopy() {
+ WeirdCopyCtorType orig;
+ WeirdCopyCtorType neg_weird_1(orig, false);
+ WeirdCopyCtorType neg_weird_2(orig, true);
+}
+void WarningOnlyMultiDeclStmt() {
+ ExpensiveToCopyType orig;
+ ExpensiveToCopyType copy = orig, copy2;
+ // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy' of the variable 'orig' is never modified; consider avoiding the copy [performance-unnecessary-copy-initialization]
+ // CHECK-FIXES: ExpensiveToCopyType copy = orig, copy2;
+}
+
+class Element {};
+class Container {
+public:
+ class Iterator {
+ public:
+ void operator++();
+ Element operator*();
+ bool operator!=(const Iterator &);
+ WeirdCopyCtorType c;
+ };
+ const Iterator &begin() const;
+ const Iterator &end() const;
+};
+
+void implicitVarFalsePositive() {
+ for (const Element &E : Container()) {
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-arc.m b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-arc.m
new file mode 100644
index 0000000..0a9ea06
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-arc.m
@@ -0,0 +1,16 @@
+// RUN: clang-tidy %s -checks=-*,performance-unnecessary-value-param -- \
+// RUN: -xobjective-c -fobjc-abi-version=2 -fobjc-arc | count 0
+
+#if !__has_feature(objc_arc)
+#error Objective-C ARC not enabled as expected
+#endif
+
+// Passing an Objective-C ARC-managed object to a C function should
+// not raise performance-unnecessary-value-param.
+void foo(id object) { }
+
+// Same for explcitly non-ARC-managed Objective-C objects.
+void bar(__unsafe_unretained id object) { }
+
+// Same for Objective-c classes.
+void baz(Class c) { }
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-arc.mm b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-arc.mm
new file mode 100644
index 0000000..4ed0506
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-arc.mm
@@ -0,0 +1,16 @@
+// RUN: clang-tidy %s -checks=-*,performance-unnecessary-value-param -- \
+// RUN: -xobjective-c++ -fobjc-abi-version=2 -fobjc-arc | count 0
+
+#if !__has_feature(objc_arc)
+#error Objective-C ARC not enabled as expected
+#endif
+
+// Passing an Objective-C ARC-managed object to a C function should
+// not raise performance-unnecessary-value-param.
+void foo(id object) { }
+
+// Same for explcitly non-ARC-managed Objective-C objects.
+void bar(__unsafe_unretained id object) { }
+
+// Same for Objective-c classes.
+void baz(Class c) { }
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-delayed.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-delayed.cpp
new file mode 100644
index 0000000..623bf8b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-delayed.cpp
@@ -0,0 +1,181 @@
+// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -- -fdelayed-template-parsing
+
+struct ExpensiveToCopyType {
+ const ExpensiveToCopyType & constReference() const {
+ return *this;
+ }
+ void nonConstMethod();
+ virtual ~ExpensiveToCopyType();
+};
+
+void mutate(ExpensiveToCopyType &);
+void mutate(ExpensiveToCopyType *);
+void useAsConstReference(const ExpensiveToCopyType &);
+void useByValue(ExpensiveToCopyType);
+
+// This class simulates std::pair<>. It is trivially copy constructible
+// and trivially destructible, but not trivially copy assignable.
+class SomewhatTrivial {
+ public:
+ SomewhatTrivial();
+ SomewhatTrivial(const SomewhatTrivial&) = default;
+ ~SomewhatTrivial() = default;
+ SomewhatTrivial& operator=(const SomewhatTrivial&);
+};
+
+void positiveExpensiveConstValue(const ExpensiveToCopyType Obj);
+// CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj);
+void positiveExpensiveConstValue(const ExpensiveToCopyType Obj) {
+ // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'Obj' is copied for each invocation; consider making it a reference [performance-unnecessary-value-param]
+ // CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj) {
+}
+
+void positiveExpensiveValue(ExpensiveToCopyType Obj);
+// CHECK-FIXES: void positiveExpensiveValue(const ExpensiveToCopyType& Obj);
+void positiveExpensiveValue(ExpensiveToCopyType Obj) {
+ // CHECK-MESSAGES: [[@LINE-1]]:49: warning: the parameter 'Obj' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]
+ // CHECK-FIXES: void positiveExpensiveValue(const ExpensiveToCopyType& Obj) {
+ Obj.constReference();
+ useAsConstReference(Obj);
+ auto Copy = Obj;
+ useByValue(Obj);
+}
+
+void positiveWithComment(const ExpensiveToCopyType /* important */ S);
+// CHECK-FIXES: void positiveWithComment(const ExpensiveToCopyType& /* important */ S);
+void positiveWithComment(const ExpensiveToCopyType /* important */ S) {
+ // CHECK-MESSAGES: [[@LINE-1]]:68: warning: the const qualified
+ // CHECK-FIXES: void positiveWithComment(const ExpensiveToCopyType& /* important */ S) {
+}
+
+void positiveUnnamedParam(const ExpensiveToCopyType) {
+ // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the const qualified parameter #1
+ // CHECK-FIXES: void positiveUnnamedParam(const ExpensiveToCopyType&) {
+}
+
+void positiveAndNegative(const ExpensiveToCopyType ConstCopy, const ExpensiveToCopyType& ConstRef, ExpensiveToCopyType Copy);
+// CHECK-FIXES: void positiveAndNegative(const ExpensiveToCopyType& ConstCopy, const ExpensiveToCopyType& ConstRef, const ExpensiveToCopyType& Copy);
+void positiveAndNegative(const ExpensiveToCopyType ConstCopy, const ExpensiveToCopyType& ConstRef, ExpensiveToCopyType Copy) {
+ // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the const qualified parameter 'ConstCopy'
+ // CHECK-MESSAGES: [[@LINE-2]]:120: warning: the parameter 'Copy'
+ // CHECK-FIXES: void positiveAndNegative(const ExpensiveToCopyType& ConstCopy, const ExpensiveToCopyType& ConstRef, const ExpensiveToCopyType& Copy) {
+}
+
+struct PositiveConstValueConstructor {
+ PositiveConstValueConstructor(const ExpensiveToCopyType ConstCopy) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:59: warning: the const qualified parameter 'ConstCopy'
+ // CHECK-FIXES: PositiveConstValueConstructor(const ExpensiveToCopyType& ConstCopy) {}
+};
+
+template <typename T> void templateWithNonTemplatizedParameter(const ExpensiveToCopyType S, T V) {
+ // CHECK-MESSAGES: [[@LINE-1]]:90: warning: the const qualified parameter 'S'
+ // CHECK-FIXES: template <typename T> void templateWithNonTemplatizedParameter(const ExpensiveToCopyType& S, T V) {
+}
+
+void instantiated() {
+ templateWithNonTemplatizedParameter(ExpensiveToCopyType(), ExpensiveToCopyType());
+ templateWithNonTemplatizedParameter(ExpensiveToCopyType(), 5);
+}
+
+template <typename T> void negativeTemplateType(const T V) {
+}
+
+void negativeArray(const ExpensiveToCopyType[]) {
+}
+
+void negativePointer(ExpensiveToCopyType* Obj) {
+}
+
+void negativeConstPointer(const ExpensiveToCopyType* Obj) {
+}
+
+void negativeConstReference(const ExpensiveToCopyType& Obj) {
+}
+
+void negativeReference(ExpensiveToCopyType& Obj) {
+}
+
+void negativeUniversalReference(ExpensiveToCopyType&& Obj) {
+}
+
+void negativeSomewhatTrivialConstValue(const SomewhatTrivial Somewhat) {
+}
+
+void negativeSomewhatTrivialValue(SomewhatTrivial Somewhat) {
+}
+
+void negativeConstBuiltIn(const int I) {
+}
+
+void negativeValueBuiltIn(int I) {
+}
+
+void negativeValueIsMutatedByReference(ExpensiveToCopyType Obj) {
+ mutate(Obj);
+}
+
+void negativeValueIsMutatatedByPointer(ExpensiveToCopyType Obj) {
+ mutate(&Obj);
+}
+
+void negativeValueIsReassigned(ExpensiveToCopyType Obj) {
+ Obj = ExpensiveToCopyType();
+}
+
+void negativeValueNonConstMethodIsCalled(ExpensiveToCopyType Obj) {
+ Obj.nonConstMethod();
+}
+
+struct PositiveValueUnusedConstructor {
+ PositiveValueUnusedConstructor(ExpensiveToCopyType Copy) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:54: warning: the parameter 'Copy'
+ // CHECK-FIXES: PositiveValueUnusedConstructor(const ExpensiveToCopyType& Copy) {}
+};
+
+struct PositiveValueCopiedConstructor {
+ PositiveValueCopiedConstructor(ExpensiveToCopyType Copy) : Field(Copy) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:54: warning: the parameter 'Copy'
+ // CHECK-FIXES: PositiveValueCopiedConstructor(const ExpensiveToCopyType& Copy) : Field(Copy) {}
+ ExpensiveToCopyType Field;
+};
+
+template <typename T>
+struct Container {
+ typedef const T & const_reference;
+};
+
+void NegativeTypedefParam(const Container<ExpensiveToCopyType>::const_reference Param) {
+}
+
+#define UNNECESSARY_VALUE_PARAM_IN_MACRO_BODY() \
+ void inMacro(const ExpensiveToCopyType T) { \
+ } \
+// Ensure fix is not applied.
+// CHECK-FIXES: void inMacro(const ExpensiveToCopyType T) {
+
+UNNECESSARY_VALUE_PARAM_IN_MACRO_BODY()
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: the const qualified parameter 'T'
+
+#define UNNECESSARY_VALUE_PARAM_IN_MACRO_ARGUMENT(ARGUMENT) \
+ ARGUMENT
+
+UNNECESSARY_VALUE_PARAM_IN_MACRO_ARGUMENT(void inMacroArgument(const ExpensiveToCopyType InMacroArg) {})
+// CHECK-MESSAGES: [[@LINE-1]]:90: warning: the const qualified parameter 'InMacroArg'
+// CHECK-FIXES: void inMacroArgument(const ExpensiveToCopyType InMacroArg) {}
+
+struct VirtualMethod {
+ virtual ~VirtualMethod() {}
+ virtual void handle(ExpensiveToCopyType T) const = 0;
+};
+
+struct NegativeOverriddenMethod : public VirtualMethod {
+ void handle(ExpensiveToCopyType Overridden) const {
+ // CHECK-FIXES: handle(ExpensiveToCopyType Overridden) const {
+ }
+};
+
+struct NegativeDeletedMethod {
+ ~NegativeDeletedMethod() {}
+ NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete;
+ // CHECK-FIXES: NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete;
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-header.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-header.cpp
new file mode 100644
index 0000000..9e4c246
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-header.cpp
@@ -0,0 +1,20 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: cp %S/Inputs/performance-unnecessary-value-param/header.h %t/header.h
+// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t/temp -- -- -std=c++11 -I %t
+// RUN: diff %t/header.h %S/Inputs/performance-unnecessary-value-param/header-fixed.h
+
+#include "header.h"
+
+
+
+int f1(int n, ABC v1, ABC v2) {
+ // CHECK-MESSAGES: [[@LINE-1]]:19: warning: the parameter 'v1' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]
+ // CHECK-MESSAGES: [[@LINE-2]]:27: warning: the parameter 'v2' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]
+ // CHECK-FIXES: int f1(int n, const ABC& v1, const ABC& v2) {
+ return v1.get(n) + v2.get(n);
+}
+int f2(int n, ABC v2) {
+ // CHECK-MESSAGES: [[@LINE-1]]:19: warning: the parameter 'v2' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]
+ // CHECK-FIXES: int f2(int n, const ABC& v2) {
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp
new file mode 100644
index 0000000..cd8c4da
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param-incomplete-type.cpp
@@ -0,0 +1,9 @@
+// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -fix-errors -- --std=c++11
+
+// Ensure that incomplete types result in an error from the frontend and not a
+// clang-tidy diagnostic about IncompleteType being expensive to copy.
+struct IncompleteType;
+void NegativeForIncompleteType(IncompleteType I) {
+ // CHECK-MESSAGES: [[@LINE-1]]:47: error: variable has incomplete type 'IncompleteType' [clang-diagnostic-error]
+}
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param.cpp
new file mode 100644
index 0000000..dcf82df
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/performance-unnecessary-value-param.cpp
@@ -0,0 +1,361 @@
+// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t
+
+// CHECK-FIXES: #include <utility>
+
+struct ExpensiveToCopyType {
+ const ExpensiveToCopyType & constReference() const {
+ return *this;
+ }
+ void nonConstMethod();
+ virtual ~ExpensiveToCopyType();
+};
+
+void mutate(ExpensiveToCopyType &);
+void mutate(ExpensiveToCopyType *);
+void useAsConstReference(const ExpensiveToCopyType &);
+void useByValue(ExpensiveToCopyType);
+
+// This class simulates std::pair<>. It is trivially copy constructible
+// and trivially destructible, but not trivially copy assignable.
+class SomewhatTrivial {
+ public:
+ SomewhatTrivial();
+ SomewhatTrivial(const SomewhatTrivial&) = default;
+ ~SomewhatTrivial() = default;
+ SomewhatTrivial& operator=(const SomewhatTrivial&);
+};
+
+struct MoveOnlyType {
+ MoveOnlyType(const MoveOnlyType &) = delete;
+ MoveOnlyType(MoveOnlyType &&) = default;
+ ~MoveOnlyType();
+ void constMethod() const;
+};
+
+struct ExpensiveMovableType {
+ ExpensiveMovableType();
+ ExpensiveMovableType(ExpensiveMovableType &&);
+ ExpensiveMovableType(const ExpensiveMovableType &) = default;
+ ExpensiveMovableType &operator=(const ExpensiveMovableType &) = default;
+ ExpensiveMovableType &operator=(ExpensiveMovableType &&);
+ ~ExpensiveMovableType();
+};
+
+void positiveExpensiveConstValue(const ExpensiveToCopyType Obj);
+// CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj);
+void positiveExpensiveConstValue(const ExpensiveToCopyType Obj) {
+ // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'Obj' is copied for each invocation; consider making it a reference [performance-unnecessary-value-param]
+ // CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj) {
+}
+
+void positiveExpensiveValue(ExpensiveToCopyType Obj);
+// CHECK-FIXES: void positiveExpensiveValue(const ExpensiveToCopyType& Obj);
+void positiveExpensiveValue(ExpensiveToCopyType Obj) {
+ // CHECK-MESSAGES: [[@LINE-1]]:49: warning: the parameter 'Obj' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]
+ // CHECK-FIXES: void positiveExpensiveValue(const ExpensiveToCopyType& Obj) {
+ Obj.constReference();
+ useAsConstReference(Obj);
+ auto Copy = Obj;
+ useByValue(Obj);
+}
+
+void positiveWithComment(const ExpensiveToCopyType /* important */ S);
+// CHECK-FIXES: void positiveWithComment(const ExpensiveToCopyType& /* important */ S);
+void positiveWithComment(const ExpensiveToCopyType /* important */ S) {
+ // CHECK-MESSAGES: [[@LINE-1]]:68: warning: the const qualified
+ // CHECK-FIXES: void positiveWithComment(const ExpensiveToCopyType& /* important */ S) {
+}
+
+void positiveUnnamedParam(const ExpensiveToCopyType) {
+ // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the const qualified parameter #1
+ // CHECK-FIXES: void positiveUnnamedParam(const ExpensiveToCopyType&) {
+}
+
+void positiveAndNegative(const ExpensiveToCopyType ConstCopy, const ExpensiveToCopyType& ConstRef, ExpensiveToCopyType Copy);
+// CHECK-FIXES: void positiveAndNegative(const ExpensiveToCopyType& ConstCopy, const ExpensiveToCopyType& ConstRef, const ExpensiveToCopyType& Copy);
+void positiveAndNegative(const ExpensiveToCopyType ConstCopy, const ExpensiveToCopyType& ConstRef, ExpensiveToCopyType Copy) {
+ // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the const qualified parameter 'ConstCopy'
+ // CHECK-MESSAGES: [[@LINE-2]]:120: warning: the parameter 'Copy'
+ // CHECK-FIXES: void positiveAndNegative(const ExpensiveToCopyType& ConstCopy, const ExpensiveToCopyType& ConstRef, const ExpensiveToCopyType& Copy) {
+}
+
+struct PositiveConstValueConstructor {
+ PositiveConstValueConstructor(const ExpensiveToCopyType ConstCopy) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:59: warning: the const qualified parameter 'ConstCopy'
+ // CHECK-FIXES: PositiveConstValueConstructor(const ExpensiveToCopyType& ConstCopy) {}
+};
+
+template <typename T> void templateWithNonTemplatizedParameter(const ExpensiveToCopyType S, T V) {
+ // CHECK-MESSAGES: [[@LINE-1]]:90: warning: the const qualified parameter 'S'
+ // CHECK-FIXES: template <typename T> void templateWithNonTemplatizedParameter(const ExpensiveToCopyType& S, T V) {
+}
+
+void instantiated() {
+ templateWithNonTemplatizedParameter(ExpensiveToCopyType(), ExpensiveToCopyType());
+ templateWithNonTemplatizedParameter(ExpensiveToCopyType(), 5);
+}
+
+template <typename T> void negativeTemplateType(const T V) {
+}
+
+void negativeArray(const ExpensiveToCopyType[]) {
+}
+
+void negativePointer(ExpensiveToCopyType* Obj) {
+}
+
+void negativeConstPointer(const ExpensiveToCopyType* Obj) {
+}
+
+void negativeConstReference(const ExpensiveToCopyType& Obj) {
+}
+
+void negativeReference(ExpensiveToCopyType& Obj) {
+}
+
+void negativeUniversalReference(ExpensiveToCopyType&& Obj) {
+}
+
+void negativeSomewhatTrivialConstValue(const SomewhatTrivial Somewhat) {
+}
+
+void negativeSomewhatTrivialValue(SomewhatTrivial Somewhat) {
+}
+
+void negativeConstBuiltIn(const int I) {
+}
+
+void negativeValueBuiltIn(int I) {
+}
+
+void negativeValueIsMutatedByReference(ExpensiveToCopyType Obj) {
+ mutate(Obj);
+}
+
+void negativeValueIsMutatatedByPointer(ExpensiveToCopyType Obj) {
+ mutate(&Obj);
+}
+
+void negativeValueIsReassigned(ExpensiveToCopyType Obj) {
+ Obj = ExpensiveToCopyType();
+}
+
+void negativeValueNonConstMethodIsCalled(ExpensiveToCopyType Obj) {
+ Obj.nonConstMethod();
+}
+
+struct PositiveValueUnusedConstructor {
+ PositiveValueUnusedConstructor(ExpensiveToCopyType Copy) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:54: warning: the parameter 'Copy'
+ // CHECK-FIXES: PositiveValueUnusedConstructor(const ExpensiveToCopyType& Copy) {}
+};
+
+struct PositiveValueCopiedConstructor {
+ PositiveValueCopiedConstructor(ExpensiveToCopyType Copy) : Field(Copy) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:54: warning: the parameter 'Copy'
+ // CHECK-FIXES: PositiveValueCopiedConstructor(const ExpensiveToCopyType& Copy) : Field(Copy) {}
+ ExpensiveToCopyType Field;
+};
+
+struct PositiveValueMovableConstructor {
+ PositiveValueMovableConstructor(ExpensiveMovableType Copy) : Field(Copy) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:70: warning: parameter 'Copy'
+ // CHECK-FIXES: PositiveValueMovableConstructor(ExpensiveMovableType Copy) : Field(std::move(Copy)) {}
+ ExpensiveMovableType Field;
+};
+
+struct NegativeValueMovedConstructor {
+ NegativeValueMovedConstructor(ExpensiveMovableType Copy) : Field(static_cast<ExpensiveMovableType &&>(Copy)) {}
+ ExpensiveMovableType Field;
+};
+
+template <typename T>
+struct Container {
+ typedef const T & const_reference;
+};
+
+void NegativeTypedefParam(const Container<ExpensiveToCopyType>::const_reference Param) {
+}
+
+#define UNNECESSARY_VALUE_PARAM_IN_MACRO_BODY() \
+ void inMacro(const ExpensiveToCopyType T) { \
+ } \
+// Ensure fix is not applied.
+// CHECK-FIXES: void inMacro(const ExpensiveToCopyType T) {
+
+UNNECESSARY_VALUE_PARAM_IN_MACRO_BODY()
+// CHECK-MESSAGES: [[@LINE-1]]:1: warning: the const qualified parameter 'T'
+
+#define UNNECESSARY_VALUE_PARAM_IN_MACRO_ARGUMENT(ARGUMENT) \
+ ARGUMENT
+
+UNNECESSARY_VALUE_PARAM_IN_MACRO_ARGUMENT(void inMacroArgument(const ExpensiveToCopyType InMacroArg) {})
+// CHECK-MESSAGES: [[@LINE-1]]:90: warning: the const qualified parameter 'InMacroArg'
+// CHECK-FIXES: void inMacroArgument(const ExpensiveToCopyType InMacroArg) {}
+
+struct VirtualMethod {
+ virtual ~VirtualMethod() {}
+ virtual void handle(ExpensiveToCopyType T) const = 0;
+};
+
+struct NegativeOverriddenMethod : public VirtualMethod {
+ void handle(ExpensiveToCopyType Overridden) const {
+ // CHECK-FIXES: handle(ExpensiveToCopyType Overridden) const {
+ }
+};
+
+struct VirtualMethodWarningOnly {
+ virtual void methodWithExpensiveValueParam(ExpensiveToCopyType T) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'T' is copied
+ // CHECK-FIXES: virtual void methodWithExpensiveValueParam(ExpensiveToCopyType T) {}
+ virtual ~VirtualMethodWarningOnly() {}
+};
+
+struct PositiveNonVirualMethod {
+ void method(const ExpensiveToCopyType T) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:41: warning: the const qualified parameter 'T' is copied
+ // CHECK-FIXES: void method(const ExpensiveToCopyType& T) {}
+};
+
+struct NegativeDeletedMethod {
+ ~NegativeDeletedMethod() {}
+ NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete;
+ // CHECK-FIXES: NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete;
+};
+
+void NegativeMoveOnlyTypePassedByValue(MoveOnlyType M) {
+ M.constMethod();
+}
+
+void PositiveMoveOnCopyConstruction(ExpensiveMovableType E) {
+ auto F = E;
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: parameter 'E' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param]
+ // CHECK-FIXES: auto F = std::move(E);
+}
+
+void PositiveConstRefNotMoveSinceReferencedMultipleTimes(ExpensiveMovableType E) {
+ // CHECK-MESSAGES: [[@LINE-1]]:79: warning: the parameter 'E' is copied
+ // CHECK-FIXES: void PositiveConstRefNotMoveSinceReferencedMultipleTimes(const ExpensiveMovableType& E) {
+ auto F = E;
+ auto G = E;
+}
+
+void PositiveMoveOnCopyAssignment(ExpensiveMovableType E) {
+ ExpensiveMovableType F;
+ F = E;
+ // CHECK-MESSAGES: [[@LINE-1]]:7: warning: parameter 'E' is passed by value
+ // CHECK-FIXES: F = std::move(E);
+}
+
+struct NotCopyAssigned {
+ NotCopyAssigned &operator=(const ExpensiveMovableType &);
+};
+
+void PositiveNoMoveForNonCopyAssigmentOperator(ExpensiveMovableType E) {
+ // CHECK-MESSAGES: [[@LINE-1]]:69: warning: the parameter 'E' is copied
+ // CHECK-FIXES: void PositiveNoMoveForNonCopyAssigmentOperator(const ExpensiveMovableType& E) {
+ NotCopyAssigned N;
+ N = E;
+}
+
+// The argument could be moved but is not since copy statement is inside a loop.
+void PositiveNoMoveInsideLoop(ExpensiveMovableType E) {
+ // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the parameter 'E' is copied
+ // CHECK-FIXES: void PositiveNoMoveInsideLoop(const ExpensiveMovableType& E) {
+ for (;;) {
+ auto F = E;
+ }
+}
+
+void PositiveConstRefNotMoveConstructible(ExpensiveToCopyType T) {
+ // CHECK-MESSAGES: [[@LINE-1]]:63: warning: the parameter 'T' is copied
+ // CHECK-FIXES: void PositiveConstRefNotMoveConstructible(const ExpensiveToCopyType& T) {
+ auto U = T;
+}
+
+void PositiveConstRefNotMoveAssignable(ExpensiveToCopyType A) {
+ // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the parameter 'A' is copied
+ // CHECK-FIXES: void PositiveConstRefNotMoveAssignable(const ExpensiveToCopyType& A) {
+ ExpensiveToCopyType B;
+ B = A;
+}
+
+// Case where parameter in declaration is already const-qualified but not in
+// implementation. Make sure a second 'const' is not added to the declaration.
+void PositiveConstDeclaration(const ExpensiveToCopyType A);
+// CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A);
+void PositiveConstDeclaration(ExpensiveToCopyType A) {
+ // CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied
+ // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) {
+}
+
+void PositiveNonConstDeclaration(ExpensiveToCopyType A);
+// CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A);
+void PositiveNonConstDeclaration(const ExpensiveToCopyType A) {
+ // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A'
+ // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) {
+}
+
+void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) {
+ // CHECK-MESSAGES: [[@LINE-1]]:75: warning: the parameter 'A' is copied
+ // CHECK-FIXES: void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) {
+}
+
+void ReferenceFunctionOutsideOfCallExpr() {
+ void (*ptr)(ExpensiveToCopyType) = &PositiveOnlyMessageAsReferencedInCompilationUnit;
+}
+
+void PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType A) {
+ // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'A' is copied
+ // CHECK-FIXES: void PositiveMessageAndFixAsFunctionIsCalled(const ExpensiveToCopyType& A) {
+}
+
+void ReferenceFunctionByCallingIt() {
+ PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType());
+}
+
+// Virtual method overrides of dependent types cannot be recognized unless they
+// are marked as override or final. Test that check is not triggered on methods
+// marked with override or final.
+template <typename T>
+struct NegativeDependentTypeInterface {
+ virtual void Method(ExpensiveToCopyType E) = 0;
+};
+
+template <typename T>
+struct NegativeOverrideImpl : public NegativeDependentTypeInterface<T> {
+ void Method(ExpensiveToCopyType E) override {}
+};
+
+template <typename T>
+struct NegativeFinalImpl : public NegativeDependentTypeInterface<T> {
+ void Method(ExpensiveToCopyType E) final {}
+};
+
+struct PositiveConstructor {
+ PositiveConstructor(ExpensiveToCopyType E) : E(E) {}
+ // CHECK-MESSAGES: [[@LINE-1]]:43: warning: the parameter 'E' is copied
+ // CHECK-FIXES: PositiveConstructor(const ExpensiveToCopyType& E) : E(E) {}
+
+ ExpensiveToCopyType E;
+};
+
+struct NegativeUsingConstructor : public PositiveConstructor {
+ using PositiveConstructor::PositiveConstructor;
+};
+
+void fun() {
+ ExpensiveToCopyType E;
+ NegativeUsingConstructor S(E);
+}
+
+template<typename T>
+void templateFunction(T) {
+}
+
+template<>
+void templateFunction<ExpensiveToCopyType>(ExpensiveToCopyType E) {
+ // CHECK-MESSAGES: [[@LINE-1]]:64: warning: the parameter 'E' is copied
+ // CHECK-FIXES: void templateFunction<ExpensiveToCopyType>(ExpensiveToCopyType E) {
+ E.constReference();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/portability-simd-intrinsics-ppc.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/portability-simd-intrinsics-ppc.cpp
new file mode 100644
index 0000000..be0ef76
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/portability-simd-intrinsics-ppc.cpp
@@ -0,0 +1,13 @@
+// RUN: %check_clang_tidy %s portability-simd-intrinsics %t -- \
+// RUN: -config='{CheckOptions: [ \
+// RUN: {key: portability-simd-intrinsics.Suggest, value: 1} \
+// RUN: ]}' -- -target ppc64le -maltivec -std=c++11
+
+vector int vec_add(vector int, vector int);
+
+void PPC() {
+ vector int i0, i1;
+
+ vec_add(i0, i1);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'vec_add' can be replaced by operator+ on std::experimental::simd objects [portability-simd-intrinsics]
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/portability-simd-intrinsics-x86.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/portability-simd-intrinsics-x86.cpp
new file mode 100644
index 0000000..1fb2289
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/portability-simd-intrinsics-x86.cpp
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s portability-simd-intrinsics %t -- \
+// RUN: -config='{CheckOptions: [ \
+// RUN: {key: portability-simd-intrinsics.Suggest, value: 1} \
+// RUN: ]}' -- -target x86_64 -std=c++11
+
+typedef long long __m128i __attribute__((vector_size(16)));
+typedef double __m256 __attribute__((vector_size(32)));
+
+__m128i _mm_add_epi32(__m128i, __m128i);
+__m256 _mm256_load_pd(double const *);
+void _mm256_store_pd(double *, __m256);
+
+int _mm_add_fake(int, int);
+
+void X86() {
+ __m128i i0, i1;
+ __m256 d0;
+
+ _mm_add_epi32(i0, i1);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: '_mm_add_epi32' can be replaced by operator+ on std::experimental::simd objects [portability-simd-intrinsics]
+ d0 = _mm256_load_pd(0);
+ _mm256_store_pd(0, d0);
+
+ _mm_add_fake(0, 1);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/pr37091.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/pr37091.cpp
new file mode 100644
index 0000000..e56115a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/pr37091.cpp
@@ -0,0 +1,10 @@
+// REQUIRES: shell
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+
+// This is a reproducer for PR37091.
+//
+// Verify that no temporary files are left behind by the clang-tidy invocation.
+
+// RUN: env TMPDIR=%t TEMP=%t TMP=%t clang-tidy %s -- --target=mips64
+// RUN: rmdir %t
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/read_file_config.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/read_file_config.cpp
new file mode 100644
index 0000000..3635c21
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/read_file_config.cpp
@@ -0,0 +1,12 @@
+// RUN: mkdir -p %T/read-file-config/
+// RUN: cp %s %T/read-file-config/test.cpp
+// RUN: echo 'Checks: "-*,modernize-use-nullptr"' > %T/read-file-config/.clang-tidy
+// RUN: echo '[{"command": "cc -c -o test.o test.cpp", "directory": "%/T/read-file-config", "file": "%/T/read-file-config/test.cpp"}]' > %T/read-file-config/compile_commands.json
+// RUN: clang-tidy %T/read-file-config/test.cpp | not grep "warning: .*\[clang-analyzer-deadcode.DeadStores\]$"
+// RUN: clang-tidy -checks="-*,clang-analyzer-*" %T/read-file-config/test.cpp | grep "warning: .*\[clang-analyzer-deadcode.DeadStores\]$"
+
+void f() {
+ int x;
+ x = 1;
+ x = 2;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-avoid-const-params-in-decls.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-avoid-const-params-in-decls.cpp
new file mode 100644
index 0000000..c2c12a4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-avoid-const-params-in-decls.cpp
@@ -0,0 +1,133 @@
+// RUN: %check_clang_tidy %s readability-avoid-const-params-in-decls %t
+
+using alias_type = bool;
+using alias_const_type = const bool;
+
+
+void F1(const int i);
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'i' is const-qualified in the function declaration; const-qualification of parameters only has an effect in function definitions [readability-avoid-const-params-in-decls]
+// CHECK-FIXES: void F1(int i);
+
+void F2(const int *const i);
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'i' is const-qualified
+// CHECK-FIXES: void F2(const int *i);
+
+void F3(int const i);
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'i' is const-qualified
+// CHECK-FIXES: void F3(int i);
+
+void F4(alias_type const i);
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'i' is const-qualified
+// CHECK-FIXES: void F4(alias_type i);
+
+void F5(const int);
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 1 is const-qualified
+// CHECK-FIXES: void F5(int);
+
+void F6(const int *const);
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 1 is const-qualified
+// CHECK-FIXES: void F6(const int *);
+
+void F7(int, const int);
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: parameter 2 is const-qualified
+// CHECK-FIXES: void F7(int, int);
+
+void F8(const int, const int);
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 1 is const-qualified
+// CHECK-MESSAGES: :[[@LINE-2]]:20: warning: parameter 2 is const-qualified
+// CHECK-FIXES: void F8(int, int);
+
+void F9(const int long_name);
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'long_name'
+// CHECK-FIXES: void F9(int long_name);
+
+void F10(const int *const *const long_name);
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: parameter 'long_name'
+// CHECK-FIXES: void F10(const int *const *long_name);
+
+void F11(const unsigned int /*v*/);
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: parameter 1
+// CHECK-FIXES: void F11(unsigned int /*v*/);
+
+void F12(const bool b = true);
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: parameter 'b'
+// CHECK-FIXES: void F12(bool b = true);
+
+template<class T>
+int F13(const bool b = true);
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'b'
+// CHECK-FIXES: int F13(bool b = true);
+int f13 = F13<int>();
+
+struct Foo {
+ Foo(const int i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: parameter 'i'
+ // CHECK-FIXES: Foo(int i);
+
+ void operator()(const int i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: parameter 'i'
+ // CHECK-FIXES: void operator()(int i);
+};
+
+template <class T>
+struct FooT {
+ FooT(const int i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: parameter 'i'
+ // CHECK-FIXES: FooT(int i);
+
+ void operator()(const int i);
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: parameter 'i'
+ // CHECK-FIXES: void operator()(int i);
+};
+FooT<int> f(1);
+
+// Do not match on definitions
+void NF1(const int i) {}
+void NF2(const int *const i) {}
+void NF3(int const i) {}
+void NF4(alias_type const i) {}
+void NF5(const int) {}
+void NF6(const int *const) {}
+void NF7(int, const int) {}
+void NF8(const int, const int) {}
+template <class T>
+int NF9(const int, const int) { return 0; }
+int nf9 = NF9<int>(1, 2);
+
+// Do not match on inline member functions
+struct Bar {
+ Bar(const int i) {}
+
+ void operator()(const int i) {}
+};
+
+// Do not match on inline member functions of a templated class
+template <class T>
+struct BarT {
+ BarT(const int i) {}
+
+ void operator()(const int i) {}
+};
+BarT<int> b(1);
+
+// Do not match on other stuff
+void NF(const alias_type& i);
+void NF(const int &i);
+void NF(const int *i);
+void NF(alias_const_type i);
+void NF(const alias_type&);
+void NF(const int&);
+void NF(const int*);
+void NF(const int* const*);
+void NF(alias_const_type);
+
+// Regression test for when the 'const' token is not in the code.
+#define CONCAT(a, b) a##b
+void ConstNotVisible(CONCAT(cons, t) int i);
+// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: parameter 'i'
+// We warn, but we can't give a fix
+// CHECK-FIXES: void ConstNotVisible(CONCAT(cons, t) int i);
+
+// Regression test. We should not warn (or crash) on lambda expressions
+auto lambda_with_name = [](const int n) {};
+auto lambda_without_name = [](const int) {};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-assert-failure.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-assert-failure.cpp
new file mode 100644
index 0000000..7d619c0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-assert-failure.cpp
@@ -0,0 +1,12 @@
+// RUN: not clang-tidy -checks='-*,readability-braces-around-statements' %s --
+
+// Note: this test expects no assert failure happened in clang-tidy.
+
+int test_failure() {
+ if (std::rand()) {
+ }
+}
+
+void test_failure2() {
+ for (a b c;;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-few-lines.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-few-lines.cpp
new file mode 100644
index 0000000..00d253a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-few-lines.cpp
@@ -0,0 +1,30 @@
+// RUN: %check_clang_tidy %s readability-braces-around-statements %t -- -config="{CheckOptions: [{key: readability-braces-around-statements.ShortStatementLines, value: 4}]}" --
+
+void do_something(const char *) {}
+
+bool cond(const char *) {
+ return false;
+}
+
+void test() {
+ if (cond("if1") /*comment*/) do_something("same-line");
+
+ if (cond("if2"))
+ do_something("single-line");
+
+ if (cond("if3") /*comment*/)
+ // some comment
+ do_something("three"
+ "lines");
+
+ if (cond("if4") /*comment*/)
+ // some comment
+ do_something("many"
+ "many"
+ "many"
+ "many"
+ "lines");
+ // CHECK-MESSAGES: :[[@LINE-7]]:31: warning: statement should be inside braces
+ // CHECK-FIXES: if (cond("if4") /*comment*/) {
+ // CHECK-FIXES: }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-format.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-format.cpp
new file mode 100644
index 0000000..81f832d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-format.cpp
@@ -0,0 +1,33 @@
+// RUN: %check_clang_tidy %s readability-braces-around-statements %t -- -format-style="{IndentWidth: 3}" --
+
+void do_something(const char *) {}
+
+bool cond(const char *) {
+ return false;
+}
+
+void test() {
+ if (cond("if0") /*comment*/) do_something("same-line");
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: statement should be inside braces
+ // CHECK-FIXES: {{^}} if (cond("if0") /*comment*/) {{{$}}
+ // CHECK-FIXES-NEXT: {{^}} do_something("same-line");{{$}}
+ // CHECK-FIXES-NEXT: {{^}} }{{$}}
+
+ if (1) while (2) if (3) for (;;) do ; while(false) /**/;/**/
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: statement should be inside braces
+ // CHECK-MESSAGES: :[[@LINE-2]]:19: warning: statement should be inside braces
+ // CHECK-MESSAGES: :[[@LINE-3]]:26: warning: statement should be inside braces
+ // CHECK-MESSAGES: :[[@LINE-4]]:35: warning: statement should be inside braces
+ // CHECK-MESSAGES: :[[@LINE-5]]:38: warning: statement should be inside braces
+ // CHECK-FIXES: {{^}} if (1) {{{$}}
+ // CHECK-FIXES-NEXT: {{^}} while (2) {
+ // CHECK-FIXES-NEXT: {{^}} if (3) {
+ // CHECK-FIXES-NEXT: {{^}} for (;;) {
+ // CHECK-FIXES-NEXT: {{^}} do {
+ // CHECK-FIXES-NEXT: {{^}} ;
+ // CHECK-FIXES-NEXT: {{^}} } while (false) /**/; /**/
+ // CHECK-FIXES-NEXT: {{^}} }
+ // CHECK-FIXES-NEXT: {{^}} }
+ // CHECK-FIXES-NEXT: {{^}} }
+ // CHECK-FIXES-NEXT: {{^}} }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-same-line.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-same-line.cpp
new file mode 100644
index 0000000..504043f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-same-line.cpp
@@ -0,0 +1,36 @@
+// RUN: %check_clang_tidy %s readability-braces-around-statements %t -- -config="{CheckOptions: [{key: readability-braces-around-statements.ShortStatementLines, value: 1}]}" --
+
+void do_something(const char *) {}
+
+bool cond(const char *) {
+ return false;
+}
+
+void test() {
+ if (cond("if1") /*comment*/) do_something("same-line");
+
+ if (cond("if2"))
+ do_something("single-line");
+ // CHECK-MESSAGES: :[[@LINE-2]]:19: warning: statement should be inside braces
+ // CHECK-FIXES: if (cond("if2")) {
+ // CHECK-FIXES: }
+
+ if (cond("if3") /*comment*/)
+ // some comment
+ do_something("three"
+ "lines");
+ // CHECK-MESSAGES: :[[@LINE-4]]:31: warning: statement should be inside braces
+ // CHECK-FIXES: if (cond("if3") /*comment*/) {
+ // CHECK-FIXES: }
+
+ if (cond("if4") /*comment*/)
+ // some comment
+ do_something("many"
+ "many"
+ "many"
+ "many"
+ "lines");
+ // CHECK-MESSAGES: :[[@LINE-7]]:31: warning: statement should be inside braces
+ // CHECK-FIXES: if (cond("if4") /*comment*/) {
+ // CHECK-FIXES: }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-single-line.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-single-line.cpp
new file mode 100644
index 0000000..3edbd4b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements-single-line.cpp
@@ -0,0 +1,33 @@
+// RUN: %check_clang_tidy %s readability-braces-around-statements %t -- -config="{CheckOptions: [{key: readability-braces-around-statements.ShortStatementLines, value: 2}]}" --
+
+void do_something(const char *) {}
+
+bool cond(const char *) {
+ return false;
+}
+
+void test() {
+ if (cond("if1") /*comment*/) do_something("same-line");
+
+ if (cond("if2"))
+ do_something("single-line");
+
+ if (cond("if3") /*comment*/)
+ // some comment
+ do_something("three"
+ "lines");
+ // CHECK-MESSAGES: :[[@LINE-4]]:31: warning: statement should be inside braces
+ // CHECK-FIXES: if (cond("if3") /*comment*/) {
+ // CHECK-FIXES: }
+
+ if (cond("if4") /*comment*/)
+ // some comment
+ do_something("many"
+ "many"
+ "many"
+ "many"
+ "lines");
+ // CHECK-MESSAGES: :[[@LINE-7]]:31: warning: statement should be inside braces
+ // CHECK-FIXES: if (cond("if4") /*comment*/) {
+ // CHECK-FIXES: }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements.cpp
new file mode 100644
index 0000000..8dc5bf1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-braces-around-statements.cpp
@@ -0,0 +1,206 @@
+// RUN: %check_clang_tidy %s readability-braces-around-statements %t
+
+void do_something(const char *) {}
+
+bool cond(const char *) {
+ return false;
+}
+
+#define EMPTY_MACRO
+#define EMPTY_MACRO_FUN()
+
+void test() {
+ if (cond("if0") /*comment*/) do_something("same-line");
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: statement should be inside braces
+ // CHECK-FIXES: if (cond("if0") /*comment*/) { do_something("same-line");
+ // CHECK-FIXES: }
+
+ if (cond("if0.1"))
+ do_something("single-line");
+ // CHECK-MESSAGES: :[[@LINE-2]]:21: warning: statement should be inside braces
+ // CHECK-FIXES: if (cond("if0.1")) {
+ // CHECK-FIXES: }
+
+ if (cond("if1") /*comment*/)
+ // some comment
+ do_something("if1");
+ // CHECK-MESSAGES: :[[@LINE-3]]:31: warning: statement should be inside braces
+ // CHECK-FIXES: if (cond("if1") /*comment*/) {
+ // CHECK-FIXES: }
+ if (cond("if2")) {
+ do_something("if2");
+ }
+ if (cond("if3"))
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:19: warning: statement should be inside braces
+ // CHECK-FIXES: if (cond("if3")) {
+ // CHECK-FIXES: }
+
+ if (cond("if-else1"))
+ do_something("if-else1");
+ // CHECK-MESSAGES: :[[@LINE-2]]:24: warning: statement should be inside braces
+ // CHECK-FIXES: if (cond("if-else1")) {
+ // CHECK-FIXES: } else {
+ else
+ do_something("if-else1 else");
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: statement should be inside braces
+ // CHECK-FIXES: }
+ if (cond("if-else2")) {
+ do_something("if-else2");
+ } else {
+ do_something("if-else2 else");
+ }
+
+ if (cond("if-else if-else1"))
+ do_something("if");
+ // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: statement should be inside braces
+ // CHECK-FIXES: } else if (cond("else if1")) {
+ else if (cond("else if1"))
+ do_something("else if");
+ // CHECK-MESSAGES: :[[@LINE-2]]:29: warning: statement should be inside braces
+ else
+ do_something("else");
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: statement should be inside braces
+ // CHECK-FIXES: }
+ if (cond("if-else if-else2")) {
+ do_something("if");
+ } else if (cond("else if2")) {
+ do_something("else if");
+ } else {
+ do_something("else");
+ }
+
+ for (;;)
+ do_something("for");
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: statement should be inside braces
+ // CHECK-FIXES: for (;;) {
+ // CHECK-FIXES: }
+ for (;;) {
+ do_something("for");
+ }
+ for (;;)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: statement should be inside braces
+ // CHECK-FIXES: for (;;) {
+ // CHECK-FIXES: }
+
+ int arr[4] = {1, 2, 3, 4};
+ for (int a : arr)
+ do_something("for-range");
+ // CHECK-MESSAGES: :[[@LINE-2]]:20: warning: statement should be inside braces
+ // CHECK-FIXES: for (int a : arr) {
+ // CHECK-FIXES: }
+ for (int a : arr) {
+ do_something("for-range");
+ }
+ for (int a : arr)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:20: warning: statement should be inside braces
+ // CHECK-FIXES: for (int a : arr) {
+ // CHECK-FIXES: }
+
+ while (cond("while1"))
+ do_something("while");
+ // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: statement should be inside braces
+ // CHECK-FIXES: while (cond("while1")) {
+ // CHECK-FIXES: }
+ while (cond("while2")) {
+ do_something("while");
+ }
+ while (false)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:16: warning: statement should be inside braces
+ // CHECK-FIXES: while (false) {
+ // CHECK-FIXES: }
+
+ do
+ do_something("do1");
+ while (cond("do1"));
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: statement should be inside braces
+ // CHECK-FIXES: do {
+ // CHECK-FIXES: } while (cond("do1"));
+ do {
+ do_something("do2");
+ } while (cond("do2"));
+
+ do
+ ;
+ while (false);
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: statement should be inside braces
+ // CHECK-FIXES: do {
+ // CHECK-FIXES: } while (false);
+
+ if (cond("ifif1"))
+ // comment
+ if (cond("ifif2"))
+ // comment
+ /*comment*/ ; // comment
+ // CHECK-MESSAGES: :[[@LINE-5]]:21: warning: statement should be inside braces
+ // CHECK-MESSAGES: :[[@LINE-4]]:23: warning: statement should be inside braces
+ // CHECK-FIXES: if (cond("ifif1")) {
+ // CHECK-FIXES: if (cond("ifif2")) {
+ // CHECK-FIXES: }
+ // CHECK-FIXES-NEXT: }
+
+ if (cond("ifif3"))
+ // comment
+ if (cond("ifif4")) {
+ // comment
+ /*comment*/; // comment
+ }
+ // CHECK-MESSAGES: :[[@LINE-6]]:21: warning: statement should be inside braces
+ // CHECK-FIXES: if (cond("ifif3")) {
+ // CHECK-FIXES: }
+
+ if (cond("ifif5"))
+ ; /* multi-line
+ comment */
+ // CHECK-MESSAGES: :[[@LINE-3]]:21: warning: statement should be inside braces
+ // CHECK-FIXES: if (cond("ifif5")) {
+ // CHECK-FIXES: }/* multi-line
+
+ if (1) while (2) if (3) for (;;) do ; while(false) /**/;/**/
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: statement should be inside braces
+ // CHECK-MESSAGES: :[[@LINE-2]]:19: warning: statement should be inside braces
+ // CHECK-MESSAGES: :[[@LINE-3]]:26: warning: statement should be inside braces
+ // CHECK-MESSAGES: :[[@LINE-4]]:35: warning: statement should be inside braces
+ // CHECK-MESSAGES: :[[@LINE-5]]:38: warning: statement should be inside braces
+ // CHECK-FIXES: if (1) { while (2) { if (3) { for (;;) { do { ; } while(false) /**/;/**/
+ // CHECK-FIXES-NEXT: }
+ // CHECK-FIXES-NEXT: }
+ // CHECK-FIXES-NEXT: }
+ // CHECK-FIXES-NEXT: }
+}
+
+void f(const char *p) {
+ if (!p)
+ f("\
+");
+} // end of f
+// CHECK-MESSAGES: :[[@LINE-4]]:10: warning: statement should be inside braces
+// CHECK-FIXES: {{^}} if (!p) {{{$}}
+// CHECK-FIXES-NEXT: {{^}} f("\{{$}}
+// CHECK-FIXES-NEXT: {{^}}");{{$}}
+// CHECK-FIXES-NEXT: {{^}}}{{$}}
+// CHECK-FIXES-NEXT: {{^}}} // end of f{{$}}
+
+#define M(x) x
+
+int test_macros(bool b) {
+ if (b) {
+ return 1;
+ } else
+ M(return 2);
+ // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: statement should be inside braces
+ // CHECK-FIXES: } else {
+ // CHECK-FIXES-NEXT: M(return 2);
+ // CHECK-FIXES-NEXT: }
+ M(
+ for (;;)
+ ;
+ );
+ // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: statement should be inside braces
+ // CHECK-FIXES: {{^}} for (;;) {{{$}}
+ // CHECK-FIXES-NEXT: {{^ ;$}}
+ // CHECK-FIXES-NEXT: {{^}$}}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-container-size-empty.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-container-size-empty.cpp
new file mode 100644
index 0000000..3c3c9a6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-container-size-empty.cpp
@@ -0,0 +1,439 @@
+// RUN: %check_clang_tidy %s readability-container-size-empty %t
+
+namespace std {
+template <typename T> struct vector {
+ vector();
+ bool operator==(const vector<T>& other) const;
+ bool operator!=(const vector<T>& other) const;
+ unsigned long size() const;
+ bool empty() const;
+};
+
+template <typename T> struct basic_string {
+ basic_string();
+ bool operator==(const basic_string<T>& other) const;
+ bool operator!=(const basic_string<T>& other) const;
+ bool operator==(const char *) const;
+ bool operator!=(const char *) const;
+ basic_string<T> operator+(const basic_string<T>& other) const;
+ unsigned long size() const;
+ bool empty() const;
+};
+
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+
+inline namespace __v2 {
+template <typename T> struct set {
+ set();
+ bool operator==(const set<T>& other) const;
+ bool operator!=(const set<T>& other) const;
+ unsigned long size() const;
+ bool empty() const;
+};
+}
+
+}
+
+template <typename T>
+class TemplatedContainer {
+public:
+ bool operator==(const TemplatedContainer<T>& other) const;
+ bool operator!=(const TemplatedContainer<T>& other) const;
+ int size() const;
+ bool empty() const;
+};
+
+template <typename T>
+class PrivateEmpty {
+public:
+ bool operator==(const PrivateEmpty<T>& other) const;
+ bool operator!=(const PrivateEmpty<T>& other) const;
+ int size() const;
+private:
+ bool empty() const;
+};
+
+struct BoolSize {
+ bool size() const;
+ bool empty() const;
+};
+
+struct EnumSize {
+ enum E { one };
+ enum E size() const;
+ bool empty() const;
+};
+
+class Container {
+public:
+ bool operator==(const Container& other) const;
+ int size() const;
+ bool empty() const;
+};
+
+class Derived : public Container {
+};
+
+class Container2 {
+public:
+ int size() const;
+ bool empty() const { return size() == 0; }
+};
+
+class Container3 {
+public:
+ int size() const;
+ bool empty() const;
+};
+
+bool Container3::empty() const { return this->size() == 0; }
+
+class Container4 {
+public:
+ bool operator==(const Container4& rhs) const;
+ int size() const;
+ bool empty() const { return *this == Container4(); }
+};
+
+std::string s_func() {
+ return std::string();
+}
+
+int main() {
+ std::set<int> intSet;
+ std::string str;
+ std::string str2;
+ std::wstring wstr;
+ str.size() + 0;
+ str.size() - 0;
+ 0 + str.size();
+ 0 - str.size();
+ if (intSet.size() == 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
+ // CHECK-FIXES: {{^ }}if (intSet.empty()){{$}}
+ // CHECK-MESSAGES: :32:8: note: method 'set<int>'::empty() defined here
+ if (intSet == std::set<int>())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness
+ // CHECK-FIXES: {{^ }}if (intSet.empty()){{$}}
+ // CHECK-MESSAGES: :32:8: note: method 'set<int>'::empty() defined here
+ if (s_func() == "")
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (s_func().empty()){{$}}
+ if (str.size() == 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (str.empty()){{$}}
+ if ((str + str2).size() == 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if ((str + str2).empty()){{$}}
+ if (str == "")
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (str.empty()){{$}}
+ if (str + str2 == "")
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if ((str + str2).empty()){{$}}
+ if (wstr.size() == 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (wstr.empty()){{$}}
+ if (wstr == "")
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (wstr.empty()){{$}}
+ std::vector<int> vect;
+ if (vect.size() == 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (vect.empty()){{$}}
+ if (vect == std::vector<int>())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (vect.empty()){{$}}
+ if (vect.size() != 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!vect.empty()){{$}}
+ if (vect != std::vector<int>())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!vect.empty()){{$}}
+ if (0 == vect.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (vect.empty()){{$}}
+ if (0 != vect.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!vect.empty()){{$}}
+ if (std::vector<int>() == vect)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (vect.empty()){{$}}
+ if (std::vector<int>() != vect)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!vect.empty()){{$}}
+ if (vect.size() > 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!vect.empty()){{$}}
+ if (0 < vect.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!vect.empty()){{$}}
+ if (vect.size() < 1)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (vect.empty()){{$}}
+ if (1 > vect.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (vect.empty()){{$}}
+ if (vect.size() >= 1)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!vect.empty()){{$}}
+ if (1 <= vect.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!vect.empty()){{$}}
+ if (vect.size() > 1) // no warning
+ ;
+ if (1 < vect.size()) // no warning
+ ;
+ if (vect.size() <= 1) // no warning
+ ;
+ if (1 >= vect.size()) // no warning
+ ;
+ if (!vect.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (vect.empty()){{$}}
+ if (vect.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!vect.empty()){{$}}
+
+ if (vect.empty())
+ ;
+
+ const std::vector<int> vect2;
+ if (vect2.size() != 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!vect2.empty()){{$}}
+
+ std::vector<int> *vect3 = new std::vector<int>();
+ if (vect3->size() == 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (vect3->empty()){{$}}
+ if ((*vect3).size() == 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if ((*vect3).empty()){{$}}
+ if ((*vect3) == std::vector<int>())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (vect3->empty()){{$}}
+ if (*vect3 == std::vector<int>())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (vect3->empty()){{$}}
+
+ delete vect3;
+
+ const std::vector<int> &vect4 = vect2;
+ if (vect4.size() == 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (vect4.empty()){{$}}
+ if (vect4 == std::vector<int>())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (vect4.empty()){{$}}
+
+ TemplatedContainer<void> templated_container;
+ if (templated_container.size() == 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (templated_container.empty()){{$}}
+ if (templated_container == TemplatedContainer<void>())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (templated_container.empty()){{$}}
+ if (templated_container.size() != 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!templated_container.empty()){{$}}
+ if (templated_container != TemplatedContainer<void>())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!templated_container.empty()){{$}}
+ if (0 == templated_container.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (templated_container.empty()){{$}}
+ if (TemplatedContainer<void>() == templated_container)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (templated_container.empty()){{$}}
+ if (0 != templated_container.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!templated_container.empty()){{$}}
+ if (TemplatedContainer<void>() != templated_container)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!templated_container.empty()){{$}}
+ if (templated_container.size() > 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!templated_container.empty()){{$}}
+ if (0 < templated_container.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!templated_container.empty()){{$}}
+ if (templated_container.size() < 1)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (templated_container.empty()){{$}}
+ if (1 > templated_container.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (templated_container.empty()){{$}}
+ if (templated_container.size() >= 1)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!templated_container.empty()){{$}}
+ if (1 <= templated_container.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!templated_container.empty()){{$}}
+ if (templated_container.size() > 1) // no warning
+ ;
+ if (1 < templated_container.size()) // no warning
+ ;
+ if (templated_container.size() <= 1) // no warning
+ ;
+ if (1 >= templated_container.size()) // no warning
+ ;
+ if (!templated_container.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (templated_container.empty()){{$}}
+ if (templated_container.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!templated_container.empty()){{$}}
+
+ if (templated_container.empty())
+ ;
+
+ // No warnings expected.
+ PrivateEmpty<void> private_empty;
+ if (private_empty.size() == 0)
+ ;
+ if (private_empty == PrivateEmpty<void>())
+ ;
+ if (private_empty.size() != 0)
+ ;
+ if (private_empty != PrivateEmpty<void>())
+ ;
+ if (0 == private_empty.size())
+ ;
+ if (PrivateEmpty<void>() == private_empty)
+ ;
+ if (0 != private_empty.size())
+ ;
+ if (PrivateEmpty<void>() != private_empty)
+ ;
+ if (private_empty.size() > 0)
+ ;
+ if (0 < private_empty.size())
+ ;
+ if (private_empty.size() < 1)
+ ;
+ if (1 > private_empty.size())
+ ;
+ if (private_empty.size() >= 1)
+ ;
+ if (1 <= private_empty.size())
+ ;
+ if (private_empty.size() > 1)
+ ;
+ if (1 < private_empty.size())
+ ;
+ if (private_empty.size() <= 1)
+ ;
+ if (1 >= private_empty.size())
+ ;
+ if (!private_empty.size())
+ ;
+ if (private_empty.size())
+ ;
+
+ // Types with weird size() return type.
+ BoolSize bs;
+ if (bs.size() == 0)
+ ;
+ EnumSize es;
+ if (es.size() == 0)
+ ;
+
+ Derived derived;
+ if (derived.size() == 0)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (derived.empty()){{$}}
+ if (derived == Derived())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (derived.empty()){{$}}
+}
+
+#define CHECKSIZE(x) if (x.size())
+// CHECK-FIXES: #define CHECKSIZE(x) if (x.size())
+
+template <typename T> void f() {
+ std::vector<T> v;
+ if (v.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
+ // CHECK-FIXES: {{^ }}if (!v.empty()){{$}}
+ if (v == std::vector<T>())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness instead of comparing to an empty object [readability-container-size-empty]
+ // CHECK-FIXES: {{^ }}if (v.empty()){{$}}
+ // CHECK-FIXES-NEXT: ;
+ CHECKSIZE(v);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: the 'empty' method should be used
+ // CHECK-MESSAGES: CHECKSIZE(v);
+
+ TemplatedContainer<T> templated_container;
+ if (templated_container.size())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!templated_container.empty()){{$}}
+ if (templated_container != TemplatedContainer<T>())
+ ;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used
+ // CHECK-FIXES: {{^ }}if (!templated_container.empty()){{$}}
+ // CHECK-FIXES-NEXT: ;
+ CHECKSIZE(templated_container);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: the 'empty' method should be used
+ // CHECK-MESSAGES: CHECKSIZE(templated_container);
+}
+
+void g() {
+ f<int>();
+ f<double>();
+ f<char *>();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-delete-null-pointer.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-delete-null-pointer.cpp
new file mode 100644
index 0000000..b46e52a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-delete-null-pointer.cpp
@@ -0,0 +1,86 @@
+// RUN: %check_clang_tidy %s readability-delete-null-pointer %t
+
+#define NULL 0
+
+void f() {
+ int *p = 0;
+
+ // #1
+ if (p) { // #2
+ delete p;
+ } // #3
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: 'if' statement is unnecessary; deleting null pointer has no effect [readability-delete-null-pointer]
+
+ // CHECK-FIXES: {{^ }}// #1
+ // CHECK-FIXES-NEXT: {{^ }}// #2
+ // CHECK-FIXES-NEXT: delete p;
+ // CHECK-FIXES-NEXT: {{^ }}// #3
+
+ int *p2 = new int[3];
+ // #4
+ if (p2) // #5
+ delete[] p2;
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: 'if' statement is unnecessary;
+
+ // CHECK-FIXES: // #4
+ // CHECK-FIXES-NEXT: {{^ }}// #5
+ // CHECK-FIXES-NEXT: delete[] p2;
+
+ int *p3 = 0;
+ if (NULL != p3) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'if' statement is unnecessary;
+ delete p3;
+ }
+ // CHECK-FIXES-NOT: if (NULL != p3) {
+ // CHECK-FIXES: delete p3;
+
+ int *p4 = nullptr;
+ if (p4 != nullptr) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'if' statement is unnecessary;
+ delete p4;
+ }
+ // CHECK-FIXES-NOT: if (p4 != nullptr) {
+ // CHECK-FIXES: delete p4;
+
+ char *c;
+ if (c != 0) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'if' statement is unnecessary;
+ delete c;
+ }
+ // CHECK-FIXES-NOT: if (c != 0) {
+ // CHECK-FIXES: delete c;
+
+ char *c2;
+ if (c2) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'if' statement is unnecessary;
+ // CHECK-FIXES: } else {
+ // CHECK-FIXES: c2 = c;
+ delete c2;
+ } else {
+ c2 = c;
+ }
+ struct A {
+ void foo() {
+ if (mp) // #6
+ delete mp;
+ // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: 'if' statement is unnecessary; deleting null pointer has no effect [readability-delete-null-pointer]
+ // CHECK-FIXES: {{^ }}// #6
+ // CHECK-FIXES-NEXT: delete mp;
+ }
+ int *mp;
+ };
+}
+
+void g() {
+ int *p5, *p6;
+ if (p5)
+ delete p6;
+
+ if (p5 && p6)
+ delete p5;
+
+ if (p6) {
+ int x = 5;
+ delete p6;
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-deleted-default.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-deleted-default.cpp
new file mode 100644
index 0000000..bf27e00
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-deleted-default.cpp
@@ -0,0 +1,127 @@
+// RUN: %check_clang_tidy %s readability-deleted-default %t -- -- -std=c++11 -fno-ms-compatibility
+
+class NoDefault {
+public:
+ NoDefault() = delete;
+ NoDefault(NoDefault &&Other) = delete;
+ NoDefault(const NoDefault &Other) = delete;
+};
+
+class MissingEverything {
+public:
+ MissingEverything() = default;
+ // CHECK-MESSAGES: warning: default constructor is explicitly defaulted but implicitly deleted, probably because a non-static data member or a base class is lacking a default constructor; definition can either be removed or explicitly deleted [readability-deleted-default]
+ MissingEverything(MissingEverything &&Other) = default;
+ // CHECK-MESSAGES: warning: move constructor is explicitly defaulted but implicitly deleted, probably because a non-static data member or a base class is neither copyable nor movable; definition can either be removed or explicitly deleted [readability-deleted-default]
+ MissingEverything(const MissingEverything &Other) = default;
+ // CHECK-MESSAGES: warning: copy constructor is explicitly defaulted but implicitly deleted, probably because a non-static data member or a base class is not copyable; definition can either be removed or explicitly deleted [readability-deleted-default]
+ MissingEverything &operator=(MissingEverything &&Other) = default;
+ // CHECK-MESSAGES: warning: move assignment operator is explicitly defaulted but implicitly deleted, probably because a base class or a non-static data member is not assignable, e.g. because the latter is marked 'const'; definition can either be removed or explicitly deleted [readability-deleted-default]
+ MissingEverything &operator=(const MissingEverything &Other) = default;
+ // CHECK-MESSAGES: warning: copy assignment operator is explicitly defaulted but implicitly deleted, probably because a base class or a non-static data member is not assignable, e.g. because the latter is marked 'const'; definition can either be removed or explicitly deleted [readability-deleted-default]
+
+private:
+ NoDefault ND;
+};
+
+class NotAssignable {
+public:
+ NotAssignable(NotAssignable &&Other) = default;
+ NotAssignable(const NotAssignable &Other) = default;
+ NotAssignable &operator=(NotAssignable &&Other) = default;
+ // CHECK-MESSAGES: warning: move assignment operator is explicitly defaulted but implicitly deleted
+ NotAssignable &operator=(const NotAssignable &Other) = default;
+ // CHECK-MESSAGES: warning: copy assignment operator is explicitly defaulted but implicitly deleted
+
+private:
+ const int I = 0;
+};
+
+class Movable {
+public:
+ Movable() = default;
+ Movable(Movable &&Other) = default;
+ Movable(const Movable &Other) = delete;
+ Movable &operator=(Movable &&Other) = default;
+ Movable &operator=(const Movable &Other) = delete;
+};
+
+class NotCopyable {
+public:
+ NotCopyable(NotCopyable &&Other) = default;
+ NotCopyable(const NotCopyable &Other) = default;
+ // CHECK-MESSAGES: warning: copy constructor is explicitly defaulted but implicitly deleted
+ NotCopyable &operator=(NotCopyable &&Other) = default;
+ NotCopyable &operator=(const NotCopyable &Other) = default;
+ // CHECK-MESSAGES: warning: copy assignment operator is explicitly defaulted but implicitly deleted
+private:
+ Movable M;
+};
+
+template <typename T> class Templated {
+public:
+ // No warning here, it is a templated class.
+ Templated() = default;
+ Templated(Templated &&Other) = default;
+ Templated(const Templated &Other) = default;
+ Templated &operator=(Templated &&Other) = default;
+ Templated &operator=(const Templated &Other) = default;
+
+ class InnerTemplated {
+ public:
+ // This class is not in itself templated, but we still don't have warning.
+ InnerTemplated() = default;
+ InnerTemplated(InnerTemplated &&Other) = default;
+ InnerTemplated(const InnerTemplated &Other) = default;
+ InnerTemplated &operator=(InnerTemplated &&Other) = default;
+ InnerTemplated &operator=(const InnerTemplated &Other) = default;
+
+ private:
+ T TVar;
+ };
+
+ class InnerNotTemplated {
+ public:
+ // This one could technically have warnings, but currently doesn't.
+ InnerNotTemplated() = default;
+ InnerNotTemplated(InnerNotTemplated &&Other) = default;
+ InnerNotTemplated(const InnerNotTemplated &Other) = default;
+ InnerNotTemplated &operator=(InnerNotTemplated &&Other) = default;
+ InnerNotTemplated &operator=(const InnerNotTemplated &Other) = default;
+
+ private:
+ int I;
+ };
+
+private:
+ const T TVar{};
+};
+
+int FunctionWithInnerClass() {
+ class InnerNotAssignable {
+ public:
+ InnerNotAssignable &operator=(InnerNotAssignable &&Other) = default;
+ // CHECK-MESSAGES: warning: move assignment operator is explicitly defaulted but implicitly deleted
+ private:
+ const int I = 0;
+ };
+ return 1;
+};
+
+template <typename T>
+int TemplateFunctionWithInnerClass() {
+ class InnerNotAssignable {
+ public:
+ InnerNotAssignable &operator=(InnerNotAssignable &&Other) = default;
+ private:
+ const T TVar{};
+ };
+ return 1;
+};
+
+void Foo() {
+ Templated<const int> V1;
+ Templated<int>::InnerTemplated V2;
+ Templated<float>::InnerNotTemplated V3;
+ TemplateFunctionWithInnerClass<int>();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-else-after-return.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-else-after-return.cpp
new file mode 100644
index 0000000..7e95092
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-else-after-return.cpp
@@ -0,0 +1,107 @@
+// RUN: %check_clang_tidy %s readability-else-after-return %t -- -- -std=c++11 -fexceptions
+
+namespace std {
+struct string {
+ string(const char *);
+ ~string();
+};
+} // namespace std
+
+struct my_exception {
+ my_exception(const std::string &s);
+};
+
+void f(int a) {
+ if (a > 0)
+ return;
+ else // comment-0
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'else' after 'return'
+ // CHECK-FIXES: {{^}} // comment-0
+ return;
+
+ if (a > 0) {
+ return;
+ } else { // comment-1
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
+ // CHECK-FIXES: {{^}} } // comment-1
+ return;
+ }
+
+ if (a > 0) {
+ f(0);
+ if (a > 10)
+ return;
+ } else {
+ return;
+ }
+
+ if (a > 0)
+ f(0);
+ else if (a > 10)
+ return;
+ else // comment-2
+ // CHECK-FIXES-NOT: {{^}} // comment-2
+ f(0);
+
+ if (a > 0)
+ if (a < 10)
+ return;
+ else // comment-3
+ // CHECK-FIXES-NOT: {{^}} // comment-3
+ f(0);
+ else
+ if (a > 10)
+ return;
+ else // comment-4
+ // CHECK-FIXES-NOT: {{^}} // comment-4
+ f(0);
+
+ if (a > 0) {
+ if (a < 10)
+ return;
+ else // comment-5
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
+ // CHECK-FIXES: {{^}} // comment-5
+ f(0);
+ } else {
+ if (a > 10)
+ return;
+ else // comment-6
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
+ // CHECK-FIXES: {{^}} // comment-6
+ f(0);
+ }
+}
+
+void foo() {
+ for (unsigned x = 0; x < 42; ++x) {
+ if (x) {
+ continue;
+ } else { // comment-7
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'continue'
+ // CHECK-FIXES: {{^}} } // comment-7
+ x++;
+ }
+ if (x) {
+ break;
+ } else { // comment-8
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'break'
+ // CHECK-FIXES: {{^}} } // comment-8
+ x++;
+ }
+ if (x) {
+ throw 42;
+ } else { // comment-9
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'throw'
+ // CHECK-FIXES: {{^}} } // comment-9
+ x++;
+ }
+ if (x) {
+ throw my_exception("foo");
+ } else { // comment-10
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'throw'
+ // CHECK-FIXES: {{^}} } // comment-10
+ x++;
+ }
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-function-size-variables-c++17.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-function-size-variables-c++17.cpp
new file mode 100644
index 0000000..8af0d96
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-function-size-variables-c++17.cpp
@@ -0,0 +1,21 @@
+// RUN: %check_clang_tidy %s readability-function-size %t -- -config='{CheckOptions: [{key: readability-function-size.LineThreshold, value: 0}, {key: readability-function-size.StatementThreshold, value: 0}, {key: readability-function-size.BranchThreshold, value: 0}, {key: readability-function-size.ParameterThreshold, value: 5}, {key: readability-function-size.NestingThreshold, value: 2}, {key: readability-function-size.VariableThreshold, value: 1}]}' -- -std=c++17
+
+void structured_bindings() {
+ int a[2] = {1, 2};
+ auto [x, y] = a;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: warning: function 'structured_bindings' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 3 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 2 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-7]]:6: note: 3 variables (threshold 1)
+
+#define SWAP(x, y) ({auto& [x0, x1] = x; __typeof__(x) t = {x0, x1}; auto& [y0, y1] = y; auto& [t0, t1] = t; x0 = y0; x1 = y1; y0 = t0; y1 = t1; })
+void variables_13() {
+ int a[2] = {1, 2};
+ int b[2] = {3, 4};
+ SWAP(a, b);
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:6: warning: function 'variables_13' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 4 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-7]]:6: note: 11 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: 2 variables (threshold 1)
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-function-size.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-function-size.cpp
new file mode 100644
index 0000000..efb41a1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-function-size.cpp
@@ -0,0 +1,301 @@
+// RUN: %check_clang_tidy %s readability-function-size %t -- -config='{CheckOptions: [{key: readability-function-size.LineThreshold, value: 0}, {key: readability-function-size.StatementThreshold, value: 0}, {key: readability-function-size.BranchThreshold, value: 0}, {key: readability-function-size.ParameterThreshold, value: 5}, {key: readability-function-size.NestingThreshold, value: 2}, {key: readability-function-size.VariableThreshold, value: 1}]}' -- -std=c++11
+
+// Bad formatting is intentional, don't run clang-format over the whole file!
+
+void foo1() {
+}
+
+void foo2() {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'foo2' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-2]]:6: note: 1 statements (threshold 0)
+
+void foo3() {
+;
+
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: warning: function 'foo3' exceeds recommended size/complexity
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 3 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 1 statements (threshold 0)
+
+void foo4(int i) { if (i) {} else; {}
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:6: warning: function 'foo4' exceeds recommended size/complexity
+// CHECK-MESSAGES: :[[@LINE-3]]:6: note: 1 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: 3 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 1 branches (threshold 0)
+
+void foo5(int i) {for(;i;)while(i)
+do;while(i);
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:6: warning: function 'foo5' exceeds recommended size/complexity
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: 2 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 7 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 3 branches (threshold 0)
+
+template <typename T> T foo6(T i) {return i;
+}
+int x = foo6(0);
+// CHECK-MESSAGES: :[[@LINE-3]]:25: warning: function 'foo6' exceeds recommended size/complexity
+// CHECK-MESSAGES: :[[@LINE-4]]:25: note: 1 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-5]]:25: note: 1 statements (threshold 0)
+
+void foo7(int p1, int p2, int p3, int p4, int p5, int p6) {;}
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'foo7' exceeds recommended size/complexity
+// CHECK-MESSAGES: :[[@LINE-2]]:6: note: 1 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-3]]:6: note: 6 parameters (threshold 5)
+
+void bar1() { [](){;;;;;;;;;;;if(1){}}();
+
+
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: warning: function 'bar1' exceeds recommended size/complexity
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 3 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 14 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-7]]:6: note: 1 branches (threshold 0)
+
+void bar2() { class A { void barx() {;;} }; }
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'bar2' exceeds recommended size/complexity
+// CHECK-MESSAGES: :[[@LINE-2]]:6: note: 3 statements (threshold 0)
+//
+// CHECK-MESSAGES: :[[@LINE-4]]:30: warning: function 'barx' exceeds recommended size/complexity
+// CHECK-MESSAGES: :[[@LINE-5]]:30: note: 2 statements (threshold 0)
+
+#define macro() {int x; {int y; {int z;}}}
+
+void baz0() { // 1
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'baz0' exceeds recommended size/complexity
+ // CHECK-MESSAGES: :[[@LINE-2]]:6: note: 28 lines including whitespace and comments (threshold 0)
+ // CHECK-MESSAGES: :[[@LINE-3]]:6: note: 9 statements (threshold 0)
+ int a;
+ { // 2
+ int b;
+ { // 3
+// CHECK-MESSAGES: :[[@LINE-1]]:5: note: nesting level 3 starts here (threshold 2)
+ int c;
+ { // 4
+ int d;
+ }
+ }
+ }
+ { // 2
+ int e;
+ }
+ { // 2
+ { // 3
+// CHECK-MESSAGES: :[[@LINE-1]]:5: note: nesting level 3 starts here (threshold 2)
+ int j;
+ }
+ }
+ macro()
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: note: nesting level 3 starts here (threshold 2)
+ // CHECK-MESSAGES: :[[@LINE-28]]:25: note: expanded from macro 'macro'
+ // CHECK-MESSAGES: :[[@LINE-27]]:6: note: 9 variables (threshold 1)
+}
+
+// check that nested if's are not reported. this was broken initially
+void nesting_if() { // 1
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'nesting_if' exceeds recommended size/complexity
+ // CHECK-MESSAGES: :[[@LINE-2]]:6: note: 23 lines including whitespace and comments (threshold 0)
+ // CHECK-MESSAGES: :[[@LINE-3]]:6: note: 18 statements (threshold 0)
+ // CHECK-MESSAGES: :[[@LINE-4]]:6: note: 6 branches (threshold 0)
+ if (true) { // 2
+ int j;
+ } else if (true) { // 2
+ int j;
+ if (true) { // 3
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: note: nesting level 3 starts here (threshold 2)
+ int j;
+ }
+ } else if (true) { // 2
+ int j;
+ if (true) { // 3
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: note: nesting level 3 starts here (threshold 2)
+ int j;
+ }
+ } else if (true) { // 2
+ int j;
+ }
+ // CHECK-MESSAGES: :[[@LINE-22]]:6: note: 6 variables (threshold 1)
+}
+
+// however this should warn
+void bad_if_nesting() { // 1
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'bad_if_nesting' exceeds recommended size/complexity
+// CHECK-MESSAGES: :[[@LINE-2]]:6: note: 23 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-3]]:6: note: 12 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: 4 branches (threshold 0)
+ if (true) { // 2
+ int j;
+ } else { // 2
+ if (true) { // 3
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: note: nesting level 3 starts here (threshold 2)
+ int j;
+ } else { // 3
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: note: nesting level 3 starts here (threshold 2)
+ if (true) { // 4
+ int j;
+ } else { // 4
+ if (true) { // 5
+ int j;
+ }
+ }
+ }
+ }
+ // CHECK-MESSAGES: :[[@LINE-22]]:6: note: 4 variables (threshold 1)
+}
+
+void variables_0() {
+ int i;
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:6: warning: function 'variables_0' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: 2 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 1 statements (threshold 0)
+void variables_1(int i) {
+ int j;
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:6: warning: function 'variables_1' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: 2 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 1 statements (threshold 0)
+void variables_2(int i, int j) {
+ ;
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:6: warning: function 'variables_2' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: 2 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 1 statements (threshold 0)
+void variables_3() {
+ int i[2];
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:6: warning: function 'variables_3' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: 2 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 1 statements (threshold 0)
+void variables_4() {
+ int i;
+ int j;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: warning: function 'variables_4' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 3 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 2 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-7]]:6: note: 2 variables (threshold 1)
+void variables_5() {
+ int i, j;
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:6: warning: function 'variables_5' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: 2 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 1 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 2 variables (threshold 1)
+void variables_6() {
+ for (int i;;)
+ for (int j;;)
+ ;
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:6: warning: function 'variables_6' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 4 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-7]]:6: note: 5 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: 2 branches (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-9]]:6: note: 2 variables (threshold 1)
+void variables_7() {
+ if (int a = 1)
+ if (int b = 2)
+ ;
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:6: warning: function 'variables_7' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 4 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-7]]:6: note: 7 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: 2 branches (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-9]]:6: note: 2 variables (threshold 1)
+void variables_8() {
+ int a[2];
+ for (auto i : a)
+ for (auto j : a)
+ ;
+}
+// CHECK-MESSAGES: :[[@LINE-6]]:6: warning: function 'variables_8' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-7]]:6: note: 5 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: 8 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-9]]:6: note: 2 branches (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-10]]:6: note: 3 variables (threshold 1)
+void variables_9() {
+ int a, b;
+ struct A {
+ A(int c, int d) {
+ int e, f;
+ }
+ };
+}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: warning: function 'variables_9' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-9]]:6: note: 7 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-10]]:6: note: 3 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-11]]:6: note: 2 variables (threshold 1)
+// CHECK-MESSAGES: :[[@LINE-9]]:5: warning: function 'A' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-10]]:5: note: 2 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-11]]:5: note: 1 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-12]]:5: note: 2 variables (threshold 1)
+void variables_10() {
+ int a, b;
+ struct A {
+ int c;
+ int d;
+ };
+}
+// CHECK-MESSAGES: :[[@LINE-7]]:6: warning: function 'variables_10' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: 6 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-9]]:6: note: 2 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-10]]:6: note: 2 variables (threshold 1)
+void variables_11() {
+ struct S {
+ void bar() {
+ int a, b;
+ }
+ };
+}
+// CHECK-MESSAGES: :[[@LINE-7]]:6: warning: function 'variables_11' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: 6 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-7]]:10: warning: function 'bar' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-8]]:10: note: 2 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-9]]:10: note: 2 variables (threshold 1)
+void variables_12() {
+ int v;
+ auto test = [](int a, int b) -> void {};
+ test({}, {});
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:6: warning: function 'variables_12' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 4 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-7]]:6: note: 3 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: 2 variables (threshold 1)
+void variables_13() {
+ int v;
+ auto test = []() -> void {
+ int a;
+ int b;
+ };
+ test();
+}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: warning: function 'variables_13' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-9]]:6: note: 7 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-10]]:6: note: 5 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-11]]:6: note: 2 variables (threshold 1)
+void variables_14() {
+ (void)({int a = 12; a; });
+ (void)({int a = 12; a; });
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: warning: function 'variables_14' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 3 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 6 statements (threshold 0)
+#define SWAP(x, y) ({__typeof__(x) temp = x; x = y; y = temp; })
+void variables_15() {
+ int a = 10, b = 12;
+ SWAP(a, b);
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: warning: function 'variables_15' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 3 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 5 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-7]]:6: note: 2 variables (threshold 1)
+#define vardecl(type, name) type name;
+void variables_16() {
+ vardecl(int, a);
+ vardecl(int, b);
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: warning: function 'variables_16' exceeds recommended size/complexity thresholds [readability-function-size]
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: 3 lines including whitespace and comments (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-6]]:6: note: 4 statements (threshold 0)
+// CHECK-MESSAGES: :[[@LINE-7]]:6: note: 2 variables (threshold 1)
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-identifier-naming-objc.m b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-identifier-naming-objc.m
new file mode 100644
index 0000000..ab123c2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-identifier-naming-objc.m
@@ -0,0 +1,12 @@
+// RUN: %check_clang_tidy %s readability-identifier-naming %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: readability-identifier-naming.ObjcIvarPrefix, value: '_'}]}' \
+// RUN: --
+
+@interface Foo {
+ int _bar;
+ int barWithoutPrefix;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for objc ivar 'barWithoutPrefix' [readability-identifier-naming]
+ // CHECK-FIXES: int _barWithoutPrefix;
+}
+@end
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-identifier-naming.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-identifier-naming.cpp
new file mode 100644
index 0000000..436e844
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-identifier-naming.cpp
@@ -0,0 +1,476 @@
+// Remove UNSUPPORTED for powerpc64le when the problem introduced by
+// r288563 is resolved.
+// UNSUPPORTED: powerpc64le
+// RUN: %check_clang_tidy %s readability-identifier-naming %t -- \
+// RUN: -config='{CheckOptions: [ \
+// RUN: {key: readability-identifier-naming.AbstractClassCase, value: CamelCase}, \
+// RUN: {key: readability-identifier-naming.AbstractClassPrefix, value: 'A'}, \
+// RUN: {key: readability-identifier-naming.ClassCase, value: CamelCase}, \
+// RUN: {key: readability-identifier-naming.ClassPrefix, value: 'C'}, \
+// RUN: {key: readability-identifier-naming.ClassConstantCase, value: CamelCase}, \
+// RUN: {key: readability-identifier-naming.ClassConstantPrefix, value: 'k'}, \
+// RUN: {key: readability-identifier-naming.ClassMemberCase, value: CamelCase}, \
+// RUN: {key: readability-identifier-naming.ClassMethodCase, value: camelBack}, \
+// RUN: {key: readability-identifier-naming.ConstantCase, value: UPPER_CASE}, \
+// RUN: {key: readability-identifier-naming.ConstantSuffix, value: '_CST'}, \
+// RUN: {key: readability-identifier-naming.ConstexprFunctionCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.ConstexprMethodCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.ConstexprVariableCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.EnumCase, value: CamelCase}, \
+// RUN: {key: readability-identifier-naming.EnumPrefix, value: 'E'}, \
+// RUN: {key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE}, \
+// RUN: {key: readability-identifier-naming.FunctionCase, value: camelBack}, \
+// RUN: {key: readability-identifier-naming.GlobalConstantCase, value: UPPER_CASE}, \
+// RUN: {key: readability-identifier-naming.GlobalFunctionCase, value: CamelCase}, \
+// RUN: {key: readability-identifier-naming.GlobalVariableCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.GlobalVariablePrefix, value: 'g_'}, \
+// RUN: {key: readability-identifier-naming.InlineNamespaceCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.LocalConstantCase, value: CamelCase}, \
+// RUN: {key: readability-identifier-naming.LocalConstantPrefix, value: 'k'}, \
+// RUN: {key: readability-identifier-naming.LocalVariableCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.MemberCase, value: CamelCase}, \
+// RUN: {key: readability-identifier-naming.MemberPrefix, value: 'm_'}, \
+// RUN: {key: readability-identifier-naming.ConstantMemberCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.PrivateMemberPrefix, value: '__'}, \
+// RUN: {key: readability-identifier-naming.ProtectedMemberPrefix, value: '_'}, \
+// RUN: {key: readability-identifier-naming.PublicMemberCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.MethodCase, value: camelBack}, \
+// RUN: {key: readability-identifier-naming.PrivateMethodPrefix, value: '__'}, \
+// RUN: {key: readability-identifier-naming.ProtectedMethodPrefix, value: '_'}, \
+// RUN: {key: readability-identifier-naming.NamespaceCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.ParameterCase, value: camelBack}, \
+// RUN: {key: readability-identifier-naming.ParameterPrefix, value: 'a_'}, \
+// RUN: {key: readability-identifier-naming.ConstantParameterCase, value: camelBack}, \
+// RUN: {key: readability-identifier-naming.ConstantParameterPrefix, value: 'i_'}, \
+// RUN: {key: readability-identifier-naming.ParameterPackCase, value: camelBack}, \
+// RUN: {key: readability-identifier-naming.PureFunctionCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.PureMethodCase, value: camelBack}, \
+// RUN: {key: readability-identifier-naming.StaticConstantCase, value: UPPER_CASE}, \
+// RUN: {key: readability-identifier-naming.StaticVariableCase, value: camelBack}, \
+// RUN: {key: readability-identifier-naming.StaticVariablePrefix, value: 's_'}, \
+// RUN: {key: readability-identifier-naming.StructCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.TemplateParameterCase, value: UPPER_CASE}, \
+// RUN: {key: readability-identifier-naming.TemplateTemplateParameterCase, value: CamelCase}, \
+// RUN: {key: readability-identifier-naming.TemplateUsingCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.TemplateUsingPrefix, value: 'u_'}, \
+// RUN: {key: readability-identifier-naming.TypeTemplateParameterCase, value: camelBack}, \
+// RUN: {key: readability-identifier-naming.TypeTemplateParameterSuffix, value: '_t'}, \
+// RUN: {key: readability-identifier-naming.TypedefCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.TypedefSuffix, value: '_t'}, \
+// RUN: {key: readability-identifier-naming.UnionCase, value: CamelCase}, \
+// RUN: {key: readability-identifier-naming.UnionPrefix, value: 'U'}, \
+// RUN: {key: readability-identifier-naming.UsingCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.ValueTemplateParameterCase, value: camelBack}, \
+// RUN: {key: readability-identifier-naming.VariableCase, value: lower_case}, \
+// RUN: {key: readability-identifier-naming.VirtualMethodCase, value: Camel_Snake_Case}, \
+// RUN: {key: readability-identifier-naming.VirtualMethodPrefix, value: 'v_'}, \
+// RUN: {key: readability-identifier-naming.MacroDefinitionCase, value: UPPER_CASE}, \
+// RUN: {key: readability-identifier-naming.TypeAliasCase, value: camel_Snake_Back}, \
+// RUN: {key: readability-identifier-naming.TypeAliasSuffix, value: '_t'}, \
+// RUN: {key: readability-identifier-naming.IgnoreFailedSplit, value: 0} \
+// RUN: ]}' -- -std=c++11 -fno-delayed-template-parsing \
+// RUN: -I%S/Inputs/readability-identifier-naming \
+// RUN: -isystem %S/Inputs/readability-identifier-naming/system
+
+// clang-format off
+
+#include <system-header.h>
+#include "user-header.h"
+// NO warnings or fixes expected from declarations within header files without
+// the -header-filter= option
+
+namespace FOO_NS {
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: invalid case style for namespace 'FOO_NS' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}namespace foo_ns {{{$}}
+inline namespace InlineNamespace {
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: invalid case style for inline namespace 'InlineNamespace'
+// CHECK-FIXES: {{^}}inline namespace inline_namespace {{{$}}
+
+SYSTEM_NS::structure g_s1;
+// NO warnings or fixes expected as SYSTEM_NS and structure are declared in a header file
+
+USER_NS::object g_s2;
+// NO warnings or fixes expected as USER_NS and object are declared in a header file
+
+SYSTEM_MACRO(var1);
+// NO warnings or fixes expected as var1 is from macro expansion
+
+USER_MACRO(var2);
+// NO warnings or fixes expected as var2 is declared in a macro expansion
+
+#define BLA int FOO_bar
+BLA;
+// NO warnings or fixes expected as FOO_bar is from macro expansion
+
+int global0;
+#define USE_NUMBERED_GLOBAL(number) auto use_global##number = global##number
+USE_NUMBERED_GLOBAL(0);
+// NO warnings or fixes expected as global0 is pieced together in a macro
+// expansion.
+
+int global1;
+#define USE_NUMBERED_BAL(prefix, number) \
+ auto use_##prefix##bal##number = prefix##bal##number
+USE_NUMBERED_BAL(glo, 1);
+// NO warnings or fixes expected as global1 is pieced together in a macro
+// expansion.
+
+int global2;
+#define USE_RECONSTRUCTED(glo, bal) auto use_##glo##bal = glo##bal
+USE_RECONSTRUCTED(glo, bal2);
+// NO warnings or fixes expected as global2 is pieced together in a macro
+// expansion.
+
+int global;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for global variable 'global'
+// CHECK-FIXES: {{^}}int g_global;{{$}}
+#define USE_IN_MACRO(m) auto use_##m = m
+USE_IN_MACRO(global);
+
+int global3;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for global variable 'global3'
+// CHECK-FIXES: {{^}}int g_global3;{{$}}
+#define ADD_TO_SELF(m) (m) + (m)
+int g_twice_global3 = ADD_TO_SELF(global3);
+// CHECK-FIXES: {{^}}int g_twice_global3 = ADD_TO_SELF(g_global3);{{$}}
+
+enum my_enumeration {
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: invalid case style for enum 'my_enumeration'
+// CHECK-FIXES: {{^}}enum EMyEnumeration {{{$}}
+ MyConstant = 1,
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for enum constant 'MyConstant'
+// CHECK-FIXES: {{^}} MY_CONSTANT = 1,{{$}}
+ your_CONST = 1,
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for enum constant 'your_CONST'
+// CHECK-FIXES: {{^}} YOUR_CONST = 1,{{$}}
+ THIS_ConstValue = 1,
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for enum constant 'THIS_ConstValue'
+// CHECK-FIXES: {{^}} THIS_CONST_VALUE = 1,{{$}}
+};
+
+constexpr int ConstExpr_variable = MyConstant;
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: invalid case style for constexpr variable 'ConstExpr_variable'
+// CHECK-FIXES: {{^}}constexpr int const_expr_variable = MY_CONSTANT;{{$}}
+
+class my_class {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for class 'my_class'
+// CHECK-FIXES: {{^}}class CMyClass {{{$}}
+public:
+ my_class();
+// CHECK-FIXES: {{^}} CMyClass();{{$}}
+
+ my_class(void*) : my_class() {}
+// CHECK-FIXES: {{^}} CMyClass(void*) : CMyClass() {}{{$}}
+
+ ~
+ my_class();
+// (space in destructor token test, we could check trigraph but they will be deprecated)
+// CHECK-FIXES: {{^}} ~{{$}}
+// CHECK-FIXES: {{^}} CMyClass();{{$}}
+
+private:
+ const int MEMBER_one_1 = ConstExpr_variable;
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: invalid case style for constant member 'MEMBER_one_1'
+// CHECK-FIXES: {{^}} const int member_one_1 = const_expr_variable;{{$}}
+ int member2 = 2;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for private member 'member2'
+// CHECK-FIXES: {{^}} int __member2 = 2;{{$}}
+ int _memberWithExtraUnderscores_ = 42;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for private member '_memberWithExtraUnderscores_'
+// CHECK-FIXES: {{^}} int __memberWithExtraUnderscores = 42;{{$}}
+
+private:
+ int private_member = 3;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for private member 'private_member'
+// CHECK-FIXES: {{^}} int __private_member = 3;{{$}}
+
+protected:
+ int ProtMember;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for protected member 'ProtMember'
+// CHECK-FIXES: {{^}} int _ProtMember;{{$}}
+
+public:
+ int PubMem;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for public member 'PubMem'
+// CHECK-FIXES: {{^}} int pub_mem;{{$}}
+
+ static const int classConstant;
+// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: invalid case style for class constant 'classConstant'
+// CHECK-FIXES: {{^}} static const int kClassConstant;{{$}}
+ static int ClassMember_2;
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for class member 'ClassMember_2'
+// CHECK-FIXES: {{^}} static int ClassMember2;{{$}}
+};
+class my_class;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for class 'my_class'
+// CHECK-FIXES: {{^}}class CMyClass;{{$}}
+
+class my_forward_declared_class; // No warning should be triggered.
+
+const int my_class::classConstant = 4;
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: invalid case style for class constant 'classConstant'
+// CHECK-FIXES: {{^}}const int CMyClass::kClassConstant = 4;{{$}}
+
+int my_class::ClassMember_2 = 5;
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: invalid case style for class member 'ClassMember_2'
+// CHECK-FIXES: {{^}}int CMyClass::ClassMember2 = 5;{{$}}
+
+class my_derived_class : public virtual my_class {};
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for class 'my_derived_class'
+// CHECK-FIXES: {{^}}class CMyDerivedClass : public virtual CMyClass {};{{$}}
+
+class CMyWellNamedClass {};
+// No warning expected as this class is well named.
+
+template <typename t_t>
+class CMyWellNamedClass2 : public my_class {
+ // CHECK-FIXES: {{^}}class CMyWellNamedClass2 : public CMyClass {{{$}}
+ t_t my_Bad_Member;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for private member 'my_Bad_Member'
+ // CHECK-FIXES: {{^}} t_t __my_Bad_Member;{{$}}
+ int my_Other_Bad_Member = 42;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for private member 'my_Other_Bad_Member'
+ // CHECK-FIXES: {{^}} int __my_Other_Bad_Member = 42;{{$}}
+public:
+ CMyWellNamedClass2() = default;
+ CMyWellNamedClass2(CMyWellNamedClass2 const&) = default;
+ CMyWellNamedClass2(CMyWellNamedClass2 &&) = default;
+ CMyWellNamedClass2(t_t a_v, void *a_p) : my_class(a_p), my_Bad_Member(a_v) {}
+ // CHECK-FIXES: {{^}} CMyWellNamedClass2(t_t a_v, void *a_p) : CMyClass(a_p), __my_Bad_Member(a_v) {}{{$}}
+
+ CMyWellNamedClass2(t_t a_v) : my_class(), my_Bad_Member(a_v), my_Other_Bad_Member(11) {}
+ // CHECK-FIXES: {{^}} CMyWellNamedClass2(t_t a_v) : CMyClass(), __my_Bad_Member(a_v), __my_Other_Bad_Member(11) {}{{$}}
+};
+void InstantiateClassMethods() {
+ // Ensure we trigger the instantiation of each constructor
+ CMyWellNamedClass2<int> x;
+ CMyWellNamedClass2<int> x2 = x;
+ CMyWellNamedClass2<int> x3 = static_cast<CMyWellNamedClass2<int>&&>(x2);
+ CMyWellNamedClass2<int> x4(42);
+ CMyWellNamedClass2<int> x5(42, nullptr);
+}
+
+template<typename T>
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: invalid case style for type template parameter 'T'
+// CHECK-FIXES: {{^}}template<typename t_t>{{$}}
+class my_templated_class : CMyWellNamedClass {};
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for class 'my_templated_class'
+// CHECK-FIXES: {{^}}class CMyTemplatedClass : CMyWellNamedClass {};{{$}}
+
+template<typename T>
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: invalid case style for type template parameter 'T'
+// CHECK-FIXES: {{^}}template<typename t_t>{{$}}
+class my_other_templated_class : my_templated_class< my_class>, private my_derived_class {};
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for class 'my_other_templated_class'
+// CHECK-FIXES: {{^}}class CMyOtherTemplatedClass : CMyTemplatedClass< CMyClass>, private CMyDerivedClass {};{{$}}
+
+template<typename t_t>
+using mysuper_tpl_t = my_other_templated_class <:: FOO_NS ::my_class>;
+// CHECK-FIXES: {{^}}using mysuper_tpl_t = CMyOtherTemplatedClass <:: foo_ns ::CMyClass>;{{$}}
+
+const int global_Constant = 6;
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: invalid case style for global constant 'global_Constant'
+// CHECK-FIXES: {{^}}const int GLOBAL_CONSTANT = 6;{{$}}
+int Global_variable = 7;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for global variable 'Global_variable'
+// CHECK-FIXES: {{^}}int g_global_variable = 7;{{$}}
+
+void global_function(int PARAMETER_1, int const CONST_parameter) {
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: invalid case style for global function 'global_function'
+// CHECK-MESSAGES: :[[@LINE-2]]:26: warning: invalid case style for parameter 'PARAMETER_1'
+// CHECK-MESSAGES: :[[@LINE-3]]:49: warning: invalid case style for constant parameter 'CONST_parameter'
+// CHECK-FIXES: {{^}}void GlobalFunction(int a_parameter1, int const i_constParameter) {{{$}}
+ static const int THIS_static_ConsTant = 4;
+// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: invalid case style for static constant 'THIS_static_ConsTant'
+// CHECK-FIXES: {{^}} static const int THIS_STATIC_CONS_TANT = 4;{{$}}
+ static int THIS_static_variable;
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for static variable 'THIS_static_variable'
+// CHECK-FIXES: {{^}} static int s_thisStaticVariable;{{$}}
+ int const local_Constant = 3;
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: invalid case style for local constant 'local_Constant'
+// CHECK-FIXES: {{^}} int const kLocalConstant = 3;{{$}}
+ int LOCAL_VARIABLE;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for local variable 'LOCAL_VARIABLE'
+// CHECK-FIXES: {{^}} int local_variable;{{$}}
+
+ int LOCAL_Array__[] = {0, 1, 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for local variable 'LOCAL_Array__'
+// CHECK-FIXES: {{^}} int local_array[] = {0, 1, 2};{{$}}
+
+ for (auto _ : LOCAL_Array__) {
+ }
+}
+
+template<typename ... TYPE_parameters>
+// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: invalid case style for type template parameter 'TYPE_parameters'
+// CHECK-FIXES: {{^}}template<typename ... typeParameters_t>{{$}}
+void Global_Fun(TYPE_parameters... PARAMETER_PACK) {
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: invalid case style for global function 'Global_Fun'
+// CHECK-MESSAGES: :[[@LINE-2]]:36: warning: invalid case style for parameter pack 'PARAMETER_PACK'
+// CHECK-FIXES: {{^}}void GlobalFun(typeParameters_t... parameterPack) {{{$}}
+ global_function(1, 2);
+// CHECK-FIXES: {{^}} GlobalFunction(1, 2);{{$}}
+ FOO_bar = Global_variable;
+// CHECK-FIXES: {{^}} FOO_bar = g_global_variable;{{$}}
+// NO fix expected for FOO_bar declared in macro expansion
+}
+
+template<template<typename> class TPL_parameter, int COUNT_params, typename ... TYPE_parameters>
+// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: invalid case style for template template parameter 'TPL_parameter'
+// CHECK-MESSAGES: :[[@LINE-2]]:54: warning: invalid case style for value template parameter 'COUNT_params'
+// CHECK-MESSAGES: :[[@LINE-3]]:81: warning: invalid case style for type template parameter 'TYPE_parameters'
+// CHECK-FIXES: {{^}}template<template<typename> class TplParameter, int countParams, typename ... typeParameters_t>{{$}}
+class test_CLASS {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for class 'test_CLASS'
+// CHECK-FIXES: {{^}}class CTestClass {{{$}}
+};
+
+class abstract_class {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for abstract class 'abstract_class'
+// CHECK-FIXES: {{^}}class AAbstractClass {{{$}}
+ virtual ~abstract_class() = 0;
+// CHECK-FIXES: {{^}} virtual ~AAbstractClass() = 0;{{$}}
+ virtual void VIRTUAL_METHOD();
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: invalid case style for virtual method 'VIRTUAL_METHOD'
+// CHECK-FIXES: {{^}} virtual void v_Virtual_Method();{{$}}
+ void non_Virtual_METHOD() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for private method 'non_Virtual_METHOD'
+// CHECK-FIXES: {{^}} void __non_Virtual_METHOD() {}{{$}}
+
+public:
+ static void CLASS_METHOD() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: invalid case style for class method 'CLASS_METHOD'
+// CHECK-FIXES: {{^}} static void classMethod() {}{{$}}
+
+ constexpr int CST_expr_Method() { return 2; }
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: invalid case style for constexpr method 'CST_expr_Method'
+// CHECK-FIXES: {{^}} constexpr int cst_expr_method() { return 2; }{{$}}
+
+private:
+ void PRIVate_Method();
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for private method 'PRIVate_Method'
+// CHECK-FIXES: {{^}} void __PRIVate_Method();{{$}}
+protected:
+ void protected_Method();
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for protected method 'protected_Method'
+// CHECK-FIXES: {{^}} void _protected_Method();{{$}}
+public:
+ void public_Method();
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for method 'public_Method'
+// CHECK-FIXES: {{^}} void publicMethod();{{$}}
+};
+
+constexpr int CE_function() { return 3; }
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: invalid case style for constexpr function 'CE_function'
+// CHECK-FIXES: {{^}}constexpr int ce_function() { return 3; }{{$}}
+
+struct THIS___Structure {
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: invalid case style for struct 'THIS___Structure'
+// CHECK-FIXES: {{^}}struct this_structure {{{$}}
+ THIS___Structure();
+// CHECK-FIXES: {{^}} this_structure();{{$}}
+
+ union __MyUnion_is_wonderful__ {};
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for union '__MyUnion_is_wonderful__'
+// CHECK-FIXES: {{^}} union UMyUnionIsWonderful {};{{$}}
+};
+
+typedef THIS___Structure struct_type;
+// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: invalid case style for typedef 'struct_type'
+// CHECK-FIXES: {{^}}typedef this_structure struct_type_t;{{$}}
+
+struct_type GlobalTypedefTestFunction(struct_type a_argument1) {
+// CHECK-FIXES: {{^}}struct_type_t GlobalTypedefTestFunction(struct_type_t a_argument1) {
+ struct_type typedef_test_1;
+// CHECK-FIXES: {{^}} struct_type_t typedef_test_1;
+}
+
+using my_struct_type = THIS___Structure;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for type alias 'my_struct_type'
+// CHECK-FIXES: {{^}}using my_Struct_Type_t = this_structure;{{$}}
+
+template<typename t_t>
+using SomeOtherTemplate = my_other_templated_class <:: FOO_NS ::my_class>;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for type alias 'SomeOtherTemplate'
+// CHECK-FIXES: {{^}}using some_Other_Template_t = CMyOtherTemplatedClass <:: foo_ns ::CMyClass>;{{$}}
+
+static void static_Function() {
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: invalid case style for function 'static_Function'
+// CHECK-FIXES: {{^}}static void staticFunction() {{{$}}
+
+ ::FOO_NS::InlineNamespace::abstract_class::CLASS_METHOD();
+// CHECK-FIXES: {{^}} ::foo_ns::inline_namespace::AAbstractClass::classMethod();{{$}}
+ ::FOO_NS::InlineNamespace::static_Function();
+// CHECK-FIXES: {{^}} ::foo_ns::inline_namespace::staticFunction();{{$}}
+
+ using ::FOO_NS::InlineNamespace::CE_function;
+// CHECK-FIXES: {{^}} using ::foo_ns::inline_namespace::ce_function;{{$}}
+
+ unsigned MY_LOCAL_array[] = {1,2,3};
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: invalid case style for local variable 'MY_LOCAL_array'
+// CHECK-FIXES: {{^}} unsigned my_local_array[] = {1,2,3};{{$}}
+
+ unsigned const MyConstLocal_array[] = {1,2,3};
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: invalid case style for local constant 'MyConstLocal_array'
+// CHECK-FIXES: {{^}} unsigned const kMyConstLocalArray[] = {1,2,3};{{$}}
+
+ static unsigned MY_STATIC_array[] = {1,2,3};
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: invalid case style for static variable 'MY_STATIC_array'
+// CHECK-FIXES: {{^}} static unsigned s_myStaticArray[] = {1,2,3};{{$}}
+
+ static unsigned const MyConstStatic_array[] = {1,2,3};
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: invalid case style for static constant 'MyConstStatic_array'
+// CHECK-FIXES: {{^}} static unsigned const MY_CONST_STATIC_ARRAY[] = {1,2,3};{{$}}
+
+ char MY_LOCAL_string[] = "123";
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: invalid case style for local variable 'MY_LOCAL_string'
+// CHECK-FIXES: {{^}} char my_local_string[] = "123";{{$}}
+
+ char const MyConstLocal_string[] = "123";
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: invalid case style for local constant 'MyConstLocal_string'
+// CHECK-FIXES: {{^}} char const kMyConstLocalString[] = "123";{{$}}
+
+ static char MY_STATIC_string[] = "123";
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: invalid case style for static variable 'MY_STATIC_string'
+// CHECK-FIXES: {{^}} static char s_myStaticString[] = "123";{{$}}
+
+ static char const MyConstStatic_string[] = "123";
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: invalid case style for static constant 'MyConstStatic_string'
+// CHECK-FIXES: {{^}} static char const MY_CONST_STATIC_STRING[] = "123";{{$}}
+}
+
+#define MY_TEST_Macro(X) X()
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for macro definition 'MY_TEST_Macro'
+// CHECK-FIXES: {{^}}#define MY_TEST_MACRO(X) X()
+
+void MY_TEST_Macro(function) {}
+// CHECK-FIXES: {{^}}void MY_TEST_MACRO(function) {}
+}
+}
+
+template <typename t_t> struct a {
+ typename t_t::template b<> c;
+
+ char const MY_ConstMember_string[4] = "123";
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: invalid case style for constant member 'MY_ConstMember_string'
+// CHECK-FIXES: {{^}} char const my_const_member_string[4] = "123";{{$}}
+
+ static char const MyConstClass_string[];
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: invalid case style for class constant 'MyConstClass_string'
+// CHECK-FIXES: {{^}} static char const kMyConstClassString[];{{$}}
+};
+
+template<typename t_t>
+char const a<t_t>::MyConstClass_string[] = "123";
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: invalid case style for class constant 'MyConstClass_string'
+// CHECK-FIXES: {{^}}char const a<t_t>::kMyConstClassString[] = "123";{{$}}
+
+template <template <typename> class A> struct b { A<int> c; };
+
+unsigned MY_GLOBAL_array[] = {1,2,3};
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for global variable 'MY_GLOBAL_array'
+// CHECK-FIXES: {{^}}unsigned g_my_global_array[] = {1,2,3};{{$}}
+
+unsigned const MyConstGlobal_array[] = {1,2,3};
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for global constant 'MyConstGlobal_array'
+// CHECK-FIXES: {{^}}unsigned const MY_CONST_GLOBAL_ARRAY[] = {1,2,3};{{$}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion-allow-in-conditions.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion-allow-in-conditions.cpp
new file mode 100644
index 0000000..c50b798
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion-allow-in-conditions.cpp
@@ -0,0 +1,72 @@
+// RUN: %check_clang_tidy %s readability-implicit-bool-conversion %t \
+// RUN: -config='{CheckOptions: \
+// RUN: [{key: readability-implicit-bool-conversion.AllowIntegerConditions, value: 1}, \
+// RUN: {key: readability-implicit-bool-conversion.AllowPointerConditions, value: 1}]}' \
+// RUN: -- -std=c++11
+
+template<typename T>
+void functionTaking(T);
+
+int functionReturningInt();
+int* functionReturningPointer();
+
+struct Struct {
+ int member;
+ unsigned bitfield : 1;
+};
+
+
+void regularImplicitConversionIntegerToBoolIsNotIgnored() {
+ int integer = 0;
+ functionTaking<bool>(integer);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool [readability-implicit-bool-conversion]
+ // CHECK-FIXES: functionTaking<bool>(integer != 0);
+}
+
+void implicitConversionIntegerToBoolInConditionalsIsAllowed() {
+ Struct s = {};
+ if (s.member) {}
+ if (!s.member) {}
+ if (s.bitfield) {}
+ if (!s.bitfield) {}
+ if (functionReturningInt()) {}
+ if (!functionReturningInt()) {}
+ if (functionReturningInt() && functionReturningPointer()) {}
+ if (!functionReturningInt() && !functionReturningPointer()) {}
+ for (; functionReturningInt(); ) {}
+ for (; functionReturningPointer(); ) {}
+ for (; functionReturningInt() && !functionReturningPointer() || (!functionReturningInt() && functionReturningPointer()); ) {}
+ while (functionReturningInt()) {}
+ while (functionReturningPointer()) {}
+ while (functionReturningInt() && !functionReturningPointer() || (!functionReturningInt() && functionReturningPointer())) {}
+ int value1 = functionReturningInt() ? 1 : 2;
+ int value2 = !functionReturningInt() ? 1 : 2;
+ int value3 = (functionReturningInt() && functionReturningPointer() || !functionReturningInt()) ? 1 : 2;
+ int value4 = functionReturningInt() ?: value3;
+ int *p1 = functionReturningPointer() ?: &value3;
+}
+
+void regularImplicitConversionPointerToBoolIsNotIgnored() {
+ int* pointer = nullptr;
+ functionTaking<bool>(pointer);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int *' -> bool
+ // CHECK-FIXES: functionTaking<bool>(pointer != nullptr);
+
+ int Struct::* memberPointer = &Struct::member;
+ functionTaking<bool>(memberPointer);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int Struct::*' -> bool
+ // CHECK-FIXES: functionTaking<bool>(memberPointer != nullptr);
+}
+
+void implicitConversionPointerToBoolInConditionalsIsAllowed() {
+ if (functionReturningPointer()) {}
+ if (not functionReturningPointer()) {}
+ int value1 = functionReturningPointer() ? 1 : 2;
+ int value2 = (not functionReturningPointer()) ? 1 : 2;
+
+ int Struct::* memberPointer = &Struct::member;
+ if (memberPointer) {}
+ if (memberPointer) {}
+ int value3 = memberPointer ? 1 : 2;
+ int value4 = (not memberPointer) ? 1 : 2;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion-cxx98.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion-cxx98.cpp
new file mode 100644
index 0000000..587f7e2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion-cxx98.cpp
@@ -0,0 +1,45 @@
+// RUN: %check_clang_tidy %s readability-implicit-bool-conversion %t -- -- -std=c++98
+
+// We need NULL macro, but some buildbots don't like including <cstddef> header
+// This is a portable way of getting it to work
+#undef NULL
+#define NULL 0L
+
+template<typename T>
+void functionTaking(T);
+
+struct Struct {
+ int member;
+};
+
+void useOldNullMacroInReplacements() {
+ int* pointer = NULL;
+ functionTaking<bool>(pointer);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int *' -> bool [readability-implicit-bool-conversion]
+ // CHECK-FIXES: functionTaking<bool>(pointer != 0);
+
+ int Struct::* memberPointer = NULL;
+ functionTaking<bool>(!memberPointer);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion 'int Struct::*' -> bool
+ // CHECK-FIXES: functionTaking<bool>(memberPointer == 0);
+}
+
+void fixFalseLiteralConvertingToNullPointer() {
+ functionTaking<int*>(false);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion bool -> 'int *'
+ // CHECK-FIXES: functionTaking<int*>(0);
+
+ int* pointer = NULL;
+ if (pointer == false) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: implicit conversion bool -> 'int *'
+ // CHECK-FIXES: if (pointer == 0) {}
+
+ functionTaking<int Struct::*>(false);
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion bool -> 'int Struct::*'
+ // CHECK-FIXES: functionTaking<int Struct::*>(0);
+
+ int Struct::* memberPointer = NULL;
+ if (memberPointer != false) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion bool -> 'int Struct::*'
+ // CHECK-FIXES: if (memberPointer != 0) {}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion.cpp
new file mode 100644
index 0000000..0bdd670
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-implicit-bool-conversion.cpp
@@ -0,0 +1,439 @@
+// RUN: %check_clang_tidy %s readability-implicit-bool-conversion %t
+
+// We need NULL macro, but some buildbots don't like including <cstddef> header
+// This is a portable way of getting it to work
+#undef NULL
+#define NULL 0L
+
+template<typename T>
+void functionTaking(T);
+
+struct Struct {
+ int member;
+};
+
+
+////////// Implicit conversion from bool.
+
+void implicitConversionFromBoolSimpleCases() {
+ bool boolean = true;
+
+ functionTaking<bool>(boolean);
+
+ functionTaking<int>(boolean);
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion bool -> 'int' [readability-implicit-bool-conversion]
+ // CHECK-FIXES: functionTaking<int>(static_cast<int>(boolean));
+
+ functionTaking<unsigned long>(boolean);
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion bool -> 'unsigned long'
+ // CHECK-FIXES: functionTaking<unsigned long>(static_cast<unsigned long>(boolean));
+
+ functionTaking<char>(boolean);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion bool -> 'char'
+ // CHECK-FIXES: functionTaking<char>(static_cast<char>(boolean));
+
+ functionTaking<float>(boolean);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion bool -> 'float'
+ // CHECK-FIXES: functionTaking<float>(static_cast<float>(boolean));
+
+ functionTaking<double>(boolean);
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: implicit conversion bool -> 'double'
+ // CHECK-FIXES: functionTaking<double>(static_cast<double>(boolean));
+}
+
+float implicitConversionFromBoolInReturnValue() {
+ bool boolean = false;
+ return boolean;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion bool -> 'float'
+ // CHECK-FIXES: return static_cast<float>(boolean);
+}
+
+void implicitConversionFromBoolInSingleBoolExpressions(bool b1, bool b2) {
+ bool boolean = true;
+ boolean = b1 ^ b2;
+ boolean = b1 && b2;
+ boolean |= !b1 || !b2;
+ boolean &= b1;
+ boolean = b1 == true;
+ boolean = b2 != false;
+
+ int integer = boolean - 3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit conversion bool -> 'int'
+ // CHECK-FIXES: int integer = static_cast<int>(boolean) - 3;
+
+ float floating = boolean / 0.3f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion bool -> 'float'
+ // CHECK-FIXES: float floating = static_cast<float>(boolean) / 0.3f;
+
+ char character = boolean;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion bool -> 'char'
+ // CHECK-FIXES: char character = static_cast<char>(boolean);
+}
+
+void implicitConversionFromBoollInComplexBoolExpressions() {
+ bool boolean = true;
+ bool anotherBoolean = false;
+
+ int integer = boolean && anotherBoolean;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: implicit conversion bool -> 'int'
+ // CHECK-FIXES: int integer = static_cast<int>(boolean && anotherBoolean);
+
+ unsigned long unsignedLong = (! boolean) + 4ul;
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit conversion bool -> 'unsigned long'
+ // CHECK-FIXES: unsigned long unsignedLong = static_cast<unsigned long>(! boolean) + 4ul;
+
+ float floating = (boolean || anotherBoolean) * 0.3f;
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: implicit conversion bool -> 'float'
+ // CHECK-FIXES: float floating = static_cast<float>(boolean || anotherBoolean) * 0.3f;
+
+ double doubleFloating = (boolean && (anotherBoolean || boolean)) * 0.3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: implicit conversion bool -> 'double'
+ // CHECK-FIXES: double doubleFloating = static_cast<double>(boolean && (anotherBoolean || boolean)) * 0.3;
+}
+
+void implicitConversionFromBoolLiterals() {
+ functionTaking<int>(true);
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: implicit conversion bool -> 'int'
+ // CHECK-FIXES: functionTaking<int>(1);
+
+ functionTaking<unsigned long>(false);
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion bool -> 'unsigned long'
+ // CHECK-FIXES: functionTaking<unsigned long>(0u);
+
+ functionTaking<signed char>(true);
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: implicit conversion bool -> 'signed char'
+ // CHECK-FIXES: functionTaking<signed char>(1);
+
+ functionTaking<float>(false);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: implicit conversion bool -> 'float'
+ // CHECK-FIXES: functionTaking<float>(0.0f);
+
+ functionTaking<double>(true);
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: implicit conversion bool -> 'double'
+ // CHECK-FIXES: functionTaking<double>(1.0);
+}
+
+void implicitConversionFromBoolInComparisons() {
+ bool boolean = true;
+ int integer = 0;
+
+ functionTaking<bool>(boolean == integer);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion bool -> 'int'
+ // CHECK-FIXES: functionTaking<bool>(static_cast<int>(boolean) == integer);
+
+ functionTaking<bool>(integer != boolean);
+ // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: implicit conversion bool -> 'int'
+ // CHECK-FIXES: functionTaking<bool>(integer != static_cast<int>(boolean));
+}
+
+void ignoreBoolComparisons() {
+ bool boolean = true;
+ bool anotherBoolean = false;
+
+ functionTaking<bool>(boolean == anotherBoolean);
+ functionTaking<bool>(boolean != anotherBoolean);
+}
+
+void ignoreExplicitCastsFromBool() {
+ bool boolean = true;
+
+ int integer = static_cast<int>(boolean) + 3;
+ float floating = static_cast<float>(boolean) * 0.3f;
+ char character = static_cast<char>(boolean);
+}
+
+void ignoreImplicitConversionFromBoolInMacroExpansions() {
+ bool boolean = true;
+
+ #define CAST_FROM_BOOL_IN_MACRO_BODY boolean + 3
+ int integerFromMacroBody = CAST_FROM_BOOL_IN_MACRO_BODY;
+
+ #define CAST_FROM_BOOL_IN_MACRO_ARGUMENT(x) x + 3
+ int integerFromMacroArgument = CAST_FROM_BOOL_IN_MACRO_ARGUMENT(boolean);
+}
+
+namespace ignoreImplicitConversionFromBoolInTemplateInstantiations {
+
+template<typename T>
+void templateFunction() {
+ bool boolean = true;
+ T uknownType = boolean + 3;
+}
+
+void useOfTemplateFunction() {
+ templateFunction<int>();
+}
+
+} // namespace ignoreImplicitConversionFromBoolInTemplateInstantiations
+
+////////// Implicit conversions to bool.
+
+void implicitConversionToBoolSimpleCases() {
+ int integer = 10;
+ functionTaking<bool>(integer);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
+ // CHECK-FIXES: functionTaking<bool>(integer != 0);
+
+ unsigned long unsignedLong = 10;
+ functionTaking<bool>(unsignedLong);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'unsigned long' -> bool
+ // CHECK-FIXES: functionTaking<bool>(unsignedLong != 0u);
+
+ float floating = 0.0f;
+ functionTaking<bool>(floating);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
+ // CHECK-FIXES: functionTaking<bool>(floating != 0.0f);
+
+ double doubleFloating = 1.0f;
+ functionTaking<bool>(doubleFloating);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> bool
+ // CHECK-FIXES: functionTaking<bool>(doubleFloating != 0.0);
+
+ signed char character = 'a';
+ functionTaking<bool>(character);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'signed char' -> bool
+ // CHECK-FIXES: functionTaking<bool>(character != 0);
+
+ int* pointer = nullptr;
+ functionTaking<bool>(pointer);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int *' -> bool
+ // CHECK-FIXES: functionTaking<bool>(pointer != nullptr);
+
+ auto pointerToMember = &Struct::member;
+ functionTaking<bool>(pointerToMember);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int Struct::*' -> bool
+ // CHECK-FIXES: functionTaking<bool>(pointerToMember != nullptr);
+}
+
+void implicitConversionToBoolInSingleExpressions() {
+ int integer = 10;
+ bool boolComingFromInt = integer;
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: implicit conversion 'int' -> bool
+ // CHECK-FIXES: bool boolComingFromInt = integer != 0;
+
+ float floating = 10.0f;
+ bool boolComingFromFloat = floating;
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: implicit conversion 'float' -> bool
+ // CHECK-FIXES: bool boolComingFromFloat = floating != 0.0f;
+
+ signed char character = 'a';
+ bool boolComingFromChar = character;
+ // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: implicit conversion 'signed char' -> bool
+ // CHECK-FIXES: bool boolComingFromChar = character != 0;
+
+ int* pointer = nullptr;
+ bool boolComingFromPointer = pointer;
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit conversion 'int *' -> bool
+ // CHECK-FIXES: bool boolComingFromPointer = pointer != nullptr;
+}
+
+void implicitConversionToBoolInComplexExpressions() {
+ bool boolean = true;
+
+ int integer = 10;
+ int anotherInteger = 20;
+ bool boolComingFromInteger = integer + anotherInteger;
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: implicit conversion 'int' -> bool
+ // CHECK-FIXES: bool boolComingFromInteger = (integer + anotherInteger) != 0;
+
+ float floating = 0.2f;
+ bool boolComingFromFloating = floating - 0.3f || boolean;
+ // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: implicit conversion 'float' -> bool
+ // CHECK-FIXES: bool boolComingFromFloating = ((floating - 0.3f) != 0.0f) || boolean;
+
+ double doubleFloating = 0.3;
+ bool boolComingFromDoubleFloating = (doubleFloating - 0.4) && boolean;
+ // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit conversion 'double' -> bool
+ // CHECK-FIXES: bool boolComingFromDoubleFloating = ((doubleFloating - 0.4) != 0.0) && boolean;
+}
+
+void implicitConversionInNegationExpressions() {
+ int integer = 10;
+ bool boolComingFromNegatedInt = !integer;
+ // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: implicit conversion 'int' -> bool
+ // CHECK-FIXES: bool boolComingFromNegatedInt = integer == 0;
+
+ float floating = 10.0f;
+ bool boolComingFromNegatedFloat = ! floating;
+ // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit conversion 'float' -> bool
+ // CHECK-FIXES: bool boolComingFromNegatedFloat = floating == 0.0f;
+
+ signed char character = 'a';
+ bool boolComingFromNegatedChar = (! character);
+ // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: implicit conversion 'signed char' -> bool
+ // CHECK-FIXES: bool boolComingFromNegatedChar = (character == 0);
+
+ int* pointer = nullptr;
+ bool boolComingFromNegatedPointer = not pointer;
+ // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: implicit conversion 'int *' -> bool
+ // CHECK-FIXES: bool boolComingFromNegatedPointer = pointer == nullptr;
+}
+
+void implicitConversionToBoolInControlStatements() {
+ int integer = 10;
+ if (integer) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: implicit conversion 'int' -> bool
+ // CHECK-FIXES: if (integer != 0) {}
+
+ long int longInteger = 0.2f;
+ for (;longInteger;) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: implicit conversion 'long' -> bool
+ // CHECK-FIXES: for (;longInteger != 0;) {}
+
+ float floating = 0.3f;
+ while (floating) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> bool
+ // CHECK-FIXES: while (floating != 0.0f) {}
+
+ double doubleFloating = 0.4;
+ do {} while (doubleFloating);
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: implicit conversion 'double' -> bool
+ // CHECK-FIXES: do {} while (doubleFloating != 0.0);
+}
+
+bool implicitConversionToBoolInReturnValue() {
+ float floating = 1.0f;
+ return floating;
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: implicit conversion 'float' -> bool
+ // CHECK-FIXES: return floating != 0.0f;
+}
+
+void implicitConversionToBoolFromLiterals() {
+ functionTaking<bool>(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
+ // CHECK-FIXES: functionTaking<bool>(false);
+
+ functionTaking<bool>(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
+ // CHECK-FIXES: functionTaking<bool>(true);
+
+ functionTaking<bool>(2ul);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'unsigned long' -> bool
+ // CHECK-FIXES: functionTaking<bool>(true);
+
+
+ functionTaking<bool>(0.0f);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
+ // CHECK-FIXES: functionTaking<bool>(false);
+
+ functionTaking<bool>(1.0f);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
+ // CHECK-FIXES: functionTaking<bool>(true);
+
+ functionTaking<bool>(2.0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> bool
+ // CHECK-FIXES: functionTaking<bool>(true);
+
+
+ functionTaking<bool>('\0');
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'char' -> bool
+ // CHECK-FIXES: functionTaking<bool>(false);
+
+ functionTaking<bool>('a');
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'char' -> bool
+ // CHECK-FIXES: functionTaking<bool>(true);
+
+
+ functionTaking<bool>("");
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'const char *' -> bool
+ // CHECK-FIXES: functionTaking<bool>(true);
+
+ functionTaking<bool>("abc");
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'const char *' -> bool
+ // CHECK-FIXES: functionTaking<bool>(true);
+
+ functionTaking<bool>(NULL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'long' -> bool
+ // CHECK-FIXES: functionTaking<bool>(false);
+}
+
+void implicitConversionToBoolFromUnaryMinusAndZeroLiterals() {
+ functionTaking<bool>(-0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
+ // CHECK-FIXES: functionTaking<bool>((-0) != 0);
+
+ functionTaking<bool>(-0.0f);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'float' -> bool
+ // CHECK-FIXES: functionTaking<bool>((-0.0f) != 0.0f);
+
+ functionTaking<bool>(-0.0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'double' -> bool
+ // CHECK-FIXES: functionTaking<bool>((-0.0) != 0.0);
+}
+
+void implicitConversionToBoolInWithOverloadedOperators() {
+ struct UserStruct {
+ int operator()(int x) { return x; }
+ int operator+(int y) { return y; }
+ };
+
+ UserStruct s;
+
+ functionTaking<bool>(s(0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
+ // CHECK-FIXES: functionTaking<bool>(s(0) != 0);
+
+ functionTaking<bool>(s + 2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: implicit conversion 'int' -> bool
+ // CHECK-FIXES: functionTaking<bool>((s + 2) != 0);
+}
+
+int functionReturningInt();
+int* functionReturningPointer();
+
+void ignoreImplicitConversionToBoolWhenDeclaringVariableInControlStatements() {
+ if (int integer = functionReturningInt()) {}
+
+ while (int* pointer = functionReturningPointer()) {}
+}
+
+void ignoreExplicitCastsToBool() {
+ int integer = 10;
+ bool boolComingFromInt = static_cast<bool>(integer);
+
+ float floating = 10.0f;
+ bool boolComingFromFloat = static_cast<bool>(floating);
+
+ char character = 'a';
+ bool boolComingFromChar = static_cast<bool>(character);
+
+ int* pointer = nullptr;
+ bool booleanComingFromPointer = static_cast<bool>(pointer);
+}
+
+void ignoreImplicitConversionToBoolInMacroExpansions() {
+ int integer = 3;
+
+ #define CAST_TO_BOOL_IN_MACRO_BODY integer && false
+ bool boolFromMacroBody = CAST_TO_BOOL_IN_MACRO_BODY;
+
+ #define CAST_TO_BOOL_IN_MACRO_ARGUMENT(x) x || true
+ bool boolFromMacroArgument = CAST_TO_BOOL_IN_MACRO_ARGUMENT(integer);
+}
+
+namespace ignoreImplicitConversionToBoolInTemplateInstantiations {
+
+template<typename T>
+void templateFunction() {
+ T unknownType = 0;
+ bool boolean = unknownType;
+}
+
+void useOfTemplateFunction() {
+ templateFunction<int>();
+}
+
+} // namespace ignoreImplicitConversionToBoolInTemplateInstantiations
+
+namespace ignoreUserDefinedConversionOperator {
+
+struct StructWithUserConversion {
+ operator bool();
+};
+
+void useOfUserConversion() {
+ StructWithUserConversion structure;
+ functionTaking<bool>(structure);
+}
+
+} // namespace ignoreUserDefinedConversionOperator
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-inconsistent-declaration-parameter-name-macros.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-inconsistent-declaration-parameter-name-macros.cpp
new file mode 100644
index 0000000..c06bbfb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-inconsistent-declaration-parameter-name-macros.cpp
@@ -0,0 +1,25 @@
+// RUN: %check_clang_tidy %s readability-inconsistent-declaration-parameter-name %t -- \
+// RUN: -config="{CheckOptions: [{key: readability-inconsistent-declaration-parameter-name.IgnoreMacros, value: 0}]}" \
+// RUN: -- -std=c++11
+
+#define MACRO() \
+ void f(int x);
+
+struct S {
+ MACRO();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'S::f' has a definition with different parameter names
+};
+
+void S::f(int y) {
+}
+
+//////////////////////////////////////////////////////
+
+#define DECLARE_FUNCTION_WITH_PARAM_NAME(function_name, param_name) \
+ void function_name(int param_name)
+
+// CHECK-MESSAGES: :[[@LINE+1]]:34: warning: function 'macroFunction' has 1 other declaration with different parameter names [readability-inconsistent-declaration-parameter-name]
+DECLARE_FUNCTION_WITH_PARAM_NAME(macroFunction, a);
+// CHECK-MESSAGES: :[[@LINE+2]]:34: note: the 1st inconsistent declaration seen here
+// CHECK-MESSAGES: :[[@LINE+1]]:34: note: differing parameters are named here: ('b'), in the other declaration: ('a')
+DECLARE_FUNCTION_WITH_PARAM_NAME(macroFunction, b);
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-inconsistent-declaration-parameter-name-strict.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-inconsistent-declaration-parameter-name-strict.cpp
new file mode 100644
index 0000000..90ac45f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-inconsistent-declaration-parameter-name-strict.cpp
@@ -0,0 +1,11 @@
+// RUN: %check_clang_tidy %s readability-inconsistent-declaration-parameter-name %t -- \
+// RUN: -config="{CheckOptions: [{key: readability-inconsistent-declaration-parameter-name.Strict, value: 1}]}" \
+// RUN: -- -std=c++11
+
+void inconsistentFunction(int a, int b, int c);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'inconsistentFunction' has 1 other declaration with different parameter names
+void inconsistentFunction(int prefixA, int b, int cSuffix);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: note: the 1st inconsistent declaration seen here
+// CHECK-MESSAGES: :[[@LINE-2]]:6: note: differing parameters are named here: ('prefixA', 'cSuffix'), in the other declaration: ('a', 'c')
+void inconsistentFunction(int a, int b, int c);
+void inconsistentFunction(int /*c*/, int /*c*/, int /*c*/);
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-inconsistent-declaration-parameter-name.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-inconsistent-declaration-parameter-name.cpp
new file mode 100644
index 0000000..c98258b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-inconsistent-declaration-parameter-name.cpp
@@ -0,0 +1,193 @@
+// RUN: %check_clang_tidy %s readability-inconsistent-declaration-parameter-name %t -- -- -std=c++11 -fno-delayed-template-parsing
+
+void consistentFunction(int a, int b, int c);
+void consistentFunction(int a, int b, int c);
+void consistentFunction(int prefixA, int b, int cSuffix);
+void consistentFunction(int a, int b, int c);
+void consistentFunction(int a, int b, int /*c*/);
+void consistentFunction(int /*c*/, int /*c*/, int /*c*/);
+
+//////////////////////////////////////////////////////
+
+// CHECK-MESSAGES: :[[@LINE+1]]:6: warning: function 'inconsistentFunction' has 2 other declarations with different parameter names [readability-inconsistent-declaration-parameter-name]
+void inconsistentFunction(int a, int b, int c);
+// CHECK-MESSAGES: :[[@LINE+2]]:6: note: the 1st inconsistent declaration seen here
+// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('d', 'e', 'f'), in the other declaration: ('a', 'b', 'c')
+void inconsistentFunction(int d, int e, int f);
+// CHECK-MESSAGES: :[[@LINE+2]]:6: note: the 2nd inconsistent declaration seen here
+// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('x', 'y', 'z'), in the other declaration: ('a', 'b', 'c')
+void inconsistentFunction(int x, int y, int z);
+
+//////////////////////////////////////////////////////
+
+// CHECK-MESSAGES: :[[@LINE+4]]:6: warning: function 'inconsistentFunctionWithVisibleDefinition' has a definition with different parameter names [readability-inconsistent-declaration-parameter-name]
+// CHECK-MESSAGES: :[[@LINE+9]]:6: note: the definition seen here
+// CHECK-MESSAGES: :[[@LINE+2]]:6: note: differing parameters are named here: ('a'), in definition: ('c')
+// CHECK-FIXES: void inconsistentFunctionWithVisibleDefinition(int c);
+void inconsistentFunctionWithVisibleDefinition(int a);
+// CHECK-MESSAGES: :[[@LINE+4]]:6: warning: function 'inconsistentFunctionWithVisibleDefinition' has a definition
+// CHECK-MESSAGES: :[[@LINE+4]]:6: note: the definition seen here
+// CHECK-MESSAGES: :[[@LINE+2]]:6: note: differing parameters are named here: ('b'), in definition: ('c')
+// CHECK-FIXES: void inconsistentFunctionWithVisibleDefinition(int c);
+void inconsistentFunctionWithVisibleDefinition(int b);
+void inconsistentFunctionWithVisibleDefinition(int c) { c; }
+
+// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: function 'inconsidentFunctionWithUnreferencedParameterInDefinition' has a definition
+// CHECK-MESSAGES: :[[@LINE+3]]:6: note: the definition seen here
+// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('a'), in definition: ('b')
+void inconsidentFunctionWithUnreferencedParameterInDefinition(int a);
+void inconsidentFunctionWithUnreferencedParameterInDefinition(int b) {}
+
+//////////////////////////////////////////////////////
+
+struct Struct {
+// CHECK-MESSAGES: :[[@LINE+4]]:8: warning: function 'Struct::inconsistentFunction' has a definition
+// CHECK-MESSAGES: :[[@LINE+6]]:14: note: the definition seen here
+// CHECK-MESSAGES: :[[@LINE+2]]:8: note: differing parameters are named here: ('a'), in definition: ('b')
+// CHECK-FIXES: void inconsistentFunction(int b);
+ void inconsistentFunction(int a);
+};
+
+void Struct::inconsistentFunction(int b) { b = 0; }
+
+//////////////////////////////////////////////////////
+
+struct SpecialFunctions {
+// CHECK-MESSAGES: :[[@LINE+4]]:3: warning: function 'SpecialFunctions::SpecialFunctions' has a definition
+// CHECK-MESSAGES: :[[@LINE+12]]:19: note: the definition seen here
+// CHECK-MESSAGES: :[[@LINE+2]]:3: note: differing parameters are named here: ('a'), in definition: ('b')
+// CHECK-FIXES: SpecialFunctions(int b);
+ SpecialFunctions(int a);
+
+// CHECK-MESSAGES: :[[@LINE+4]]:21: warning: function 'SpecialFunctions::operator=' has a definition
+// CHECK-MESSAGES: :[[@LINE+8]]:37: note: the definition seen here
+// CHECK-MESSAGES: :[[@LINE+2]]:21: note: differing parameters are named here: ('a'), in definition: ('b')
+// CHECK-FIXES: SpecialFunctions& operator=(const SpecialFunctions& b);
+ SpecialFunctions& operator=(const SpecialFunctions& a);
+};
+
+SpecialFunctions::SpecialFunctions(int b) { b; }
+
+SpecialFunctions& SpecialFunctions::operator=(const SpecialFunctions& b) { b; return *this; }
+
+//////////////////////////////////////////////////////
+
+// CHECK-MESSAGES: :[[@LINE+5]]:6: warning: function 'templateFunctionWithSeparateDeclarationAndDefinition' has a definition
+// CHECK-MESSAGES: :[[@LINE+7]]:6: note: the definition seen here
+// CHECK-MESSAGES: :[[@LINE+3]]:6: note: differing parameters are named here: ('a'), in definition: ('b')
+// CHECK-FIXES: void templateFunctionWithSeparateDeclarationAndDefinition(T b);
+template<typename T>
+void templateFunctionWithSeparateDeclarationAndDefinition(T a);
+
+template<typename T>
+void templateFunctionWithSeparateDeclarationAndDefinition(T b) { b; }
+
+//////////////////////////////////////////////////////
+
+template<typename T>
+void templateFunctionWithSpecializations(T a) { a; }
+
+template<>
+// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: function template specialization 'templateFunctionWithSpecializations<int>' has a primary template declaration with different parameter names [readability-inconsistent-declaration-parameter-name]
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: the primary template declaration seen here
+// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('b'), in primary template declaration: ('a')
+void templateFunctionWithSpecializations(int b) { b; }
+
+template<>
+// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: function template specialization 'templateFunctionWithSpecializations<float>' has a primary template
+// CHECK-MESSAGES: :[[@LINE-10]]:6: note: the primary template declaration seen here
+// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('c'), in primary template declaration: ('a')
+void templateFunctionWithSpecializations(float c) { c; }
+
+//////////////////////////////////////////////////////
+
+template<typename T>
+void templateFunctionWithoutDefinitionButWithSpecialization(T a);
+
+template<>
+// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: function template specialization 'templateFunctionWithoutDefinitionButWithSpecialization<int>' has a primary template
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: the primary template declaration seen here
+// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('b'), in primary template declaration: ('a')
+void templateFunctionWithoutDefinitionButWithSpecialization(int b) { b; }
+
+//////////////////////////////////////////////////////
+
+template<typename T>
+void templateFunctionWithSeparateSpecializationDeclarationAndDefinition(T a);
+
+template<>
+// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: function template specialization 'templateFunctionWithSeparateSpecializationDeclarationAndDefinition<int>' has a primary template
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: the primary template declaration seen here
+// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('b'), in primary template declaration: ('a')
+void templateFunctionWithSeparateSpecializationDeclarationAndDefinition(int b);
+
+template<>
+// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: function template specialization 'templateFunctionWithSeparateSpecializationDeclarationAndDefinition<int>' has a primary template
+// CHECK-MESSAGES: :[[@LINE-10]]:6: note: the primary template declaration seen here
+// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('c'), in primary template declaration: ('a')
+void templateFunctionWithSeparateSpecializationDeclarationAndDefinition(int c) { c; }
+
+//////////////////////////////////////////////////////
+
+template<typename T>
+class ClassTemplate
+{
+public:
+// CHECK-MESSAGES: :[[@LINE+4]]:10: warning: function 'ClassTemplate::functionInClassTemplateWithSeparateDeclarationAndDefinition' has a definition
+// CHECK-MESSAGES: :[[@LINE+7]]:24: note: the definition seen here
+// CHECK-MESSAGES: :[[@LINE+2]]:10: note: differing parameters are named here: ('a'), in definition: ('b')
+// CHECK-FIXES: void functionInClassTemplateWithSeparateDeclarationAndDefinition(int b);
+ void functionInClassTemplateWithSeparateDeclarationAndDefinition(int a);
+};
+
+template<typename T>
+void ClassTemplate<T>::functionInClassTemplateWithSeparateDeclarationAndDefinition(int b) { b; }
+
+//////////////////////////////////////////////////////
+
+class Class
+{
+public:
+ template<typename T>
+// CHECK-MESSAGES: :[[@LINE+4]]:8: warning: function 'Class::memberFunctionTemplateWithSeparateDeclarationAndDefinition' has a definition
+// CHECK-MESSAGES: :[[@LINE+12]]:13: note: the definition seen here
+// CHECK-MESSAGES: :[[@LINE+2]]:8: note: differing parameters are named here: ('a'), in definition: ('b')
+// CHECK-FIXES: void memberFunctionTemplateWithSeparateDeclarationAndDefinition(T b);
+ void memberFunctionTemplateWithSeparateDeclarationAndDefinition(T a);
+
+ template<typename T>
+ void memberFunctionTemplateWithSpecializations(T a) { a; }
+};
+
+//////////////////////////////////////////////////////
+
+template<typename T>
+void Class::memberFunctionTemplateWithSeparateDeclarationAndDefinition(T b) { b; }
+
+//////////////////////////////////////////////////////
+
+template<>
+// CHECK-MESSAGES: :[[@LINE+3]]:13: warning: function template specialization 'Class::memberFunctionTemplateWithSpecializations<int>' has a primary template
+// CHECK-MESSAGES: :[[@LINE-12]]:8: note: the primary template declaration seen here
+// CHECK-MESSAGES: :[[@LINE+1]]:13: note: differing parameters are named here: ('b'), in primary template declaration: ('a')
+void Class::memberFunctionTemplateWithSpecializations(int b) { b; }
+
+template<>
+// CHECK-MESSAGES: :[[@LINE+3]]:13: warning: function template specialization 'Class::memberFunctionTemplateWithSpecializations<float>' has a primary template
+// CHECK-MESSAGES: :[[@LINE-18]]:8: note: the primary template declaration seen here
+// CHECK-MESSAGES: :[[@LINE+1]]:13: note: differing parameters are named here: ('c'), in primary template declaration: ('a')
+void Class::memberFunctionTemplateWithSpecializations(float c) { c; }
+
+//////////////////////////////////////////////////////
+
+// This resulted in a warning by default.
+#define MACRO() \
+ void f(int x);
+
+struct S {
+ MACRO();
+};
+
+void S::f(int y)
+{
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-misleading-indentation.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-misleading-indentation.cpp
new file mode 100644
index 0000000..59d5f40
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-misleading-indentation.cpp
@@ -0,0 +1,111 @@
+// RUN: %check_clang_tidy %s readability-misleading-indentation %t
+
+void foo1();
+void foo2();
+
+#define BLOCK \
+ if (cond1) \
+ foo1(); \
+ foo2();
+
+int main()
+{
+ bool cond1 = true;
+ bool cond2 = true;
+
+ if (cond1)
+ if (cond2)
+ foo1();
+ else
+ foo2();
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: different indentation for 'if' and corresponding 'else' [readability-misleading-indentation]
+
+ if (cond1) {
+ if (cond2)
+ foo1();
+ }
+ else
+ foo2();
+
+ if (cond1)
+ if (cond2)
+ foo1();
+ else
+ foo2();
+
+ if (cond2)
+ foo1();
+ foo2();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: misleading indentation: statement is indented too deeply [readability-misleading-indentation]
+ // CHECK-MESSAGES: :[[@LINE-4]]:3: note: did you mean this line to be inside this 'if'
+ foo2(); // No redundant warning.
+
+ if (cond1)
+ {
+ foo1();
+ }
+ foo2();
+
+ if (cond1)
+ foo1();
+ foo2();
+
+ if (cond2)
+ if (cond1) foo1(); else foo2();
+
+ if (cond1) {
+ } else {
+ }
+
+ if (cond1) {
+ }
+ else {
+ }
+
+ if (cond1)
+ {
+ }
+ else
+ {
+ }
+
+ if (cond1)
+ {
+ }
+ else
+ {
+ }
+
+ if(cond1) {
+ }
+ else if (cond2) {
+ }
+ else {
+ }
+
+ if(cond1) {
+ }
+ else if (cond2) {
+ }
+ else {
+ }
+ // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: different indentation for 'if' and corresponding 'else' [readability-misleading-indentation]
+
+ if (cond1) {
+ if (cond1) {
+ }
+ else if (cond2) {
+ }
+ else {
+ }
+ if (cond1) {
+ } else if (cond2) {
+ } else if (!cond2) {
+ } else {
+ }
+ }
+ else if (cond2) {
+ }
+
+ BLOCK
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-misplaced-array-index.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-misplaced-array-index.cpp
new file mode 100644
index 0000000..43dd458
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-misplaced-array-index.cpp
@@ -0,0 +1,34 @@
+// RUN: %check_clang_tidy %s readability-misplaced-array-index %t
+
+#define ABC "abc"
+
+struct XY { int *X; int *Y; };
+
+void dostuff(int);
+
+void unusualSyntax(int *P1, struct XY *P2) {
+ 10[P1] = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: confusing array subscript expression, usually the index is inside the []
+ // CHECK-FIXES: P1[10] = 0;
+
+ 10[P2->X] = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: confusing array subscript expression
+ // CHECK-FIXES: P2->X[10] = 0;
+
+ dostuff(1["abc"]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: confusing array subscript expression
+ // CHECK-FIXES: dostuff("abc"[1]);
+
+ dostuff(1[ABC]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: confusing array subscript expression
+ // CHECK-FIXES: dostuff(ABC[1]);
+
+ dostuff(0[0 + ABC]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: confusing array subscript expression
+ // CHECK-FIXES: dostuff(0[0 + ABC]);
+ // No fixit. Probably the code should be ABC[0]
+}
+
+void normalSyntax(int *X) {
+ X[10] = 0;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-named-parameter.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-named-parameter.cpp
new file mode 100644
index 0000000..af2c195
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-named-parameter.cpp
@@ -0,0 +1,133 @@
+// RUN: %check_clang_tidy %s readability-named-parameter %t
+
+void Method(char *) { /* */ }
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: all parameters should be named in a function
+// CHECK-FIXES: void Method(char * /*unused*/) { /* */ }
+void Method2(char *) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: all parameters should be named in a function
+// CHECK-FIXES: void Method2(char * /*unused*/) {}
+void Method3(char *, void *) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: all parameters should be named in a function
+// CHECK-FIXES: void Method3(char * /*unused*/, void * /*unused*/) {}
+void Method4(char *, int /*unused*/) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: all parameters should be named in a function
+// CHECK-FIXES: void Method4(char * /*unused*/, int /*unused*/) {}
+void operator delete[](void *) throw() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: all parameters should be named in a function
+// CHECK-FIXES: void operator delete[](void * /*unused*/) throw() {}
+int Method5(int) { return 0; }
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: all parameters should be named in a function
+// CHECK-FIXES: int Method5(int /*unused*/) { return 0; }
+void Method6(void (*)(void *)) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: all parameters should be named in a function
+// CHECK-FIXES: void Method6(void (* /*unused*/)(void *)) {}
+template <typename T> void Method7(T) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: all parameters should be named in a function
+// CHECK-FIXES: template <typename T> void Method7(T /*unused*/) {}
+
+// Don't warn in macros.
+#define M void MethodM(int) {}
+M
+
+void operator delete(void *x) throw() {}
+void Method7(char * /*x*/) {}
+void Method8(char *x) {}
+typedef void (*TypeM)(int x);
+void operator delete[](void *x) throw();
+void operator delete[](void * /*x*/) throw();
+
+struct X {
+ X operator++(int) {}
+ X operator--(int) {}
+
+ X(X&) = delete;
+ X &operator=(X&) = default;
+
+ const int &i;
+};
+
+void (*Func1)(void *);
+void Func2(void (*func)(void *)) {}
+template <void Func(void *)> void Func3() {}
+
+template <typename T>
+struct Y {
+ void foo(T) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: all parameters should be named in a function
+// CHECK-FIXES: void foo(T /*unused*/) {}
+};
+
+Y<int> y;
+Y<float> z;
+
+struct Base {
+ virtual void foo(bool notThisOne);
+ virtual void foo(int argname);
+};
+
+struct Derived : public Base {
+ void foo(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: all parameters should be named in a function
+// CHECK-FIXES: void foo(int /*argname*/);
+};
+
+void FDef(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: all parameters should be named in a function
+// CHECK-FIXES: void FDef(int /*n*/);
+void FDef(int n) {}
+
+void FDef2(int, int);
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: all parameters should be named in a function
+// CHECK-FIXES: void FDef2(int /*n*/, int /*unused*/);
+void FDef2(int n, int) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: all parameters should be named in a function
+// CHECK-FIXES: void FDef2(int n, int /*unused*/) {}
+
+void FNoDef(int);
+
+class Z {};
+
+Z &operator++(Z&) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: all parameters should be named in a function
+// CHECK-FIXES: Z &operator++(Z& /*unused*/) {}
+
+Z &operator++(Z&, int) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: all parameters should be named in a function
+// CHECK-FIXES: Z &operator++(Z& /*unused*/, int) {}
+
+Z &operator--(Z&) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: all parameters should be named in a function
+// CHECK-FIXES: Z &operator--(Z& /*unused*/) {}
+
+Z &operator--(Z&, int) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: all parameters should be named in a function
+// CHECK-FIXES: Z &operator--(Z& /*unused*/, int) {}
+
+namespace testing {
+namespace internal {
+class IgnoredValue {
+ public:
+ template <typename T>
+ IgnoredValue(const T& /* ignored */) {}
+};
+}
+typedef internal::IgnoredValue Unused;
+}
+
+using ::testing::Unused;
+
+void MockFunction(Unused, int q, Unused) {
+ ++q;
+ ++q;
+ ++q;
+}
+
+namespace std {
+typedef decltype(nullptr) nullptr_t;
+}
+
+void f(std::nullptr_t) {}
+
+typedef void (F)(int);
+F f;
+void f(int x) {}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-non-const-parameter.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-non-const-parameter.cpp
new file mode 100644
index 0000000..6cd1f91
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-non-const-parameter.cpp
@@ -0,0 +1,289 @@
+// RUN: %check_clang_tidy %s readability-non-const-parameter %t
+
+// Currently the checker only warns about pointer arguments.
+//
+// It can be defined both that the data is const and that the pointer is const,
+// the checker only checks if the data can be const-specified.
+//
+// It does not warn about pointers to records or function pointers.
+
+// Some external function where first argument is nonconst and second is const.
+char *strcpy1(char *dest, const char *src);
+unsigned my_strcpy(char *buf, const char *s);
+unsigned my_strlen(const char *buf);
+
+// CHECK-MESSAGES: :[[@LINE+1]]:29: warning: pointer parameter 'last' can be pointer to const [readability-non-const-parameter]
+void warn1(int *first, int *last) {
+ // CHECK-FIXES: {{^}}void warn1(int *first, const int *last) {{{$}}
+ *first = 0;
+ if (first < last) {
+ } // <- last can be const
+}
+
+// TODO: warning should be written here
+void warn2(char *p) {
+ char buf[10];
+ strcpy1(buf, p);
+}
+
+// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be
+void assign1(int *p) {
+ // CHECK-FIXES: {{^}}void assign1(const int *p) {{{$}}
+ const int *q;
+ q = p;
+}
+
+// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be
+void assign2(int *p) {
+ // CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}}
+ const int *q;
+ q = p + 1;
+}
+
+void assign3(int *p) {
+ *p = 0;
+}
+
+void assign4(int *p) {
+ *p += 2;
+}
+
+void assign5(char *p) {
+ p[0] = 0;
+}
+
+void assign6(int *p) {
+ int *q;
+ q = p++;
+}
+
+void assign7(char *p) {
+ char *a, *b;
+ a = b = p;
+}
+
+void assign8(char *a, char *b) {
+ char *x;
+ x = (a ? a : b);
+}
+
+void assign9(unsigned char *str, const unsigned int i) {
+ unsigned char *p;
+ for (p = str + i; *p;) {
+ }
+}
+
+void assign10(int *buf) {
+ int i, *p;
+ for (i = 0, p = buf; i < 10; i++, p++) {
+ *p = 1;
+ }
+}
+
+// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be
+void init1(int *p) {
+ // CHECK-FIXES: {{^}}void init1(const int *p) {{{$}}
+ const int *q = p;
+}
+
+// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be
+void init2(int *p) {
+ // CHECK-FIXES: {{^}}void init2(const int *p) {{{$}}
+ const int *q = p + 1;
+}
+
+void init3(int *p) {
+ int *q = p;
+}
+
+void init4(float *p) {
+ int *q = (int *)p;
+}
+
+void init5(int *p) {
+ int *i = p ? p : 0;
+}
+
+void init6(int *p) {
+ int *a[] = {p, p, 0};
+}
+
+void init7(int *p, int x) {
+ for (int *q = p + x - 1; 0; q++)
+ ;
+}
+
+// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: pointer parameter 'p' can be
+int return1(int *p) {
+ // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}}
+ return *p;
+}
+
+// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be
+const int *return2(int *p) {
+ // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}}
+ return p;
+}
+
+// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be
+const int *return3(int *p) {
+ // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}}
+ return p + 1;
+}
+
+// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be
+const char *return4(char *p) {
+ // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}}
+ return p ? p : "";
+}
+
+char *return5(char *s) {
+ return s;
+}
+
+char *return6(char *s) {
+ return s + 1;
+}
+
+char *return7(char *a, char *b) {
+ return a ? a : b;
+}
+
+char return8(int *p) {
+ return ++(*p);
+}
+
+void dontwarn1(int *p) {
+ ++(*p);
+}
+
+void dontwarn2(int *p) {
+ (*p)++;
+}
+
+int dontwarn3(_Atomic(int) * p) {
+ return *p;
+}
+
+void callFunction1(char *p) {
+ strcpy1(p, "abc");
+}
+
+void callFunction2(char *p) {
+ strcpy1(&p[0], "abc");
+}
+
+void callFunction3(char *p) {
+ strcpy1(p + 2, "abc");
+}
+
+char *callFunction4(char *p) {
+ return strcpy1(p, "abc");
+}
+
+unsigned callFunction5(char *buf) {
+ unsigned len = my_strlen(buf);
+ return len + my_strcpy(buf, "abc");
+}
+
+void f6(int **p);
+void callFunction6(int *p) { f6(&p); }
+
+typedef union { void *v; } t;
+void f7(t obj);
+void callFunction7(int *p) {
+ f7((t){p});
+}
+
+void f8(int &x);
+void callFunction8(int *p) {
+ f8(*p);
+}
+
+// Don't warn about nonconst function pointers that can be const.
+void functionpointer(double f(double), int x) {
+ f(x);
+}
+
+// TODO: This is a false positive.
+// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be
+int functionpointer2(int *p) {
+ return *p;
+}
+void use_functionpointer2() {
+ int (*fp)(int *) = functionpointer2; // <- the parameter 'p' can't be const
+}
+
+// Don't warn about nonconst record pointers that can be const.
+struct XY {
+ int *x;
+ int *y;
+};
+void recordpointer(struct XY *xy) {
+ *(xy->x) = 0;
+}
+
+class C {
+public:
+ C(int *p) : p(p) {}
+
+private:
+ int *p;
+};
+
+class C2 {
+public:
+ // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: pointer parameter 'p' can be
+ C2(int *p) : p(p) {}
+ // CHECK-FIXES: {{^}} C2(const int *p) : p(p) {}{{$}}
+
+private:
+ const int *p;
+};
+
+void tempObject(int *p) {
+ C c(p);
+}
+
+// avoid fp for const pointer array
+void constPointerArray(const char *remapped[][2]) {
+ const char *name = remapped[0][0];
+}
+
+class Warn {
+public:
+ // CHECK-MESSAGES: :[[@LINE+1]]:21: warning: pointer parameter 'p' can be
+ void doStuff(int *p) {
+ // CHECK-FIXES: {{^}} void doStuff(const int *p) {{{$}}
+ x = *p;
+ }
+
+private:
+ int x;
+};
+
+class Base {
+public:
+ // Ensure there is no false positive for this method. It is virtual.
+ virtual void doStuff(int *p) {
+ int x = *p;
+ }
+};
+
+class Derived : public Base {
+public:
+ // Ensure there is no false positive for this method. It overrides a method.
+ void doStuff(int *p) override {
+ int x = *p;
+ }
+};
+
+extern char foo(char *s); // 1
+// CHECK-FIXES: {{^}}extern char foo(const char *s); // 1{{$}}
+// CHECK-MESSAGES: :[[@LINE+1]]:16: warning: pointer parameter 's' can be
+char foo(char *s) {
+ // CHECK-FIXES: {{^}}char foo(const char *s) {{{$}}
+ return *s;
+}
+char foo(char *s); // 2
+// CHECK-FIXES: {{^}}char foo(const char *s); // 2{{$}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-control-flow.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-control-flow.cpp
new file mode 100644
index 0000000..0352e3a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-control-flow.cpp
@@ -0,0 +1,224 @@
+// RUN: %check_clang_tidy %s readability-redundant-control-flow %t
+
+void g(int i);
+void j();
+
+void f() {
+ return;
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: redundant return statement at the end of a function with a void return type [readability-redundant-control-flow]
+// CHECK-FIXES: {{^}}void f() {{{$}}
+// CHECK-FIXES-NEXT: {{^ *}$}}
+
+void g() {
+ f();
+ return;
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: redundant return statement
+// CHECK-FIXES: {{^ }}f();{{$}}
+// CHECK-FIXES-NEXT: {{^ *}$}}
+
+void g(int i) {
+ if (i < 0) {
+ return;
+ }
+ if (i < 10) {
+ f();
+ }
+}
+
+int h() {
+ return 1;
+}
+
+void j() {
+}
+
+void k() {
+ for (int i = 0; i < 10; ++i) {
+ continue;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:5: warning: redundant continue statement at the end of loop statement
+// CHECK-FIXES: {{^}} for (int i = 0; i < 10; ++i) {{{$}}
+// CHECK-FIXES-NEXT: {{^ *}$}}
+
+void k2() {
+ int v[10] = { 0 };
+ for (auto i : v) {
+ continue;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:5: warning: redundant continue statement
+// CHECK-FIXES: {{^}} for (auto i : v) {{{$}}
+// CHECK-FIXES-NEXT: {{^ *}$}}
+
+void m() {
+ int i = 0;
+ do {
+ ++i;
+ continue;
+ } while (i < 10);
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:5: warning: redundant continue statement
+// CHECK-FIXES: {{^ do {$}}
+// CHECK-FIXES-NEXT: {{^}} ++i;{{$}}
+// CHECK-FIXES-NEXT: {{^ *}}} while (i < 10);{{$}}
+
+void p() {
+ int i = 0;
+ while (i < 10) {
+ ++i;
+ continue;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:5: warning: redundant continue statement
+// CHECK-FIXES: {{^}} while (i < 10) {{{$}}
+// CHECK-FIXES-NEXT: {{^}} ++i;{{$}}
+// CHECK-FIXES-NEXT: {{^ *}$}}
+
+void im_not_dead(int i) {
+ if (i > 0) {
+ return;
+ }
+ g();
+}
+
+void im_still_not_dead(int i) {
+ for (int j = 0; j < 10; ++j) {
+ if (i < 10) {
+ continue;
+ }
+ g();
+ }
+}
+
+void im_dead(int i) {
+ if (i > 0) {
+ return;
+ g();
+ }
+ g();
+}
+
+void im_still_dead(int i) {
+ for (int j = 0; j < 10; ++j) {
+ if (i < 10) {
+ continue;
+ g();
+ }
+ g();
+ }
+}
+
+void void_return() {
+ return g();
+}
+
+void nested_return_unmolested() {
+ g();
+ {
+ g();
+ return;
+ }
+}
+
+void nested_continue_unmolested() {
+ for (int i = 0; i < 10; ++i) {
+ if (i < 5) {
+ continue;
+ }
+ }
+}
+
+#define MACRO_RETURN_UNMOLESTED(fn_) \
+ (fn_)(); \
+ return
+
+#define MACRO_CONTINUE_UNMOLESTED(x_) \
+ do { \
+ for (int i = 0; i < (x_); ++i) { \
+ continue; \
+ } \
+ } while (false)
+
+void macro_return() {
+ MACRO_RETURN_UNMOLESTED(g);
+}
+
+void macro_continue() {
+ MACRO_CONTINUE_UNMOLESTED(10);
+}
+
+#define MACRO_RETURN_ARG(stmt_) \
+ stmt_
+
+#define MACRO_CONTINUE_ARG(stmt_) \
+ do { \
+ for (int i = 0; i < 10; ++i) { \
+ stmt_; \
+ } \
+ } while (false)
+
+void macro_arg_return() {
+ MACRO_RETURN_ARG(return);
+}
+
+void macro_arg_continue() {
+ MACRO_CONTINUE_ARG(continue);
+}
+
+template <typename T>
+void template_return(T check) {
+ if (check < T(0)) {
+ return;
+ }
+ return;
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: redundant return statement
+// CHECK-FIXES: {{^}} if (check < T(0)) {{{$}}
+// CHECK-FIXES-NEXT: {{^ return;$}}
+// CHECK-FIXES-NEXT: {{^ *}$}}
+// CHECK-FIXES-NEXT: {{^ *}$}}
+
+template <>
+void template_return(int check) {
+ if (check < 0) {
+ return;
+ }
+ return;
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: redundant return statement
+// CHECK-FIXES: {{^}} if (check < 0) {{{$}}
+// CHECK-FIXES-NEXT: {{^ return;$}}
+// CHECK-FIXES-NEXT: {{^ *}$}}
+// CHECK-FIXES-NEXT: {{^ *}$}}
+
+template <typename T>
+void template_loop(T end) {
+ for (T i = 0; i < end; ++i) {
+ continue;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:5: warning: redundant continue statement
+// CHECK-FIXES: {{^}} for (T i = 0; i < end; ++i) {{{$}}
+// CHECK-FIXES-NEXT: {{^ *}$}}
+
+template <>
+void template_loop(int end) {
+ for (int i = 0; i < end; ++i) {
+ continue;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:5: warning: redundant continue statement
+// CHECK-FIXES: {{^}} for (int i = 0; i < end; ++i) {{{$}}
+// CHECK-FIXES-NEXT: {{^ *}$}}
+
+void call_templates() {
+ template_return(10);
+ template_return(10.0f);
+ template_return(10.0);
+ template_loop(10);
+ template_loop(10L);
+ template_loop(10U);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-declaration-ignore-macros.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-declaration-ignore-macros.cpp
new file mode 100644
index 0000000..2dc8618
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-declaration-ignore-macros.cpp
@@ -0,0 +1,22 @@
+// RUN: %check_clang_tidy %s readability-redundant-declaration %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-declaration.IgnoreMacros, \
+// RUN: value: 1}]}" \
+// RUN: -- -std=c++11
+
+extern int Xyz;
+extern int Xyz; // Xyz
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant 'Xyz' declaration [readability-redundant-declaration]
+// CHECK-FIXES: {{^}}// Xyz{{$}}
+
+namespace macros {
+#define DECLARE(x) extern int x
+#define DEFINE(x) extern int x; int x = 42
+DECLARE(test);
+DEFINE(test);
+// CHECK-FIXES: {{^}}#define DECLARE(x) extern int x{{$}}
+// CHECK-FIXES: {{^}}#define DEFINE(x) extern int x; int x = 42{{$}}
+// CHECK-FIXES: {{^}}DECLARE(test);{{$}}
+// CHECK-FIXES: {{^}}DEFINE(test);{{$}}
+
+} // namespace macros
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-declaration.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-declaration.cpp
new file mode 100644
index 0000000..83d1b5b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-declaration.cpp
@@ -0,0 +1,70 @@
+// RUN: %check_clang_tidy %s readability-redundant-declaration %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: readability-redundant-declaration.IgnoreMacros, \
+// RUN: value: 0}]}" \
+// RUN: -- -std=c++11
+
+extern int Xyz;
+extern int Xyz; // Xyz
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant 'Xyz' declaration [readability-redundant-declaration]
+// CHECK-FIXES: {{^}}// Xyz{{$}}
+int Xyz = 123;
+
+extern int A;
+extern int A, B;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant 'A' declaration
+// CHECK-FIXES: {{^}}extern int A, B;{{$}}
+
+extern int Buf[10];
+extern int Buf[10]; // Buf[10]
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant 'Buf' declaration
+// CHECK-FIXES: {{^}}// Buf[10]{{$}}
+
+static int f();
+static int f(); // f
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant 'f' declaration
+// CHECK-FIXES: {{^}}// f{{$}}
+static int f() {}
+
+// Original check crashed for the code below.
+namespace std {
+typedef decltype(sizeof(0)) size_t;
+}
+void *operator new(std::size_t) __attribute__((__externally_visible__));
+void *operator new[](std::size_t) __attribute__((__externally_visible__));
+
+// Don't warn about static member definition.
+struct C {
+ static int I;
+};
+int C::I;
+
+template <class T>
+struct C2 {
+ C2();
+};
+
+template <class T>
+C2<T>::C2() = default;
+
+void best_friend();
+
+struct Friendly {
+ friend void best_friend();
+ friend void enemy();
+};
+
+void enemy();
+
+namespace macros {
+#define DECLARE(x) extern int x
+#define DEFINE(x) extern int x; int x = 42
+DECLARE(test);
+DEFINE(test);
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant 'test' declaration
+// CHECK-FIXES: {{^}}#define DECLARE(x) extern int x{{$}}
+// CHECK-FIXES: {{^}}#define DEFINE(x) extern int x; int x = 42{{$}}
+// CHECK-FIXES: {{^}}DECLARE(test);{{$}}
+// CHECK-FIXES: {{^}}DEFINE(test);{{$}}
+
+} // namespace macros
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-function-ptr-dereference.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-function-ptr-dereference.cpp
new file mode 100644
index 0000000..2b34ce1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-function-ptr-dereference.cpp
@@ -0,0 +1,45 @@
+// RUN: %check_clang_tidy %s readability-redundant-function-ptr-dereference %t
+
+void f(int i);
+
+void positive() {
+ void (*p)(int) = f;
+
+ (**p)(1);
+ // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: redundant repeated dereference of function pointer [readability-redundant-function-ptr-dereference]
+ // CHECK-FIXES: (*p)(1);
+ (*****p)(2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: redundant repeated
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: redundant repeated
+ // CHECK-MESSAGES: :[[@LINE-3]]:6: warning: redundant repeated
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: redundant repeated
+ // CHECK-FIXES: (*p)(2);
+}
+
+template<typename T>
+void invoke(const T& fn) {
+ fn(0); // 1
+ (*fn)(0); // 2
+ // CHECK-MESSAGES: :[[@LINE-1]]:4: warning: redundant repeated
+ // CHECK-FIXES: fn(0); // 1
+ // CHECK-FIXES: (fn)(0); // 2
+ // FIXME: Remove unnecessary parentheses.
+}
+
+void f1(int);
+void f2(double);
+void f3(char);
+
+void instantiate() {
+ invoke(f1);
+ invoke(f2);
+ invoke(f3);
+ invoke([](unsigned) {});
+}
+
+void negative() {
+ void (*q)(int) = &f;
+
+ q(1);
+ (*q)(2);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp
new file mode 100644
index 0000000..90b52fd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-member-init.cpp
@@ -0,0 +1,219 @@
+// RUN: %check_clang_tidy %s readability-redundant-member-init %t
+
+struct S {
+ S() = default;
+ S(int i) : i(i) {}
+ int i = 1;
+};
+
+struct T {
+ T(int i = 1) : i(i) {}
+ int i;
+};
+
+struct U {
+ int i;
+};
+
+union V {
+ int i;
+ double f;
+};
+
+// Initializer calls default constructor
+struct F1 {
+ F1() : f() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'f' is redundant
+ // CHECK-FIXES: F1() {}
+ S f;
+};
+
+// Initializer calls default constructor with default argument
+struct F2 {
+ F2() : f() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'f' is redundant
+ // CHECK-FIXES: F2() {}
+ T f;
+};
+
+// Multiple redundant initializers for same constructor
+struct F3 {
+ F3() : f(), g(1), h() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'f' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:21: warning: initializer for member 'h' is redundant
+ // CHECK-FIXES: F3() : g(1) {}
+ S f, g, h;
+};
+
+// Templated class independent type
+template <class V>
+struct F4 {
+ F4() : f() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'f' is redundant
+ // CHECK-FIXES: F4() {}
+ S f;
+};
+F4<int> f4i;
+F4<S> f4s;
+
+// Base class
+struct F5 : S {
+ F5() : S() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for base class 'S' is redundant
+ // CHECK-FIXES: F5() {}
+};
+
+// Constructor call requires cleanup
+struct Cleanup {
+ ~Cleanup() {}
+};
+
+struct UsesCleanup {
+ UsesCleanup(const Cleanup &c = Cleanup()) {}
+};
+
+struct F6 {
+ F6() : uc() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'uc' is redundant
+ // CHECK-FIXES: F6() {}
+ UsesCleanup uc;
+};
+
+// Multiple inheritance
+struct F7 : S, T {
+ F7() : S(), T() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for base class 'S' is redundant
+ // CHECK-MESSAGES: :[[@LINE-2]]:15: warning: initializer for base class 'T' is redundant
+ // CHECK-FIXES: F7() {}
+};
+
+namespace Foo {
+inline namespace Bar {
+template <int N>
+struct Template {
+ Template() = default;
+ int i = N;
+};
+}
+}
+
+enum { N_THINGS = 5 };
+
+struct F8 : Foo::Template<N_THINGS> {
+ F8() : Template() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for base class 'Foo::Template<N_THINGS>' is redundant
+ // CHECK-FIXES: F8() {}
+};
+
+// Anonymous struct
+struct F9 {
+ F9() : s1() {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 's1' is redundant
+ // CHECK-FIXES: F9() {}
+ struct {
+ S s1;
+ S s2;
+ };
+};
+
+// Initializer not written
+struct NF1 {
+ NF1() {}
+ S f;
+};
+
+// Initializer doesn't call default constructor
+struct NF2 {
+ NF2() : f(1) {}
+ S f;
+};
+
+// Initializer calls default constructor without using default argument
+struct NF3 {
+ NF3() : f(1) {}
+ T f;
+};
+
+// Initializer calls default constructor without using default argument
+struct NF4 {
+ NF4() : f(2) {}
+ T f;
+};
+
+// Initializer is zero-initialization
+struct NF5 {
+ NF5() : i() {}
+ int i;
+};
+
+// Initializer is direct-initialization
+struct NF6 {
+ NF6() : i(1) {}
+ int i;
+};
+
+// Initializer is aggregate initialization of struct
+struct NF7 {
+ NF7() : f{} {}
+ U f;
+};
+
+// Initializer is zero-initialization of struct
+struct NF7b {
+ NF7b() : f() {}
+ U f;
+};
+
+// Initializer is aggregate initialization of array
+struct NF8 {
+ NF8() : f{} {}
+ int f[2];
+};
+
+struct NF9 {
+ NF9() : f{} {}
+ S f[2];
+};
+
+// Initializing member of union
+union NF10 {
+ NF10() : s() {}
+ int i;
+ S s;
+};
+
+// Templated class dependent type
+template <class V>
+struct NF11 {
+ NF11() : f() {}
+ V f;
+};
+NF11<int> nf11i;
+NF11<S> nf11s;
+
+// Delegating constructor
+class NF12 {
+ NF12() = default;
+ NF12(int) : NF12() {}
+};
+
+// Const member
+struct NF13 {
+ NF13() : f() {}
+ const S f;
+};
+
+// Union member
+struct NF14 {
+ NF14() : f() {}
+ V f;
+};
+
+// Anonymous union member
+struct NF15 {
+ NF15() : s1() {}
+ union {
+ S s1;
+ S s2;
+ };
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-smartptr-get.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-smartptr-get.cpp
new file mode 100644
index 0000000..685a57c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-smartptr-get.cpp
@@ -0,0 +1,196 @@
+// RUN: %check_clang_tidy %s readability-redundant-smartptr-get %t
+
+#define NULL __null
+
+namespace std {
+
+template <typename T>
+struct unique_ptr {
+ T& operator*() const;
+ T* operator->() const;
+ T* get() const;
+ explicit operator bool() const noexcept;
+};
+
+template <typename T>
+struct shared_ptr {
+ T& operator*() const;
+ T* operator->() const;
+ T* get() const;
+ explicit operator bool() const noexcept;
+};
+
+} // namespace std
+
+struct Bar {
+ void Do();
+ void ConstDo() const;
+};
+struct BarPtr {
+ Bar* operator->();
+ Bar& operator*();
+ Bar* get();
+ explicit operator bool() const;
+};
+struct int_ptr {
+ int* get();
+ int* operator->();
+ int& operator*();
+};
+
+struct Fail1 {
+ Bar* get();
+};
+struct Fail2 {
+ Bar* get();
+ int* operator->();
+ int& operator*();
+};
+
+struct PointerWithOverloadedGet {
+ int* get();
+ template <typename T>
+ T* get();
+ int* operator->();
+ int& operator*();
+};
+
+void Positive() {
+ BarPtr u;
+ // CHECK-FIXES: BarPtr u;
+ BarPtr().get()->Do();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant get() call on smart pointer [readability-redundant-smartptr-get]
+ // CHECK-MESSAGES: BarPtr().get()->Do();
+ // CHECK-FIXES: BarPtr()->Do();
+
+ u.get()->ConstDo();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant get() call
+ // CHECK-MESSAGES: u.get()->ConstDo();
+ // CHECK-FIXES: u->ConstDo();
+
+ Bar& b = *BarPtr().get();
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant get() call
+ // CHECK-MESSAGES: Bar& b = *BarPtr().get();
+ // CHECK-FIXES: Bar& b = *BarPtr();
+
+ Bar& b2 = *std::unique_ptr<Bar>().get();
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant get() call
+ // CHECK-MESSAGES: Bar& b2 = *std::unique_ptr<Bar>().get();
+ // CHECK-FIXES: Bar& b2 = *std::unique_ptr<Bar>();
+
+ (*BarPtr().get()).ConstDo();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant get() call
+ // CHECK-MESSAGES: (*BarPtr().get()).ConstDo();
+ // CHECK-FIXES: (*BarPtr()).ConstDo();
+
+ (*std::unique_ptr<Bar>().get()).ConstDo();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant get() call
+ // CHECK-MESSAGES: (*std::unique_ptr<Bar>().get()).ConstDo();
+ // CHECK-FIXES: (*std::unique_ptr<Bar>()).ConstDo();
+
+ std::unique_ptr<Bar>* up;
+ (*up->get()).Do();
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant get() call
+ // CHECK-MESSAGES: (*up->get()).Do();
+ // CHECK-FIXES: (**up).Do();
+
+ int_ptr ip;
+ int i = *ip.get();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant get() call
+ // CHECK-MESSAGES: int i = *ip.get();
+ // CHECK-FIXES: int i = *ip;
+
+ auto ip2 = ip;
+ i = *ip2.get();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call
+ // CHECK-MESSAGES: i = *ip2.get();
+ // CHECK-FIXES: i = *ip2;
+
+ std::unique_ptr<int> uu;
+ std::shared_ptr<double> *ss;
+ bool bb = uu.get() == nullptr;
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant get() call
+ // CHECK-MESSAGES: uu.get() == nullptr;
+ // CHECK-FIXES: bool bb = uu == nullptr;
+
+ if (up->get());
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant get() call
+ // CHECK-MESSAGES: if (up->get());
+ // CHECK-FIXES: if (*up);
+ if ((uu.get()));
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call
+ // CHECK-MESSAGES: if ((uu.get()));
+ // CHECK-FIXES: if ((uu));
+ bb = !ss->get();
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant get() call
+ // CHECK-MESSAGES: bb = !ss->get();
+ // CHECK-FIXES: bb = !*ss;
+ bb = u.get() ? true : false;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call
+ // CHECK-MESSAGES: bb = u.get() ? true : false;
+ // CHECK-FIXES: bb = u ? true : false;
+
+ bb = nullptr != ss->get();
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: redundant get() call
+ // CHECK-MESSAGES: nullptr != ss->get();
+ // CHECK-FIXES: bb = nullptr != *ss;
+
+ i = *PointerWithOverloadedGet().get();
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call
+ // CHECK-MESSAGES: i = *PointerWithOverloadedGet().get();
+ // CHECK-FIXES: i = *PointerWithOverloadedGet();
+
+ bb = std::unique_ptr<int>().get() == NULL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call
+ // CHECK-MESSAGES: bb = std::unique_ptr<int>().get() == NULL;
+ // CHECK-FIXES: bb = std::unique_ptr<int>() == NULL;
+ bb = ss->get() == NULL;
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call
+ // CHECK-MESSAGES: bb = ss->get() == NULL;
+ // CHECK-FIXES: bb = *ss == NULL;
+
+ std::unique_ptr<int> x, y;
+ if (x.get() == nullptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant get() call
+ // CHECK-MESSAGES: if (x.get() == nullptr);
+ // CHECK-FIXES: if (x == nullptr);
+ if (nullptr == y.get());
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: redundant get() call
+ // CHECK-MESSAGES: if (nullptr == y.get());
+ // CHECK-FIXES: if (nullptr == y);
+ if (x.get() == NULL);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant get() call
+ // CHECK-MESSAGES: if (x.get() == NULL);
+ // CHECK-FIXES: if (x == NULL);
+ if (NULL == x.get());
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: redundant get() call
+ // CHECK-MESSAGES: if (NULL == x.get());
+ // CHECK-FIXES: if (NULL == x);
+}
+
+void Negative() {
+ struct NegPtr {
+ int* get();
+ int* operator->() {
+ return &*this->get();
+ }
+ int& operator*() {
+ return *get();
+ }
+ };
+
+ long l = *PointerWithOverloadedGet().get<long>();
+
+ std::unique_ptr<Bar>* u;
+ u->get()->Do();
+
+ Fail1().get()->Do();
+ Fail2().get()->Do();
+ const Bar& b = *Fail1().get();
+ (*Fail2().get()).Do();
+
+ int_ptr ip;
+ bool bb = ip.get() == nullptr;
+ bb = !ip.get();
+ bb = ip.get() ? true : false;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-string-cstr-msvc.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-string-cstr-msvc.cpp
new file mode 100644
index 0000000..a6b6b20
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-string-cstr-msvc.cpp
@@ -0,0 +1,47 @@
+// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t
+
+namespace std {
+template <typename T>
+class allocator {};
+template <typename T>
+class char_traits {};
+template <typename C, typename T, typename A>
+struct basic_string {
+ basic_string();
+ // MSVC headers define two constructors instead of using optional arguments.
+ basic_string(const C *p);
+ basic_string(const C *p, const A &a);
+ const C *c_str() const;
+ const C *data() const;
+};
+typedef basic_string<char, std::char_traits<char>, std::allocator<char>> string;
+}
+namespace llvm {
+struct StringRef {
+ StringRef(const char *p);
+ StringRef(const std::string &);
+};
+}
+
+void f1(const std::string &s) {
+ f1(s.c_str());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+ // CHECK-FIXES: {{^ }}f1(s);{{$}}
+ f1(s.data());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'data' [readability-redundant-string-cstr]
+ // CHECK-FIXES: {{^ }}f1(s);{{$}}
+}
+void f2(const llvm::StringRef r) {
+ std::string s;
+ f2(s.c_str());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}std::string s;{{$}}
+ // CHECK-FIXES-NEXT: {{^ }}f2(s);{{$}}
+}
+void f3(const llvm::StringRef &r) {
+ std::string s;
+ f3(s.c_str());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}std::string s;{{$}}
+ // CHECK-FIXES-NEXT: {{^ }}f3(s);{{$}}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-string-cstr.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-string-cstr.cpp
new file mode 100644
index 0000000..976a54f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-string-cstr.cpp
@@ -0,0 +1,207 @@
+// RUN: %check_clang_tidy %s readability-redundant-string-cstr %t -- -- -std=c++11
+
+typedef unsigned __INT16_TYPE__ char16;
+typedef unsigned __INT32_TYPE__ char32;
+typedef __SIZE_TYPE__ size;
+
+namespace std {
+template <typename T>
+class allocator {};
+template <typename T>
+class char_traits {};
+template <typename C, typename T, typename A>
+struct basic_string {
+ typedef basic_string<C, T, A> _Type;
+ basic_string();
+ basic_string(const C *p, const A &a = A());
+
+ const C *c_str() const;
+ const C *data() const;
+
+ _Type& append(const C *s);
+ _Type& append(const C *s, size n);
+ _Type& assign(const C *s);
+ _Type& assign(const C *s, size n);
+
+ int compare(const _Type&) const;
+ int compare(const C* s) const;
+ int compare(size pos, size len, const _Type&) const;
+ int compare(size pos, size len, const C* s) const;
+
+ size find(const _Type& str, size pos = 0) const;
+ size find(const C* s, size pos = 0) const;
+ size find(const C* s, size pos, size n) const;
+
+ _Type& insert(size pos, const _Type& str);
+ _Type& insert(size pos, const C* s);
+ _Type& insert(size pos, const C* s, size n);
+
+ _Type& operator+=(const _Type& str);
+ _Type& operator+=(const C* s);
+ _Type& operator=(const _Type& str);
+ _Type& operator=(const C* s);
+};
+
+typedef basic_string<char, std::char_traits<char>, std::allocator<char>> string;
+typedef basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>> wstring;
+typedef basic_string<char16, std::char_traits<char16>, std::allocator<char16>> u16string;
+typedef basic_string<char32, std::char_traits<char32>, std::allocator<char32>> u32string;
+}
+
+std::string operator+(const std::string&, const std::string&);
+std::string operator+(const std::string&, const char*);
+std::string operator+(const char*, const std::string&);
+
+bool operator==(const std::string&, const std::string&);
+bool operator==(const std::string&, const char*);
+bool operator==(const char*, const std::string&);
+
+namespace llvm {
+struct StringRef {
+ StringRef(const char *p);
+ StringRef(const std::string &);
+};
+}
+
+// Tests for std::string.
+
+void f1(const std::string &s) {
+ f1(s.c_str());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+ // CHECK-FIXES: {{^ }}f1(s);{{$}}
+ f1(s.data());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'data' [readability-redundant-string-cstr]
+ // CHECK-FIXES: {{^ }}f1(s);{{$}}
+}
+void f2(const llvm::StringRef r) {
+ std::string s;
+ f2(s.c_str());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}std::string s;{{$}}
+ // CHECK-FIXES-NEXT: {{^ }}f2(s);{{$}}
+}
+void f3(const llvm::StringRef &r) {
+ std::string s;
+ f3(s.c_str());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}std::string s;{{$}}
+ // CHECK-FIXES-NEXT: {{^ }}f3(s);{{$}}
+}
+void f4(const std::string &s) {
+ const std::string* ptr = &s;
+ f1(ptr->c_str());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+ // CHECK-FIXES: {{^ }}f1(*ptr);{{$}}
+}
+void f5(const std::string &s) {
+ std::string tmp;
+ tmp.append(s.c_str());
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}tmp.append(s);{{$}}
+ tmp.assign(s.c_str());
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}tmp.assign(s);{{$}}
+
+ if (tmp.compare(s.c_str()) == 0) return;
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}if (tmp.compare(s) == 0) return;{{$}}
+
+ if (tmp.compare(1, 2, s.c_str()) == 0) return;
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}if (tmp.compare(1, 2, s) == 0) return;{{$}}
+
+ if (tmp.find(s.c_str()) == 0) return;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}if (tmp.find(s) == 0) return;{{$}}
+
+ if (tmp.find(s.c_str(), 2) == 0) return;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}if (tmp.find(s, 2) == 0) return;{{$}}
+
+ if (tmp.find(s.c_str(), 2) == 0) return;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}if (tmp.find(s, 2) == 0) return;{{$}}
+
+ tmp.insert(1, s.c_str());
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}tmp.insert(1, s);{{$}}
+
+ tmp = s.c_str();
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}tmp = s;{{$}}
+
+ tmp += s.c_str();
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}tmp += s;{{$}}
+
+ if (tmp == s.c_str()) return;
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}if (tmp == s) return;{{$}}
+
+ tmp = s + s.c_str();
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}tmp = s + s;{{$}}
+
+ tmp = s.c_str() + s;
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant call {{.*}}
+ // CHECK-FIXES: {{^ }}tmp = s + s;{{$}}
+}
+void f6(const std::string &s) {
+ std::string tmp;
+ tmp.append(s.c_str(), 2);
+ tmp.assign(s.c_str(), 2);
+
+ if (tmp.compare(s) == 0) return;
+ if (tmp.compare(1, 2, s) == 0) return;
+
+ tmp = s;
+ tmp += s;
+
+ if (tmp == s)
+ return;
+
+ tmp = s + s;
+
+ if (tmp.find(s.c_str(), 2, 4) == 0) return;
+
+ tmp.insert(1, s);
+ tmp.insert(1, s.c_str(), 2);
+}
+
+// Tests for std::wstring.
+
+void g1(const std::wstring &s) {
+ g1(s.c_str());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+ // CHECK-FIXES: {{^ }}g1(s);{{$}}
+}
+
+// Tests for std::u16string.
+
+void h1(const std::u16string &s) {
+ h1(s.c_str());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+ // CHECK-FIXES: {{^ }}h1(s);{{$}}
+}
+
+// Tests for std::u32string.
+
+void k1(const std::u32string &s) {
+ k1(s.c_str());
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+ // CHECK-FIXES: {{^ }}k1(s);{{$}}
+}
+
+// Tests on similar classes that aren't good candidates for this checker.
+
+struct NotAString {
+ NotAString();
+ NotAString(const NotAString&);
+ const char *c_str() const;
+};
+
+void dummy(const char*) {}
+
+void invalid(const NotAString &s) {
+ dummy(s.c_str());
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-string-init-msvc.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-string-init-msvc.cpp
new file mode 100644
index 0000000..0299519
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-string-init-msvc.cpp
@@ -0,0 +1,61 @@
+// RUN: %check_clang_tidy %s readability-redundant-string-init %t
+
+namespace std {
+template <typename T>
+class allocator {};
+template <typename T>
+class char_traits {};
+template <typename C, typename T = std::char_traits<C>, typename A = std::allocator<C>>
+struct basic_string {
+ basic_string();
+ basic_string(const basic_string&);
+ // MSVC headers define two constructors instead of using optional arguments.
+ basic_string(const C *);
+ basic_string(const C *, const A &);
+ ~basic_string();
+};
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+}
+
+void f() {
+ std::string a = "";
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization [readability-redundant-string-init]
+ // CHECK-FIXES: std::string a;
+ std::string b("");
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+ // CHECK-FIXES: std::string b;
+ std::string c = R"()";
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+ // CHECK-FIXES: std::string c;
+ std::string d(R"()");
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+ // CHECK-FIXES: std::string d;
+
+ std::string u = "u";
+ std::string w("w");
+ std::string x = R"(x)";
+ std::string y(R"(y)");
+ std::string z;
+}
+
+void g() {
+ std::wstring a = L"";
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+ // CHECK-FIXES: std::wstring a;
+ std::wstring b(L"");
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+ // CHECK-FIXES: std::wstring b;
+ std::wstring c = LR"()";
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+ // CHECK-FIXES: std::wstring c;
+ std::wstring d(LR"()");
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+ // CHECK-FIXES: std::wstring d;
+
+ std::wstring u = L"u";
+ std::wstring w(L"w");
+ std::wstring x = LR"(x)";
+ std::wstring y(LR"(y)");
+ std::wstring z;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-string-init.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-string-init.cpp
new file mode 100644
index 0000000..4455ad4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-redundant-string-init.cpp
@@ -0,0 +1,140 @@
+// RUN: %check_clang_tidy %s readability-redundant-string-init %t
+
+namespace std {
+template <typename T>
+class allocator {};
+template <typename T>
+class char_traits {};
+template <typename C, typename T = std::char_traits<C>, typename A = std::allocator<C>>
+struct basic_string {
+ basic_string();
+ basic_string(const basic_string&);
+ basic_string(const C *, const A &a = A());
+ ~basic_string();
+};
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+}
+
+void f() {
+ std::string a = "";
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization [readability-redundant-string-init]
+ // CHECK-FIXES: std::string a;
+ std::string b("");
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+ // CHECK-FIXES: std::string b;
+ std::string c = R"()";
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+ // CHECK-FIXES: std::string c;
+ std::string d(R"()");
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+ // CHECK-FIXES: std::string d;
+
+ std::string u = "u";
+ std::string w("w");
+ std::string x = R"(x)";
+ std::string y(R"(y)");
+ std::string z;
+}
+
+void g() {
+ std::wstring a = L"";
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+ // CHECK-FIXES: std::wstring a;
+ std::wstring b(L"");
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+ // CHECK-FIXES: std::wstring b;
+ std::wstring c = LR"()";
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+ // CHECK-FIXES: std::wstring c;
+ std::wstring d(LR"()");
+ // CHECK-MESSAGES: [[@LINE-1]]:16: warning: redundant string initialization
+ // CHECK-FIXES: std::wstring d;
+
+ std::wstring u = L"u";
+ std::wstring w(L"w");
+ std::wstring x = LR"(x)";
+ std::wstring y(LR"(y)");
+ std::wstring z;
+}
+
+template <typename T>
+void templ() {
+ std::string s = "";
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+ // CHECK-FIXES: std::string s;
+}
+
+#define M(x) x
+#define N { std::string s = ""; }
+// CHECK-FIXES: #define N { std::string s = ""; }
+
+void h() {
+ templ<int>();
+ templ<double>();
+
+ M({ std::string s = ""; })
+ // CHECK-MESSAGES: [[@LINE-1]]:19: warning: redundant string initialization
+ // CHECK-FIXES: M({ std::string s; })
+
+ N
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: redundant string initialization
+ // CHECK-FIXES: N
+ N
+ // CHECK-MESSAGES: [[@LINE-1]]:3: warning: redundant string initialization
+ // CHECK-FIXES: N
+}
+
+typedef std::string MyString;
+#define STRING MyString
+#define DECL_STRING(name, val) STRING name = val
+
+void i() {
+ MyString a = "";
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant string initialization
+ // CHECK-FIXES: MyString a;
+ STRING b = "";
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: redundant string initialization
+ // CHECK-FIXES: STRING b;
+ MyString c = "" "" "";
+ // CHECK-MESSAGES: [[@LINE-1]]:12: warning: redundant string initialization
+ // CHECK-FIXES: MyString c;
+ STRING d = "" "" "";
+ // CHECK-MESSAGES: [[@LINE-1]]:10: warning: redundant string initialization
+ // CHECK-FIXES: STRING d;
+ DECL_STRING(e, "");
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+
+ MyString f = "u";
+ STRING g = "u";
+ DECL_STRING(h, "u");
+}
+
+#define EMPTY_STR ""
+void j() {
+ std::string a(EMPTY_STR);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+ // CHECK-FIXES: std::string a;
+ std::string b = (EMPTY_STR);
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+ // CHECK-FIXES: std::string b;
+
+ std::string c(EMPTY_STR "u" EMPTY_STR);
+}
+
+void k() {
+ std::string a = "", b = "", c = "";
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: redundant string initialization
+ // CHECK-MESSAGES: [[@LINE-2]]:23: warning: redundant string initialization
+ // CHECK-MESSAGES: [[@LINE-3]]:31: warning: redundant string initialization
+ // CHECK-FIXES: std::string a, b, c;
+
+ std::string d = "u", e = "u", f = "u";
+}
+
+// These cases should not generate warnings.
+extern void Param1(std::string param = "");
+extern void Param2(const std::string& param = "");
+void Param3(std::string param = "") {}
+void Param4(STRING param = "") {}
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-simplify-bool-expr-chained-conditional-assignment.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-simplify-bool-expr-chained-conditional-assignment.cpp
new file mode 100644
index 0000000..65b86c3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-simplify-bool-expr-chained-conditional-assignment.cpp
@@ -0,0 +1,34 @@
+// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t -- -config="{CheckOptions: [{key: "readability-simplify-boolean-expr.ChainedConditionalAssignment", value: 1}]}" --
+
+void chained_conditional_compound_assignment(int i) {
+ bool b;
+ if (i < 0) {
+ b = true;
+ } else if (i < 10) {
+ b = false;
+ } else if (i > 20) {
+ b = true;
+ } else {
+ b = false;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:9: warning: redundant boolean literal in conditional assignment [readability-simplify-boolean-expr]
+ // CHECK-FIXES: {{^}} } else if (i < 10) {{{$}}
+ // CHECK-FIXES-NEXT: {{^}} b = false;{{$}}
+ // CHECK-FIXES-NEXT: {{^}} } else b = i > 20;{{$}}
+}
+
+void chained_conditional_assignment(int i) {
+ bool b;
+ if (i < 0)
+ b = true;
+ else if (i < 10)
+ b = false;
+ else if (i > 20)
+ b = true;
+ else
+ b = false;
+ // CHECK-MESSAGES: :[[@LINE-3]]:9: warning: {{.*}} in conditional assignment
+ // CHECK-FIXES: {{^}} else if (i < 10)
+ // CHECK-FIXES-NEXT: {{^}} b = false;
+ // CHECK-FIXES-NEXT: {{^}} else b = i > 20;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-simplify-bool-expr-chained-conditional-return.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-simplify-bool-expr-chained-conditional-return.cpp
new file mode 100644
index 0000000..fb8759c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-simplify-bool-expr-chained-conditional-return.cpp
@@ -0,0 +1,94 @@
+// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t -- -config="{CheckOptions: [{key: "readability-simplify-boolean-expr.ChainedConditionalReturn", value: 1}]}" --
+
+bool chained_conditional_compound_return(int i) {
+ if (i < 0) {
+ return true;
+ } else if (i < 10) {
+ return false;
+ } else if (i > 20) {
+ return true;
+ } else {
+ return false;
+ }
+ // CHECK-MESSAGES: :[[@LINE-4]]:12: warning: redundant boolean literal in conditional return statement [readability-simplify-boolean-expr]
+ // CHECK-FIXES: {{^}} } else if (i < 10) {{{$}}
+ // CHECK-FIXES-NEXT: {{^}} return false;{{$}}
+ // CHECK-FIXES-NEXT: {{^}} } else return i > 20;{{$}}
+}
+
+bool chained_conditional_return(int i) {
+ if (i < 0)
+ return true;
+ else if (i < 10)
+ return false;
+ else if (i > 20)
+ return true;
+ else
+ return false;
+ // CHECK-MESSAGES: :[[@LINE-3]]:12: warning: {{.*}} in conditional return statement
+ // CHECK-FIXES: {{^}} else if (i < 10)
+ // CHECK-FIXES-NEXT: {{^}} return false;
+ // CHECK-FIXES-NEXT: {{^}} else return i > 20;
+}
+
+bool chained_simple_if_return(int i) {
+ if (i < 5)
+ return true;
+ if (i > 10)
+ return true;
+ return false;
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}}bool chained_simple_if_return(int i) {{{$}}
+// CHECK-FIXES: {{^}} if (i < 5){{$}}
+// CHECK-FIXES: {{^ return true;$}}
+// CHECK-FIXES: {{^ return i > 10;$}}
+// CHECK-FIXES: {{^}$}}
+
+bool chained_simple_if_return_negated(int i) {
+ if (i < 5)
+ return false;
+ if (i > 10)
+ return false;
+ return true;
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}}bool chained_simple_if_return_negated(int i) {{{$}}
+// CHECK-FIXES: {{^}} if (i < 5){{$}}
+// CHECK-FIXES: {{^ return false;$}}
+// CHECK-FIXES: {{^ return i <= 10;$}}
+// CHECK-FIXES: {{^}$}}
+
+bool complex_chained_if_return_return(int i) {
+ if (i < 5) {
+ return true;
+ }
+ if (i > 10) {
+ return true;
+ }
+ return false;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}}bool complex_chained_if_return_return(int i) {{{$}}
+// CHECK-FIXES: {{^}} if (i < 5) {{{$}}
+// CHECK-FIXES: {{^}} return true;{{$}}
+// CHECK-FIXES: {{^}} }{{$}}
+// CHECK-FIXES: {{^ return i > 10;$}}
+// CHECK-FIXES: {{^}$}}
+
+bool complex_chained_if_return_return_negated(int i) {
+ if (i < 5) {
+ return false;
+ }
+ if (i > 10) {
+ return false;
+ }
+ return true;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}}bool complex_chained_if_return_return_negated(int i) {{{$}}
+// CHECK-FIXES: {{^}} if (i < 5) {{{$}}
+// CHECK-FIXES: {{^}} return false;{{$}}
+// CHECK-FIXES: {{^}} }{{$}}
+// CHECK-FIXES: {{^ return i <= 10;$}}
+// CHECK-FIXES: {{^}$}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-simplify-bool-expr.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-simplify-bool-expr.cpp
new file mode 100644
index 0000000..cd93c5d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-simplify-bool-expr.cpp
@@ -0,0 +1,950 @@
+// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t
+
+bool a1 = false;
+
+//=-=-=-=-=-=-= operator ==
+bool aa = false == a1;
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant boolean literal supplied to boolean operator [readability-simplify-boolean-expr]
+// CHECK-FIXES: {{^bool aa = !a1;$}}
+bool ab = true == a1;
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool ab = a1;$}}
+bool a2 = a1 == false;
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool a2 = !a1;$}}
+bool a3 = a1 == true;
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool a3 = a1;$}}
+
+//=-=-=-=-=-=-= operator !=
+bool n1 = a1 != false;
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool n1 = a1;$}}
+bool n2 = a1 != true;
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool n2 = !a1;$}}
+bool n3 = false != a1;
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool n3 = a1;$}}
+bool n4 = true != a1;
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool n4 = !a1;$}}
+
+//=-=-=-=-=-=-= operator ||
+bool a4 = a1 || false;
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool a4 = a1;$}}
+bool a5 = a1 || true;
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool a5 = true;$}}
+bool a6 = false || a1;
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool a6 = a1;$}}
+bool a7 = true || a1;
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool a7 = true;$}}
+
+//=-=-=-=-=-=-= operator &&
+bool a8 = a1 && false;
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool a8 = false;$}}
+bool a9 = a1 && true;
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool a9 = a1;$}}
+bool ac = false && a1;
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool ac = false;$}}
+bool ad = true && a1;
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: {{.*}} to boolean operator
+// CHECK-FIXES: {{^bool ad = a1;$}}
+
+void if_with_bool_literal_condition() {
+ int i = 0;
+ if (false) {
+ i = 1;
+ } else {
+ i = 2;
+ }
+ i = 3;
+ // CHECK-MESSAGES: :[[@LINE-6]]:7: warning: {{.*}} in if statement condition
+ // CHECK-FIXES: {{^ int i = 0;$}}
+ // CHECK-FIXES-NEXT: {{^ {$}}
+ // CHECK-FIXES-NEXT: {{^ i = 2;$}}
+ // CHECK-FIXES-NEXT: {{^ }$}}
+ // CHECK-FIXES-NEXT: {{^ i = 3;$}}
+
+ i = 4;
+ if (true) {
+ i = 5;
+ } else {
+ i = 6;
+ }
+ i = 7;
+ // CHECK-MESSAGES: :[[@LINE-6]]:7: warning: {{.*}} in if statement condition
+ // CHECK-FIXES: {{^ i = 4;$}}
+ // CHECK-FIXES-NEXT: {{^ {$}}
+ // CHECK-FIXES-NEXT: {{^ i = 5;$}}
+ // CHECK-FIXES-NEXT: {{^ }$}}
+ // CHECK-FIXES-NEXT: {{^ i = 7;$}}
+
+ i = 8;
+ if (false) {
+ i = 9;
+ }
+ i = 11;
+ // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: {{.*}} in if statement condition
+ // CHECK-FIXES: {{^ i = 8;$}}
+ // CHECK-FIXES-NEXT: {{^ $}}
+ // CHECK-FIXES-NEXT: {{^ i = 11;$}}
+}
+
+void operator_equals() {
+ int i = 0;
+ bool b1 = (i > 2);
+ if (b1 == true) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(b1\) {$}}
+ i = 5;
+ } else {
+ i = 6;
+ }
+ bool b2 = (i > 4);
+ if (b2 == false) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(!b2\) {$}}
+ i = 7;
+ } else {
+ i = 9;
+ }
+ bool b3 = (i > 6);
+ if (true == b3) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(b3\) {$}}
+ i = 10;
+ } else {
+ i = 11;
+ }
+ bool b4 = (i > 8);
+ if (false == b4) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(!b4\) {$}}
+ i = 12;
+ } else {
+ i = 13;
+ }
+}
+
+void operator_or() {
+ int i = 0;
+ bool b5 = (i > 10);
+ if (b5 || false) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(b5\) {$}}
+ i = 14;
+ } else {
+ i = 15;
+ }
+ bool b6 = (i > 10);
+ if (b6 || true) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(true\) {$}}
+ i = 16;
+ } else {
+ i = 17;
+ }
+ bool b7 = (i > 10);
+ if (false || b7) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(b7\) {$}}
+ i = 18;
+ } else {
+ i = 19;
+ }
+ bool b8 = (i > 10);
+ if (true || b8) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(true\) {$}}
+ i = 20;
+ } else {
+ i = 21;
+ }
+}
+
+void operator_and() {
+ int i = 0;
+ bool b9 = (i > 20);
+ if (b9 && false) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(false\) {$}}
+ i = 22;
+ } else {
+ i = 23;
+ }
+ bool ba = (i > 20);
+ if (ba && true) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(ba\) {$}}
+ i = 24;
+ } else {
+ i = 25;
+ }
+ bool bb = (i > 20);
+ if (false && bb) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(false\) {$}}
+ i = 26;
+ } else {
+ i = 27;
+ }
+ bool bc = (i > 20);
+ if (true && bc) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(bc\) {$}}
+ i = 28;
+ } else {
+ i = 29;
+ }
+}
+
+void ternary_operator() {
+ int i = 0;
+ bool bd = (i > 20) ? true : false;
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: {{.*}} in ternary expression result
+ // CHECK-FIXES: {{^ bool bd = i > 20;$}}
+
+ bool be = (i > 20) ? false : true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: {{.*}} in ternary expression result
+ // CHECK-FIXES: {{^ bool be = i <= 20;$}}
+
+ bool bf = ((i > 20)) ? false : true;
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: {{.*}} in ternary expression result
+ // CHECK-FIXES: {{^ bool bf = i <= 20;$}}
+}
+
+void operator_not_equal() {
+ int i = 0;
+ bool bf = (i > 20);
+ if (false != bf) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(bf\) {$}}
+ i = 30;
+ } else {
+ i = 31;
+ }
+ bool bg = (i > 20);
+ if (true != bg) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(!bg\) {$}}
+ i = 32;
+ } else {
+ i = 33;
+ }
+ bool bh = (i > 20);
+ if (bh != false) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(bh\) {$}}
+ i = 34;
+ } else {
+ i = 35;
+ }
+ bool bi = (i > 20);
+ if (bi != true) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(!bi\) {$}}
+ i = 36;
+ } else {
+ i = 37;
+ }
+}
+
+void nested_booleans() {
+ if (false || (true || false)) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(false \|\| \(true\)\) {$}}
+ }
+ if (true && (true || false)) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(true && \(true\)\) {$}}
+ }
+ if (false || (true && false)) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(false \|\| \(false\)\) {$}}
+ }
+ if (true && (true && false)) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} to boolean operator
+ // CHECK-FIXES: {{^ if \(true && \(false\)\) {$}}
+ }
+}
+
+static constexpr bool truthy() {
+ return true;
+}
+
+#define HAS_XYZ_FEATURE true
+#define M1(what) M2(true, what)
+#define M2(condition, what) if (condition) what
+
+void macros_and_constexprs(int i = 0) {
+ bool b = (i == 1);
+ if (b && truthy()) {
+ // leave this alone; if you want it simplified, then you should
+ // inline the constexpr function first.
+ i = 1;
+ }
+ i = 2;
+ if (b && HAS_XYZ_FEATURE) {
+ // leave this alone; if you want it simplified, then you should
+ // inline the macro first.
+ i = 3;
+ }
+ if (HAS_XYZ_FEATURE) {
+ i = 5;
+ }
+ i = 4;
+ M1(i = 7);
+}
+
+#undef HAS_XYZ_FEATURE
+
+bool conditional_return_statements(int i) {
+ if (i == 0) return true; else return false;
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:22: warning: {{.*}} in conditional return statement
+// CHECK-FIXES: {{^}} return i == 0;{{$}}
+// CHECK-FIXES-NEXT: {{^}$}}
+
+bool conditional_return_statements_then_expr(int i, int j) {
+ if (i == j) return (i == 0); else return false;
+}
+
+bool conditional_return_statements_else_expr(int i, int j) {
+ if (i == j) return true; else return (i == 0);
+}
+
+bool negated_conditional_return_statements(int i) {
+ if (i == 0) return false; else return true;
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:22: warning: {{.*}} in conditional return statement
+// CHECK-FIXES: {{^}} return i != 0;{{$}}
+// CHECK-FIXES-NEXT: {{^}$}}
+
+bool negative_condition_conditional_return_statement(int i) {
+ if (!(i == 0)) return false; else return true;
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:25: warning: {{.*}} in conditional return statement
+// CHECK-FIXES: {{^}} return i == 0;{{$}}
+// CHECK-FIXES-NEXT: {{^}$}}
+
+bool conditional_compound_return_statements(int i) {
+ if (i == 1) {
+ return true;
+ } else {
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return statement
+// CHECK-FIXES: {{^}}bool conditional_compound_return_statements(int i) {{{$}}
+// CHECK-FIXES-NEXT: {{^}} return i == 1;{{$}}
+// CHECK-FIXES-NEXT: {{^}$}}
+
+bool negated_conditional_compound_return_statements(int i) {
+ if (i == 1) {
+ return false;
+ } else {
+ return true;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return statement
+// CHECK-FIXES: {{^}}bool negated_conditional_compound_return_statements(int i) {{{$}}
+// CHECK-FIXES-NEXT: {{^}} return i != 1;{{$}}
+// CHECK-FIXES-NEXT: {{^}$}}
+
+bool conditional_return_statements_side_effects_then(int i) {
+ if (i == 2) {
+ macros_and_constexprs();
+ return true;
+ } else
+ return false;
+}
+
+bool negated_conditional_return_statements_side_effects_then(int i) {
+ if (i == 2) {
+ macros_and_constexprs();
+ return false;
+ } else
+ return true;
+}
+
+bool conditional_return_statements_side_effects_else(int i) {
+ if (i == 2)
+ return true;
+ else {
+ macros_and_constexprs();
+ return false;
+ }
+}
+
+bool negated_conditional_return_statements_side_effects_else(int i) {
+ if (i == 2)
+ return false;
+ else {
+ macros_and_constexprs();
+ return true;
+ }
+}
+
+void lambda_conditional_return_statements() {
+ auto lambda = [](int n) -> bool { if (n > 0) return true; else return false; };
+ // CHECK-MESSAGES: :[[@LINE-1]]:55: warning: {{.*}} in conditional return statement
+ // CHECK-FIXES: {{^}} auto lambda = [](int n) -> bool { return n > 0; };{{$}}
+
+ auto lambda2 = [](int n) -> bool {
+ if (n > 0) {
+ return true;
+ } else {
+ return false;
+ }
+ };
+ // CHECK-MESSAGES: :[[@LINE-5]]:16: warning: {{.*}} in conditional return statement
+ // CHECK-FIXES: {{^}} auto lambda2 = [](int n) -> bool {{{$}}
+ // CHECK-FIXES-NEXT: {{^}} return n > 0;{{$}}
+ // CHECK-FIXES-NEXT: {{^}} };{{$}}
+
+ auto lambda3 = [](int n) -> bool { if (n > 0) {macros_and_constexprs(); return true; } else return false; };
+
+ auto lambda4 = [](int n) -> bool {
+ if (n > 0)
+ return true;
+ else {
+ macros_and_constexprs();
+ return false;
+ }
+ };
+
+ auto lambda5 = [](int n) -> bool { if (n > 0) return false; else return true; };
+ // CHECK-MESSAGES: :[[@LINE-1]]:56: warning: {{.*}} in conditional return statement
+ // CHECK-FIXES: {{^}} auto lambda5 = [](int n) -> bool { return n <= 0; };{{$}}
+
+ auto lambda6 = [](int n) -> bool {
+ if (n > 0) {
+ return false;
+ } else {
+ return true;
+ }
+ };
+ // CHECK-MESSAGES: :[[@LINE-5]]:16: warning: {{.*}} in conditional return statement
+ // CHECK-FIXES: {{^}} auto lambda6 = [](int n) -> bool {{{$}}
+ // CHECK-FIXES-NEXT: {{^}} return n <= 0;{{$}}
+ // CHECK-FIXES-NEXT: {{^}} };{{$}}
+}
+
+void simple_conditional_assignment_statements(int i) {
+ bool b;
+ if (i > 10)
+ b = true;
+ else
+ b = false;
+ bool bb = false;
+ // CHECK-MESSAGES: :[[@LINE-4]]:9: warning: {{.*}} in conditional assignment
+ // CHECK-FIXES: bool b;
+ // CHECK-FIXES: {{^ }}b = i > 10;{{$}}
+ // CHECK-FIXES: bool bb = false;
+
+ bool c;
+ if (i > 20)
+ c = false;
+ else
+ c = true;
+ bool c2 = false;
+ // CHECK-MESSAGES: :[[@LINE-4]]:9: warning: {{.*}} in conditional assignment
+ // CHECK-FIXES: bool c;
+ // CHECK-FIXES: {{^ }}c = i <= 20;{{$}}
+ // CHECK-FIXES: bool c2 = false;
+
+ // Unchanged: different variables.
+ bool b2;
+ if (i > 12)
+ b = true;
+ else
+ b2 = false;
+
+ // Unchanged: no else statement.
+ bool b3;
+ if (i > 15)
+ b3 = true;
+
+ // Unchanged: not boolean assignment.
+ int j;
+ if (i > 17)
+ j = 10;
+ else
+ j = 20;
+
+ // Unchanged: different variables assigned.
+ int k = 0;
+ bool b4 = false;
+ if (i > 10)
+ b4 = true;
+ else
+ k = 10;
+}
+
+void complex_conditional_assignment_statements(int i) {
+ bool d;
+ if (i > 30) {
+ d = true;
+ } else {
+ d = false;
+ }
+ d = false;
+ // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: {{.*}} in conditional assignment
+ // CHECK-FIXES: bool d;
+ // CHECK-FIXES: {{^ }}d = i > 30;{{$}}
+ // CHECK-FIXES: d = false;
+
+ bool e;
+ if (i > 40) {
+ e = false;
+ } else {
+ e = true;
+ }
+ e = false;
+ // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: {{.*}} in conditional assignment
+ // CHECK-FIXES: bool e;
+ // CHECK-FIXES: {{^ }}e = i <= 40;{{$}}
+ // CHECK-FIXES: e = false;
+
+ // Unchanged: no else statement.
+ bool b3;
+ if (i > 15) {
+ b3 = true;
+ }
+
+ // Unchanged: not a boolean assignment.
+ int j;
+ if (i > 17) {
+ j = 10;
+ } else {
+ j = 20;
+ }
+
+ // Unchanged: multiple statements.
+ bool f;
+ if (j > 10) {
+ j = 10;
+ f = true;
+ } else {
+ j = 20;
+ f = false;
+ }
+
+ // Unchanged: multiple statements.
+ bool g;
+ if (j > 10)
+ f = true;
+ else {
+ j = 20;
+ f = false;
+ }
+
+ // Unchanged: multiple statements.
+ bool h;
+ if (j > 10) {
+ j = 10;
+ f = true;
+ } else
+ f = false;
+}
+
+// Unchanged: chained return statements, but ChainedConditionalReturn not set.
+bool chained_conditional_compound_return(int i) {
+ if (i < 0) {
+ return true;
+ } else if (i < 10) {
+ return false;
+ } else if (i > 20) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// Unchanged: chained return statements, but ChainedConditionalReturn not set.
+bool chained_conditional_return(int i) {
+ if (i < 0)
+ return true;
+ else if (i < 10)
+ return false;
+ else if (i > 20)
+ return true;
+ else
+ return false;
+}
+
+// Unchanged: chained assignments, but ChainedConditionalAssignment not set.
+void chained_conditional_compound_assignment(int i) {
+ bool b;
+ if (i < 0) {
+ b = true;
+ } else if (i < 10) {
+ b = false;
+ } else if (i > 20) {
+ b = true;
+ } else {
+ b = false;
+ }
+}
+
+// Unchanged: chained return statements, but ChainedConditionalReturn not set.
+void chained_conditional_assignment(int i) {
+ bool b;
+ if (i < 0)
+ b = true;
+ else if (i < 10)
+ b = false;
+ else if (i > 20)
+ b = true;
+ else
+ b = false;
+}
+
+// Unchanged: chained return statements, but ChainedConditionalReturn not set.
+bool chained_simple_if_return_negated(int i) {
+ if (i < 5)
+ return false;
+ if (i > 10)
+ return false;
+ return true;
+}
+
+// Unchanged: chained return statements, but ChainedConditionalReturn not set.
+bool complex_chained_if_return_return(int i) {
+ if (i < 5) {
+ return true;
+ }
+ if (i > 10) {
+ return true;
+ }
+ return false;
+}
+
+// Unchanged: chained return statements, but ChainedConditionalReturn not set.
+bool complex_chained_if_return_return_negated(int i) {
+ if (i < 5) {
+ return false;
+ }
+ if (i > 10) {
+ return false;
+ }
+ return true;
+}
+
+// Unchanged: chained return statements, but ChainedConditionalReturn not set.
+bool chained_simple_if_return(int i) {
+ if (i < 5)
+ return true;
+ if (i > 10)
+ return true;
+ return false;
+}
+
+bool simple_if_return_return(int i) {
+ if (i > 10)
+ return true;
+ return false;
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}}bool simple_if_return_return(int i) {{{$}}
+// CHECK-FIXES: {{^ return i > 10;$}}
+// CHECK-FIXES: {{^}$}}
+
+bool simple_if_return_return_negated(int i) {
+ if (i > 10)
+ return false;
+ return true;
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}}bool simple_if_return_return_negated(int i) {{{$}}
+// CHECK-FIXES: {{^ return i <= 10;$}}
+// CHECK-FIXES: {{^}$}}
+
+bool complex_if_return_return(int i) {
+ if (i > 10) {
+ return true;
+ }
+ return false;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}}bool complex_if_return_return(int i) {{{$}}
+// CHECK-FIXES: {{^ return i > 10;$}}
+// CHECK-FIXES: {{^}$}}
+
+bool complex_if_return_return_negated(int i) {
+ if (i > 10) {
+ return false;
+ }
+ return true;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}}bool complex_if_return_return_negated(int i) {{{$}}
+// CHECK-FIXES: {{^ return i <= 10;$}}
+// CHECK-FIXES: {{^}$}}
+
+bool if_implicit_bool_expr(int i) {
+ if (i & 1) {
+ return true;
+ } else {
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}} return (i & 1) != 0;{{$}}
+
+bool negated_if_implicit_bool_expr(int i) {
+ if (i - 1) {
+ return false;
+ } else {
+ return true;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}} return (i - 1) == 0;{{$}}
+
+bool implicit_int(int i) {
+ if (i) {
+ return true;
+ } else {
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}} return i != 0;{{$}}
+
+bool explicit_bool(bool b) {
+ if (b) {
+ return true;
+ } else {
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}} return b;{{$}}
+
+class Implicit {
+public:
+ operator bool() {
+ return true;
+ }
+};
+
+bool object_bool_implicit_conversion(Implicit O) {
+ if (O) {
+ return true;
+ } else {
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}} return O;{{$}}
+
+bool negated_explicit_bool(bool b) {
+ if (!b) {
+ return true;
+ } else {
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}} return !b;{{$}}
+
+bool bitwise_complement_conversion(int i) {
+ if (~i) {
+ return true;
+ } else {
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}} return ~i != 0;{{$}}
+
+bool logical_or(bool a, bool b) {
+ if (a || b) {
+ return true;
+ } else {
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}} return a || b;{{$}}
+
+bool logical_and(bool a, bool b) {
+ if (a && b) {
+ return true;
+ } else {
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}} return a && b;{{$}}
+
+class Comparable
+{
+public:
+ bool operator==(Comparable const &rhs) { return true; }
+ bool operator!=(Comparable const &rhs) { return false; }
+};
+
+bool comparable_objects() {
+ Comparable c;
+ Comparable d;
+ if (c == d) {
+ return true;
+ } else {
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}} return c == d;{{$}}
+
+bool negated_comparable_objects() {
+ Comparable c;
+ Comparable d;
+ if (c == d) {
+ return false;
+ } else {
+ return true;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}} return c != d;{{$}}
+
+struct X {
+ explicit operator bool();
+};
+
+void explicit_conversion_assignment(X x) {
+ bool y;
+ if (x) {
+ y = true;
+ } else {
+ y = false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:9: warning: {{.*}} in conditional assignment
+// CHECK-FIXES: {{^ bool y;$}}
+// CHECK-FIXES: {{^}} y = static_cast<bool>(x);{{$}}
+
+void ternary_integer_condition(int i) {
+ bool b = i ? true : false;
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:16: warning: {{.*}} in ternary expression result
+// CHECK-FIXES: bool b = i != 0;{{$}}
+
+bool non_null_pointer_condition(int *p1) {
+ if (p1) {
+ return true;
+ } else {
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: return p1 != nullptr;{{$}}
+
+bool null_pointer_condition(int *p2) {
+ if (!p2) {
+ return true;
+ } else {
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: return p2 == nullptr;{{$}}
+
+bool negated_non_null_pointer_condition(int *p3) {
+ if (p3) {
+ return false;
+ } else {
+ return true;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: return p3 == nullptr;{{$}}
+
+bool negated_null_pointer_condition(int *p4) {
+ if (!p4) {
+ return false;
+ } else {
+ return true;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: return p4 != nullptr;{{$}}
+
+bool comments_in_the_middle(bool b) {
+ if (b) {
+ return true;
+ } else {
+ // something wicked this way comes
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-6]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}} if (b) {
+// CHECK-FIXES: // something wicked this way comes{{$}}
+
+bool preprocessor_in_the_middle(bool b) {
+ if (b) {
+ return true;
+ } else {
+#define SOMETHING_WICKED false
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-6]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}} if (b) {
+// CHECK-FIXES: {{^}}#define SOMETHING_WICKED false
+
+bool integer_not_zero(int i) {
+ if (i) {
+ return false;
+ } else {
+ return true;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: {{^}} return i == 0;{{$}}
+
+class A {
+public:
+ int m;
+};
+
+bool member_pointer_nullptr(int A::*p) {
+ if (p) {
+ return true;
+ } else {
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: return p != nullptr;{{$}}
+
+bool integer_member_implicit_cast(A *p) {
+ if (p->m) {
+ return true;
+ } else {
+ return false;
+ }
+}
+// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: return p->m != 0;{{$}}
+
+bool operator!=(const A&, const A&) { return false; }
+bool expr_with_cleanups(A &S) {
+ if (S != (A)S)
+ return false;
+
+ return true;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:12: warning: {{.*}} in conditional return
+// CHECK-FIXES: S == (A)S;{{$}}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-simplify-subscript-expr.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-simplify-subscript-expr.cpp
new file mode 100644
index 0000000..16197dc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-simplify-subscript-expr.cpp
@@ -0,0 +1,108 @@
+// RUN: %check_clang_tidy %s readability-simplify-subscript-expr %t \
+// RUN: -config="{CheckOptions: \
+// RUN: [{key: readability-simplify-subscript-expr.Types, \
+// RUN: value: '::std::basic_string;::std::basic_string_view;MyVector'}]}" --
+
+namespace std {
+
+template <class T>
+class basic_string {
+ public:
+ using size_type = unsigned;
+ using value_type = T;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+
+ reference operator[](size_type);
+ const_reference operator[](size_type) const;
+ T* data();
+ const T* data() const;
+};
+
+using string = basic_string<char>;
+
+template <class T>
+class basic_string_view {
+ public:
+ using size_type = unsigned;
+ using const_reference = const T&;
+ using const_pointer = const T*;
+
+ constexpr const_reference operator[](size_type) const;
+ constexpr const_pointer data() const noexcept;
+};
+
+using string_view = basic_string_view<char>;
+
+}
+
+template <class T>
+class MyVector {
+ public:
+ using size_type = unsigned;
+ using const_reference = const T&;
+ using const_pointer = const T*;
+
+ const_reference operator[](size_type) const;
+ const T* data() const noexcept;
+};
+
+#define DO(x) do { x; } while (false)
+#define ACCESS(x) (x)
+#define GET(x, i) (x).data()[i]
+
+template <class T>
+class Foo {
+ public:
+ char bar(int i) {
+ return x.data()[i];
+ }
+ private:
+ T x;
+};
+
+void f(int i) {
+ MyVector<int> v;
+ int x = v.data()[i];
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: accessing an element of the container does not require a call to 'data()'; did you mean to use 'operator[]'? [readability-simplify-subscript-expr]
+ // CHECK-FIXES: int x = v[i];
+
+ std::string s;
+ char c1 = s.data()[i];
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: accessing an element
+ // CHECK-FIXES: char c1 = s[i];
+
+ std::string_view sv;
+ char c2 = sv.data()[i];
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: accessing an element
+ // CHECK-FIXES: char c2 = sv[i];
+
+ std::string* ps = &s;
+ char c3 = ps->data()[i];
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: accessing an element
+ // CHECK-FIXES: char c3 = (*ps)[i];
+
+ char c4 = (*ps).data()[i];
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: accessing an element
+ // CHECK-FIXES: char c4 = (*ps)[i];
+
+ DO(char c5 = s.data()[i]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: accessing an element
+ // CHECK-FIXES: DO(char c5 = s[i]);
+
+ char c6 = ACCESS(s).data()[i];
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: accessing an element
+ // CHECK-FIXES: char c6 = ACCESS(s)[i];
+
+ char c7 = ACCESS(s.data())[i];
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: accessing an element
+ // CHECK-FIXES: char c7 = ACCESS(s)[i];
+
+ char c8 = ACCESS(s.data()[i]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: accessing an element
+ // CHECK-FIXES: char c8 = ACCESS(s[i]);
+
+ char c9 = GET(s, i);
+
+ char c10 = Foo<std::string>{}.bar(i);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-static-accessed-through-instance-nesting-threshold.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-static-accessed-through-instance-nesting-threshold.cpp
new file mode 100644
index 0000000..0375249
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-static-accessed-through-instance-nesting-threshold.cpp
@@ -0,0 +1,33 @@
+// RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t -- -config="{CheckOptions: [{key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold, value: 4}]}" --
+
+// Nested specifiers
+namespace M {
+namespace N {
+struct V {
+ static int v;
+ struct T {
+ static int t;
+ struct U {
+ static int u;
+ };
+ };
+};
+}
+}
+
+void f(M::N::V::T::U u) {
+ M::N::V v;
+ v.v = 12;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} M::N::V::v = 12;{{$}}
+
+ M::N::V::T w;
+ w.t = 12;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} M::N::V::T::t = 12;{{$}}
+
+ // u.u is not changed, because the nesting level is over 4
+ u.u = 12;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} u.u = 12;{{$}}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-static-accessed-through-instance.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-static-accessed-through-instance.cpp
new file mode 100644
index 0000000..fc42a1d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-static-accessed-through-instance.cpp
@@ -0,0 +1,222 @@
+// RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t
+
+struct C {
+ static void foo();
+ static int x;
+ int nsx;
+ void mf() {
+ (void)&x; // OK, x is accessed inside the struct.
+ (void)&C::x; // OK, x is accessed using a qualified-id.
+ foo(); // OK, foo() is accessed inside the struct.
+ }
+ void ns() const;
+};
+
+int C::x = 0;
+
+struct CC {
+ void foo();
+ int x;
+};
+
+template <typename T> struct CT {
+ static T foo();
+ static T x;
+ int nsx;
+ void mf() {
+ (void)&x; // OK, x is accessed inside the struct.
+ (void)&C::x; // OK, x is accessed using a qualified-id.
+ foo(); // OK, foo() is accessed inside the struct.
+ }
+};
+
+// Expressions with side effects
+C &f(int, int, int, int);
+void g() {
+ f(1, 2, 3, 4).x;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance]
+ // CHECK-FIXES: {{^}} f(1, 2, 3, 4).x;{{$}}
+}
+
+int i(int &);
+void j(int);
+C h();
+bool a();
+int k(bool);
+
+void f(C c) {
+ j(i(h().x));
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: static member
+ // CHECK-FIXES: {{^}} j(i(h().x));{{$}}
+
+ // The execution of h() depends on the return value of a().
+ j(k(a() && h().x));
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: static member
+ // CHECK-FIXES: {{^}} j(k(a() && h().x));{{$}}
+
+ if ([c]() {
+ c.ns();
+ return c;
+ }().x == 15)
+ ;
+ // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: static member
+ // CHECK-FIXES: {{^}} if ([c]() {{{$}}
+}
+
+// Nested specifiers
+namespace N {
+struct V {
+ static int v;
+ struct T {
+ static int t;
+ struct U {
+ static int u;
+ };
+ };
+};
+}
+
+void f(N::V::T::U u) {
+ N::V v;
+ v.v = 12;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} N::V::v = 12;{{$}}
+
+ N::V::T w;
+ w.t = 12;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} N::V::T::t = 12;{{$}}
+
+ // u.u is not changed to N::V::T::U::u; because the nesting level is over 3.
+ u.u = 12;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} u.u = 12;{{$}}
+
+ using B = N::V::T::U;
+ B b;
+ b.u;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} B::u;{{$}}
+}
+
+// Templates
+template <typename T> T CT<T>::x;
+
+template <typename T> struct CCT {
+ T foo();
+ T x;
+};
+
+typedef C D;
+
+using E = D;
+
+#define FOO(c) c.foo()
+#define X(c) c.x
+
+template <typename T> void f(T t, C c) {
+ t.x; // OK, t is a template parameter.
+ c.x;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} C::x;{{$}}
+}
+
+template <int N> struct S { static int x; };
+
+template <> struct S<0> { int x; };
+
+template <int N> void h() {
+ S<N> sN;
+ sN.x; // OK, value of N affects whether x is static or not.
+
+ S<2> s2;
+ s2.x;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} S<2>::x;{{$}}
+}
+
+void static_through_instance() {
+ C *c1 = new C();
+ c1->foo(); // 1
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} C::foo(); // 1{{$}}
+ c1->x; // 2
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} C::x; // 2{{$}}
+ c1->nsx; // OK, nsx is a non-static member.
+
+ const C *c2 = new C();
+ c2->foo(); // 2
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} C::foo(); // 2{{$}}
+
+ C::foo(); // OK, foo() is accessed using a qualified-id.
+ C::x; // OK, x is accessed using a qualified-id.
+
+ D d;
+ d.foo();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} D::foo();{{$}}
+ d.x;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} D::x;{{$}}
+
+ E e;
+ e.foo();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} E::foo();{{$}}
+ e.x;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} E::x;{{$}}
+
+ CC *cc = new CC;
+
+ f(*c1, *c1);
+ f(*cc, *c1);
+
+ // Macros: OK, macros are not checked.
+ FOO((*c1));
+ X((*c1));
+ FOO((*cc));
+ X((*cc));
+
+ // Templates
+ CT<int> ct;
+ ct.foo();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} CT<int>::foo();{{$}}
+ ct.x;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member
+ // CHECK-FIXES: {{^}} CT<int>::x;{{$}}
+ ct.nsx; // OK, nsx is a non-static member
+
+ CCT<int> cct;
+ cct.foo(); // OK, CCT has no static members.
+ cct.x; // OK, CCT has no static members.
+
+ h<4>();
+}
+
+// Overloaded member access operator
+struct Q {
+ static int K;
+ int y = 0;
+};
+
+int Q::K = 0;
+
+struct Qptr {
+ Q *q;
+
+ explicit Qptr(Q *qq) : q(qq) {}
+
+ Q *operator->() {
+ ++q->y;
+ return q;
+ }
+};
+
+int func(Qptr qp) {
+ qp->y = 10; // OK, the overloaded operator might have side-effects.
+ qp->K = 10; //
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-static-definition-in-anonymous-namespace.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-static-definition-in-anonymous-namespace.cpp
new file mode 100644
index 0000000..5c3c8c1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-static-definition-in-anonymous-namespace.cpp
@@ -0,0 +1,49 @@
+// RUN: %check_clang_tidy %s readability-static-definition-in-anonymous-namespace %t
+
+namespace {
+
+int a = 1;
+const int b = 1;
+static int c = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'c' is a static definition in anonymous namespace; static is redundant here [readability-static-definition-in-anonymous-namespace]
+// CHECK-FIXES: {{^}}int c = 1;
+static const int d = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'd' is a static definition in anonymous namespace
+// CHECK-FIXES: {{^}}const int d = 1;
+const static int e = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'e' is a static definition in anonymous namespace
+// CHECK-FIXES: {{^}}const int e = 1;
+
+void f() {
+ int a = 1;
+ static int b = 1;
+}
+
+static int g() {
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: 'g' is a static definition in anonymous namespace
+// CHECK-FIXES: {{^}}int g() {
+ return 1;
+}
+
+#define DEFINE_STATIC static
+// CHECK-FIXES: {{^}}#define DEFINE_STATIC static
+DEFINE_STATIC int h = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: 'h' is a static definition in anonymous namespace
+// CHECK-FIXES: {{^}}DEFINE_STATIC int h = 1;
+
+#define DEFINE_STATIC_VAR(x) static int x = 2
+// CHECK-FIXES: {{^}}#define DEFINE_STATIC_VAR(x) static int x = 2
+DEFINE_STATIC_VAR(i);
+// CHECK-FIXES: {{^}}DEFINE_STATIC_VAR(i);
+
+} // namespace
+
+namespace N {
+
+int a = 1;
+const int b = 1;
+static int c = 1;
+static const int d = 1;
+const static int e = 1;
+
+} // namespace N
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-string-compare.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-string-compare.cpp
new file mode 100644
index 0000000..9bd11da
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-string-compare.cpp
@@ -0,0 +1,119 @@
+// RUN: %check_clang_tidy %s readability-string-compare %t -- -- -std=c++11
+
+namespace std {
+template <typename T>
+class allocator {};
+template <typename T>
+class char_traits {};
+template <typename C, typename T = std::char_traits<C>, typename A = std::allocator<C>>
+class basic_string {
+public:
+ basic_string();
+ basic_string(const C *, unsigned int size);
+ int compare(const basic_string<char> &str) const;
+ int compare(const C *) const;
+ int compare(int, int, const basic_string<char> &str) const;
+ bool empty();
+};
+bool operator==(const basic_string<char> &lhs, const basic_string<char> &rhs);
+bool operator!=(const basic_string<char> &lhs, const basic_string<char> &rhs);
+bool operator==(const basic_string<char> &lhs, const char *&rhs);
+typedef basic_string<char> string;
+}
+
+void func(bool b);
+
+std::string comp() {
+ std::string str("a", 1);
+ return str;
+}
+
+void Test() {
+ std::string str1("a", 1);
+ std::string str2("b", 1);
+
+ if (str1.compare(str2)) {
+ }
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings; use the string equality operator instead [readability-string-compare]
+ if (!str1.compare(str2)) {
+ }
+ // CHECK-MESSAGES: [[@LINE-2]]:8: warning: do not use 'compare' to test equality of strings; use the string equality operator instead [readability-string-compare]
+ if (str1.compare(str2) == 0) {
+ }
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings;
+ // CHECK-FIXES: if (str1 == str2) {
+ if (str1.compare(str2) != 0) {
+ }
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings;
+ // CHECK-FIXES: if (str1 != str2) {
+ if (str1.compare("foo") == 0) {
+ }
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings;
+ // CHECK-FIXES: if (str1 == "foo") {
+ if (0 == str1.compare(str2)) {
+ }
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings;
+ // CHECK-FIXES: if (str2 == str1) {
+ if (0 != str1.compare(str2)) {
+ }
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings;
+ // CHECK-FIXES: if (str2 != str1) {
+ func(str1.compare(str2));
+ // CHECK-MESSAGES: [[@LINE-1]]:8: warning: do not use 'compare' to test equality of strings;
+ if (str2.empty() || str1.compare(str2) != 0) {
+ }
+ // CHECK-MESSAGES: [[@LINE-2]]:23: warning: do not use 'compare' to test equality of strings;
+ // CHECK-FIXES: if (str2.empty() || str1 != str2) {
+ std::string *str3 = &str1;
+ if (str3->compare(str2)) {
+ }
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings;
+ if (str3->compare(str2) == 0) {
+ }
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings;
+ // CHECK-FIXES: if (*str3 == str2) {
+ if (str2.compare(*str3) == 0) {
+ }
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings;
+ // CHECK-FIXES: if (str2 == *str3) {
+ if (comp().compare(str1) == 0) {
+ }
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings;
+ // CHECK-FIXES: if (comp() == str1) {
+ if (str1.compare(comp()) == 0) {
+ }
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings;
+ // CHECK-FIXES: if (str1 == comp()) {
+ if (str1.compare(comp())) {
+ }
+ // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings;
+}
+
+void Valid() {
+ std::string str1("a", 1);
+ std::string str2("b", 1);
+ if (str1 == str2) {
+ }
+ if (str1 != str2) {
+ }
+ if (str1.compare(str2) == str1.compare(str2)) {
+ }
+ if (0 == 0) {
+ }
+ if (str1.compare(str2) > 0) {
+ }
+ if (str1.compare(1, 3, str2)) {
+ }
+ if (str1.compare(str2) > 0) {
+ }
+ if (str1.compare(str2) < 0) {
+ }
+ if (str1.compare(str2) == 2) {
+ }
+ if (str1.compare(str2) == -3) {
+ }
+ if (str1.compare(str2) == 1) {
+ }
+ if (str1.compare(str2) == -1) {
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-uniqueptr-delete-release.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-uniqueptr-delete-release.cpp
new file mode 100644
index 0000000..bd51bc6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/readability-uniqueptr-delete-release.cpp
@@ -0,0 +1,76 @@
+// RUN: %check_clang_tidy %s readability-uniqueptr-delete-release %t
+
+namespace std {
+template <typename T>
+struct default_delete {};
+
+template <typename T, typename D = default_delete<T>>
+class unique_ptr {
+ public:
+ unique_ptr();
+ ~unique_ptr();
+ explicit unique_ptr(T*);
+ template <typename U, typename E>
+ unique_ptr(unique_ptr<U, E>&&);
+ T* release();
+};
+} // namespace std
+
+std::unique_ptr<int>& ReturnsAUnique();
+
+void Positives() {
+ std::unique_ptr<int> P;
+ delete P.release();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer '= nullptr' to 'delete x.release()' to reset unique_ptr<> objects [readability-uniqueptr-delete-release]
+ // CHECK-FIXES: {{^}} P = nullptr;
+
+ auto P2 = P;
+ delete P2.release();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer '= nullptr' to 'delete x.release()' to reset unique_ptr<> objects [readability-uniqueptr-delete-release]
+ // CHECK-FIXES: {{^}} P2 = nullptr;
+
+ std::unique_ptr<int> Array[20];
+ delete Array[4].release();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer '= nullptr' to 'delete
+ // CHECK-FIXES: {{^}} Array[4] = nullptr;
+
+ delete ReturnsAUnique().release();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer '= nullptr' to 'delete
+ // CHECK-FIXES: {{^}} ReturnsAUnique() = nullptr;
+}
+
+struct NotDefaultDeleter {};
+
+struct NotUniquePtr {
+ int* release();
+};
+
+void Negatives() {
+ std::unique_ptr<int, NotDefaultDeleter> P;
+ delete P.release();
+
+ NotUniquePtr P2;
+ delete P2.release();
+}
+
+template <typename T, typename D>
+void NegativeDeleterT() {
+ // Ideally this would trigger a warning, but we have all dependent types
+ // disabled for now.
+ std::unique_ptr<T> P;
+ delete P.release();
+
+ // We ignore this one because the deleter is a template argument.
+ // Not all instantiations will use the default deleter.
+ std::unique_ptr<int, D> P2;
+ delete P2.release();
+}
+template void NegativeDeleterT<int, std::default_delete<int>>();
+
+// Test some macros
+
+#define DELETE_RELEASE(x) delete (x).release()
+void NegativesWithTemplate() {
+ std::unique_ptr<int> P;
+ DELETE_RELEASE(P);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/run-clang-tidy.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/run-clang-tidy.cpp
new file mode 100644
index 0000000..2207e43
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/run-clang-tidy.cpp
@@ -0,0 +1,17 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %/t/test.cpp\",\"file\":\"%/t/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
+// RUN: echo "Checks: '-*,modernize-use-auto'" > %t/.clang-tidy
+// RUN: echo "WarningsAsErrors: '*'" >> %t/.clang-tidy
+// RUN: echo "CheckOptions:" >> %t/.clang-tidy
+// RUN: echo " - key: modernize-use-auto.MinTypeNameLength" >> %t/.clang-tidy
+// RUN: echo " value: '0'" >> %t/.clang-tidy
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: cd "%t"
+// RUN: not %run_clang_tidy "%t/test.cpp"
+
+int main()
+{
+ int* x = new int();
+ delete x;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/select-checks.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/select-checks.cpp
new file mode 100644
index 0000000..791def7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/select-checks.cpp
@@ -0,0 +1,11 @@
+// RUN: clang-tidy %s -checks='-*,llvm-namespace-*' -- 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s
+// RUN: not clang-tidy %s -checks='-*,an-unknown-check' -- 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' -check-prefix=CHECK2 %s
+
+// CHECK2: Error: no checks enabled.
+
+namespace i {
+}
+// CHECK: :[[@LINE-1]]:2: warning: namespace 'i' not terminated with a closing comment [llvm-namespace-comment]
+
+// Expect no warnings from the google-explicit-constructor check:
+class A { A(int i); };
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/serialize-diagnostics.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/serialize-diagnostics.cpp
new file mode 100644
index 0000000..8b0895a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/serialize-diagnostics.cpp
@@ -0,0 +1,3 @@
+// RUN: not clang-tidy -checks=-*,llvm-namespace-comment %s -- -serialize-diagnostics %t | FileCheck %s
+// CHECK: :[[@LINE+1]]:12: error: expected ';' after struct [clang-diagnostic-error]
+struct A {}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/static-analyzer-config.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/static-analyzer-config.cpp
new file mode 100644
index 0000000..cee0a4c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/static-analyzer-config.cpp
@@ -0,0 +1,19 @@
+// RUN: clang-tidy %s -checks='-*,clang-analyzer-unix.Malloc' -config='{CheckOptions: [{ key: "clang-analyzer-unix.Malloc:Optimistic", value: true}]}' -- | FileCheck %s
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+void __attribute((ownership_returns(malloc))) *my_malloc(size_t);
+void __attribute((ownership_takes(malloc, 1))) my_free(void *);
+
+void f1() {
+ void *p = malloc(12);
+ return;
+ // CHECK: warning: Potential leak of memory pointed to by 'p' [clang-analyzer-unix.Malloc]
+}
+
+void af2() {
+ void *p = my_malloc(12);
+ my_free(p);
+ free(p);
+ // CHECK: warning: Attempt to free released memory [clang-analyzer-unix.Malloc]
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/static-analyzer.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/static-analyzer.cpp
new file mode 100644
index 0000000..b0015aa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/static-analyzer.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-tidy %s -checks='-*,clang-analyzer-*' -- | FileCheck %s
+extern void *malloc(unsigned long);
+extern void free(void *);
+
+void f() {
+ int *p = new int(42);
+ delete p;
+ delete p;
+ // CHECK: warning: Attempt to free released memory [clang-analyzer-cplusplus.NewDelete]
+}
+
+void g() {
+ void *q = malloc(132);
+ free(q);
+ free(q);
+ // CHECK: warning: Attempt to free released memory [clang-analyzer-unix.Malloc]
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/temporaries.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/temporaries.cpp
new file mode 100644
index 0000000..3df4c60
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/temporaries.cpp
@@ -0,0 +1,24 @@
+// RUN: clang-tidy -checks='-*,clang-analyzer-core.NullDereference' %s -- | FileCheck %s
+
+struct NoReturnDtor {
+ ~NoReturnDtor() __attribute__((noreturn));
+};
+
+extern bool check(const NoReturnDtor &);
+
+// CHECK-NOT: warning
+void testNullPointerDereferencePositive() {
+ int *value = 0;
+ // CHECK: [[@LINE+1]]:10: warning: Dereference of null pointer (loaded from variable 'value') [clang-analyzer-core.NullDereference]
+ *value = 1;
+}
+
+// CHECK-NOT: warning
+void testNullPointerDereference() {
+ int *value = 0;
+ if (check(NoReturnDtor())) {
+ // This unreachable code causes a warning if analysis of temporary
+ // destructors is not enabled.
+ *value = 1;
+ }
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/validate-check-names.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/validate-check-names.cpp
new file mode 100644
index 0000000..35bfb09
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/validate-check-names.cpp
@@ -0,0 +1,2 @@
+// Check names may only contain alphanumeric characters, '-', '_', and '.'.
+// RUN: clang-tidy -checks=* -list-checks | grep '^ ' | cut -b5- | not grep -v '^[a-zA-Z0-9_.\-]\+$'
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/vfsoverlay.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/vfsoverlay.cpp
new file mode 100644
index 0000000..5704b71
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/vfsoverlay.cpp
@@ -0,0 +1,8 @@
+// RUN: sed -e "s:INPUT_DIR:%S/Inputs/vfsoverlay:g" -e "s:OUT_DIR:%t:g" %S/Inputs/vfsoverlay/vfsoverlay.yaml > %t.yaml
+// RUN: clang-tidy %s -checks='-*,modernize-use-nullptr' -vfsoverlay %t.yaml -- -I %t | FileCheck %s
+// REQUIRES: shell
+
+#include "not_real.h"
+
+X *ptr = 0;
+// CHECK: warning: use nullptr [modernize-use-nullptr]
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/warnings-as-errors-diagnostics.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/warnings-as-errors-diagnostics.cpp
new file mode 100644
index 0000000..9f90b62
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/warnings-as-errors-diagnostics.cpp
@@ -0,0 +1,18 @@
+// RUN: clang-tidy %s -checks='-*,llvm-namespace-comment,clang-diagnostic*' \
+// RUN: -- -Wunused-variable 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-WARN -implicit-check-not='{{warning|error}}:'
+// RUN: not clang-tidy %s -checks='-*,llvm-namespace-comment,clang-diagnostic*' \
+// RUN: -warnings-as-errors='clang-diagnostic*' -- -Wunused-variable 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-WERR -implicit-check-not='{{warning|error}}:'
+// RUN: not clang-tidy %s -checks='-*,llvm-namespace-comment,clang-diagnostic*' \
+// RUN: -warnings-as-errors='clang-diagnostic*' -quiet -- -Wunused-variable 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-WERR-QUIET -implicit-check-not='{{warning|error}}:'
+
+void f() { int i; }
+// CHECK-WARN: warning: unused variable 'i' [clang-diagnostic-unused-variable]
+// CHECK-WERR: error: unused variable 'i' [clang-diagnostic-unused-variable,-warnings-as-errors]
+// CHECK-WERR-QUIET: error: unused variable 'i' [clang-diagnostic-unused-variable,-warnings-as-errors]
+
+// CHECK-WARN-NOT: treated as
+// CHECK-WERR: 1 warning treated as error
+// CHECK-WERR-QUIET-NOT: treated as
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/warnings-as-errors-plural.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/warnings-as-errors-plural.cpp
new file mode 100644
index 0000000..a14759d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/warnings-as-errors-plural.cpp
@@ -0,0 +1,24 @@
+// RUN: clang-tidy %s -checks='-*,llvm-namespace-comment,clang-diagnostic*' -- 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-WARN -implicit-check-not='{{warning|error}}:'
+// RUN: not clang-tidy %s -checks='-*,llvm-namespace-comment,clang-diagnostic*' \
+// RUN: -warnings-as-errors='llvm-namespace-comment' -- 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-WERR -implicit-check-not='{{warning|error}}:'
+// RUN: not clang-tidy %s -checks='-*,llvm-namespace-comment,clang-diagnostic*' \
+// RUN: -warnings-as-errors='llvm-namespace-comment' -quiet -- 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-WERR-QUIET -implicit-check-not='{{warning|error}}:'
+
+namespace j {
+}
+// CHECK-WARN: warning: namespace 'j' not terminated with a closing comment [llvm-namespace-comment]
+// CHECK-WERR: error: namespace 'j' not terminated with a closing comment [llvm-namespace-comment,-warnings-as-errors]
+// CHECK-WERR-QUIET: error: namespace 'j' not terminated with a closing comment [llvm-namespace-comment,-warnings-as-errors]
+
+namespace k {
+}
+// CHECK-WARN: warning: namespace 'k' not terminated with a closing comment [llvm-namespace-comment]
+// CHECK-WERR: error: namespace 'k' not terminated with a closing comment [llvm-namespace-comment,-warnings-as-errors]
+// CHECK-WERR-QUIET: error: namespace 'k' not terminated with a closing comment [llvm-namespace-comment,-warnings-as-errors]
+
+// CHECK-WARN-NOT: treated as
+// CHECK-WERR: 2 warnings treated as errors
+// CHECK-WERR-QUIET-NOT: treated as
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/warnings-as-errors.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/warnings-as-errors.cpp
new file mode 100644
index 0000000..44afb83
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/warnings-as-errors.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-tidy %s -checks='-*,llvm-namespace-comment' -- 2>&1 | FileCheck %s --check-prefix=CHECK-WARN -implicit-check-not='{{warning|error}}:'
+// RUN: not clang-tidy %s -checks='-*,llvm-namespace-comment' -warnings-as-errors='llvm-namespace-comment' -- 2>&1 | FileCheck %s --check-prefix=CHECK-WERR -implicit-check-not='{{warning|error}}:'
+// RUN: not clang-tidy %s -checks='-*,llvm-namespace-comment' -warnings-as-errors='llvm-namespace-comment' -quiet -- 2>&1 | FileCheck %s --check-prefix=CHECK-WERR-QUIET -implicit-check-not='{{warning|error}}:'
+
+namespace i {
+}
+// CHECK-WARN: warning: namespace 'i' not terminated with a closing comment [llvm-namespace-comment]
+// CHECK-WERR: error: namespace 'i' not terminated with a closing comment [llvm-namespace-comment,-warnings-as-errors]
+// CHECK-WERR-QUIET: error: namespace 'i' not terminated with a closing comment [llvm-namespace-comment,-warnings-as-errors]
+
+// CHECK-WARN-NOT: treated as
+// CHECK-WERR: 1 warning treated as error
+// CHECK-WERR-QUIET-NOT: treated as
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/zircon-temporary-objects.cpp b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/zircon-temporary-objects.cpp
new file mode 100644
index 0000000..b29b482
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clang-tidy/zircon-temporary-objects.cpp
@@ -0,0 +1,109 @@
+// RUN: %check_clang_tidy %s zircon-temporary-objects %t -- \
+// RUN: -config="{CheckOptions: [{key: zircon-temporary-objects.Names, value: 'Foo;NS::Bar'}]}" \
+// RUN: -header-filter=.* \
+// RUN: -- -std=c++11
+
+// Should flag instances of Foo, NS::Bar.
+
+class Foo {
+public:
+ Foo() = default;
+ Foo(int Val) : Val(Val){};
+
+private:
+ int Val;
+};
+
+namespace NS {
+
+class Bar {
+public:
+ Bar() = default;
+ Bar(int Val) : Val(Val){};
+
+private:
+ int Val;
+};
+
+} // namespace NS
+
+class Bar {
+public:
+ Bar() = default;
+ Bar(int Val) : Val(Val){};
+
+private:
+ int Val;
+};
+
+int func(Foo F) { return 1; };
+
+int main() {
+ Foo F;
+ Foo *F2 = new Foo();
+ new Foo();
+ Foo();
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'Foo' is prohibited
+ Foo F3 = Foo();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: creating a temporary object of type 'Foo' is prohibited
+
+ Bar();
+ NS::Bar();
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'NS::Bar' is prohibited
+
+ int A = func(Foo());
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: creating a temporary object of type 'Foo' is prohibited
+
+ Foo F4(0);
+ Foo *F5 = new Foo(0);
+ new Foo(0);
+ Foo(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'Foo' is prohibited
+ Foo F6 = Foo(0);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: creating a temporary object of type 'Foo' is prohibited
+
+ Bar(0);
+ NS::Bar(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'NS::Bar' is prohibited
+
+ int B = func(Foo(0));
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: creating a temporary object of type 'Foo' is prohibited
+}
+
+namespace NS {
+
+void f() {
+ Bar();
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'NS::Bar' is prohibited
+ Bar(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'NS::Bar' is prohibited
+}
+
+} // namespace NS
+
+template <typename Ty>
+Ty make_ty() { return Ty(); }
+// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: creating a temporary object of type 'Foo' is prohibited
+// CHECK-MESSAGES: :[[@LINE-2]]:23: warning: creating a temporary object of type 'NS::Bar' is prohibited
+
+void ty_func() {
+ make_ty<Bar>();
+ make_ty<NS::Bar>();
+ make_ty<Foo>();
+}
+
+// Inheriting the disallowed class does not trigger the check.
+
+class Bingo : NS::Bar {}; // Not explicitly disallowed
+
+void f2() {
+ Bingo();
+}
+
+template <typename Ty>
+class Quux : Ty {};
+
+void f3() {
+ Quux<NS::Bar>();
+ Quux<Bar>();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/Inputs/sstream.h b/src/third_party/llvm-project/clang-tools-extra/test/clangd/Inputs/sstream.h
new file mode 100644
index 0000000..980963a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/Inputs/sstream.h
@@ -0,0 +1,3 @@
+namespace std {
+class basic_ostringstream {};
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/completion-snippets.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/completion-snippets.test
new file mode 100644
index 0000000..0689631
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/completion-snippets.test
@@ -0,0 +1,41 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+# RUN: clangd -lit-test -pch-storage=memory < %s | FileCheck -strict-whitespace %s
+{
+ "jsonrpc": "2.0",
+ "id": 0,
+ "method": "initialize",
+ "params": {
+ "processId": 123,
+ "rootPath": "clangd",
+ "capabilities": {
+ "textDocument": {
+ "completion": {
+ "completionItem": {
+ "snippetSupport": true
+ }
+ }
+ }
+ },
+ "trace": "off"
+ }
+}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"int func_with_args(int a, int b);\nint main() {\nfunc_with\n}"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":2,"character":7}}}
+# CHECK: "id": 1
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "isIncomplete": {{.*}}
+# CHECK-NEXT: "items": [
+# CHECK: "filterText": "func_with_args",
+# CHECK-NEXT: "insertText": "func_with_args(${1:int a}, ${2:int b})",
+# CHECK-NEXT: "insertTextFormat": 2,
+# CHECK-NEXT: "kind": 3,
+# CHECK-NEXT: "label": " func_with_args(int a, int b)",
+# CHECK-NEXT: "sortText": "{{.*}}func_with_args"
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+---
+{"jsonrpc":"2.0","id":4,"method":"shutdown"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/completion.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/completion.test
new file mode 100644
index 0000000..c679e32
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/completion.test
@@ -0,0 +1,44 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+# RUN: clangd -lit-test -pch-storage=memory < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"struct S { int a; };\nint main() {\nS().\n}"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":2,"character":4}}}
+# CHECK: "id": 1
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "isIncomplete": false,
+# CHECK-NEXT: "items": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "detail": "int",
+# CHECK-NEXT: "filterText": "a",
+# CHECK-NEXT: "insertText": "a",
+# CHECK-NEXT: "insertTextFormat": 1,
+# CHECK-NEXT: "kind": 5,
+# CHECK-NEXT: "label": " a",
+# CHECK-NEXT: "sortText": "{{.*}}a"
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+---
+# Update the source file and check for completions again.
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///main.cpp","version":2},"contentChanges":[{"text":"struct S { int b; };\nint main() {\nS().\n}"}]}}
+---
+{"jsonrpc":"2.0","id":3,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":2,"character":4}}}
+# CHECK: "id": 3,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "isIncomplete": false,
+# CHECK-NEXT: "items": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "detail": "int",
+# CHECK-NEXT: "filterText": "b",
+# CHECK-NEXT: "insertText": "b",
+# CHECK-NEXT: "insertTextFormat": 1,
+# CHECK-NEXT: "kind": 5,
+# CHECK-NEXT: "label": " b",
+# CHECK-NEXT: "sortText": "{{.*}}b"
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+---
+{"jsonrpc":"2.0","id":4,"method":"shutdown"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/crash-non-added-files.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/crash-non-added-files.test
new file mode 100644
index 0000000..d86f7d2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/crash-non-added-files.test
@@ -0,0 +1,34 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","id":2,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":104,"character":13},"end":{"line":0,"character":35}},"context":{"diagnostics":[{"range":{"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 37}},"severity":2,"message":"using the result of an assignment as a condition without parentheses"},{"range":{"start": {"line": 0, "character": 34}, "end": {"line": 0, "character": 35}},"severity":3,"message":"place parentheses around the assignment to silence this warning"},{"range":{"start": {"line": 0, "character": 34}, "end": {"line": 0, "character": 35}},"severity":3,"message":"use '==' to turn this assignment into an equality comparison"}]}}}
+# CHECK: "error": {
+# CHECK-NEXT: "code": -32602
+# CHECK-NEXT: "message": "onCodeAction called for non-added file"
+# CHECK-NEXT: },
+# CHECK-NEXT: "id": 2,
+---
+{"jsonrpc":"2.0","id":3,"method":"textDocument/rangeFormatting","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":1,"character":4},"end":{"line":1,"character":12}},"options":{"tabSize":4,"insertSpaces":true}}}
+# CHECK: "error": {
+# CHECK-NEXT: "code": -32602
+# CHECK-NEXT: "message": "onDocumentRangeFormatting called for non-added file"
+# CHECK-NEXT: },
+# CHECK-NEXT: "id": 3,
+---
+{"jsonrpc":"2.0","id":4,"method":"textDocument/formatting","params":{"textDocument":{"uri":"test:///foo.c"},"options":{"tabSize":4,"insertSpaces":true}}}
+# CHECK: "error": {
+# CHECK-NEXT: "code": -32602
+# CHECK-NEXT: "message": "onDocumentFormatting called for non-added file"
+# CHECK-NEXT: },
+# CHECK-NEXT: "id": 4,
+---
+{"jsonrpc":"2.0","id":5,"method":"textDocument/onTypeFormatting","params":{"textDocument":{"uri":"test:///foo.c"},"position":{"line":3,"character":1},"ch":"}","options":{"tabSize":4,"insertSpaces":true}}}
+# CHECK: "error": {
+# CHECK-NEXT: "code": -32602
+# CHECK-NEXT: "message": "onDocumentOnTypeFormatting called for non-added file"
+# CHECK-NEXT: },
+# CHECK-NEXT: "id": 5,
+---
+{"jsonrpc":"2.0","id":6,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/delimited-input-comment-at-the-end.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/delimited-input-comment-at-the-end.test
new file mode 100644
index 0000000..9c10b92
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/delimited-input-comment-at-the-end.test
@@ -0,0 +1,12 @@
+# RUN: clangd -input-style=delimited -run-synchronously -input-mirror-file %t < %s
+# RUN: grep '{"jsonrpc":"2.0","id":3,"method":"exit"}' %t
+#
+# RUN: clangd -lit-test -input-mirror-file %t < %s
+# RUN: grep '{"jsonrpc":"2.0","id":3,"method":"exit"}' %t
+#
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","id":3,"method":"exit"}
+# comment at the end
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/diagnostics.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/diagnostics.test
new file mode 100644
index 0000000..afd1277
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/diagnostics.test
@@ -0,0 +1,28 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///foo.c","languageId":"c","version":1,"text":"void main() {}"}}}
+# CHECK: "method": "textDocument/publishDiagnostics",
+# CHECK-NEXT: "params": {
+# CHECK-NEXT: "diagnostics": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "message": "return type of 'main' is not 'int'",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 4,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 0,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "severity": 2
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "uri": "file://{{.*}}/foo.c"
+# CHECK-NEXT: }
+---
+{"jsonrpc":"2.0","id":5,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/execute-command.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/execute-command.test
new file mode 100644
index 0000000..9686d04
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/execute-command.test
@@ -0,0 +1,64 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///foo.c","languageId":"c","version":1,"text":"int main(int i, char **a) { if (i = 2) {}}"}}}
+# CHECK: "method": "textDocument/publishDiagnostics",
+# CHECK-NEXT: "params": {
+# CHECK-NEXT: "diagnostics": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "message": "using the result of an assignment as a condition without parentheses",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 37,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 32,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "severity": 2
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "uri": "file://{{.*}}/foo.c"
+# CHECK-NEXT: }
+---
+# No command name
+{"jsonrpc":"2.0","id":3,"method":"workspace/executeCommand","params":{}}
+---
+# Invalid, non-scalar command name
+{"jsonrpc":"2.0","id":4,"method":"workspace/executeCommand","params":{"command": {}}}
+---
+{"jsonrpc":"2.0","id":5,"method":"workspace/executeCommand","params":{"command":"clangd.applyFix","custom":"foo", "arguments":[{"changes":{"test:///foo.c":[{"range":{"start":{"line":0,"character":32},"end":{"line":0,"character":32}},"newText":"("},{"range":{"start":{"line":0,"character":37},"end":{"line":0,"character":37}},"newText":")"}]}}]}}
+---
+# Arguments not a sequence.
+{"jsonrpc":"2.0","id":6,"method":"workspace/executeCommand","params":{"command":"clangd.applyFix","arguments":"foo"}}
+---
+# Unknown command.
+{"jsonrpc":"2.0","id":7,"method":"workspace/executeCommand","params":{"command":"mycommand"}}
+---
+# ApplyFix argument not a mapping node.
+{"jsonrpc":"2.0","id":8,"method":"workspace/executeCommand","params":{"command":"clangd.applyFix","custom":"foo", "arguments":[""]}}
+---
+# Custom field in WorkspaceEdit
+{"jsonrpc":"2.0","id":9,"method":"workspace/executeCommand","params":{"command":"clangd.applyFix","arguments":[{"custom":"foo", "changes":{"test:///foo.c":[{"range":{"start":{"line":0,"character":32},"end":{"line":0,"character":32}},"newText":"("},{"range":{"start":{"line":0,"character":37},"end":{"line":0,"character":37}},"newText":")"}]}}]}}
+---
+# changes in WorkspaceEdit with no mapping node
+{"jsonrpc":"2.0","id":10,"method":"workspace/executeCommand","params":{"command":"clangd.applyFix","arguments":[{"changes":"foo"}]}}
+---
+# Custom field in WorkspaceEditChange
+{"jsonrpc":"2.0","id":11,"method":"workspace/executeCommand","params":{"command":"clangd.applyFix","arguments":[{"changes":{"test:///foo.c":[{"range":{"start":{"line":0,"character":32},"end":{"line":0,"character":32}},"newText":"("},{"range":{"start":{"line":0,"character":37},"end":{"line":0,"character":37}},"newText":")"}], "custom":"foo"}}]}}
+---
+# No sequence node for TextEdits
+{"jsonrpc":"2.0","id":12,"method":"workspace/executeCommand","params":{"command":"clangd.applyFix","arguments":[{"changes":{"test:///foo.c":"bar"}}]}}
+---
+# No mapping node for TextEdit
+{"jsonrpc":"2.0","id":13,"method":"workspace/executeCommand","params":{"command":"clangd.applyFix","arguments":[{"changes":{"test:///foo.c":[""]}}]}}
+---
+# TextEdit not decoded
+{"jsonrpc":"2.0","id":14,"method":"workspace/executeCommand","params":{"command":"clangd.applyFix","arguments":[{"changes":{"test:///foo.c":[{"range":{"start":{"line":0,"character":32},"end":{"line":0,"character":32}},"newText":"("},{"range":"","newText":")"}]}}]}}
+---
+# Command name after arguments
+{"jsonrpc":"2.0","id":9,"method":"workspace/executeCommand","params":{"arguments":[{"custom":"foo", "changes":{"test:///foo.c":[{"range":{"start":{"line":0,"character":32},"end":{"line":0,"character":32}},"newText":"("},{"range":{"start":{"line":0,"character":37},"end":{"line":0,"character":37}},"newText":")"}]}}],"command":"clangd.applyFix"}}
+---
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/extra-flags.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/extra-flags.test
new file mode 100644
index 0000000..f360cca
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/extra-flags.test
@@ -0,0 +1,52 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///foo.c","languageId":"c","version":1,"text":"int main() { int i; return i; }"},"metadata":{"extraFlags":["-Wall"]}}}
+# CHECK: "method": "textDocument/publishDiagnostics",
+# CHECK-NEXT: "params": {
+# CHECK-NEXT: "diagnostics": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "message": "variable 'i' is uninitialized when used here",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 28,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 27,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "severity": 2
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "uri": "file://{{.*}}/foo.c"
+# CHECK-NEXT: }
+---
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///foo.c","version":2},"contentChanges":[{"text":"int main() { int i; return i+1; }"}]}}
+# CHECK: "method": "textDocument/publishDiagnostics",
+# CHECK-NEXT: "params": {
+# CHECK-NEXT: "diagnostics": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "message": "variable 'i' is uninitialized when used here",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 28,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 27,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "severity": 2
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "uri": "file://{{.*}}/foo.c"
+# CHECK-NEXT: }
+---
+{"jsonrpc":"2.0","id":5,"method":"shutdown"}
+---
+{"jsonrpc":"2.0":"method":"exit"}
+
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/fixits.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/fixits.test
new file mode 100644
index 0000000..f8eb20c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/fixits.test
@@ -0,0 +1,210 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///foo.c","languageId":"c","version":1,"text":"int main(int i, char **a) { if (i = 2) {}}"}}}
+# CHECK: "method": "textDocument/publishDiagnostics",
+# CHECK-NEXT: "params": {
+# CHECK-NEXT: "diagnostics": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "message": "using the result of an assignment as a condition without parentheses",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 37,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 32,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "severity": 2
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "uri": "file://{{.*}}/foo.c"
+# CHECK-NEXT: }
+---
+{"jsonrpc":"2.0","id":2,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":104,"character":13},"end":{"line":0,"character":35}},"context":{"diagnostics":[{"range":{"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 37}},"severity":2,"message":"using the result of an assignment as a condition without parentheses"}]}}}
+# CHECK: "id": 2,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "arguments": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "changes": {
+# CHECK-NEXT: "file://{{.*}}/foo.c": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "(",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 32,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 32,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": ")",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 37,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 37,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "command": "clangd.applyFix",
+# CHECK-NEXT: "title": "Apply fix: place parentheses around the assignment to silence this warning"
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "arguments": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "changes": {
+# CHECK-NEXT: "file://{{.*}}/foo.c": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "==",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 35,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 34,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "command": "clangd.applyFix",
+# CHECK-NEXT: "title": "Apply fix: use '==' to turn this assignment into an equality comparison"
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+---
+{"jsonrpc":"2.0","id":3,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":104,"character":13},"end":{"line":0,"character":35}},"context":{"diagnostics":[{"range":{"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 37}},"severity":2,"message":"using the result of an assignment as a condition without parentheses"}]}}}
+# Make sure unused "code" and "source" fields ignored gracefully
+# CHECK: "id": 3,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "arguments": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "changes": {
+# CHECK-NEXT: "file://{{.*}}/foo.c": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "(",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 32,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 32,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": ")",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 37,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 37,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "command": "clangd.applyFix",
+# CHECK-NEXT: "title": "Apply fix: place parentheses around the assignment to silence this warning"
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "arguments": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "changes": {
+# CHECK-NEXT: "file://{{.*}}/foo.c": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "==",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 35,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 34,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ],
+# CHECK-NEXT: "command": "clangd.applyFix",
+# CHECK-NEXT: "title": "Apply fix: use '==' to turn this assignment into an equality comparison"
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+---
+{"jsonrpc":"2.0","id":4,"method":"workspace/executeCommand","params":{"command":"clangd.applyFix","arguments":[{"changes":{"test:///foo.c":[{"range":{"start":{"line":0,"character":32},"end":{"line":0,"character":32}},"newText":"("},{"range":{"start":{"line":0,"character":37},"end":{"line":0,"character":37}},"newText":")"}]}}]}}
+# CHECK: "id": 4,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": "Fix applied."
+#
+# CHECK: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "method": "workspace/applyEdit",
+# CHECK-NEXT: "params": {
+# CHECK-NEXT: "edit": {
+# CHECK-NEXT: "changes": {
+# CHECK-NEXT: "{{.*}}/foo.c": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "(",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 32,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 32,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": ")",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 37,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 37,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+---
+{"jsonrpc":"2.0","id":4,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/formatting.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/formatting.test
new file mode 100644
index 0000000..8e0ae5b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/formatting.test
@@ -0,0 +1,187 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///foo.c","languageId":"c","version":1,"text":"int foo ( int x ) {\n x = x+1;\n return x;\n }"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/rangeFormatting","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":1,"character":4},"end":{"line":1,"character":12}},"options":{"tabSize":4,"insertSpaces":true}}}
+# CHECK: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "\n ",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 4,
+# CHECK-NEXT: "line": 1
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 19,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": " ",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 9,
+# CHECK-NEXT: "line": 1
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 9,
+# CHECK-NEXT: "line": 1
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": " ",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 10,
+# CHECK-NEXT: "line": 1
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 10,
+# CHECK-NEXT: "line": 1
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "\n ",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 4,
+# CHECK-NEXT: "line": 2
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 12,
+# CHECK-NEXT: "line": 1
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+---
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///foo.c","version":5},"contentChanges":[{"text":"int foo ( int x ) {\n x = x + 1;\n return x;\n }"}]}}
+#
+#
+---
+{"jsonrpc":"2.0","id":2,"method":"textDocument/rangeFormatting","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":1,"character":2},"end":{"line":1,"character":12}},"options":{"tabSize":4,"insertSpaces":true}}}
+# CHECK: "id": 2,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": []
+---
+{"jsonrpc":"2.0","id":3,"method":"textDocument/formatting","params":{"textDocument":{"uri":"test:///foo.c"},"options":{"tabSize":4,"insertSpaces":true}}}
+# CHECK: "id": 3,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 8,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 7,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 10,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 9,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 16,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 15,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "\n",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 4,
+# CHECK-NEXT: "line": 3
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 11,
+# CHECK-NEXT: "line": 2
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+---
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///foo.c","version":9},"contentChanges":[{"text":"int foo(int x) {\n x = x + 1;\n return x;\n}"}]}}
+---
+{"jsonrpc":"2.0","id":4,"method":"textDocument/formatting","params":{"textDocument":{"uri":"test:///foo.c"},"options":{"tabSize":4,"insertSpaces":true}}}
+# CHECK: "id": 4,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": []
+---
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///foo.c","version":5},"contentChanges":[{"text":"int foo ( int x ) {\n x = x + 1;\n return x;\n}"}]}}
+---
+{"jsonrpc":"2.0","id":5,"method":"textDocument/onTypeFormatting","params":{"textDocument":{"uri":"test:///foo.c"},"position":{"line":3,"character":1},"ch":"}","options":{"tabSize":4,"insertSpaces":true}}}
+# CHECK: "id": 5,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 8,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 7,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 10,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 9,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 16,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 15,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+---
+{"jsonrpc":"2.0","id":6,"method":"shutdown"}
+---
+{"jsonrpc":"2.0":"method":"exit"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/hover.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/hover.test
new file mode 100644
index 0000000..8f1ead0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/hover.test
@@ -0,0 +1,24 @@
+# RUN: clangd -lit-test < %s | FileCheck %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"void foo(); int main() { foo(); }\n"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":27}}}
+# CHECK: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "contents": {
+# CHECK-NEXT: "kind": "plaintext",
+# CHECK-NEXT: "value": "Declared in global namespace\n\nvoid foo()"
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT:}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":10}}}
+# CHECK: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": null
+---
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/initialize-params-invalid.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/initialize-params-invalid.test
new file mode 100644
index 0000000..99c04c6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/initialize-params-invalid.test
@@ -0,0 +1,46 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+# Test with invalid initialize request parameters
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":"","rootUri":"test:///workspace","capabilities":{},"trace":"off"}}
+# CHECK: "id": 0,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "capabilities": {
+# CHECK-NEXT: "codeActionProvider": true,
+# CHECK-NEXT: "completionProvider": {
+# CHECK-NEXT: "resolveProvider": false,
+# CHECK-NEXT: "triggerCharacters": [
+# CHECK-NEXT: ".",
+# CHECK-NEXT: ">",
+# CHECK-NEXT: ":"
+# CHECK-NEXT: ]
+# CHECK-NEXT: },
+# CHECK-NEXT: "definitionProvider": true,
+# CHECK-NEXT: "documentFormattingProvider": true,
+# CHECK-NEXT: "documentHighlightProvider": true,
+# CHECK-NEXT: "documentOnTypeFormattingProvider": {
+# CHECK-NEXT: "firstTriggerCharacter": "}",
+# CHECK-NEXT: "moreTriggerCharacter": []
+# CHECK-NEXT: },
+# CHECK-NEXT: "documentRangeFormattingProvider": true,
+# CHECK-NEXT: "documentSymbolProvider": true,
+# CHECK-NEXT: "executeCommandProvider": {
+# CHECK-NEXT: "commands": [
+# CHECK-NEXT: "clangd.applyFix"
+# CHECK-NEXT: ]
+# CHECK-NEXT: },
+# CHECK-NEXT: "hoverProvider": true,
+# CHECK-NEXT: "renameProvider": true,
+# CHECK-NEXT: "signatureHelpProvider": {
+# CHECK-NEXT: "triggerCharacters": [
+# CHECK-NEXT: "(",
+# CHECK-NEXT: ","
+# CHECK-NEXT: ]
+# CHECK-NEXT: },
+# CHECK-NEXT: "textDocumentSync": 2,
+# CHECK-NEXT: "workspaceSymbolProvider": true
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+---
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/initialize-params.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/initialize-params.test
new file mode 100644
index 0000000..a04d70a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/initialize-params.test
@@ -0,0 +1,49 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+# Test initialize request parameters with rootUri
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootUri":"test:///workspace","capabilities":{},"trace":"off"}}
+# CHECK: "id": 0,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "capabilities": {
+# CHECK-NEXT: "codeActionProvider": true,
+# CHECK-NEXT: "completionProvider": {
+# CHECK-NEXT: "resolveProvider": false,
+# CHECK-NEXT: "triggerCharacters": [
+# CHECK-NEXT: ".",
+# CHECK-NEXT: ">",
+# CHECK-NEXT: ":"
+# CHECK-NEXT: ]
+# CHECK-NEXT: },
+# CHECK-NEXT: "definitionProvider": true,
+# CHECK-NEXT: "documentFormattingProvider": true,
+# CHECK-NEXT: "documentHighlightProvider": true,
+# CHECK-NEXT: "documentOnTypeFormattingProvider": {
+# CHECK-NEXT: "firstTriggerCharacter": "}",
+# CHECK-NEXT: "moreTriggerCharacter": []
+# CHECK-NEXT: },
+# CHECK-NEXT: "documentRangeFormattingProvider": true,
+# CHECK-NEXT: "documentSymbolProvider": true,
+# CHECK-NEXT: "executeCommandProvider": {
+# CHECK-NEXT: "commands": [
+# CHECK-NEXT: "clangd.applyFix"
+# CHECK-NEXT: ]
+# CHECK-NEXT: },
+# CHECK-NEXT: "hoverProvider": true,
+# CHECK-NEXT: "renameProvider": true,
+# CHECK-NEXT: "signatureHelpProvider": {
+# CHECK-NEXT: "triggerCharacters": [
+# CHECK-NEXT: "(",
+# CHECK-NEXT: ","
+# CHECK-NEXT: ]
+# CHECK-NEXT: },
+# CHECK-NEXT: "textDocumentSync": 2,
+# CHECK-NEXT: "workspaceSymbolProvider": true
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+---
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+# CHECK: "id": 3,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": null
+---
+{"jsonrpc":"2.0":"method":"exit"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/input-mirror.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/input-mirror.test
new file mode 100644
index 0000000..88409c4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/input-mirror.test
@@ -0,0 +1,14 @@
+# RUN: clangd -pretty -run-synchronously -input-mirror-file %t < %s
+# Note that we have to use '-b' as -input-mirror-file does not have a newline at the end of file.
+# RUN: diff -b %t %s
+# It is absolutely vital that this file has CRLF line endings.
+#
+Content-Length: 125
+
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+Content-Length: 172
+
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"int main() {\nint a;\na;\n}\n"}}}
+Content-Length: 44
+
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/lit.local.cfg b/src/third_party/llvm-project/clang-tools-extra/test/clangd/lit.local.cfg
new file mode 100644
index 0000000..ef338c7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/lit.local.cfg
@@ -0,0 +1,6 @@
+import re
+# We rely on the default -std being derived from the filetype.
+# PS4 sets a different -std, and many tests break.
+# FIXME: make our tests less brittle instead.
+if re.match(r'.*-scei-ps4', config.target_triple):
+ config.unsupported = True
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/protocol.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/protocol.test
new file mode 100644
index 0000000..7295ca5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/protocol.test
@@ -0,0 +1,110 @@
+# RUN: not clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s
+# RUN: not clangd -pretty -run-synchronously < %s 2>&1 | FileCheck -check-prefix=STDERR %s
+# vim: fileformat=dos
+# It is absolutely vital that this file has CRLF line endings.
+#
+# Note that we invert the test because we intent to let clangd exit prematurely.
+#
+# Test protocol parsing
+Content-Length: 125
+Content-Type: application/vscode-jsonrpc; charset-utf-8
+
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+# Test message with Content-Type after Content-Length
+#
+# CHECK: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK: }
+Content-Length: 246
+
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"struct fake { int a, bb, ccc; int f(int i, const float f) const; };\nint main() {\n fake f;\n f.\n}\n"}}}
+
+Content-Length: 104
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///main.cpp"}}}
+
+Content-Type: application/vscode-jsonrpc; charset-utf-8
+Content-Length: 146
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
+# Test message with Content-Type before Content-Length
+#
+# CHECK: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "isIncomplete": false,
+# CHECK-NEXT: "items": [
+# CHECK: "filterText": "a",
+# CHECK-NEXT: "insertText": "a",
+# CHECK-NEXT: "insertTextFormat": 1,
+# CHECK-NEXT: "kind": 5,
+# CHECK-NEXT: "label": " a",
+# CHECK-NEXT: "sortText": "{{.*}}"
+# CHECK: ]
+# CHECK-NEXT: }
+
+X-Test: Testing
+Content-Type: application/vscode-jsonrpc; charset-utf-8
+Content-Length: 146
+Content-Type: application/vscode-jsonrpc; charset-utf-8
+X-Testing: Test
+
+{"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
+
+Content-Type: application/vscode-jsonrpc; charset-utf-8
+Content-Length: 10
+Content-Length: 146
+
+{"jsonrpc":"2.0","id":3,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
+# Test message with duplicate Content-Length headers
+#
+# CHECK: "id": 3,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "isIncomplete": false,
+# CHECK-NEXT: "items": [
+# CHECK: "filterText": "a",
+# CHECK-NEXT: "insertText": "a",
+# CHECK-NEXT: "insertTextFormat": 1,
+# CHECK-NEXT: "kind": 5,
+# CHECK-NEXT: "label": " a",
+# CHECK-NEXT: "sortText": "{{.*}}"
+# CHECK: ]
+# CHECK-NEXT: }
+# STDERR: Warning: Duplicate Content-Length header received. The previous value for this message (10) was ignored.
+
+Content-Type: application/vscode-jsonrpc; charset-utf-8
+Content-Length: 10
+
+{"jsonrpc":"2.0","id":4,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
+# Test message with malformed Content-Length
+#
+# STDERR: JSON parse error
+# Ensure we recover by sending another (valid) message
+
+Content-Length: 146
+
+{"jsonrpc":"2.0","id":5,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
+# Test message with Content-Type before Content-Length
+#
+# CHECK: "id": 5,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "isIncomplete": false,
+# CHECK-NEXT: "items": [
+# CHECK: "filterText": "a",
+# CHECK-NEXT: "insertText": "a",
+# CHECK-NEXT: "insertTextFormat": 1,
+# CHECK-NEXT: "kind": 5,
+# CHECK-NEXT: "label": " a",
+# CHECK-NEXT: "sortText": "{{.*}}"
+# CHECK: ]
+# CHECK-NEXT: }
+Content-Length: 1024
+
+{"jsonrpc":"2.0","id":5,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
+# Test message which reads beyond the end of the stream.
+#
+# Ensure this is the last test in the file!
+# STDERR: Input was aborted. Read only {{[0-9]+}} bytes of expected {{[0-9]+}}.
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/rename.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/rename.test
new file mode 100644
index 0000000..991cf21
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/rename.test
@@ -0,0 +1,39 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///foo.cpp","languageId":"cpp","version":1,"text":"int foo;"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/rename","params":{"textDocument":{"uri":"test:///foo.cpp"},"position":{"line":0,"character":5},"newName":"bar"}}
+# CHECK: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "changes": {
+# CHECK-NEXT: "file://{{.*}}/foo.cpp": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "newText": "bar",
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 7
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 4
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+---
+{"jsonrpc":"2.0","id":2,"method":"textDocument/rename","params":{"textDocument":{"uri":"test:///foo.cpp"},"position":{"line":0,"character":2},"newName":"bar"}}
+# CHECK: "error": {
+# CHECK-NEXT: "code": -32603,
+# CHECK-NEXT: "message": "clang diagnostic"
+# CHECK-NEXT: },
+# CHECK-NEXT: "id": 2,
+# CHECK-NEXT: "jsonrpc": "2.0"
+---
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/shutdown-with-exit.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/shutdown-with-exit.test
new file mode 100644
index 0000000..b247529
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/shutdown-with-exit.test
@@ -0,0 +1,4 @@
+# RUN: clangd -lit-test < %s
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+---
+{"jsonrpc":"2.0":"method":"exit"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/shutdown-without-exit.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/shutdown-without-exit.test
new file mode 100644
index 0000000..a3e86e9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/shutdown-without-exit.test
@@ -0,0 +1,2 @@
+# RUN: not clangd -lit-test < %s
+{"jsonrpc":"2.0":"method":"exit"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/signature-help.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/signature-help.test
new file mode 100644
index 0000000..f13f49c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/signature-help.test
@@ -0,0 +1,25 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+# Start a session.
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"void x(int);\nint main(){\nx("}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/signatureHelp","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":2,"character":2}}}
+# CHECK: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": {
+# CHECK-NEXT: "activeParameter": 0,
+# CHECK-NEXT: "activeSignature": 0,
+# CHECK-NEXT: "signatures": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "label": "x(int) -> void",
+# CHECK-NEXT: "parameters": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "label": "int"
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+---
+{"jsonrpc":"2.0","id":100000,"method":"shutdown"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/spaces-in-delimited-input.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/spaces-in-delimited-input.test
new file mode 100644
index 0000000..63e3e0b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/spaces-in-delimited-input.test
@@ -0,0 +1,13 @@
+# RUN: clangd -input-style=delimited -run-synchronously < %s 2>&1 | FileCheck %s
+# RUN: clangd -lit-test -run-synchronously < %s 2>&1 | FileCheck %s
+#
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+
+---
+
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+
+---
+
+{"jsonrpc":"2.0","id":3,"method":"exit"}
+# CHECK-NOT: JSON parse error
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/symbols.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/symbols.test
new file mode 100644
index 0000000..5b07f8f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/symbols.test
@@ -0,0 +1,84 @@
+# RUN: env CPATH=%S/Inputs clangd -lit-test < %s | FileCheck %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{"workspace":{"symbol":{"symbolKind":{"valueSet": [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]}}}},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"#include <sstream.h>\nvoid foo(); int main() { foo(); }\n"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"workspace/symbol","params":{"query":"std::basic_ostringstream"}}
+# CHECK: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "containerName": "std",
+# CHECK-NEXT: "kind": 5,
+# CHECK-NEXT: "location": {
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": {{.*}},
+# CHECK-NEXT: "line": {{.*}}
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": {{.*}},
+# CHECK-NEXT: "line": {{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "uri": "file://{{.*}}/sstream.h"
+# CHECK-NEXT: },
+# CHECK-NEXT: "name": "basic_ostringstream"
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT:}
+---
+{"jsonrpc":"2.0","id":2,"method":"textDocument/documentSymbol","params":{"textDocument":{"uri":"test:///main.cpp"}}}
+# CHECK: "id": 2,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "containerName": "",
+# CHECK-NEXT: "kind": 12,
+# CHECK-NEXT: "location": {
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": {{.*}},
+# CHECK-NEXT: "line": {{.*}}
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": {{.*}},
+# CHECK-NEXT: "line": {{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "uri": "file://{{.*}}/main.cpp"
+# CHECK-NEXT: },
+# CHECK-NEXT: "name": "foo"
+# CHECK-NEXT: }
+# CHECK-NEXT: {
+# CHECK-NEXT: "containerName": "",
+# CHECK-NEXT: "kind": 12,
+# CHECK-NEXT: "location": {
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": {{.*}},
+# CHECK-NEXT: "line": {{.*}}
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": {{.*}},
+# CHECK-NEXT: "line": {{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "uri": "file://{{.*}}/main.cpp"
+# CHECK-NEXT: },
+# CHECK-NEXT: "name": "main"
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT:}
+---
+{"jsonrpc":"2.0","id":3,"method":"textDocument/documentSymbol","params":{"textDocument":{"uri":"test:///foo.cpp"}}}
+# CHECK: "error": {
+# CHECK-NEXT: "code": -32602,
+# CHECK-NEXT: "message": "trying to get AST for non-added document"
+# CHECK-NEXT: },
+# CHECK-NEXT: "id": 3,
+# CHECK-NEXT: "jsonrpc": "2.0"
+---
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/test-uri-posix.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/test-uri-posix.test
new file mode 100644
index 0000000..15cc09f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/test-uri-posix.test
@@ -0,0 +1,11 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+# UNSUPPORTED: mingw32,win32
+# Test authority-less URI
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///foo.c","languageId":"c","version":1,"text":"void main() {}"}}}
+# CHECK: "uri": "file:///clangd-test/foo.c"
+---
+{"jsonrpc":"2.0","id":5,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/test-uri-windows.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/test-uri-windows.test
new file mode 100644
index 0000000..7ec290e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/test-uri-windows.test
@@ -0,0 +1,11 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+# REQUIRES: mingw32 || win32
+# Test authority-less URI
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///foo.c","languageId":"c","version":1,"text":"void main() {}"}}}
+# CHECK: "uri": "file:///C:/clangd-test/foo.c"
+---
+{"jsonrpc":"2.0","id":5,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/textdocument-didchange-fail.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/textdocument-didchange-fail.test
new file mode 100644
index 0000000..3bd01e9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/textdocument-didchange-fail.test
@@ -0,0 +1,37 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+# RUN: clangd -lit-test -pch-storage=memory < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"int main() {}\n"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":6}}}
+# CHECK: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 8,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 4,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "uri": "file://{{.*}}/clangd-test/main.cpp"
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+---
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///main.cpp"},"contentChanges":[{"range":{"start":{"line":100,"character":0},"end":{"line":100,"character":0}},"text": "foo"}]}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":6}}}
+# CHECK: "error": {
+# CHECK-NEXT: "code": -32602,
+# CHECK-NEXT: "message": "trying to get AST for non-added document"
+# CHECK-NEXT: },
+# CHECK-NEXT: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0"
+# CHECK-NEXT:}
+---
+{"jsonrpc":"2.0","id":4,"method":"shutdown"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/too_large.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/too_large.test
new file mode 100644
index 0000000..7b846c3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/too_large.test
@@ -0,0 +1,7 @@
+# RUN: not clangd -run-synchronously < %s 2>&1 | FileCheck -check-prefix=STDERR %s
+# vim: fileformat=dos
+# It is absolutely vital that this file has CRLF line endings.
+#
+Content-Length: 2147483648
+
+# STDERR: Refusing to read message
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/trace.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/trace.test
new file mode 100644
index 0000000..9036128
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/trace.test
@@ -0,0 +1,23 @@
+# RUN: env CLANGD_TRACE=%t clangd -lit-test < %s && FileCheck %s < %t
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///foo.c","languageId":"c","version":1,"text":"void main() {}"}}}
+# These assertions are a bit loose, to avoid brittleness.
+# CHECK: {"displayTimeUnit":"ns","traceEvents":[
+# CHECK: {
+# CHECK: "args": {
+# CHECK: "File": "{{.*(/|\\)}}foo.c"
+# CHECK: },
+# CHECK: "name": "BuildPreamble",
+# CHECK: "ph": "X",
+# CHECK: }
+# CHECK: {
+# CHECK: "args": {
+# CHECK: "File": "{{.*(/|\\)}}foo.c"
+# CHECK: },
+# CHECK: "name": "BuildAST",
+# CHECK: "ph": "X",
+# CHECK: }
+# CHECK: },
+---
+{"jsonrpc":"2.0","id":5,"method":"shutdown"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/unsupported-method.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/unsupported-method.test
new file mode 100644
index 0000000..7737b4f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/unsupported-method.test
@@ -0,0 +1,16 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":""}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/jumpInTheAirLikeYouJustDontCare","params":{}}
+# CHECK: "error": {
+# CHECK-NEXT: "code": -32601,
+# CHECK-NEXT: "message": "method not found"
+# CHECK-NEXT: },
+# CHECK-NEXT: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0"
+---
+{"jsonrpc":"2.0","id":2,"method":"shutdown"}
+---
+{"jsonrpc":"2.0":"method":"exit"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/clangd/xrefs.test b/src/third_party/llvm-project/clang-tools-extra/test/clangd/xrefs.test
new file mode 100644
index 0000000..f2e17c4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/clangd/xrefs.test
@@ -0,0 +1,57 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"int x = 0;\nint y = x;"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":1,"character":8}}}
+# CHECK: "id": 1,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 5,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 4,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: "uri": "file://{{.*}}/{{([A-Z]:/)?}}main.cpp"
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/documentHighlight","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":1,"character":8}}}
+# CHECK: "id": 1
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": [
+# CHECK-NEXT: {
+# CHECK-NEXT: "kind": 1,
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 5,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 4,
+# CHECK-NEXT: "line": 0
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: },
+# CHECK-NEXT: {
+# CHECK-NEXT: "kind": 2,
+# CHECK-NEXT: "range": {
+# CHECK-NEXT: "end": {
+# CHECK-NEXT: "character": 9,
+# CHECK-NEXT: "line": 1
+# CHECK-NEXT: },
+# CHECK-NEXT: "start": {
+# CHECK-NEXT: "character": 8,
+# CHECK-NEXT: "line": 1
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+---
+{"jsonrpc":"2.0","id":10000,"method":"shutdown"}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/Inputs/database_template.json b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/Inputs/database_template.json
new file mode 100644
index 0000000..ec71c56
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/Inputs/database_template.json
@@ -0,0 +1,7 @@
+[
+{
+ "directory": "test_dir/build",
+ "command": "clang++ -I../include -o bar.o test_dir/src/bar.cpp",
+ "file": "test_dir/src/bar.cpp"
+}
+]
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/Inputs/fake_yaml_db.yaml b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/Inputs/fake_yaml_db.yaml
new file mode 100644
index 0000000..b599005
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/Inputs/fake_yaml_db.yaml
@@ -0,0 +1,71 @@
+---
+Name: foo
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+ - ContextType: Namespace
+ ContextName: b
+FilePath: foo.h
+Type: Class
+Seen: 1
+Used: 0
+---
+Name: foo_bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+ - ContextType: Namespace
+ ContextName: b
+FilePath: foobar.h
+Type: Class
+Seen: 0
+Used: 0
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+ - ContextType: Namespace
+ ContextName: b
+FilePath: ../include/bar.h
+Type: Class
+Seen: 1
+Used: 0
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+ - ContextType: Namespace
+ ContextName: b
+FilePath: ../include/bar.h
+Type: Class
+Seen: 3
+Used: 0
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+ - ContextType: Namespace
+ ContextName: b
+FilePath: ../include/zbar.h
+Type: Class
+Seen: 3
+Used: 0
+---
+Name: b
+Contexts:
+FilePath: var.h
+Type: Variable
+Seen: 1
+Used: 0
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: c
+FilePath: test/include-fixer/baz.h
+Type: Class
+Seen: 1
+Used: 0
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/Inputs/merge/a.yaml b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/Inputs/merge/a.yaml
new file mode 100644
index 0000000..174db0e5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/Inputs/merge/a.yaml
@@ -0,0 +1,20 @@
+---
+Name: foo
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+FilePath: foo.h
+Type: Class
+Seen: 1
+Used: 1
+...
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+FilePath: ../include/bar.h
+Type: Class
+Seen: 1
+Used: 2
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/Inputs/merge/b.yaml b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/Inputs/merge/b.yaml
new file mode 100644
index 0000000..8689320
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/Inputs/merge/b.yaml
@@ -0,0 +1,20 @@
+---
+Name: foo
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+FilePath: foo.h
+Type: Class
+Seen: 1
+Used: 2
+...
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+FilePath: ../include/barbar.h
+Type: Class
+Seen: 1
+Used: 0
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/commandline_options.cpp b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/commandline_options.cpp
new file mode 100644
index 0000000..3cc77b4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/commandline_options.cpp
@@ -0,0 +1,15 @@
+// RUN: echo "foo f;" > %t.cpp
+// RUN: clang-include-fixer -db=fixed -input='foo= "foo.h","bar.h"' -output-headers %t.cpp -- | FileCheck %s
+// RUN: cat %t.cpp | clang-include-fixer -stdin -insert-header='{FilePath: "%/t.cpp", QuerySymbolInfos: [{RawIdentifier: foo, Range: {Offset: 0, Length: 3}}], HeaderInfos: [{Header: "\"foo.h\"", QualifiedName: "foo"}]}' %t.cpp | FileCheck %s -check-prefix=CHECK-CODE
+// RUN: cat %t.cpp | not clang-include-fixer -stdin -insert-header='{FilePath: "%/t.cpp", QuerySymbolInfos: [{RawIdentifier: foo, Range: {Offset: 0, Length: 3}}], HeaderInfos: [{Header: "\"foo.h\"", QualifiedName: "foo"},{Header: "\"foo2.h\"", QualifiedName: "foo"}]}' %t.cpp
+// RUN: cat %t.cpp | clang-include-fixer -stdin -insert-header='{FilePath: "%/t.cpp", QuerySymbolInfos: [{RawIdentifier: foo, Range: {Offset: 0, Length: 3}}], HeaderInfos: [{Header: "\"foo.h\"", QualifiedName: "a:foo"},{Header: "\"foo.h\"", QualifiedName: "b:foo"}]}' %t.cpp
+//
+// CHECK: "HeaderInfos": [
+// CHECK-NEXT: {"Header": "\"foo.h\"",
+// CHECK-NEXT: "QualifiedName": "foo"},
+// CHECK-NEXT: {"Header": "\"bar.h\"",
+// CHECK-NEXT: "QualifiedName": "foo"}
+// CHECK-NEXT:]
+//
+// CHECK-CODE: #include "foo.h"
+// CHECK-CODE: foo f;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/exit_on_fatal.cpp b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/exit_on_fatal.cpp
new file mode 100644
index 0000000..fc8c95a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/exit_on_fatal.cpp
@@ -0,0 +1,10 @@
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: not clang-include-fixer -db=fixed -input='foo= "foo.h"' %t.cpp --
+// RUN: FileCheck %s -input-file=%t.cpp
+
+// CHECK-NOT: #include
+// CHECK: #include "doesnotexist.h"
+// CHECK-NEXT: foo f;
+
+#include "doesnotexist.h"
+foo f;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/fixeddb.cpp b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/fixeddb.cpp
new file mode 100644
index 0000000..90068db
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/fixeddb.cpp
@@ -0,0 +1,8 @@
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: clang-include-fixer -db=fixed -input='foo= "foo.h","bar.h"' %t.cpp --
+// RUN: FileCheck %s -input-file=%t.cpp
+
+// CHECK: #include "foo.h"
+// CHECK: foo f;
+
+foo f;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/include_path.cpp b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/include_path.cpp
new file mode 100644
index 0000000..28b6ace
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/include_path.cpp
@@ -0,0 +1,19 @@
+// RUN: mkdir -p %T/include-fixer/include
+// RUN: mkdir -p %T/include-fixer/symbols
+// RUN: mkdir -p %T/include-fixer/build
+// RUN: mkdir -p %T/include-fixer/src
+// RUN: sed 's|test_dir|%/T/include-fixer|g' %S/Inputs/database_template.json > %T/include-fixer/build/compile_commands.json
+// RUN: echo -e '#include "bar.h"\nb::a::bar f;' > %T/include-fixer/src/bar.cpp
+// RUN: echo 'namespace b { namespace a { class bar {}; } }' > %T/include-fixer/include/bar.h
+// RUN: cd %T/include-fixer/build
+// RUN: find-all-symbols -output-dir=%T/include-fixer/symbols -p=. %T/include-fixer/src/bar.cpp
+// RUN: find-all-symbols -merge-dir=%T/include-fixer/symbols %T/include-fixer/build/find_all_symbols.yaml
+// RUN: FileCheck -input-file=%T/include-fixer/build/find_all_symbols.yaml -check-prefix=CHECK-YAML %s
+//
+// RUN: echo 'b::a::bar f;' > %T/include-fixer/src/bar.cpp
+// RUN: clang-include-fixer -db=yaml -input=%T/include-fixer/build/find_all_symbols.yaml -minimize-paths=true -p=. %T/include-fixer/src/bar.cpp
+// RUN: FileCheck -input-file=%T/include-fixer/src/bar.cpp %s
+
+// CHECK-YAML: ..{{[/\\]}}include{{[/\\]}}bar.h
+// CHECK: #include "bar.h"
+// CHECK: b::a::bar f;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/merge.test b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/merge.test
new file mode 100644
index 0000000..cee751b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/merge.test
@@ -0,0 +1,33 @@
+# RUN: find-all-symbols -merge-dir=%S/Inputs/merge %t.merged
+# RUN: sed '/^#/d' %s > %t.golden
+# RUN: diff -u %t.golden %t.merged
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+FilePath: ../include/bar.h
+Type: Class
+Seen: 1
+Used: 1
+...
+---
+Name: bar
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+FilePath: ../include/barbar.h
+Type: Class
+Seen: 1
+Used: 0
+...
+---
+Name: foo
+Contexts:
+ - ContextType: Namespace
+ ContextName: a
+FilePath: foo.h
+Type: Class
+Seen: 2
+Used: 2
+...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/multiple_fixes.cpp b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/multiple_fixes.cpp
new file mode 100644
index 0000000..35a73b4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/multiple_fixes.cpp
@@ -0,0 +1,13 @@
+// REQUIRES: shell
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: mkdir -p %T/include-fixer/multiple-fixes
+// RUN: echo 'foo f;' > %T/include-fixer/multiple-fixes/foo.cpp
+// RUN: echo 'bar b;' > %T/include-fixer/multiple-fixes/bar.cpp
+// RUN: clang-include-fixer -db=fixed -input='foo= "foo.h";bar= "bar.h"' %T/include-fixer/multiple-fixes/*.cpp --
+// RUN: FileCheck -input-file=%T/include-fixer/multiple-fixes/bar.cpp %s -check-prefix=CHECK-BAR
+// RUN: FileCheck -input-file=%T/include-fixer/multiple-fixes/foo.cpp %s -check-prefix=CHECK-FOO
+//
+// CHECK-FOO: #include "foo.h"
+// CHECK-FOO: foo f;
+// CHECK-BAR: #include "bar.h"
+// CHECK-BAR: bar b;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/prefix_variable.cpp b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/prefix_variable.cpp
new file mode 100644
index 0000000..b39cdb8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/prefix_variable.cpp
@@ -0,0 +1,10 @@
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: clang-include-fixer -db=yaml -input=%p/Inputs/fake_yaml_db.yaml %t.cpp --
+// RUN: FileCheck %s -input-file=%t.cpp
+
+// CHECK-NOT: #include
+// CHECK: doesnotexist f;
+
+namespace b {
+doesnotexist f;
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/query_symbol.cpp b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/query_symbol.cpp
new file mode 100644
index 0000000..84c3a23
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/query_symbol.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-include-fixer -db=fixed -input='foo= "foo.h","bar.h"' -query-symbol="foo" test.cpp -- | FileCheck %s
+
+// CHECK: "FilePath": "test.cpp",
+// CHECK-NEXT:"QuerySymbolInfos": [
+// CHECK-NEXT: {"RawIdentifier": "foo",
+// CHECK-NEXT: "Range":{"Offset":0,"Length":0}}
+// CHECK-NEXT:],
+// CHECK-NEXT:"HeaderInfos": [
+// CHECK-NEXT: {"Header": "\"foo.h\"",
+// CHECK-NEXT: "QualifiedName": "foo"},
+// CHECK-NEXT: {"Header": "\"bar.h\"",
+// CHECK-NEXT: "QualifiedName": "foo"}
+// CHECK-NEXT:]
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/ranking.cpp b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/ranking.cpp
new file mode 100644
index 0000000..2dabe16
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/ranking.cpp
@@ -0,0 +1,13 @@
+// RUN: clang-include-fixer -db=yaml -input=%S/Inputs/fake_yaml_db.yaml -output-headers %s -- | FileCheck %s
+// RUN: clang-include-fixer -query-symbol bar -db=yaml -input=%S/Inputs/fake_yaml_db.yaml -output-headers %s -- | FileCheck %s
+
+// CHECK: "HeaderInfos": [
+// CHECK-NEXT: {"Header": "\"test/include-fixer/baz.h\"",
+// CHECK-NEXT: "QualifiedName": "c::bar"},
+// CHECK-NEXT: {"Header": "\"../include/bar.h\"",
+// CHECK-NEXT: "QualifiedName": "b::a::bar"},
+// CHECK-NEXT: {"Header": "\"../include/zbar.h\"",
+// CHECK-NEXT: "QualifiedName": "b::a::bar"}
+// CHECK-NEXT:]
+
+bar b;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/yaml_fuzzy.cpp b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/yaml_fuzzy.cpp
new file mode 100644
index 0000000..705542d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/yaml_fuzzy.cpp
@@ -0,0 +1,9 @@
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: clang-include-fixer -db=fuzzyYaml -input=%p/Inputs/fake_yaml_db.yaml %t.cpp --
+// RUN: FileCheck %s -input-file=%t.cpp
+
+// include-fixer will add the include, but doesn't complete the symbol.
+// CHECK: #include "foobar.h"
+// CHECK: fba f;
+
+b::a::fba f;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/yamldb.cpp b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/yamldb.cpp
new file mode 100644
index 0000000..d17b414
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/yamldb.cpp
@@ -0,0 +1,8 @@
+// RUN: sed -e 's#//.*$##' %s > %t.cpp
+// RUN: clang-include-fixer -db=yaml -input=%p/Inputs/fake_yaml_db.yaml %t.cpp --
+// RUN: FileCheck %s -input-file=%t.cpp
+
+// CHECK: #include "foo.h"
+// CHECK: b::a::foo f;
+
+b::a::foo f;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/yamldb_autodetect.cpp b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/yamldb_autodetect.cpp
new file mode 100644
index 0000000..1997390
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/yamldb_autodetect.cpp
@@ -0,0 +1,11 @@
+// RUN: mkdir -p %T/foo/bar
+// RUN: cp %p/Inputs/fake_yaml_db.yaml %T/find_all_symbols_db.yaml
+// RUN: cd %T/foo
+// RUN: sed -e 's#//.*$##' %s > bar/test.cpp
+// RUN: clang-include-fixer -db=yaml bar/test.cpp --
+// RUN: FileCheck %s -input-file=bar/test.cpp
+
+// CHECK: #include "foo.h"
+// CHECK: b::a::foo f;
+
+b::a::foo f;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/yamldb_plugin.cpp b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/yamldb_plugin.cpp
new file mode 100644
index 0000000..5b6760a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/include-fixer/yamldb_plugin.cpp
@@ -0,0 +1,25 @@
+// REQUIRES: static-analyzer
+// RUN: c-index-test -test-load-source-reparse 2 all %s -Xclang -add-plugin -Xclang clang-include-fixer -fspell-checking -Xclang -plugin-arg-clang-include-fixer -Xclang -input=%p/Inputs/fake_yaml_db.yaml 2>&1 | FileCheck %s
+
+foo f;
+foo g;
+unknown u;
+
+// CHECK: yamldb_plugin.cpp:4:1: error: unknown type name 'foo'; did you mean 'foo'?
+// CHECK: Number FIX-ITs = 1
+// CHECK: FIX-IT: Replace [4:1 - 4:4] with "foo"
+// CHECK: yamldb_plugin.cpp:4:1: note: Add '#include "foo.h"' to provide the missing declaration [clang-include-fixer]
+// CHECK: Number FIX-ITs = 1
+// CHECK: FIX-IT: Insert "#include "foo.h"
+// CHECK: yamldb_plugin.cpp:5:1: error: unknown type name 'foo'; did you mean 'foo'?
+// CHECK: Number FIX-ITs = 1
+// CHECK: FIX-IT: Replace [5:1 - 5:4] with "foo"
+// CHECK: yamldb_plugin.cpp:5:1: note: Add '#include "foo.h"' to provide the missing declaration [clang-include-fixer]
+// CHECK: Number FIX-ITs = 1
+// CHECK: FIX-IT: Insert "#include "foo.h"
+// CHECK: " at 4:1
+// CHECK: yamldb_plugin.cpp:6:1:
+// CHECK: error: unknown type name 'unknown'
+// CHECK: Number FIX-ITs = 0
+// CHECK-NOT: error
+// CHECK-NOT: FIX-IT
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/lit.cfg b/src/third_party/llvm-project/clang-tools-extra/test/lit.cfg
new file mode 100644
index 0000000..4b4718a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/lit.cfg
@@ -0,0 +1,139 @@
+# -*- Python -*-
+
+import os
+import platform
+import re
+import subprocess
+
+import lit.formats
+import lit.util
+
+# Configuration file for the 'lit' test runner.
+
+# name: The name of this test suite.
+config.name = 'Clang Tools'
+
+# Tweak PATH for Win32
+if platform.system() == 'Windows':
+ # Seek sane tools in directories and set to $PATH.
+ path = getattr(config, 'lit_tools_dir', None)
+ path = lit_config.getToolsPath(path,
+ config.environment['PATH'],
+ ['cmp.exe', 'grep.exe', 'sed.exe'])
+ if path is not None:
+ path = os.path.pathsep.join((path,
+ config.environment['PATH']))
+ config.environment['PATH'] = path
+
+# Choose between lit's internal shell pipeline runner and a real shell. If
+# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override.
+use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL")
+if use_lit_shell:
+ # 0 is external, "" is default, and everything else is internal.
+ execute_external = (use_lit_shell == "0")
+else:
+ # Otherwise we default to internal on Windows and external elsewhere, as
+ # bash on Windows is usually very slow.
+ execute_external = (not sys.platform in ['win32'])
+
+# testFormat: The test format to use to interpret tests.
+#
+# For now we require '&&' between commands, until they get globally killed and
+# the test runner updated.
+config.test_format = lit.formats.ShTest(execute_external)
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.c', '.cpp', '.hpp', '.m', '.mm', '.cu', '.ll', '.cl', '.s',
+ '.modularize', '.module-map-checker', '.test']
+
+# Test-time dependencies located in directories called 'Inputs' are excluded
+# from test suites; there won't be any lit tests within them.
+config.excludes = ['Inputs']
+
+# test_source_root: The root path where tests are located.
+config.test_source_root = os.path.dirname(__file__)
+
+# test_exec_root: The root path where tests should be run.
+config.test_exec_root = os.path.join(config.clang_tools_binary_dir, 'test')
+
+# Clear some environment variables that might affect Clang.
+#
+# This first set of vars are read by Clang, but shouldn't affect tests
+# that aren't specifically looking for these features, or are required
+# simply to run the tests at all.
+#
+# FIXME: Should we have a tool that enforces this?
+
+# safe_env_vars = ('TMPDIR', 'TEMP', 'TMP', 'USERPROFILE', 'PWD',
+# 'MACOSX_DEPLOYMENT_TARGET', 'IPHONEOS_DEPLOYMENT_TARGET',
+# 'IOS_SIMULATOR_DEPLOYMENT_TARGET',
+# 'VCINSTALLDIR', 'VC100COMNTOOLS', 'VC90COMNTOOLS',
+# 'VC80COMNTOOLS')
+possibly_dangerous_env_vars = ['COMPILER_PATH', 'RC_DEBUG_OPTIONS',
+ 'CINDEXTEST_PREAMBLE_FILE', 'LIBRARY_PATH',
+ 'CPATH', 'C_INCLUDE_PATH', 'CPLUS_INCLUDE_PATH',
+ 'OBJC_INCLUDE_PATH', 'OBJCPLUS_INCLUDE_PATH',
+ 'LIBCLANG_TIMING', 'LIBCLANG_OBJTRACKING',
+ 'LIBCLANG_LOGGING', 'LIBCLANG_BGPRIO_INDEX',
+ 'LIBCLANG_BGPRIO_EDIT', 'LIBCLANG_NOTHREADS',
+ 'LIBCLANG_RESOURCE_USAGE',
+ 'LIBCLANG_CODE_COMPLETION_LOGGING']
+# Clang/Win32 may refer to %INCLUDE%. vsvarsall.bat sets it.
+if platform.system() != 'Windows':
+ possibly_dangerous_env_vars.append('INCLUDE')
+for name in possibly_dangerous_env_vars:
+ if name in config.environment:
+ del config.environment[name]
+
+# Tweak the PATH to include the tools dir and the scripts dir.
+path = os.path.pathsep.join((
+ config.clang_tools_dir, config.llvm_tools_dir, config.environment['PATH']))
+config.environment['PATH'] = path
+
+path = os.path.pathsep.join((config.clang_libs_dir, config.llvm_libs_dir,
+ config.environment.get('LD_LIBRARY_PATH','')))
+config.environment['LD_LIBRARY_PATH'] = path
+
+# When running under valgrind, we mangle '-vg' onto the end of the triple so we
+# can check it with XFAIL and XTARGET.
+if lit_config.useValgrind:
+ config.target_triple += '-vg'
+
+# Set available features we allow tests to conditionalize on.
+#
+# As of 2011.08, crash-recovery tests still do not pass on FreeBSD.
+if platform.system() not in ['FreeBSD']:
+ config.available_features.add('crash-recovery')
+
+# Shell execution
+if execute_external:
+ config.available_features.add('shell')
+
+# Exclude MSYS due to transforming '/' to 'X:/mingwroot/'.
+if not platform.system() in ['Windows'] or not execute_external:
+ config.available_features.add('shell-preserves-root')
+
+# ANSI escape sequences in non-dumb terminal
+if platform.system() not in ['Windows']:
+ config.available_features.add('ansi-escape-sequences')
+
+if config.clang_staticanalyzer:
+ config.available_features.add('static-analyzer')
+ check_clang_tidy = os.path.join(
+ config.test_source_root, "clang-tidy", "check_clang_tidy.py")
+ config.substitutions.append(
+ ('%check_clang_tidy',
+ '%s %s' % (config.python_executable, check_clang_tidy)) )
+ clang_tidy_diff = os.path.join(
+ config.test_source_root, "..", "clang-tidy", "tool", "clang-tidy-diff.py")
+ config.substitutions.append(
+ ('%clang_tidy_diff',
+ '%s %s' % (config.python_executable, clang_tidy_diff)) )
+ run_clang_tidy = os.path.join(
+ config.test_source_root, "..", "clang-tidy", "tool", "run-clang-tidy.py")
+ config.substitutions.append(
+ ('%run_clang_tidy',
+ '%s %s' % (config.python_executable, run_clang_tidy)) )
+else:
+ # exclude the clang-tidy test directory
+ config.excludes.append('clang-tidy')
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/lit.site.cfg.in b/src/third_party/llvm-project/clang-tools-extra/test/lit.site.cfg.in
new file mode 100644
index 0000000..948e469
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/lit.site.cfg.in
@@ -0,0 +1,29 @@
+@LIT_SITE_CFG_IN_HEADER@
+
+import sys
+
+config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
+config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
+config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
+config.clang_tools_binary_dir = "@CLANG_TOOLS_BINARY_DIR@"
+config.clang_tools_dir = "@CLANG_TOOLS_DIR@"
+config.clang_libs_dir = "@SHLIBDIR@"
+config.python_executable = "@PYTHON_EXECUTABLE@"
+config.target_triple = "@TARGET_TRIPLE@"
+config.clang_staticanalyzer = @CLANG_ENABLE_STATIC_ANALYZER@
+
+# Support substitution of the tools and libs dirs with user parameters. This is
+# used when we can't determine the tool dir at configuration time.
+try:
+ config.clang_tools_dir = config.clang_tools_dir % lit_config.params
+ config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
+ config.llvm_libs_dir = config.llvm_libs_dir % lit_config.params
+except KeyError:
+ e = sys.exc_info()[1]
+ key, = e.args
+ lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+
+@LIT_SITE_CFG_IN_FOOTER@
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@CLANG_TOOLS_SOURCE_DIR@/test/lit.cfg")
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/Anonymous.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/Anonymous.h
new file mode 100644
index 0000000..8388eca
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/Anonymous.h
@@ -0,0 +1,11 @@
+// Exercise some anonymous type issues.
+
+// Anonymous enum.
+enum {
+ Tag1
+};
+
+// Anonymous enum typedef.
+typedef enum {
+ Tag2
+} AnonymousEnum;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CompileError/HasError.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CompileError/HasError.h
new file mode 100644
index 0000000..4395cb1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CompileError/HasError.h
@@ -0,0 +1,2 @@
+typedef WithoutDep BadType;
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CompileError/Level1A.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CompileError/Level1A.h
new file mode 100644
index 0000000..10eef67
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CompileError/Level1A.h
@@ -0,0 +1 @@
+#define MACRO_1A 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CompileError/module.modulemap b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CompileError/module.modulemap
new file mode 100644
index 0000000..fbb8e7d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CompileError/module.modulemap
@@ -0,0 +1,10 @@
+// module.map
+
+module Level1A {
+ header "Level1A.h"
+ export *
+}
+module HasError {
+ header "HasError.h"
+ export *
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/Includes1/.hidden/DontFindMe.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/Includes1/.hidden/DontFindMe.h
new file mode 100644
index 0000000..f60b66c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/Includes1/.hidden/DontFindMe.h
@@ -0,0 +1,3 @@
+#error DontFindMe.h shouldn't be found.
+
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/Includes1/Level1A.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/Includes1/Level1A.h
new file mode 100644
index 0000000..10eef67
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/Includes1/Level1A.h
@@ -0,0 +1 @@
+#define MACRO_1A 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/Includes2/Level2A.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/Includes2/Level2A.h
new file mode 100644
index 0000000..9a355df
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/Includes2/Level2A.h
@@ -0,0 +1 @@
+#define MACRO_2A 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/NonIncludes/Level3A.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/NonIncludes/Level3A.h
new file mode 100644
index 0000000..594e284
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/NonIncludes/Level3A.h
@@ -0,0 +1 @@
+#define MACRO_3A 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/module.modulemap b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/module.modulemap
new file mode 100644
index 0000000..d2b0957
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageNoProblems/module.modulemap
@@ -0,0 +1,10 @@
+// module.map
+
+module Level1A {
+ header "Includes1/Level1A.h"
+ export *
+}
+module Level2A {
+ header "Includes2/Level2A.h"
+ export *
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level1A.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level1A.h
new file mode 100644
index 0000000..165efc7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level1A.h
@@ -0,0 +1,2 @@
+#include "Level2A.h"
+#define MACRO_1A 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level1B.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level1B.h
new file mode 100644
index 0000000..1e60798
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level1B.h
@@ -0,0 +1,2 @@
+#include "Level2B.h"
+#define MACRO_1B 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level2A.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level2A.h
new file mode 100644
index 0000000..9a355df
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level2A.h
@@ -0,0 +1 @@
+#define MACRO_2A 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level2B.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level2B.h
new file mode 100644
index 0000000..25b7017
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level2B.h
@@ -0,0 +1 @@
+#define MACRO_2B 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level3A.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level3A.h
new file mode 100644
index 0000000..1699061
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level3A.h
@@ -0,0 +1,2 @@
+#include "Sub/Level3B.h"
+#define MACRO_3A 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level3B b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level3B
new file mode 100644
index 0000000..e1eee7e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Level3B
@@ -0,0 +1 @@
+#define MACRO_3B 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Sub/Level3B.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Sub/Level3B.h
new file mode 100644
index 0000000..e1eee7e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/Sub/Level3B.h
@@ -0,0 +1 @@
+#define MACRO_3B 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaFile.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaFile.h
new file mode 100644
index 0000000..5417a42
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaFile.h
@@ -0,0 +1,3 @@
+#define UMBRELLA_HEADER 1
+#include "UmbrellaInclude1.h"
+#include "UmbrellaInclude2.h"
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaInclude1.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaInclude1.h
new file mode 100644
index 0000000..adf82cb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaInclude1.h
@@ -0,0 +1 @@
+#define UMBRELLA_INCLUDE_1 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaInclude2.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaInclude2.h
new file mode 100644
index 0000000..a3875ab
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaInclude2.h
@@ -0,0 +1 @@
+#define UMBRELLA_INCLUDE_2 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaSub/Umbrell1.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaSub/Umbrell1.h
new file mode 100644
index 0000000..719c223
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaSub/Umbrell1.h
@@ -0,0 +1 @@
+#define UMBRELLA_1 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaSub/Umbrell2.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaSub/Umbrell2.h
new file mode 100644
index 0000000..8efec99
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/UmbrellaSub/Umbrell2.h
@@ -0,0 +1 @@
+#define UMBRELLA_2 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/module.modulemap b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/module.modulemap
new file mode 100644
index 0000000..dbe0bb8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/CoverageProblems/module.modulemap
@@ -0,0 +1,30 @@
+// module.map
+
+module Level1A {
+ header "Level1A.h"
+ export *
+}
+module Level1B {
+ header "Level1B.h"
+ export *
+ module Level2B {
+ header "Level2B.h"
+ export *
+ }
+}
+module Level2A {
+ header "Level2A.h"
+ export *
+}
+module UmbrellaDirectoryModule {
+ umbrella "UmbrellaSub"
+}
+module UmbrellaHeaderModule {
+ umbrella header "UmbrellaFile.h"
+}
+/*
+module NoHeader {
+ header "NoHeader.h"
+ export *
+}
+*/
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/DuplicateHeader1.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/DuplicateHeader1.h
new file mode 100644
index 0000000..2936b08
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/DuplicateHeader1.h
@@ -0,0 +1,2 @@
+// Same decl as in DuplicateHeader2.h.
+typedef int TypeInt;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/DuplicateHeader2.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/DuplicateHeader2.h
new file mode 100644
index 0000000..cef0ffe
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/DuplicateHeader2.h
@@ -0,0 +1,2 @@
+// Same decl as in DuplicateHeader1.h.
+typedef int TypeInt;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/Empty.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/Empty.h
new file mode 100644
index 0000000..d74d27d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/Empty.h
@@ -0,0 +1 @@
+// Empty header for testing #include directives in blocks.
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuard.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuard.h
new file mode 100644
index 0000000..64d7476
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuard.h
@@ -0,0 +1,6 @@
+#ifndef _HEADERGUARD_H_
+#define _HEADERGUARD_H_
+#include "HeaderGuardSub1.h"
+#include "HeaderGuardSub2.h"
+#include "HeaderGuardSubSub.h"
+#endif // _HEADERGUARD_H_
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuardSub1.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuardSub1.h
new file mode 100644
index 0000000..36ad80c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuardSub1.h
@@ -0,0 +1,5 @@
+#ifndef _HEADERGUARDSUB1_H_
+#define _HEADERGUARDSUB1_H_
+#include "HeaderGuardSubSub.h"
+#include "HeaderGuardSubSubDefined.h"
+#endif // _HEADERGUARDSUB1_H_
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuardSub2.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuardSub2.h
new file mode 100644
index 0000000..4098c8e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuardSub2.h
@@ -0,0 +1,5 @@
+#ifndef _HEADERGUARDSUB2_H_
+#define _HEADERGUARDSUB2_H_
+#include "HeaderGuardSubSub.h"
+#include "HeaderGuardSubSubDefined.h"
+#endif // _HEADERGUARDSUB2_H_
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuardSubSub.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuardSubSub.h
new file mode 100644
index 0000000..3f230d2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuardSubSub.h
@@ -0,0 +1,9 @@
+#ifndef _HEADERGUARDSUBSUB_H_
+#define _HEADERGUARDSUBSUB_H_
+
+#define SOMETHING 1
+
+// Nest include. Header guard should not confuse modularize.
+#include "HeaderGuard.h"
+
+#endif // _HEADERGUARDSUBSUB_H_
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuardSubSubDefined.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuardSubSubDefined.h
new file mode 100644
index 0000000..5f0cc62
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/HeaderGuardSubSubDefined.h
@@ -0,0 +1,9 @@
+#if !defined(_HEADERGUARDSUBSUBDEFINED_H_)
+#define _HEADERGUARDSUBSUBDEFINED_H_
+
+#define SOMETHING_OTHER 1
+
+// Nest include. Header guard should not confuse modularize.
+#include "HeaderGuard.h"
+
+#endif // _HEADERGUARDSUBSUBDEFINED_H_
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/IncludeInExtern.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/IncludeInExtern.h
new file mode 100644
index 0000000..da7de8f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/IncludeInExtern.h
@@ -0,0 +1,3 @@
+extern "C" {
+ #include "Empty.h"
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/IncludeInNamespace.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/IncludeInNamespace.h
new file mode 100644
index 0000000..2122528
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/IncludeInNamespace.h
@@ -0,0 +1,3 @@
+namespace MyNamespace {
+ #include "Empty.h"
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/InconsistentHeader1.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/InconsistentHeader1.h
new file mode 100644
index 0000000..7dfcca9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/InconsistentHeader1.h
@@ -0,0 +1,4 @@
+// Define symbol such that a declaration exists when this header
+// is included, but not when InconsistentHeader2.h is included.
+#define SYMBOL1 1
+#include "InconsistentSubHeader.h"
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/InconsistentHeader2.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/InconsistentHeader2.h
new file mode 100644
index 0000000..a2bcae1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/InconsistentHeader2.h
@@ -0,0 +1,3 @@
+// Set up so the declaration in InconsistentSubHeader.h is not defined.
+#define SYMBOL2 1
+#include "InconsistentSubHeader.h"
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/InconsistentSubHeader.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/InconsistentSubHeader.h
new file mode 100644
index 0000000..f87ea65
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/InconsistentSubHeader.h
@@ -0,0 +1,18 @@
+// Set up so TypeInt only defined during InconsistentHeader1.h include.
+#ifdef SYMBOL1
+#define SYMBOL 1
+#define FUNC_STYLE(a, b) a||b
+#endif
+#ifdef SYMBOL2
+#define SYMBOL 2
+#define FUNC_STYLE(a, b) a&&b
+#endif
+
+#if SYMBOL == 1
+typedef int TypeInt;
+#endif
+
+int var = FUNC_STYLE(1, 0);
+
+#if defined(SYMBOL1)
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/IsDependent.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/IsDependent.h
new file mode 100644
index 0000000..4928110
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/IsDependent.h
@@ -0,0 +1,4 @@
+// This header depends on SomeTypes.h for the TypeInt typedef.
+
+typedef TypeInt NewTypeInt;
+typedef OtherTypeInt OtherNewTypeInt;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/MissingHeader/Level1A.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/MissingHeader/Level1A.h
new file mode 100644
index 0000000..10eef67
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/MissingHeader/Level1A.h
@@ -0,0 +1 @@
+#define MACRO_1A 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/MissingHeader/module.modulemap b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/MissingHeader/module.modulemap
new file mode 100644
index 0000000..daa06fc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/MissingHeader/module.modulemap
@@ -0,0 +1,10 @@
+// module.map
+
+module Level1A {
+ header "Level1A.h"
+ export *
+}
+module Missing {
+ header "Missing.h"
+ export *
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/NamespaceClasses.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/NamespaceClasses.h
new file mode 100644
index 0000000..57e6091
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/NamespaceClasses.h
@@ -0,0 +1,20 @@
+// Define same class name in different namespaces.
+
+namespace Namespace1 {
+ class NamespaceClass {
+ public:
+ NamespaceClass() : Member(0) {}
+ private:
+ int Member;
+ };
+}
+
+namespace Namespace2 {
+ class NamespaceClass {
+ public:
+ NamespaceClass() : Member(0) {}
+ private:
+ int Member;
+ };
+}
+
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/NestedMacro.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/NestedMacro.h
new file mode 100644
index 0000000..2cfc92c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/NestedMacro.h
@@ -0,0 +1,5 @@
+// Verification of fix for nested macro.
+
+#define FUNCMACROINNER(a) a
+#define FUNCMACROOUTER(b, c) FUNCMACROINNER(b) + FUNCMACROINNER(c)
+int FuncMacroValue = FUNCMACROOUTER(1, 2);
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/NoProblems.modulemap b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/NoProblems.modulemap
new file mode 100644
index 0000000..82029c1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/NoProblems.modulemap
@@ -0,0 +1,9 @@
+// NoProblems.modulemap
+module SomeTypes {
+ header "SomeTypes.h"
+ export *
+}
+module SomeDecls {
+ header "SomeDecls.h"
+ export *
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/ProblemsDuplicate.modulemap b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/ProblemsDuplicate.modulemap
new file mode 100644
index 0000000..ff1d2f5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/ProblemsDuplicate.modulemap
@@ -0,0 +1,9 @@
+// ProblemsDuplicate.modulemap
+module DuplicateHeader1 {
+ header "DuplicateHeader1.h"
+ export *
+}
+module DuplicateHeader2 {
+ header "DuplicateHeader2.h"
+ export *
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SomeDecls.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SomeDecls.h
new file mode 100644
index 0000000..8892b65
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SomeDecls.h
@@ -0,0 +1,16 @@
+// Declare a couple of functions - no modules problems.
+
+void FuncOne();
+
+int FuncTwo(int arg);
+
+void FuncOverload(int arg) {}
+void FuncOverload(char *arg) {}
+
+namespace Namespace1 {
+ void FuncNameSpace() {}
+}
+
+namespace Namespace2 {
+ void FuncNameSpace() {}
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SomeOtherTypes.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SomeOtherTypes.h
new file mode 100644
index 0000000..288faff
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SomeOtherTypes.h
@@ -0,0 +1,4 @@
+// Declare another type for the dependency check.
+// This file dependent on SomeTypes.h being included first.
+
+typedef TypeInt OtherTypeInt;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SomeTypes.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SomeTypes.h
new file mode 100644
index 0000000..46c4316
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SomeTypes.h
@@ -0,0 +1,16 @@
+// Define a few different kinds of types - no modules problems.
+
+typedef int TypeInt;
+
+typedef TypeInt NestedTypeInt;
+
+struct TypeStruct {
+ int Member;
+};
+
+class TypeClass {
+public:
+ TypeClass() : Member(0) {}
+private:
+ int Member;
+};
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SubModule1/Header1.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SubModule1/Header1.h
new file mode 100644
index 0000000..ea89f0f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SubModule1/Header1.h
@@ -0,0 +1 @@
+// Header1.h - Empty.
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SubModule1/Header2.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SubModule1/Header2.h
new file mode 100644
index 0000000..7c71e98
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SubModule1/Header2.h
@@ -0,0 +1 @@
+// Header2.h - Empty.
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SubModule2/Header3.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SubModule2/Header3.h
new file mode 100644
index 0000000..bb56afa
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SubModule2/Header3.h
@@ -0,0 +1 @@
+// Header3.h - Empty.
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SubModule2/Header4.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SubModule2/Header4.h
new file mode 100644
index 0000000..07ec951
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/SubModule2/Header4.h
@@ -0,0 +1 @@
+// Header4.h - Empty.
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/TemplateClasses.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/TemplateClasses.h
new file mode 100644
index 0000000..3eab6d9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/Inputs/TemplateClasses.h
@@ -0,0 +1,15 @@
+// Exercise some template issues. Should not produce errors.
+
+// Forward declaration.
+template<class T> class TemplateClass;
+
+// Full declaration.
+template<class T>class TemplateClass {
+public:
+ TemplateClass() {}
+private:
+ T Member;
+};
+
+// Template alias.
+template<class T> using TemplateClassAlias = TemplateClass<T>;
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblems.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblems.modularize
new file mode 100644
index 0000000..b3cc36b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblems.modularize
@@ -0,0 +1,6 @@
+# RUN: modularize %s -x c++
+# RUN: modularize -prefix=%p %s -x c++
+# RUN: modularize -no-coverage-check %S/Inputs/NoProblems.modulemap -x c++
+
+Inputs/SomeTypes.h
+Inputs/SomeDecls.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsAnonymous.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsAnonymous.modularize
new file mode 100644
index 0000000..20b1898
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsAnonymous.modularize
@@ -0,0 +1,3 @@
+# RUN: modularize %s -x c++
+
+Inputs/Anonymous.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsAssistant.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsAssistant.modularize
new file mode 100644
index 0000000..7ddc726
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsAssistant.modularize
@@ -0,0 +1,50 @@
+# RUN: modularize -module-map-path=Output/NoProblemsAssistant.txt -root-module=Root -prefix=%S/Input %s
+# RUN: FileCheck --input-file=%T/NoProblemsAssistant.txt %s
+
+SomeTypes.h
+SomeDecls.h
+SubModule1/Header1.h
+SubModule1/Header2.h
+SubModule2/Header3.h
+SubModule2/Header4.h
+SubModule2/Header5-dash.dot.h
+SubModule2.h
+
+# CHECK: // Output/NoProblemsAssistant.txt
+# CHECK-NEXT: // Generated by: modularize -module-map-path=Output/NoProblemsAssistant.txt -root-module=Root -prefix={{.*}}{{[/\\]}}{{.*}} {{.*}}{{[/\\]}}NoProblemsAssistant.modularize
+# CHECK: module Root {
+# CHECK-NEXT: module SomeTypes {
+# CHECK-NEXT: header "SomeTypes.h"
+# CHECK-NEXT: export *
+# CHECK-NEXT: }
+# CHECK-NEXT: module SomeDecls {
+# CHECK-NEXT: header "SomeDecls.h"
+# CHECK-NEXT: export *
+# CHECK-NEXT: }
+# CHECK-NEXT: module SubModule1 {
+# CHECK-NEXT: module Header1 {
+# CHECK-NEXT: header "SubModule1/Header1.h"
+# CHECK-NEXT: export *
+# CHECK-NEXT: }
+# CHECK-NEXT: module Header2 {
+# CHECK-NEXT: header "SubModule1/Header2.h"
+# CHECK-NEXT: export *
+# CHECK-NEXT: }
+# CHECK-NEXT: }
+# CHECK-NEXT: module SubModule2 {
+# CHECK-NEXT: module Header3 {
+# CHECK-NEXT: header "SubModule2/Header3.h"
+# CHECK-NEXT: export *
+# CHECK-NEXT: }
+# CHECK-NEXT: module Header4 {
+# CHECK-NEXT: header "SubModule2/Header4.h"
+# CHECK-NEXT: export *
+# CHECK-NEXT: }
+# CHECK-NEXT: module Header5_dash_dot {
+# CHECK-NEXT: header "SubModule2/Header5-dash.dot.h"
+# CHECK-NEXT: export *
+# CHECK-NEXT: }
+# CHECK-NEXT: header "SubModule2.h"
+# CHECK-NEXT: export *
+# CHECK-NEXT: }
+# CHECK-NEXT: }
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsCoverage.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsCoverage.modularize
new file mode 100644
index 0000000..bcb06f8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsCoverage.modularize
@@ -0,0 +1 @@
+# RUN: modularize -I Includes1 -I Includes2 %S/Inputs/CoverageNoProblems/module.modulemap
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsDependencies.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsDependencies.modularize
new file mode 100644
index 0000000..bd5292b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsDependencies.modularize
@@ -0,0 +1,3 @@
+# RUN: modularize %s -x c++
+
+Inputs/IsDependent.h: Inputs/SomeTypes.h Inputs/SomeOtherTypes.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsGuard.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsGuard.modularize
new file mode 100644
index 0000000..a5a80f0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsGuard.modularize
@@ -0,0 +1,5 @@
+# RUN: modularize %s -x c++
+
+Inputs/HeaderGuardSub1.h
+Inputs/HeaderGuardSub2.h
+Inputs/HeaderGuard.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsList.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsList.modularize
new file mode 100644
index 0000000..39261ce
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsList.modularize
@@ -0,0 +1,2 @@
+# RUN: modularize %S/NoProblems.modularize,%S/NoProblemsAnonymous.modularize -x c++
+# RUN: modularize -prefix=%p %S/NoProblems.modularize,%S/NoProblemsAnonymous.modularize -x c++
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsNamespace.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsNamespace.modularize
new file mode 100644
index 0000000..93a4fea
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsNamespace.modularize
@@ -0,0 +1,3 @@
+# RUN: modularize -block-check-header-list-only %s
+
+Inputs/IncludeInNamespace.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsNamespaceClasses.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsNamespaceClasses.modularize
new file mode 100644
index 0000000..1d02c78
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsNamespaceClasses.modularize
@@ -0,0 +1,3 @@
+# RUN: modularize %s -x c++
+
+Inputs/NamespaceClasses.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsNestedMacro.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsNestedMacro.modularize
new file mode 100644
index 0000000..a1c627d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsNestedMacro.modularize
@@ -0,0 +1,3 @@
+# RUN: modularize %s -x c++
+
+Inputs/NestedMacro.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsTemplateClasses.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsTemplateClasses.modularize
new file mode 100644
index 0000000..d41c43c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/NoProblemsTemplateClasses.modularize
@@ -0,0 +1,3 @@
+# RUN: modularize %s -x c++
+
+Inputs/TemplateClasses.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsCompileError.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsCompileError.modularize
new file mode 100644
index 0000000..a7ad298
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsCompileError.modularize
@@ -0,0 +1,3 @@
+# RUN: not modularize %S/Inputs/CompileError/module.modulemap 2>&1 | FileCheck %s
+
+# CHECK: {{.*}}{{[/\\]}}Inputs{{[/\\]}}CompileError{{[/\\]}}HasError.h:1:9: error: unknown type name 'WithoutDep'
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsCoverage.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsCoverage.modularize
new file mode 100644
index 0000000..5a1c348
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsCoverage.modularize
@@ -0,0 +1,5 @@
+# RUN: not modularize %S/Inputs/CoverageProblems/module.modulemap 2>&1 | FileCheck %s
+
+# CHECK: warning: {{.*}}{{[/\\]}}Inputs/CoverageProblems/module.modulemap does not account for file: {{.*}}{{[/\\]}}Inputs/CoverageProblems/Level3A.h
+# CHECK-NEXT: warning: {{.*}}{{[/\\]}}Inputs/CoverageProblems/module.modulemap does not account for file: {{.*}}{{[/\\]}}Inputs/CoverageProblems/Level3B
+# CHECK-NEXT: warning: {{.*}}{{[/\\]}}Inputs/CoverageProblems/module.modulemap does not account for file: {{.*}}{{[/\\]}}Inputs/CoverageProblems/Sub/Level3B.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsDisplayLists.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsDisplayLists.modularize
new file mode 100644
index 0000000..31be95c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsDisplayLists.modularize
@@ -0,0 +1,16 @@
+# RUN: not modularize -display-file-lists %S/Inputs/CompileError/module.modulemap 2>&1 | FileCheck %s
+
+# CHECK: {{.*}}{{[/\\]}}Inputs{{[/\\]}}CompileError{{[/\\]}}HasError.h:1:9: error: unknown type name 'WithoutDep'
+
+# CHECK: These are the files with possible errors:
+
+# CHECK: Inputs/CompileError/HasError.h
+
+# CHECK: These are the files with no detected errors:
+
+# CHECK: Inputs/CompileError/Level1A.h
+
+# CHECK: These are the combined files, with problem files preceded by #:
+
+# CHECK: {{.*}}Inputs/CompileError/HasError.h
+# CHECK: Inputs/CompileError/Level1A.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsDuplicate.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsDuplicate.modularize
new file mode 100644
index 0000000..301c9cc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsDuplicate.modularize
@@ -0,0 +1,9 @@
+# RUN: not modularize %s -x c++ 2>&1 | FileCheck %s
+# RUN: not modularize %S/Inputs/ProblemsDuplicate.modulemap -x c++ 2>&1 | FileCheck %s
+
+Inputs/DuplicateHeader1.h
+Inputs/DuplicateHeader2.h
+
+# CHECK: error: value 'TypeInt' defined at multiple locations:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}DuplicateHeader1.h:2:13
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}DuplicateHeader2.h:2:13
\ No newline at end of file
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsExternC.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsExternC.modularize
new file mode 100644
index 0000000..b91d7e5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsExternC.modularize
@@ -0,0 +1,12 @@
+# RUN: not modularize %s -x c++ 2>&1 | FileCheck %s
+
+Inputs/IncludeInExtern.h
+
+# CHECK: {{.*}}{{[/\\]}}Inputs{{[/\\]}}IncludeInExtern.h:2:3:
+# CHECK-NEXT: #include "Empty.h"
+# CHECK-NEXT: ^
+# CHECK-NEXT: error: Include directive within extern "C" {}.
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}IncludeInExtern.h:1:1:
+# CHECK-NEXT: extern "C" {
+# CHECK-NEXT: ^
+# CHECK-NEXT: The "extern "C" {}" block is here.
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsInconsistent.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsInconsistent.modularize
new file mode 100644
index 0000000..04d0b01
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsInconsistent.modularize
@@ -0,0 +1,108 @@
+# RUN: not modularize %s -x c++ 2>&1 | FileCheck %s
+
+Inputs/InconsistentHeader1.h
+Inputs/InconsistentHeader2.h
+
+# CHECK: error: macro 'SYMBOL' defined at multiple locations:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:3:9
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:7:9
+# CHECK-NEXT: error: macro 'FUNC_STYLE' defined at multiple locations:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:4:9
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:8:9
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:15:11:
+# CHECK-NEXT: int var = FUNC_STYLE(1, 0);
+# CHECK-NEXT: ^
+# CHECK-NEXT: error: Macro instance 'FUNC_STYLE(1, 0);' has different values in this header, depending on how it was included.
+# CHECK-NEXT: 'FUNC_STYLE(1, 0);' expanded to: '1||0' with respect to these inclusion paths:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:4:9:
+# CHECK-NEXT: #define FUNC_STYLE(a, b) a||b
+# CHECK-NEXT: ^
+# CHECK-NEXT: Macro defined here.
+# CHECK-NEXT: 'FUNC_STYLE(1, 0);' expanded to: '1&&0' with respect to these inclusion paths:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:8:9:
+# CHECK-NEXT: #define FUNC_STYLE(a, b) a&&b
+# CHECK-NEXT: ^
+# CHECK-NEXT: Macro defined here.
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:11:5:
+# CHECK-NEXT: #if SYMBOL == 1
+# CHECK-NEXT: ^
+# CHECK-NEXT: error: Macro instance 'SYMBOL' has different values in this header, depending on how it was included.
+# CHECK-NEXT: 'SYMBOL' expanded to: '1' with respect to these inclusion paths:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:3:9:
+# CHECK-NEXT: #define SYMBOL 1
+# CHECK-NEXT: ^
+# CHECK-NEXT: Macro defined here.
+# CHECK-NEXT: 'SYMBOL' expanded to: '2' with respect to these inclusion paths:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:7:9:
+# CHECK-NEXT: #define SYMBOL 2
+# CHECK-NEXT: ^
+# CHECK-NEXT: Macro defined here.
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:17:5:
+# CHECK-NEXT: #if defined(SYMBOL1)
+# CHECK-NEXT: ^
+# CHECK-NEXT: error: Macro instance 'defined(SYMBOL1)' has different values in this header, depending on how it was included.
+# CHECK-NEXT: 'defined(SYMBOL1)' expanded to: 'true' with respect to these inclusion paths:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h:3:9:
+# CHECK-NEXT: #define SYMBOL1 1
+# CHECK-NEXT: ^
+# CHECK-NEXT: Macro defined here.
+# CHECK-NEXT: 'defined(SYMBOL1)' expanded to: 'false' with respect to these inclusion paths:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
+# CHECK-NEXT: (no macro definition)
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:11:2
+# CHECK-NEXT: #if SYMBOL == 1
+# CHECK-NEXT: ^
+# CHECK-NEXT: error: Conditional expression instance 'SYMBOL == 1' has different values in this header, depending on how it was included.
+# CHECK-NEXT: 'SYMBOL == 1' expanded to: 'true' with respect to these inclusion paths:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
+# CHECK-NEXT: 'SYMBOL == 1' expanded to: 'false' with respect to these inclusion paths:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:2:2
+# CHECK-NEXT: #ifdef SYMBOL1
+# CHECK-NEXT: ^
+# CHECK-NEXT: error: Conditional expression instance 'SYMBOL1' has different values in this header, depending on how it was included.
+# CHECK-NEXT: 'SYMBOL1' expanded to: 'true' with respect to these inclusion paths:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
+# CHECK-NEXT: 'SYMBOL1' expanded to: 'false' with respect to these inclusion paths:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:6:2
+# CHECK-NEXT: #ifdef SYMBOL2
+# CHECK-NEXT: ^
+# CHECK-NEXT: error: Conditional expression instance 'SYMBOL2' has different values in this header, depending on how it was included.
+# CHECK-NEXT: 'SYMBOL2' expanded to: 'false' with respect to these inclusion paths:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
+# CHECK-NEXT: 'SYMBOL2' expanded to: 'true' with respect to these inclusion paths:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:17:2
+# CHECK-NEXT: #if defined(SYMBOL1)
+# CHECK-NEXT: ^
+# CHECK-NEXT: error: Conditional expression instance 'defined(SYMBOL1)' has different values in this header, depending on how it was included.
+# CHECK-NEXT: 'defined(SYMBOL1)' expanded to: 'true' with respect to these inclusion paths:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
+# CHECK-NEXT: 'defined(SYMBOL1)' expanded to: 'false' with respect to these inclusion paths:
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
+# CHECK-NEXT: error: header '{{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h' has different contents depending on how it was included.
+# CHECK-NEXT: note: 'SYMBOL' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 3:9 not always provided
+# CHECK-NEXT: note: 'FUNC_STYLE' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 4:9 not always provided
+# CHECK-NEXT: note: 'SYMBOL' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 7:9 not always provided
+# CHECK-NEXT: note: 'FUNC_STYLE' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 8:9 not always provided
+# CHECK-NEXT: note: 'TypeInt' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 12:13 not always provided
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsMissingHeader.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsMissingHeader.modularize
new file mode 100644
index 0000000..bc731fb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsMissingHeader.modularize
@@ -0,0 +1,3 @@
+# RUN: not modularize %S/Inputs/MissingHeader/module.modulemap 2>&1 | FileCheck %s
+
+# CHECK: {{.*}}{{[/\\]}}Inputs/MissingHeader/module.modulemap:8:10: error : Header not found: Missing.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsNamespace.modularize b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsNamespace.modularize
new file mode 100644
index 0000000..d4bc353
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/ProblemsNamespace.modularize
@@ -0,0 +1,12 @@
+# RUN: not modularize %s -x c++ 2>&1 | FileCheck %s
+
+Inputs/IncludeInNamespace.h
+
+# CHECK: {{.*}}{{[/\\]}}Inputs{{[/\\]}}IncludeInNamespace.h:2:3:
+# CHECK-NEXT: #include "Empty.h"
+# CHECK-NEXT: ^
+# CHECK-NEXT: error: Include directive within namespace MyNamespace {}.
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}IncludeInNamespace.h:1:1:
+# CHECK-NEXT: namespace MyNamespace {
+# CHECK-NEXT: ^
+# CHECK-NEXT: The "namespace MyNamespace {}" block is here.
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/modularize/SubModule2.h b/src/third_party/llvm-project/clang-tools-extra/test/modularize/SubModule2.h
new file mode 100644
index 0000000..70d711b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/modularize/SubModule2.h
@@ -0,0 +1,3 @@
+// SubModule2.h - Master header with same name as directory.
+#include "SubModule2/Header3.h"
+#include "SubModule2/Header4.h"
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/Level1A.h b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/Level1A.h
new file mode 100644
index 0000000..165efc7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/Level1A.h
@@ -0,0 +1,2 @@
+#include "Level2A.h"
+#define MACRO_1A 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/Level1B.h b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/Level1B.h
new file mode 100644
index 0000000..1e60798
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/Level1B.h
@@ -0,0 +1,2 @@
+#include "Level2B.h"
+#define MACRO_1B 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/Level2A.h b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/Level2A.h
new file mode 100644
index 0000000..9a355df
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/Level2A.h
@@ -0,0 +1 @@
+#define MACRO_2A 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/Level2B.h b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/Level2B.h
new file mode 100644
index 0000000..25b7017
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/Level2B.h
@@ -0,0 +1 @@
+#define MACRO_2B 1
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/ModularizeList.txt b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/ModularizeList.txt
new file mode 100644
index 0000000..8193db6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/ModularizeList.txt
@@ -0,0 +1,4 @@
+Level1A.h
+Level1B.h
+Level2A.h
+Level2B.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/module.map b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/module.map
new file mode 100644
index 0000000..31f33c5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/Inputs/module.map
@@ -0,0 +1,18 @@
+// module.map
+
+module Level1A {
+ header "Level1A.h"
+ export *
+}
+module Level1B {
+ header "Level1B.h"
+ export *
+ module Level2B {
+ header "Level2B.h"
+ export *
+ }
+}
+module Level2A {
+ header "Level2A.h"
+ export *
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-conditional.cpp b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-conditional.cpp
new file mode 100644
index 0000000..ac5d3b3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-conditional.cpp
@@ -0,0 +1,304 @@
+// RUN: pp-trace -ignore FileChanged %s -undef -target x86_64 -std=c++11 | FileCheck --strict-whitespace %s
+
+#if 1
+#endif
+
+#if 0
+#endif
+
+#if 1
+#else
+#endif
+
+#if 0
+#else
+#endif
+
+#if 1
+#elif 1
+#endif
+#if 1
+#elif 0
+#endif
+
+#if 0
+#elif 1
+#endif
+#if 0
+#elif 0
+#endif
+#if 1
+#elif 1
+#endif
+#if 1
+#elif 0
+#endif
+
+#if 0
+#elif 1
+#else
+#endif
+#if 0
+#elif 0
+#else
+#endif
+#if 1
+#elif 1
+#else
+#endif
+#if 1
+#elif 0
+#else
+#endif
+
+#define MACRO 1
+#ifdef MACRO
+#endif
+#ifdef NO_MACRO
+#endif
+#ifndef MACRO
+#endif
+#ifndef NO_MACRO
+#endif
+
+// CHECK: ---
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __STDC__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __STDC_HOSTED__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __cplusplus
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __STDC_UTF_16__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __STDC_UTF_32__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:3:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:3:4", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:4:1"]
+// CHECK-NEXT: ConditionValue: CVK_True
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:4:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:3:2"
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:6:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:6:4", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:7:1"]
+// CHECK-NEXT: ConditionValue: CVK_False
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:7:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:6:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:6:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:7:2"]
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:9:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:9:4", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:10:1"]
+// CHECK-NEXT: ConditionValue: CVK_True
+// CHECK-NEXT: - Callback: Else
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:10:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:9:2"
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:11:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:9:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:10:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:11:2"]
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:13:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:13:4", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:14:1"]
+// CHECK-NEXT: ConditionValue: CVK_False
+// CHECK-NEXT: - Callback: Else
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:14:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:13:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:13:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:14:2"]
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:15:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:13:2"
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:17:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:17:4", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:18:1"]
+// CHECK-NEXT: ConditionValue: CVK_True
+// CHECK-NEXT: - Callback: Elif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:18:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:18:6", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:19:1"]
+// CHECK-NEXT: ConditionValue: CVK_NotEvaluated
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:17:2"
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:19:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:17:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:18:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:19:2"]
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:20:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:20:4", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:21:1"]
+// CHECK-NEXT: ConditionValue: CVK_True
+// CHECK-NEXT: - Callback: Elif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:21:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:21:6", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:22:1"]
+// CHECK-NEXT: ConditionValue: CVK_NotEvaluated
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:20:2"
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:22:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:20:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:21:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:22:2"]
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:24:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:24:4", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:25:1"]
+// CHECK-NEXT: ConditionValue: CVK_False
+// CHECK-NEXT: - Callback: Elif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:25:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:25:6", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:26:1"]
+// CHECK-NEXT: ConditionValue: CVK_True
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:24:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:24:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:25:2"]
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:26:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:24:2"
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:27:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:27:4", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:28:1"]
+// CHECK-NEXT: ConditionValue: CVK_False
+// CHECK-NEXT: - Callback: Elif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:28:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:28:6", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:29:1"]
+// CHECK-NEXT: ConditionValue: CVK_False
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:27:2"
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:29:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:27:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:27:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:29:2"]
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:30:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:30:4", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:31:1"]
+// CHECK-NEXT: ConditionValue: CVK_True
+// CHECK-NEXT: - Callback: Elif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:31:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:31:6", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:32:1"]
+// CHECK-NEXT: ConditionValue: CVK_NotEvaluated
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:30:2"
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:32:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:30:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:31:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:32:2"]
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:33:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:33:4", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:34:1"]
+// CHECK-NEXT: ConditionValue: CVK_True
+// CHECK-NEXT: - Callback: Elif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:34:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:34:6", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:35:1"]
+// CHECK-NEXT: ConditionValue: CVK_NotEvaluated
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:33:2"
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:35:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:33:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:34:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:35:2"]
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:37:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:37:4", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:38:1"]
+// CHECK-NEXT: ConditionValue: CVK_False
+// CHECK-NEXT: - Callback: Elif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:38:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:38:6", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:39:1"]
+// CHECK-NEXT: ConditionValue: CVK_True
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:37:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:37:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:38:2"]
+// CHECK-NEXT: - Callback: Else
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:39:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:37:2"
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:40:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:37:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:39:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:40:2"]
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:41:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:41:4", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:42:1"]
+// CHECK-NEXT: ConditionValue: CVK_False
+// CHECK-NEXT: - Callback: Elif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:42:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:42:6", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:43:1"]
+// CHECK-NEXT: ConditionValue: CVK_False
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:41:2"
+// CHECK-NEXT: - Callback: Else
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:43:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:41:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:41:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:43:2"]
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:44:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:41:2"
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:45:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:45:4", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:46:1"]
+// CHECK-NEXT: ConditionValue: CVK_True
+// CHECK-NEXT: - Callback: Elif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:46:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:46:6", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:47:1"]
+// CHECK-NEXT: ConditionValue: CVK_NotEvaluated
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:45:2"
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:48:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:45:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:46:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:48:2"]
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:49:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:49:4", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:50:1"]
+// CHECK-NEXT: ConditionValue: CVK_True
+// CHECK-NEXT: - Callback: Elif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:50:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:50:6", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:51:1"]
+// CHECK-NEXT: ConditionValue: CVK_NotEvaluated
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:49:2"
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:52:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:49:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:50:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:52:2"]
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK-NEXT: MacroNameTok: MACRO
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: Ifdef
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:55:2"
+// CHECK-NEXT: MacroNameTok: MACRO
+// CHECK-NEXT: MacroDefinition: [(local)]
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:56:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:55:2"
+// CHECK-NEXT: - Callback: Ifdef
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:57:2"
+// CHECK-NEXT: MacroNameTok: NO_MACRO
+// CHECK-NEXT: MacroDefinition: []
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:58:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:57:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:57:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:58:2"]
+// CHECK-NEXT: - Callback: Ifndef
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:59:2"
+// CHECK-NEXT: MacroNameTok: MACRO
+// CHECK-NEXT: MacroDefinition: [(local)]
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:60:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:59:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-conditional.cpp:59:1", "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:60:2"]
+// CHECK-NEXT: - Callback: Ifndef
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:61:2"
+// CHECK-NEXT: MacroNameTok: NO_MACRO
+// CHECK-NEXT: MacroDefinition: []
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:62:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-conditional.cpp:61:2"
+// CHECK-NEXT: - Callback: EndOfMainFile
+// CHECK-NEXT: ...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-ident.cpp b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-ident.cpp
new file mode 100644
index 0000000..9981c39
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-ident.cpp
@@ -0,0 +1,10 @@
+// RUN: pp-trace -ignore FileChanged,MacroDefined %s -undef -target x86_64 -std=c++11 | FileCheck --strict-whitespace %s
+
+#ident "$Id$"
+
+// CHECK: ---
+// CHECK-NEXT: - Callback: Ident
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-ident.cpp:3:2"
+// CHECK-NEXT: Str: "$Id$"
+// CHECK-NEXT: - Callback: EndOfMainFile
+// CHECK-NEXT: ...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-include.cpp b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-include.cpp
new file mode 100644
index 0000000..7d925d8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-include.cpp
@@ -0,0 +1,141 @@
+// RUN: pp-trace %s -undef -target x86_64 -std=c++11 | FileCheck --strict-whitespace %s
+
+#include "Inputs/Level1A.h"
+#include "Inputs/Level1B.h"
+
+// CHECK: ---
+// CHECK-NEXT: - Callback: FileChanged
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-include.cpp:1:1"
+// CHECK-NEXT: Reason: EnterFile
+// CHECK-NEXT: FileType: C_User
+// CHECK-NEXT: PrevFID: (invalid)
+// CHECK-NEXT: - Callback: FileChanged
+// CHECK-NEXT: Loc: "<built-in>:1:1"
+// CHECK-NEXT: Reason: EnterFile
+// CHECK-NEXT: FileType: C_User
+// CHECK-NEXT: PrevFID: (invalid)
+// CHECK-NEXT: - Callback: FileChanged
+// CHECK-NEXT: Loc: "<built-in>:1:1"
+// CHECK-NEXT: Reason: RenameFile
+// CHECK-NEXT: FileType: C_System
+// CHECK-NEXT: PrevFID: (invalid)
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __STDC__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __STDC_HOSTED__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __cplusplus
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __STDC_UTF_16__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __STDC_UTF_32__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK: - Callback: FileChanged
+// CHECK-NEXT: Loc: "<command line>:1:1"
+// CHECK-NEXT: Reason: EnterFile
+// CHECK-NEXT: FileType: C_User
+// CHECK-NEXT: PrevFID: (invalid)
+// CHECK-NEXT: - Callback: FileChanged
+// CHECK-NEXT: Loc: "<built-in>:1:1"
+// CHECK-NEXT: Reason: ExitFile
+// CHECK-NEXT: FileType: C_User
+// CHECK-NEXT: PrevFID: (invalid)
+// CHECK-NEXT: - Callback: FileChanged
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-include.cpp:1:1"
+// CHECK-NEXT: Reason: ExitFile
+// CHECK-NEXT: FileType: C_User
+// CHECK-NEXT: PrevFID: (getFileEntryForID failed)
+// CHECK-NEXT: - Callback: InclusionDirective
+// CHECK-NEXT: IncludeTok: include
+// CHECK-NEXT: FileName: "Inputs/Level1A.h"
+// CHECK-NEXT: IsAngled: false
+// CHECK-NEXT: FilenameRange: "Inputs/Level1A.h"
+// CHECK-NEXT: File: "{{.*}}{{[/\\]}}Inputs/Level1A.h"
+// CHECK-NEXT: SearchPath: "{{.*}}{{[/\\]}}pp-trace"
+// CHECK-NEXT: RelativePath: "Inputs/Level1A.h"
+// CHECK-NEXT: Imported: (null)
+// CHECK-NEXT: - Callback: FileChanged
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}Inputs/Level1A.h:1:1"
+// CHECK-NEXT: Reason: EnterFile
+// CHECK-NEXT: FileType: C_User
+// CHECK-NEXT: PrevFID: (invalid)
+// CHECK-NEXT: - Callback: InclusionDirective
+// CHECK-NEXT: IncludeTok: include
+// CHECK-NEXT: FileName: "Level2A.h"
+// CHECK-NEXT: IsAngled: false
+// CHECK-NEXT: FilenameRange: "Level2A.h"
+// CHECK-NEXT: File: "{{.*}}{{[/\\]}}Inputs/Level2A.h"
+// CHECK-NEXT: SearchPath: "{{.*}}{{[/\\]}}Inputs"
+// CHECK-NEXT: RelativePath: "Level2A.h"
+// CHECK-NEXT: Imported: (null)
+// CHECK-NEXT: - Callback: FileChanged
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}Inputs/Level2A.h:1:1"
+// CHECK-NEXT: Reason: EnterFile
+// CHECK-NEXT: FileType: C_User
+// CHECK-NEXT: PrevFID: (invalid)
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK-NEXT: MacroNameTok: MACRO_2A
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: FileChanged
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}Inputs/Level1A.h:2:1"
+// CHECK-NEXT: Reason: ExitFile
+// CHECK-NEXT: FileType: C_User
+// CHECK-NEXT: PrevFID: "{{.*}}{{[/\\]}}Inputs/Level2A.h"
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK-NEXT: MacroNameTok: MACRO_1A
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: FileChanged
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-include.cpp:4:1"
+// CHECK-NEXT: Reason: ExitFile
+// CHECK-NEXT: FileType: C_User
+// CHECK-NEXT: PrevFID: "{{.*}}{{[/\\]}}Inputs/Level1A.h"
+// CHECK-NEXT: - Callback: InclusionDirective
+// CHECK-NEXT: IncludeTok: include
+// CHECK-NEXT: FileName: "Inputs/Level1B.h"
+// CHECK-NEXT: IsAngled: false
+// CHECK-NEXT: FilenameRange: "Inputs/Level1B.h"
+// CHECK-NEXT: File: "{{.*}}{{[/\\]}}Inputs/Level1B.h"
+// CHECK-NEXT: SearchPath: "{{.*}}{{[/\\]}}pp-trace"
+// CHECK-NEXT: RelativePath: "Inputs/Level1B.h"
+// CHECK-NEXT: Imported: (null)
+// CHECK-NEXT: - Callback: FileChanged
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}Inputs/Level1B.h:1:1"
+// CHECK-NEXT: Reason: EnterFile
+// CHECK-NEXT: FileType: C_User
+// CHECK-NEXT: PrevFID: (invalid)
+// CHECK-NEXT: - Callback: InclusionDirective
+// CHECK-NEXT: IncludeTok: include
+// CHECK-NEXT: FileName: "Level2B.h"
+// CHECK-NEXT: IsAngled: false
+// CHECK-NEXT: FilenameRange: "Level2B.h"
+// CHECK-NEXT: File: "{{.*}}{{[/\\]}}Inputs/Level2B.h"
+// CHECK-NEXT: SearchPath: "{{.*}}{{[/\\]}}Inputs"
+// CHECK-NEXT: RelativePath: "Level2B.h"
+// CHECK-NEXT: Imported: (null)
+// CHECK-NEXT: - Callback: FileChanged
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}Inputs/Level2B.h:1:1"
+// CHECK-NEXT: Reason: EnterFile
+// CHECK-NEXT: FileType: C_User
+// CHECK-NEXT: PrevFID: (invalid)
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK-NEXT: MacroNameTok: MACRO_2B
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: FileChanged
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}Inputs/Level1B.h:2:1"
+// CHECK-NEXT: Reason: ExitFile
+// CHECK-NEXT: FileType: C_User
+// CHECK-NEXT: PrevFID: "{{.*}}{{[/\\]}}Inputs/Level2B.h"
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK-NEXT: MacroNameTok: MACRO_1B
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: FileChanged
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-include.cpp:5:1"
+// CHECK-NEXT: Reason: ExitFile
+// CHECK-NEXT: FileType: C_User
+// CHECK-NEXT: PrevFID: "{{.*}}{{[/\\]}}Inputs/Level1B.h"
+// CHECK-NEXT: - Callback: EndOfMainFile
+// CHECK-NEXT: ...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-macro.cpp b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-macro.cpp
new file mode 100644
index 0000000..e6ba761
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-macro.cpp
@@ -0,0 +1,101 @@
+// RUN: pp-trace -ignore FileChanged %s -undef -target x86_64 -std=c++11 | FileCheck --strict-whitespace %s
+
+#define MACRO 1
+int i = MACRO;
+#if defined(MACRO)
+#endif
+#undef MACRO
+#if defined(MACRO)
+#endif
+#define FUNCMACRO(ARG1) ARG1
+int j = FUNCMACRO(1);
+#define X X_IMPL(a+y,b) X_IMPL2(c)
+#define X_IMPL(p1,p2)
+#define X_IMPL2(p1)
+X
+
+// CHECK: ---
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __STDC__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __STDC_HOSTED__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __cplusplus
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __STDC_UTF_16__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK: MacroNameTok: __STDC_UTF_32__
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK: - Callback: MacroDefined
+// CHECK-NEXT: MacroNameTok: MACRO
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroExpands
+// CHECK-NEXT: MacroNameTok: MACRO
+// CHECK-NEXT: MacroDefinition: [(local)]
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-macro.cpp:4:9", "{{.*}}{{[/\\]}}pp-trace-macro.cpp:4:9"]
+// CHECK-NEXT: Args: (null)
+// CHECK-NEXT: - Callback: Defined
+// CHECK-NEXT: MacroNameTok: MACRO
+// CHECK-NEXT: MacroDefinition: [(local)]
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-macro.cpp:5:5", "{{.*}}{{[/\\]}}pp-trace-macro.cpp:5:19"]
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-macro.cpp:5:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-macro.cpp:5:4", "{{.*}}{{[/\\]}}pp-trace-macro.cpp:6:1"]
+// CHECK-NEXT: ConditionValue: CVK_True
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-macro.cpp:6:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-macro.cpp:5:2"
+// CHECK-NEXT: - Callback: MacroUndefined
+// CHECK-NEXT: MacroNameTok: MACRO
+// CHECK-NEXT: MacroDefinition: [(local)]
+// CHECK-NEXT: - Callback: Defined
+// CHECK-NEXT: MacroNameTok: MACRO
+// CHECK-NEXT: MacroDefinition: []
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-macro.cpp:8:5", "{{.*}}{{[/\\]}}pp-trace-macro.cpp:8:19"]
+// CHECK-NEXT: - Callback: If
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-macro.cpp:8:2"
+// CHECK-NEXT: ConditionRange: ["{{.*}}{{[/\\]}}pp-trace-macro.cpp:8:4", "{{.*}}{{[/\\]}}pp-trace-macro.cpp:9:1"]
+// CHECK-NEXT: ConditionValue: CVK_False
+// CHECK-NEXT: - Callback: Endif
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-macro.cpp:9:2"
+// CHECK-NEXT: IfLoc: "{{.*}}{{[/\\]}}pp-trace-macro.cpp:8:2"
+// CHECK-NEXT: - Callback: SourceRangeSkipped
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-macro.cpp:8:1", "{{.*}}{{[/\\]}}pp-trace-macro.cpp:9:2"]
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK-NEXT: MacroNameTok: FUNCMACRO
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroExpands
+// CHECK-NEXT: MacroNameTok: FUNCMACRO
+// CHECK-NEXT: MacroDefinition: [(local)]
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-macro.cpp:11:9", "{{.*}}{{[/\\]}}pp-trace-macro.cpp:11:20"]
+// CHECK-NEXT: Args: [1]
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK-NEXT: MacroNameTok: X
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK-NEXT: MacroNameTok: X_IMPL
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroDefined
+// CHECK-NEXT: MacroNameTok: X_IMPL2
+// CHECK-NEXT: MacroDirective: MD_Define
+// CHECK-NEXT: - Callback: MacroExpands
+// CHECK-NEXT: MacroNameTok: X
+// CHECK-NEXT: MacroDefinition: [(local)]
+// CHECK-NEXT: Range: ["{{.*}}{{[/\\]}}pp-trace-macro.cpp:15:1", "{{.*}}{{[/\\]}}pp-trace-macro.cpp:15:1"]
+// CHECK-NEXT: Args: (null)
+// CHECK-NEXT: - Callback: MacroExpands
+// CHECK-NEXT: MacroNameTok: X_IMPL
+// CHECK-NEXT: MacroDefinition: [(local)]
+// CHECK-NEXT: Range: [(nonfile), (nonfile)]
+// CHECK-NEXT: Args: [a <plus> y, b]
+// CHECK-NEXT: - Callback: MacroExpands
+// CHECK-NEXT: MacroNameTok: X_IMPL2
+// CHECK-NEXT: MacroDefinition: [(local)]
+// CHECK-NEXT: Range: [(nonfile), (nonfile)]
+// CHECK-NEXT: Args: [c]
+// CHECK-NEXT: - Callback: EndOfMainFile
+// CHECK-NEXT: ...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-modules.cpp b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-modules.cpp
new file mode 100644
index 0000000..5e9e1de
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-modules.cpp
@@ -0,0 +1,20 @@
+// RUN: rm -rf %t
+// RUN: pp-trace -ignore FileChanged,MacroDefined %s -x objective-c++ -undef -target x86_64 -std=c++11 -fmodules -fcxx-modules -fmodules-cache-path=%t -I%S -I%S/Input | FileCheck --strict-whitespace %s
+
+// CHECK: ---
+
+@import Level1A;
+
+// CHECK-NEXT: - Callback: moduleImport
+// CHECK-NEXT: ImportLoc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-3]]:2"
+// CHECK-NEXT: Path: [{Name: Level1A, Loc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-4]]:9"}]
+// CHECK-NEXT: Imported: Level1A
+
+@import Level1B.Level2B;
+
+// CHECK-NEXT: - Callback: moduleImport
+// CHECK-NEXT: ImportLoc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-3]]:2"
+// CHECK-NEXT: Path: [{Name: Level1B, Loc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-4]]:9"}, {Name: Level2B, Loc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-4]]:17"}]
+// CHECK-NEXT: Imported: Level2B
+// CHECK-NEXT: - Callback: EndOfMainFile
+// CHECK-NEXT: ...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-pragma-general.cpp b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-pragma-general.cpp
new file mode 100644
index 0000000..6caef0b
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-pragma-general.cpp
@@ -0,0 +1,118 @@
+// RUN: pp-trace -ignore FileChanged,MacroDefined %s | FileCheck --strict-whitespace %s
+
+#pragma clang diagnostic push
+#pragma clang diagnostic pop
+#pragma clang diagnostic ignored "-Wformat"
+#pragma clang diagnostic warning "-Wformat"
+#pragma clang diagnostic error "-Wformat"
+#pragma clang diagnostic fatal "-Wformat"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic pop
+#pragma GCC diagnostic ignored "-Wformat"
+#pragma GCC diagnostic warning "-Wformat"
+#pragma GCC diagnostic error "-Wformat"
+#pragma GCC diagnostic fatal "-Wformat"
+
+void foo() {
+#pragma clang __debug captured
+{ }
+}
+
+// CHECK: ---
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:3:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDiagnosticPush
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:3:15"
+// CHECK-NEXT: Namespace: clang
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:4:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDiagnosticPop
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:4:15"
+// CHECK-NEXT: Namespace: clang
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:5:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDiagnostic
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:5:15"
+// CHECK-NEXT: Namespace: clang
+// CHECK-NEXT: Mapping: MAP_IGNORE
+// CHECK-NEXT: Str: -Wformat
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:6:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDiagnostic
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:6:15"
+// CHECK-NEXT: Namespace: clang
+// CHECK-NEXT: Mapping: MAP_WARNING
+// CHECK-NEXT: Str: -Wformat
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:7:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDiagnostic
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:7:15"
+// CHECK-NEXT: Namespace: clang
+// CHECK-NEXT: Mapping: MAP_ERROR
+// CHECK-NEXT: Str: -Wformat
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:8:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDiagnostic
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:8:15"
+// CHECK-NEXT: Namespace: clang
+// CHECK-NEXT: Mapping: MAP_FATAL
+// CHECK-NEXT: Str: -Wformat
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:10:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDiagnosticPush
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:10:13"
+// CHECK-NEXT: Namespace: GCC
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:11:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDiagnosticPop
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:11:13"
+// CHECK-NEXT: Namespace: GCC
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:12:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDiagnostic
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:12:13"
+// CHECK-NEXT: Namespace: GCC
+// CHECK-NEXT: Mapping: MAP_IGNORE
+// CHECK-NEXT: Str: -Wformat
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:13:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDiagnostic
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:13:13"
+// CHECK-NEXT: Namespace: GCC
+// CHECK-NEXT: Mapping: MAP_WARNING
+// CHECK-NEXT: Str: -Wformat
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:14:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDiagnostic
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:14:13"
+// CHECK-NEXT: Namespace: GCC
+// CHECK-NEXT: Mapping: MAP_ERROR
+// CHECK-NEXT: Str: -Wformat
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:15:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDiagnostic
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:15:13"
+// CHECK-NEXT: Namespace: GCC
+// CHECK-NEXT: Mapping: MAP_FATAL
+// CHECK-NEXT: Str: -Wformat
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:18:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDebug
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:18:23"
+// CHECK-NEXT: DebugType: captured
+// CHECK-NEXT: - Callback: EndOfMainFile
+// CHECK-NEXT: ...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-pragma-ms.cpp b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-pragma-ms.cpp
new file mode 100644
index 0000000..33c9f7f
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-pragma-ms.cpp
@@ -0,0 +1,100 @@
+// RUN: pp-trace -ignore FileChanged,MacroDefined %s -target x86_64-unknown-windows-msvc -fms-extensions -w | FileCheck --strict-whitespace %s
+
+#pragma comment(compiler, "compiler comment")
+#pragma comment(exestr, "exestr comment")
+#pragma comment(lib, "lib comment")
+#pragma comment(linker, "linker comment")
+#pragma comment(user, "user comment")
+
+#pragma detect_mismatch("name argument", "value argument")
+
+#pragma __debug(assert)
+
+#pragma message("message argument")
+
+#pragma warning(push, 1)
+#pragma warning(pop)
+#pragma warning(disable : 1 2 3 ; error : 4 5 6 ; suppress : 7 8 9)
+
+// CHECK: ---
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:3:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaComment
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:3:9"
+// CHECK-NEXT: Kind: compiler
+// CHECK-NEXT: Str: compiler comment
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:4:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaComment
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:4:9"
+// CHECK-NEXT: Kind: exestr
+// CHECK-NEXT: Str: exestr comment
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:5:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaComment
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:5:9"
+// CHECK-NEXT: Kind: lib
+// CHECK-NEXT: Str: lib comment
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:6:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaComment
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:6:9"
+// CHECK-NEXT: Kind: linker
+// CHECK-NEXT: Str: linker comment
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:7:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaComment
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:7:9"
+// CHECK-NEXT: Kind: user
+// CHECK-NEXT: Str: user comment
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:9:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDetectMismatch
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:9:9"
+// CHECK-NEXT: Name: name argument
+// CHECK-NEXT: Value: value argument
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:11:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:13:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaMessage
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:13:9"
+// CHECK-NEXT: Namespace:
+// CHECK-NEXT: Kind: PMK_Message
+// CHECK-NEXT: Str: message argument
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:15:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaWarningPush
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:15:9"
+// CHECK-NEXT: Level: 1
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:16:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaWarningPop
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:16:9"
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:17:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaWarning
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:17:9"
+// CHECK-NEXT: WarningSpec: disable
+// CHECK-NEXT: Ids: [1, 2, 3]
+// CHECK-NEXT: - Callback: PragmaWarning
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:17:9"
+// CHECK-NEXT: WarningSpec: error
+// CHECK-NEXT: Ids: [4, 5, 6]
+// CHECK-NEXT: - Callback: PragmaWarning
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:17:9"
+// CHECK-NEXT: WarningSpec: suppress
+// CHECK-NEXT: Ids: [7, 8, 9]
+// CHECK-NEXT: - Callback: EndOfMainFile
+// CHECK-NEXT: ...
diff --git a/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-pragma-opencl.cpp b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-pragma-opencl.cpp
new file mode 100644
index 0000000..cfd72c0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/test/pp-trace/pp-trace-pragma-opencl.cpp
@@ -0,0 +1,33 @@
+// RUN: pp-trace -ignore FileChanged,MacroDefined %s -x cl | FileCheck --strict-whitespace %s
+
+#pragma OPENCL EXTENSION all : disable
+#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : disable
+#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable
+
+// CHECK: ---
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-opencl.cpp:3:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaOpenCLExtension
+// CHECK-NEXT: NameLoc: "{{.*}}{{[/\\]}}pp-trace-pragma-opencl.cpp:3:26"
+// CHECK-NEXT: Name: all
+// CHECK-NEXT: StateLoc: "{{.*}}{{[/\\]}}pp-trace-pragma-opencl.cpp:3:32"
+// CHECK-NEXT: State: 0
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-opencl.cpp:4:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaOpenCLExtension
+// CHECK-NEXT: NameLoc: "{{.*}}{{[/\\]}}pp-trace-pragma-opencl.cpp:4:26"
+// CHECK-NEXT: Name: cl_khr_int64_base_atomics
+// CHECK-NEXT: StateLoc: "{{.*}}{{[/\\]}}pp-trace-pragma-opencl.cpp:4:54"
+// CHECK-NEXT: State: 0
+// CHECK-NEXT: - Callback: PragmaDirective
+// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-opencl.cpp:5:1"
+// CHECK-NEXT: Introducer: PIK_HashPragma
+// CHECK-NEXT: - Callback: PragmaOpenCLExtension
+// CHECK-NEXT: NameLoc: "{{.*}}{{[/\\]}}pp-trace-pragma-opencl.cpp:5:26"
+// CHECK-NEXT: Name: cl_khr_int64_base_atomics
+// CHECK-NEXT: StateLoc: "{{.*}}{{[/\\]}}pp-trace-pragma-opencl.cpp:5:54"
+// CHECK-NEXT: State: 1
+// CHECK-NEXT: - Callback: EndOfMainFile
+// CHECK-NEXT: ...
diff --git a/src/third_party/llvm-project/clang-tools-extra/tool-template/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/tool-template/CMakeLists.txt
new file mode 100644
index 0000000..6478157
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/tool-template/CMakeLists.txt
@@ -0,0 +1,17 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_executable(tool-template
+ ToolTemplate.cpp
+ )
+
+target_link_libraries(tool-template
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFrontend
+ clangTooling
+ clangToolingRefactor
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/tool-template/ToolTemplate.cpp b/src/third_party/llvm-project/clang-tools-extra/tool-template/ToolTemplate.cpp
new file mode 100644
index 0000000..5345d77
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/tool-template/ToolTemplate.cpp
@@ -0,0 +1,122 @@
+//===---- tools/extra/ToolTemplate.cpp - Template for refactoring tool ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements an empty refactoring tool using the clang tooling.
+// The goal is to lower the "barrier to entry" for writing refactoring tools.
+//
+// Usage:
+// tool-template <cmake-output-dir> <file1> <file2> ...
+//
+// Where <cmake-output-dir> is a CMake build directory in which a file named
+// compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
+// CMake to get this output).
+//
+// <file1> ... specify the paths of files in the CMake source tree. This path
+// is looked up in the compile command database. If the path of a file is
+// absolute, it needs to point into CMake's source tree. If the path is
+// relative, the current working directory needs to be in the CMake source
+// tree and the file must be in a subdirectory of the current working
+// directory. "./" prefixes in the relative files will be automatically
+// removed, but the rest of a relative path must be a suffix of a path in
+// the compile command line database.
+//
+// For example, to use tool-template on all files in a subtree of the
+// source tree, use:
+//
+// /path/in/subtree $ find . -name '*.cpp'|
+// xargs tool-template /path/to/build
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Execution.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Signals.h"
+
+using namespace clang;
+using namespace clang::ast_matchers;
+using namespace clang::tooling;
+using namespace llvm;
+
+namespace {
+class ToolTemplateCallback : public MatchFinder::MatchCallback {
+public:
+ ToolTemplateCallback(ExecutionContext &Context) : Context(Context) {}
+
+ void run(const MatchFinder::MatchResult &Result) override {
+ // TODO: This routine will get called for each thing that the matchers
+ // find.
+ // At this point, you can examine the match, and do whatever you want,
+ // including replacing the matched text with other text
+ auto *D = Result.Nodes.getNodeAs<NamedDecl>("decl");
+ assert(D);
+ // Use AtomicChange to get a key.
+ if (D->getLocStart().isValid()) {
+ AtomicChange Change(*Result.SourceManager, D->getLocStart());
+ Context.reportResult(Change.getKey(), D->getQualifiedNameAsString());
+ }
+ }
+
+ void onStartOfTranslationUnit() override {
+ Context.reportResult("START", "Start of TU.");
+ }
+ void onEndOfTranslationUnit() override {
+ Context.reportResult("END", "End of TU.");
+ }
+
+private:
+ ExecutionContext &Context;
+};
+} // end anonymous namespace
+
+// Set up the command line options
+static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+static cl::OptionCategory ToolTemplateCategory("tool-template options");
+
+int main(int argc, const char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+
+ auto Executor = clang::tooling::createExecutorFromCommandLineArgs(
+ argc, argv, ToolTemplateCategory);
+
+ if (!Executor) {
+ llvm::errs() << llvm::toString(Executor.takeError()) << "\n";
+ return 1;
+ }
+
+ ast_matchers::MatchFinder Finder;
+ ToolTemplateCallback Callback(*Executor->get()->getExecutionContext());
+
+ // TODO: Put your matchers here.
+ // Use Finder.addMatcher(...) to define the patterns in the AST that you
+ // want to match against. You are not limited to just one matcher!
+ //
+ // This is a sample matcher:
+ Finder.addMatcher(
+ namedDecl(cxxRecordDecl(), isExpansionInMainFile()).bind("decl"),
+ &Callback);
+
+ auto Err = Executor->get()->execute(newFrontendActionFactory(&Finder));
+ if (Err) {
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ }
+ Executor->get()->getToolResults()->forEachResult(
+ [](llvm::StringRef key, llvm::StringRef value) {
+ llvm::errs() << "----" << key.str() << "\n" << value.str() << "\n";
+ });
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/unittests/CMakeLists.txt
new file mode 100644
index 0000000..82f54d5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/CMakeLists.txt
@@ -0,0 +1,25 @@
+add_custom_target(ExtraToolsUnitTests)
+set_target_properties(ExtraToolsUnitTests PROPERTIES FOLDER "Extra Tools Unit Tests")
+
+function(add_extra_unittest test_dirname)
+ add_unittest(ExtraToolsUnitTests ${test_dirname} ${ARGN})
+endfunction()
+
+if(CLANG_BUILT_STANDALONE)
+ # LLVMTestingSupport library is needed for clangd tests.
+ if (EXISTS ${LLVM_MAIN_SRC_DIR}/lib/Testing/Support
+ AND NOT TARGET LLVMTestingSupport)
+ add_subdirectory(${LLVM_MAIN_SRC_DIR}/lib/Testing/Support
+ lib/Testing/Support)
+ endif()
+endif()
+
+add_subdirectory(change-namespace)
+add_subdirectory(clang-apply-replacements)
+add_subdirectory(clang-move)
+add_subdirectory(clang-query)
+if(CLANG_ENABLE_STATIC_ANALYZER)
+ add_subdirectory(clang-tidy)
+endif()
+add_subdirectory(clangd)
+add_subdirectory(include-fixer)
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/change-namespace/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/unittests/change-namespace/CMakeLists.txt
new file mode 100644
index 0000000..3745bbd
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/change-namespace/CMakeLists.txt
@@ -0,0 +1,29 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+get_filename_component(CHANGE_NAMESPACE_SOURCE_DIR
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../change-namespace REALPATH)
+include_directories(
+ ${CHANGE_NAMESPACE_SOURCE_DIR}
+ )
+
+# We'd like clang/unittests/Tooling/RewriterTestContext.h in the test.
+include_directories(${CLANG_SOURCE_DIR})
+
+add_extra_unittest(ChangeNamespaceTests
+ ChangeNamespaceTests.cpp
+ )
+
+target_link_libraries(ChangeNamespaceTests
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangChangeNamespace
+ clangFormat
+ clangFrontend
+ clangRewrite
+ clangTooling
+ clangToolingCore
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/change-namespace/ChangeNamespaceTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/change-namespace/ChangeNamespaceTests.cpp
new file mode 100644
index 0000000..917f7b0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/change-namespace/ChangeNamespaceTests.cpp
@@ -0,0 +1,2249 @@
+//===-- ChangeNamespaceTests.cpp - Change namespace unit tests ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ChangeNamespace.h"
+#include "unittests/Tooling/RewriterTestContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/PCHContainerOperations.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace change_namespace {
+namespace {
+
+class ChangeNamespaceTest : public ::testing::Test {
+public:
+ std::string runChangeNamespaceOnCode(llvm::StringRef Code) {
+ clang::RewriterTestContext Context;
+ clang::FileID ID = Context.createInMemoryFile(FileName, Code);
+
+ std::map<std::string, tooling::Replacements> FileToReplacements;
+ change_namespace::ChangeNamespaceTool NamespaceTool(
+ OldNamespace, NewNamespace, FilePattern,
+ /*WhiteListedSymbolPatterns*/ {}, &FileToReplacements);
+ ast_matchers::MatchFinder Finder;
+ NamespaceTool.registerMatchers(&Finder);
+ std::unique_ptr<tooling::FrontendActionFactory> Factory =
+ tooling::newFrontendActionFactory(&Finder);
+ if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, {"-std=c++11"},
+ FileName))
+ return "";
+ formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite);
+ return format(Context.getRewrittenText(ID));
+ }
+
+ std::string format(llvm::StringRef Code) {
+ tooling::Replacements Replaces = format::reformat(
+ format::getLLVMStyle(), Code, {tooling::Range(0, Code.size())});
+ auto ChangedCode = tooling::applyAllReplacements(Code, Replaces);
+ EXPECT_TRUE(static_cast<bool>(ChangedCode));
+ if (!ChangedCode) {
+ llvm::errs() << llvm::toString(ChangedCode.takeError());
+ return "";
+ }
+ return *ChangedCode;
+ }
+
+protected:
+ std::string FileName = "input.cc";
+ std::string OldNamespace = "na::nb";
+ std::string NewNamespace = "x::y";
+ std::string FilePattern = "input.cc";
+};
+
+TEST_F(ChangeNamespaceTest, NoMatchingNamespace) {
+ std::string Code = "namespace na {\n"
+ "namespace nx {\n"
+ "class A {};\n"
+ "} // namespace nx\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "namespace nx {\n"
+ "class A {};\n"
+ "} // namespace nx\n"
+ "} // namespace na\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, SimpleMoveWithoutTypeRefs) {
+ std::string Code = "namespace na {\n"
+ "namespace nb {\n"
+ "class A {};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "\n\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "class A {};\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, NewNsNestedInOldNs) {
+ NewNamespace = "na::nb::nc";
+ std::string Code = "namespace na {\n"
+ "namespace nb {\n"
+ "class A {};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "namespace nb {\n"
+ "namespace nc {\n"
+ "class A {};\n"
+ "} // namespace nc\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, NewNsNestedInOldNsWithSurroundingNewLines) {
+ NewNamespace = "na::nb::nc";
+ std::string Code = "namespace na {\n"
+ "namespace nb {\n"
+ "\n"
+ "class A {};\n"
+ "\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "namespace nb {\n"
+ "namespace nc {\n"
+ "\n"
+ "class A {};\n"
+ "\n"
+ "} // namespace nc\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, MoveOldNsWithSurroundingNewLines) {
+ NewNamespace = "nx::ny";
+ std::string Code = "namespace na {\n"
+ "namespace nb {\n"
+ "\n"
+ "class A {};\n"
+ "\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "\n\n"
+ "namespace nx {\n"
+ "namespace ny {\n"
+ "\n"
+ "class A {};\n"
+ "\n"
+ "} // namespace ny\n"
+ "} // namespace nx\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, NewNsNestedInOldNsWithRefs) {
+ NewNamespace = "na::nb::nc";
+ std::string Code = "namespace na {\n"
+ "class A {};\n"
+ "namespace nb {\n"
+ "class B {};\n"
+ "class C {};\n"
+ "void f() { A a; B b; }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "class A {};\n"
+ "namespace nb {\n"
+ "namespace nc {\n"
+ "class B {};\n"
+ "class C {};\n"
+ "void f() { A a; B b; }\n"
+ "} // namespace nc\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, SimpleMoveIntoAnotherNestedNamespace) {
+ NewNamespace = "na::nc";
+ std::string Code = "namespace na {\n"
+ "namespace nb {\n"
+ "class A {};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "\n"
+ "namespace nc {\n"
+ "class A {};\n"
+ "} // namespace nc\n"
+ "} // namespace na\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, MoveIntoAnotherNestedNamespaceWithRef) {
+ NewNamespace = "na::nc";
+ std::string Code = "namespace na {\n"
+ "class A {};\n"
+ "namespace nb {\n"
+ "class X { A a; };\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "class A {};\n"
+ "\n"
+ "namespace nc {\n"
+ "class X { A a; };\n"
+ "} // namespace nc\n"
+ "} // namespace na\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, MoveIntoExistingNamespaceAndShortenRefs) {
+ std::string Code = "namespace x {\n"
+ "namespace z {\n"
+ "class Z {};\n"
+ "} // namespace z\n"
+ "namespace y {\n"
+ "class T {};\n"
+ "} // namespace y\n"
+ "} // namespace x\n"
+ "namespace na {\n"
+ "class A{};\n"
+ "namespace nb {\n"
+ "class X { A a; x::z::Z zz; x::y::T t; };\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace x {\n"
+ "namespace z {\n"
+ "class Z {};\n"
+ "} // namespace z\n"
+ "namespace y {\n"
+ "class T {};\n"
+ "} // namespace y\n"
+ "} // namespace x\n"
+ "namespace na {\n"
+ "class A {};\n\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "class X { na::A a; z::Z zz; T t; };\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, SimpleMoveNestedNamespace) {
+ NewNamespace = "na::x::y";
+ std::string Code = "namespace na {\n"
+ "class A {};\n"
+ "namespace nb {\n"
+ "class B {};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "class A {};\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "class B {};\n"
+ "} // namespace y\n"
+ "} // namespace x\n"
+ "} // namespace na\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, SimpleMoveWithTypeRefs) {
+ std::string Code = "namespace na {\n"
+ "class C_A {};\n"
+ "namespace nc {\n"
+ "class C_C {};"
+ "} // namespace nc\n"
+ "namespace nb {\n"
+ "class C_X {\n"
+ "public:\n"
+ " C_A a;\n"
+ " nc::C_C c;\n"
+ "};\n"
+ "class C_Y {\n"
+ " C_X x;\n"
+ "};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "class C_A {};\n"
+ "namespace nc {\n"
+ "class C_C {};"
+ "} // namespace nc\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "class C_X {\n"
+ "public:\n"
+ " na::C_A a;\n"
+ " na::nc::C_C c;\n"
+ "};\n"
+ "class C_Y {\n"
+ " C_X x;\n"
+ "};\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, TypeLocInTemplateSpecialization) {
+ std::string Code = "namespace na {\n"
+ "class A {};\n"
+ "template <typename T>\n"
+ "class B {};\n"
+ "template <typename T1, typename T2>\n"
+ "class Two {};\n"
+ "namespace nc { class C {}; }\n"
+ "} // na\n"
+ "\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() {\n"
+ " B<A> b;\n"
+ " B<nc::C> b_c;\n"
+ " Two<A, nc::C> two;\n"
+ "}\n"
+ "} // nb\n"
+ "} // na\n";
+ std::string Expected = "namespace na {\n"
+ "class A {};\n"
+ "template <typename T>\n"
+ "class B {};\n"
+ "template <typename T1, typename T2>\n"
+ "class Two {};\n"
+ "namespace nc { class C {}; }\n"
+ "} // na\n"
+ "\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() {\n"
+ " na::B<na::A> b;\n"
+ " na::B<na::nc::C> b_c;\n"
+ " na::Two<na::A, na::nc::C> two;\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, LeaveForwardDeclarationBehind) {
+ std::string Code = "namespace na {\n"
+ "namespace nb {\n"
+ "class FWD;\n"
+ "class FWD2;\n"
+ "class A {\n"
+ " FWD *fwd;\n"
+ "};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "namespace nb {\n"
+ "class FWD;\n"
+ "class FWD2;\n"
+ "} // namespace nb\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "\n"
+ "class A {\n"
+ " na::nb::FWD *fwd;\n"
+ "};\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, InsertForwardDeclsProperly) {
+ std::string Code = "namespace na {\n"
+ "namespace nb {\n"
+ "\n"
+ "class FWD;\n"
+ "class FWD2;\n"
+ "class A {\n"
+ " FWD *fwd;\n"
+ "};\n"
+ "\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "namespace nb {\n"
+ "class FWD;\n"
+ "class FWD2;\n"
+ "} // namespace nb\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "\n"
+ "class A {\n"
+ " na::nb::FWD *fwd;\n"
+ "};\n"
+ "\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, TemplateClassForwardDeclaration) {
+ std::string Code = "namespace na {\n"
+ "namespace nb {\n"
+ "class FWD;\n"
+ "template<typename T> class FWD_TEMP;\n"
+ "class A {\n"
+ " FWD *fwd;\n"
+ "};\n"
+ "template<typename T> class TEMP {};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "namespace nb {\n"
+ "class FWD;\n"
+ "template<typename T> class FWD_TEMP;\n"
+ "} // namespace nb\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "\n"
+ "class A {\n"
+ " na::nb::FWD *fwd;\n"
+ "};\n"
+ "template<typename T> class TEMP {};\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, DontMoveForwardDeclarationInClass) {
+ std::string Code = "namespace na {\n"
+ "namespace nb {\n"
+ "class A {\n"
+ " class FWD;\n"
+ " FWD *fwd;\n"
+ " template<typename T> class FWD_TEMP;\n"
+ "};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "\n\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "class A {\n"
+ " class FWD;\n"
+ " FWD *fwd;\n"
+ " template<typename T> class FWD_TEMP;\n"
+ "};\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, MoveFunctions) {
+ std::string Code = "namespace na {\n"
+ "class C_A {};\n"
+ "namespace nc {\n"
+ "class C_C {};"
+ "} // namespace nc\n"
+ "namespace nb {\n"
+ "void fwd();\n"
+ "void f(C_A ca, nc::C_C cc) {\n"
+ " C_A ca_1 = ca;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace na {\n"
+ "class C_A {};\n"
+ "namespace nc {\n"
+ "class C_C {};"
+ "} // namespace nc\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void fwd();\n"
+ "void f(na::C_A ca, na::nc::C_C cc) {\n"
+ " na::C_A ca_1 = ca;\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, FixUsingShadowDecl) {
+ std::string Code = "class GLOB {};\n"
+ "using BLOG = GLOB;\n"
+ "namespace na {\n"
+ "namespace nc {\n"
+ "class SAME {};\n"
+ "}\n"
+ "namespace nd {\n"
+ "class SAME {};\n"
+ "}\n"
+ "namespace nb {\n"
+ "using nc::SAME;\n"
+ "using YO = nd::SAME;\n"
+ "typedef nd::SAME IDENTICAL;\n"
+ "void f(nd::SAME Same) {}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "class GLOB {};\n"
+ "using BLOG = GLOB;\n"
+ "namespace na {\n"
+ "namespace nc {\n"
+ "class SAME {};\n"
+ "}\n"
+ "namespace nd {\n"
+ "class SAME {};\n"
+ "}\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "using ::na::nc::SAME;\n"
+ "using YO = na::nd::SAME;\n"
+ "typedef na::nd::SAME IDENTICAL;\n"
+ "void f(na::nd::SAME Same) {}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, DontFixUsingShadowDeclInClasses) {
+ std::string Code = "namespace na {\n"
+ "class A {};\n"
+ "class Base { public: Base() {} void m() {} };\n"
+ "namespace nb {\n"
+ "class D : public Base {\n"
+ "public:\n"
+ " using AA = A; using B = Base;\n"
+ " using Base::m; using Base::Base;\n"
+ "};"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace na {\n"
+ "class A {};\n"
+ "class Base { public: Base() {} void m() {} };\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "class D : public na::Base {\n"
+ "public:\n"
+ " using AA = na::A; using B = na::Base;\n"
+ " using Base::m; using Base::Base;\n"
+ "};"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, TypeInNestedNameSpecifier) {
+ std::string Code =
+ "namespace na {\n"
+ "class C_A {\n"
+ "public:\n"
+ " class Nested {\n"
+ " public:\n"
+ " static int NestedX;\n"
+ " static void nestedFunc() {}\n"
+ " };\n"
+ "};\n"
+ "namespace nb {\n"
+ "class C_X {\n"
+ " C_A na;\n"
+ " C_A::Nested nested;\n"
+ " void f() {\n"
+ " C_A::Nested::nestedFunc();\n"
+ " int X = C_A::Nested::NestedX;\n"
+ " }\n"
+ "};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected =
+ "namespace na {\n"
+ "class C_A {\n"
+ "public:\n"
+ " class Nested {\n"
+ " public:\n"
+ " static int NestedX;\n"
+ " static void nestedFunc() {}\n"
+ " };\n"
+ "};\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "class C_X {\n"
+ " na::C_A na;\n"
+ " na::C_A::Nested nested;\n"
+ " void f() {\n"
+ " na::C_A::Nested::nestedFunc();\n"
+ " int X = na::C_A::Nested::NestedX;\n"
+ " }\n"
+ "};\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, FixFunctionNameSpecifiers) {
+ std::string Code =
+ "namespace na {\n"
+ "class A {\n"
+ "public:\n"
+ " static void f() {}\n"
+ " static void g();\n"
+ "};\n"
+ "void A::g() {}"
+ "void a_f() {}\n"
+ "static void static_f() {}\n"
+ "namespace nb {\n"
+ "void f() { a_f(); static_f(); A::f(); }\n"
+ "void g() { f(); A::g(); }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected =
+ "namespace na {\n"
+ "class A {\n"
+ "public:\n"
+ " static void f() {}\n"
+ " static void g();\n"
+ "};\n"
+ "void A::g() {}"
+ "void a_f() {}\n"
+ "static void static_f() {}\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() { na::a_f(); na::static_f(); na::A::f(); }\n"
+ "void g() { f(); na::A::g(); }\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, FixOverloadedOperatorFunctionNameSpecifiers) {
+ std::string Code =
+ "namespace na {\n"
+ "class A {\n"
+ "public:\n"
+ " int x;\n"
+ " bool operator==(const A &RHS) const { return x == RHS.x; }\n"
+ "};\n"
+ "bool operator<(const A &LHS, const A &RHS) { return LHS.x == RHS.x; }\n"
+ "namespace nb {\n"
+ "bool f() {\n"
+ " A x, y;\n"
+ " auto f = operator<;\n"
+ " return (x == y) && (x < y) && (operator<(x, y));\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected =
+ "namespace na {\n"
+ "class A {\n"
+ "public:\n"
+ " int x;\n"
+ " bool operator==(const A &RHS) const { return x == RHS.x; }\n"
+ "};\n"
+ "bool operator<(const A &LHS, const A &RHS) { return LHS.x == RHS.x; }\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "bool f() {\n"
+ " na::A x, y;\n"
+ " auto f = na::operator<;\n"
+ // FIXME: function calls to overloaded operators are not fixed now even if
+ // they are referenced by qualified names.
+ " return (x == y) && (x < y) && (operator<(x,y));\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, FixNonCallingFunctionReferences) {
+ std::string Code = "namespace na {\n"
+ "class A {\n"
+ "public:\n"
+ " static void f() {}\n"
+ "};\n"
+ "void a_f() {}\n"
+ "static void s_f() {}\n"
+ "namespace nb {\n"
+ "void f() {\n"
+ " auto *ref1 = A::f;\n"
+ " auto *ref2 = a_f;\n"
+ " auto *ref3 = s_f;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected =
+ "namespace na {\n"
+ "class A {\n"
+ "public:\n"
+ " static void f() {}\n"
+ "};\n"
+ "void a_f() {}\n"
+ "static void s_f() {}\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() {\n"
+ " auto *ref1 = na::A::f;\n"
+ " auto *ref2 = na::a_f;\n"
+ " auto *ref3 = na::s_f;\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, MoveAndFixGlobalVariables) {
+ std::string Code = "namespace na {\n"
+ "int GlobA;\n"
+ "static int GlobAStatic = 0;\n"
+ "namespace nc { int GlobC; }\n"
+ "namespace nb {\n"
+ "int GlobB;\n"
+ "void f() {\n"
+ " int a = GlobA;\n"
+ " int b = GlobAStatic;\n"
+ " int c = nc::GlobC;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace na {\n"
+ "int GlobA;\n"
+ "static int GlobAStatic = 0;\n"
+ "namespace nc { int GlobC; }\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "int GlobB;\n"
+ "void f() {\n"
+ " int a = na::GlobA;\n"
+ " int b = na::GlobAStatic;\n"
+ " int c = na::nc::GlobC;\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, DoNotFixStaticVariableOfClass) {
+ std::string Code = "namespace na {\n"
+ "class A {\n"
+ "public:\n"
+ "static int A1;\n"
+ "static int A2;\n"
+ "};\n"
+ "int A::A1 = 0;\n"
+ "namespace nb {\n"
+ "void f() {\n"
+ " int a = A::A1; int b = A::A2;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace na {\n"
+ "class A {\n"
+ "public:\n"
+ "static int A1;\n"
+ "static int A2;\n"
+ "};\n"
+ "int A::A1 = 0;\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() {\n"
+ " int a = na::A::A1; int b = na::A::A2;\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, NoMisplaceAtEOF) {
+ std::string Code = "namespace na {\n"
+ "namespace nb {\n"
+ "class A;\n"
+ "class B {};\n"
+ "}"
+ "}";
+ std::string Expected = "namespace na {\n"
+ "namespace nb {\n"
+ "class A;\n"
+ "}\n"
+ "}\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "\n"
+ "class B {};\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, CommentsBeforeMovedClass) {
+ std::string Code = "namespace na {\n"
+ "namespace nb {\n"
+ "\n\n"
+ "// Wild comments.\n"
+ "\n"
+ "// Comments.\n"
+ "// More comments.\n"
+ "class B {\n"
+ " // Private comments.\n"
+ " int a;\n"
+ "};\n"
+ "}\n"
+ "}";
+ std::string Expected = "\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "\n\n"
+ "// Wild comments.\n"
+ "\n"
+ "// Comments.\n"
+ "// More comments.\n"
+ "class B {\n"
+ " // Private comments.\n"
+ " int a;\n"
+ "};\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingShadowDeclInGlobal) {
+ std::string Code = "namespace glob {\n"
+ "class Glob {};\n"
+ "void GFunc() {}\n"
+ "}\n"
+ "using glob::Glob;\n"
+ "using glob::GFunc;\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() { Glob g; GFunc(); }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace glob {\n"
+ "class Glob {};\n"
+ "void GFunc() {}\n"
+ "}\n"
+ "using glob::Glob;\n"
+ "using glob::GFunc;\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() { Glob g; GFunc(); }\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingShadowDeclsInAnonymousNamespaces) {
+ std::string Code = "namespace util {\n"
+ "class Util {};\n"
+ "void func() {}\n"
+ "}\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "namespace {\n"
+ "using ::util::Util;\n"
+ "using ::util::func;\n"
+ "void f() { Util u; func(); }\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace util {\n"
+ "class Util {};\n"
+ "void func() {}\n"
+ "} // namespace util\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "namespace {\n"
+ "using ::util::Util;\n"
+ "using ::util::func;\n"
+ "void f() { Util u; func(); }\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingNamespaceInGlobal) {
+ std::string Code = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "using namespace glob;\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() { Glob g; }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "using namespace glob;\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() { Glob g; }\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, NamespaceAliasInGlobal) {
+ std::string Code = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "namespace glob2 { class Glob2 {}; }\n"
+ "namespace gl = glob;\n"
+ "namespace gl2 = glob2;\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() { gl::Glob g; gl2::Glob2 g2; }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected =
+ "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "namespace glob2 { class Glob2 {}; }\n"
+ "namespace gl = glob;\n"
+ "namespace gl2 = glob2;\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() { gl::Glob g; gl2::Glob2 g2; }\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, NamespaceAliasInNamespace) {
+ std::string Code = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "namespace gl = glob;\n"
+ "void f() { gl::Glob g; }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "namespace gl = glob;\n"
+ "void f() { gl::Glob g; }\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, NamespaceAliasInAncestorNamespace) {
+ NewNamespace = "na::nx";
+ std::string Code = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "namespace other { namespace gl = glob; }\n"
+ "namespace na {\n"
+ "namespace ga = glob;\n"
+ "namespace nb {\n"
+ "void f() { ga::Glob g; }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "namespace other { namespace gl = glob; }\n"
+ "namespace na {\n"
+ "namespace ga = glob;\n"
+ "\n"
+ "namespace nx {\n"
+ "void f() { ga::Glob g; }\n"
+ "} // namespace nx\n"
+ "} // namespace na\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, NamespaceAliasInOtherNamespace) {
+ std::string Code = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "namespace other { namespace gl = glob; }\n"
+ "namespace na {\n"
+ "namespace ga = glob;\n"
+ "namespace nb {\n"
+ "void f() { glob::Glob g; }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "namespace other { namespace gl = glob; }\n"
+ "namespace na {\n"
+ "namespace ga = glob;\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() { glob::Glob g; }\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingDeclAfterReference) {
+ std::string Code = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() { glob::Glob g; }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n"
+ "using glob::Glob;\n"
+ "using namespace glob;\n";
+
+ std::string Expected = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() { glob::Glob g; }\n"
+ "} // namespace y\n"
+ "} // namespace x\n"
+ "using glob::Glob;\n"
+ "using namespace glob;\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingNamespaceAfterReference) {
+ NewNamespace = "na::nc";
+ std::string Code = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() { glob::Glob g; }\n"
+ "} // namespace nb\n"
+ "using namespace glob;\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "namespace na {\n"
+ "\n"
+ "namespace nc {\n"
+ "void f() { glob::Glob g; }\n"
+ "} // namespace nc\n"
+ "using namespace glob;\n"
+ "} // namespace na\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingNamespaceAndUsingShadowInGlobal) {
+ std::string Code = "namespace glob1 {\n"
+ "namespace glob2 {\n"
+ "class Glob {};\n"
+ "}\n"
+ "}\n"
+ "using glob1::glob2::Glob;\n"
+ "using namespace glob1;\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() { Glob g; }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace glob1 {\n"
+ "namespace glob2 {\n"
+ "class Glob {};\n"
+ "}\n"
+ "}\n"
+ "using glob1::glob2::Glob;\n"
+ "using namespace glob1;\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() { Glob g; }\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingAliasInGlobal) {
+ std::string Code = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "using GLB = glob::Glob;\n"
+ "using BLG = glob::Glob;\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() { GLB g; BLG blg; }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "using GLB = glob::Glob;\n"
+ "using BLG = glob::Glob;\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() { GLB g; BLG blg; }\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingShadowDeclAndMovedNamespace) {
+ std::string Code = "namespace na { class C_A {};\n }\n"
+ "using na::C_A;\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "class C_X {\n"
+ "public:\n"
+ " C_A a;\n"
+ "};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na { class C_A {};\n }\n"
+ "using na::C_A;\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "class C_X {\n"
+ "public:\n"
+ " C_A a;\n"
+ "};\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingNamespaceDeclAndMovedNamespace) {
+ std::string Code = "namespace na { class C_A {};\n }\n"
+ "using namespace na;\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "class C_X {\n"
+ "public:\n"
+ " C_A ca;\n"
+ "};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na { class C_A {};\n }\n"
+ "using namespace na;\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "class C_X {\n"
+ "public:\n"
+ " C_A ca;\n"
+ "};\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingShadowDeclInFunction) {
+ std::string Code = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() {\n"
+ " using glob::Glob;\n"
+ " Glob g;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace glob {\n"
+ "class Glob {};\n"
+ "}\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() {\n"
+ " using ::glob::Glob;\n"
+ " Glob g;\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingShadowDeclInClass) {
+ std::string Code = "namespace na { class C_A {}; }\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() {\n"
+ " using ::na::C_A;\n"
+ " C_A ca;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na { class C_A {}; }\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() {\n"
+ " using ::na::C_A;\n"
+ " C_A ca;\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingDeclInMovedNamespace) {
+ std::string Code = "namespace nx { void f(); }\n"
+ "namespace na {\n"
+ "using nx::f;\n"
+ "namespace nb {\n"
+ "void d() { f(); }\n"
+ "} // nb\n"
+ "} // na\n";
+
+ std::string Expected = "namespace nx { void f(); }\n"
+ "namespace na {\n"
+ "using nx::f;\n"
+ "\n"
+ "} // na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void d() { nx::f(); }\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingDeclInMovedNamespaceNotNested) {
+ OldNamespace = "na";
+ std::string Code = "namespace nx { void f(); }\n"
+ "namespace na {\n"
+ "using ::nx::f;\n"
+ "void d() { f(); }\n"
+ "} // na\n";
+
+ std::string Expected = "namespace nx { void f(); }\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "using ::nx::f;\n"
+ "void d() { f(); }\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingDeclInMovedNamespaceMultiNested) {
+ OldNamespace = "a::b::c::d";
+ NewNamespace = "a::b::x::y";
+ std::string Code = "namespace nx { void f(); void g(); }\n"
+ "namespace a {\n"
+ "namespace b {\n"
+ "using ::nx::f;\n"
+ "namespace c {\n"
+ "using ::nx::g;\n"
+ "namespace d {\n"
+ "void d() { f(); g(); }\n"
+ "} // d\n"
+ "} // c\n"
+ "} // b\n"
+ "} // a\n";
+
+ std::string Expected = "namespace nx { void f(); void g(); }\n"
+ "namespace a {\n"
+ "namespace b {\n"
+ "using ::nx::f;\n"
+ "namespace c {\n"
+ "using ::nx::g;\n"
+ "\n"
+ "} // c\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void d() { f(); nx::g(); }\n"
+ "} // namespace y\n"
+ "} // namespace x\n"
+ "} // b\n"
+ "} // a\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingShadowDeclInTheParentOfOldNamespace) {
+ OldNamespace = "nb::nc";
+ NewNamespace = "nb::nd";
+ std::string Code = "namespace na { class A {}; }\n"
+ "namespace nb {\n"
+ "using na::A;\n"
+ "namespace nc {\n"
+ "void d() { A a; }\n"
+ "} // nc\n"
+ "} // nb\n";
+
+ std::string Expected = "namespace na { class A {}; }\n"
+ "namespace nb {\n"
+ "using na::A;\n"
+ "\n"
+ "namespace nd {\n"
+ "void d() { A a; }\n"
+ "} // namespace nd\n"
+ "} // nb\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingShadowDeclInOldNamespace) {
+ OldNamespace = "nb";
+ NewNamespace = "nc";
+ std::string Code = "namespace na { class A {}; }\n"
+ "namespace nb {\n"
+ "using na::A;\n"
+ "void d() { A a; }\n"
+ "struct X { A a; };\n"
+ "} // nb\n";
+
+ std::string Expected = "namespace na { class A {}; }\n"
+ "\n"
+ "namespace nc {\n"
+ "using ::na::A;\n"
+ "void d() { A a; }\n"
+ "struct X { A a; };\n"
+ "} // namespace nc\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingShadowDeclOfTemplateClass) {
+ OldNamespace = "nb";
+ NewNamespace = "nc";
+ std::string Code = "namespace na {\n"
+ "template <typename T>\n"
+ "class A { T t; };\n"
+ "} // namespace na\n"
+ "namespace nb {\n"
+ "using na::A;\n"
+ "void d() { A<int> a; }\n"
+ "} // nb\n";
+
+ std::string Expected = "namespace na {\n"
+ "template <typename T>\n"
+ "class A { T t; };\n"
+ "} // namespace na\n"
+ "\n"
+ "namespace nc {\n"
+ "using ::na::A;\n"
+ "void d() { A<int> a; }\n"
+ "} // namespace nc\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingShadowDeclOfTemplateFunction) {
+ OldNamespace = "nb";
+ NewNamespace = "nc";
+ std::string Code = "namespace na {\n"
+ "template <typename T>\n"
+ "void f() { T t; };\n"
+ "} // namespace na\n"
+ "namespace nb {\n"
+ "using na::f;\n"
+ "void d() { f<int>(); }\n"
+ "} // nb\n";
+
+ std::string Expected = "namespace na {\n"
+ "template <typename T>\n"
+ "void f() { T t; };\n"
+ "} // namespace na\n"
+ "\n"
+ "namespace nc {\n"
+ "using ::na::f;\n"
+ "void d() { f<int>(); }\n"
+ "} // namespace nc\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingAliasDecl) {
+ std::string Code =
+ "namespace nx { namespace ny { class X {}; } }\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "using Y = nx::ny::X;\n"
+ "void f() { Y y; }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace nx { namespace ny { class X {}; } }\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "using Y = nx::ny::X;\n"
+ "void f() { Y y; }\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingAliasDeclInGlobal) {
+ std::string Code =
+ "namespace nx { namespace ny { class X {}; } }\n"
+ "using Y = nx::ny::X;\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() { Y y; }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace nx { namespace ny { class X {}; } }\n"
+ "using Y = nx::ny::X;\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() { Y y; }\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+
+TEST_F(ChangeNamespaceTest, TypedefAliasDecl) {
+ std::string Code =
+ "namespace nx { namespace ny { class X {}; } }\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "typedef nx::ny::X Y;\n"
+ "void f() { Y y; }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+
+ std::string Expected = "namespace nx { namespace ny { class X {}; } }\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "typedef nx::ny::X Y;\n"
+ "void f() { Y y; }\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, DerivedClassWithConstructors) {
+ std::string Code =
+ "namespace nx { namespace ny { class X { public: X(int i) {} }; } }\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "class A : public nx::ny::X {\n"
+ "public:\n"
+ " A() : X(0) {}\n"
+ " A(int i);\n"
+ "};\n"
+ "A::A(int i) : X(i) {}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected =
+ "namespace nx { namespace ny { class X { public: X(int i) {} }; } }\n"
+ "\n\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "class A : public nx::ny::X {\n"
+ "public:\n"
+ " A() : X(0) {}\n"
+ " A(int i);\n"
+ "};\n"
+ "A::A(int i) : X(i) {}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, DerivedClassWithQualifiedConstructors) {
+ std::string Code =
+ "namespace nx { namespace ny { class X { public: X(int i) {} }; } }\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "class A : public nx::ny::X {\n"
+ "public:\n"
+ " A() : X::X(0) {}\n"
+ " A(int i);\n"
+ "};\n"
+ "A::A(int i) : X::X(i) {}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected =
+ "namespace nx { namespace ny { class X { public: X(int i) {} }; } }\n"
+ "\n\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "class A : public nx::ny::X {\n"
+ "public:\n"
+ " A() : X::X(0) {}\n"
+ " A(int i);\n"
+ "};\n"
+ "A::A(int i) : X::X(i) {}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, DerivedClassWithConstructorsAndTypeRefs) {
+ std::string Code =
+ "namespace nx { namespace ny { class X { public: X(int i) {} }; } }\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "class A : public nx::ny::X {\n"
+ "public:\n"
+ " A() : X(0) {}\n"
+ " A(int i);\n"
+ "};\n"
+ "A::A(int i) : X(i) { X x(1);}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected =
+ "namespace nx { namespace ny { class X { public: X(int i) {} }; } }\n"
+ "\n\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "class A : public nx::ny::X {\n"
+ "public:\n"
+ " A() : X(0) {}\n"
+ " A(int i);\n"
+ "};\n"
+ "A::A(int i) : X(i) { nx::ny::X x(1);}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, MoveToGlobalNamespace) {
+ NewNamespace = "";
+ std::string Code = "namespace na {\n"
+ "class C_A {};\n"
+ "namespace nc {\n"
+ "class C_C {};"
+ "} // namespace nc\n"
+ "namespace nb {\n"
+ "class C_X {\n"
+ "public:\n"
+ " C_A a;\n"
+ " nc::C_C c;\n"
+ "};\n"
+ "class C_Y {\n"
+ " C_X x;\n"
+ "};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "class C_A {};\n"
+ "namespace nc {\n"
+ "class C_C {};"
+ "} // namespace nc\n"
+ "\n"
+ "} // namespace na\n"
+ "class C_X {\n"
+ "public:\n"
+ " na::C_A a;\n"
+ " na::nc::C_C c;\n"
+ "};\n"
+ "class C_Y {\n"
+ " C_X x;\n"
+ "};\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, KeepGlobalSpecifier) {
+ std::string Code = "class Glob {};\n"
+ "namespace na {\n"
+ "class C_A {};\n"
+ "namespace nc {\n"
+ "class C_C {};"
+ "} // namespace nc\n"
+ "namespace nb {\n"
+ "class C_X {\n"
+ "public:\n"
+ " ::Glob glob_1;\n"
+ " Glob glob_2;\n"
+ " C_A a_1;\n"
+ " ::na::C_A a_2;\n"
+ " nc::C_C c;\n"
+ "};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "class Glob {};\n"
+ "namespace na {\n"
+ "class C_A {};\n"
+ "namespace nc {\n"
+ "class C_C {};"
+ "} // namespace nc\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "class C_X {\n"
+ "public:\n"
+ " ::Glob glob_1;\n"
+ " Glob glob_2;\n"
+ " na::C_A a_1;\n"
+ " ::na::C_A a_2;\n"
+ " na::nc::C_C c;\n"
+ "};\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingAliasInTemplate) {
+ NewNamespace = "na::nb::nc";
+ std::string Code = "namespace some_ns {\n"
+ "template <typename T, typename S>\n"
+ "class G {};\n"
+ "} // namespace some_ns\n"
+ "namespace na {\n"
+ "template<typename P>\n"
+ "using GG = some_ns::G<int, P>;\n"
+ "} // namespace na\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() {\n"
+ " GG<float> g;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace some_ns {\n"
+ "template <typename T, typename S>\n"
+ "class G {};\n"
+ "} // namespace some_ns\n"
+ "namespace na {\n"
+ "template<typename P>\n"
+ "using GG = some_ns::G<int, P>;\n"
+ "} // namespace na\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "namespace nc {\n"
+ "void f() {\n"
+ " GG<float> g;\n"
+ "}\n"
+ "} // namespace nc\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, TemplateUsingAliasInBaseClass) {
+ NewNamespace = "na::nb::nc";
+ std::string Code = "namespace some_ns {\n"
+ "template <typename T, typename S>\n"
+ "class G {};\n"
+ "} // namespace some_ns\n"
+ "namespace na {\n"
+ "class Base {\n"
+ "public:\n"
+ " template<typename P>\n"
+ " using GG = some_ns::G<int, P>;\n"
+ "\n"
+ " struct Nested {};\n"
+ "};\n"
+ "class Derived : public Base {};\n"
+ "} // namespace na\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() {\n"
+ " Derived::GG<float> g;\n"
+ " const Derived::GG<int> gg;\n"
+ " const Derived::GG<int>* gg_ptr;\n"
+ " struct Derived::Nested nested;\n"
+ " const struct Derived::Nested *nested_ptr;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace some_ns {\n"
+ "template <typename T, typename S>\n"
+ "class G {};\n"
+ "} // namespace some_ns\n"
+ "namespace na {\n"
+ "class Base {\n"
+ "public:\n"
+ " template<typename P>\n"
+ " using GG = some_ns::G<int, P>;\n"
+ "\n"
+ " struct Nested {};\n"
+ "};\n"
+ "class Derived : public Base {};\n"
+ "} // namespace na\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "namespace nc {\n"
+ "void f() {\n"
+ " Derived::GG<float> g;\n"
+ " const Derived::GG<int> gg;\n"
+ " const Derived::GG<int>* gg_ptr;\n"
+ " struct Derived::Nested nested;\n"
+ " const struct Derived::Nested *nested_ptr;\n"
+ "}\n"
+ "} // namespace nc\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, ExistingNamespaceConflictWithNewNamespace) {
+ OldNamespace = "nx";
+ NewNamespace = "ny::na::nc";
+ std::string Code = "namespace na {\n"
+ "class A {};\n"
+ "} // namespace na\n"
+ "namespace nb {\n"
+ "class B {};\n"
+ "} // namespace nb\n"
+ "namespace nx {\n"
+ "class X {\n"
+ " na::A a; nb::B b;\n"
+ "};\n"
+ "} // namespace nx\n";
+ std::string Expected = "namespace na {\n"
+ "class A {};\n"
+ "} // namespace na\n"
+ "namespace nb {\n"
+ "class B {};\n"
+ "} // namespace nb\n"
+ "\n"
+ "namespace ny {\n"
+ "namespace na {\n"
+ "namespace nc {\n"
+ "class X {\n"
+ " ::na::A a; nb::B b;\n"
+ "};\n"
+ "} // namespace nc\n"
+ "} // namespace na\n"
+ "} // namespace ny\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, SymbolConflictWithNewNamespace) {
+ OldNamespace = "nx";
+ NewNamespace = "ny::na::nc";
+ std::string Code = "namespace na {\n"
+ "class A {};\n"
+ "namespace nb {\n"
+ "class B {};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n"
+ "namespace ny {\n"
+ "class Y {};\n"
+ "}\n"
+ "namespace nx {\n"
+ "class X {\n"
+ " na::A a; na::nb::B b;\n"
+ " ny::Y y;"
+ "};\n"
+ "} // namespace nx\n";
+ std::string Expected = "namespace na {\n"
+ "class A {};\n"
+ "namespace nb {\n"
+ "class B {};\n"
+ "} // namespace nb\n"
+ "} // namespace na\n"
+ "namespace ny {\n"
+ "class Y {};\n"
+ "}\n"
+ "\n"
+ "namespace ny {\n"
+ "namespace na {\n"
+ "namespace nc {\n"
+ "class X {\n"
+ " ::na::A a; ::na::nb::B b;\n"
+ " Y y;\n"
+ "};\n"
+ "} // namespace nc\n"
+ "} // namespace na\n"
+ "} // namespace ny\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, ShortenNamespaceSpecifier) {
+ OldNamespace = "nx";
+ NewNamespace = "ny::na";
+ std::string Code = "class G {};\n"
+ "namespace ny {\n"
+ "class Y {};\n"
+ "namespace na {\n"
+ "class A {};\n"
+ "namespace nc { class C {}; } // namespace nc\n"
+ "}\n // namespace na\n"
+ "}\n // namespace ny\n"
+ "namespace nx {\n"
+ "class X {\n"
+ " G g; ny::Y y; ny::na::A a; ny::na::nc::C c;\n"
+ "};\n"
+ "} // namespace nx\n";
+ std::string Expected = "class G {};\n"
+ "namespace ny {\n"
+ "class Y {};\n"
+ "namespace na {\n"
+ "class A {};\n"
+ "namespace nc { class C {}; } // namespace nc\n"
+ "}\n // namespace na\n"
+ "}\n // namespace ny\n"
+ "\n"
+ "namespace ny {\n"
+ "namespace na {\n"
+ "class X {\n"
+ " G g; Y y; A a; nc::C c;\n"
+ "};\n"
+ "} // namespace na\n"
+ "} // namespace ny\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, ShortenNamespaceSpecifierInAnonymousNamespace) {
+ OldNamespace = "nx";
+ NewNamespace = "ny::na";
+ std::string Code = "class G {};\n"
+ "namespace ny {\n"
+ "class Y {};\n"
+ "namespace na {\n"
+ "class A {};\n"
+ "namespace nc { class C {}; } // namespace nc\n"
+ "}\n // namespace na\n"
+ "}\n // namespace ny\n"
+ "namespace nx {\n"
+ "namespace {\n"
+ "class X {\n"
+ " G g; ::ny::Y y; ::ny::na::A a; ::ny::na::nc::C c;\n"
+ "};\n"
+ "} // namespace\n"
+ "} // namespace nx\n";
+ std::string Expected = "class G {};\n"
+ "namespace ny {\n"
+ "class Y {};\n"
+ "namespace na {\n"
+ "class A {};\n"
+ "namespace nc { class C {}; } // namespace nc\n"
+ "}\n // namespace na\n"
+ "}\n // namespace ny\n"
+ "\n"
+ "namespace ny {\n"
+ "namespace na {\n"
+ "namespace {\n"
+ "class X {\n"
+ " G g; Y y; A a; nc::C c;\n"
+ "};\n"
+ "} // namespace\n"
+ "} // namespace na\n"
+ "} // namespace ny\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, SimpleMoveEnum) {
+ std::string Code = "namespace na {\n"
+ "namespace nb {\n"
+ "enum class X { X1, X2 };\n"
+ "enum Y { Y1, Y2 };\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "\n\nnamespace x {\n"
+ "namespace y {\n"
+ "enum class X { X1, X2 };\n"
+ "enum Y { Y1, Y2 };\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, ReferencesToEnums) {
+ std::string Code = "enum Glob { G1, G2 };\n"
+ "namespace na {\n"
+ "enum class X { X1 };\n"
+ "enum Y { Y1, Y2 };\n"
+ "namespace nb {\n"
+ "void f() {\n"
+ " Glob g1 = Glob::G1;\n"
+ " Glob g2 = G2;\n"
+ " X x1 = X::X1;\n"
+ " Y y1 = Y::Y1;\n"
+ " Y y2 = Y2;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "enum Glob { G1, G2 };\n"
+ "namespace na {\n"
+ "enum class X { X1 };\n"
+ "enum Y { Y1, Y2 };\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() {\n"
+ " Glob g1 = Glob::G1;\n"
+ " Glob g2 = G2;\n"
+ " na::X x1 = na::X::X1;\n"
+ " na::Y y1 = na::Y::Y1;\n"
+ " na::Y y2 = na::Y2;\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, NoRedundantEnumUpdate) {
+ std::string Code = "namespace ns {\n"
+ "enum class X { X1 };\n"
+ "enum Y { Y1, Y2 };\n"
+ "} // namespace ns\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() {\n"
+ " ns::X x1 = ns::X::X1;\n"
+ " ns::Y y1 = ns::Y::Y1;\n"
+ " ns::Y y2 = ns::Y2;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace ns {\n"
+ "enum class X { X1 };\n"
+ "enum Y { Y1, Y2 };\n"
+ "} // namespace ns\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() {\n"
+ " ns::X x1 = ns::X::X1;\n"
+ " ns::Y y1 = ns::Y::Y1;\n"
+ " ns::Y y2 = ns::Y2;\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ ;
+
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, EnumsAndUsingShadows) {
+ std::string Code = "namespace ns {\n"
+ "enum class X { X1 };\n"
+ "enum Y { Y1, Y2, Y3 };\n"
+ "} // namespace ns\n"
+ "using ns::X;\n"
+ "using ns::Y;\n"
+ "using ns::Y::Y2;\n"
+ "using ns::Y::Y3;\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() {\n"
+ " X x1 = X::X1;\n"
+ " Y y1 = Y::Y1;\n"
+ " Y y2 = Y2;\n"
+ " Y y3 = Y3;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace ns {\n"
+ "enum class X { X1 };\n"
+ "enum Y { Y1, Y2, Y3 };\n"
+ "} // namespace ns\n"
+ "using ns::X;\n"
+ "using ns::Y;\n"
+ "using ns::Y::Y2;\n"
+ "using ns::Y::Y3;\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() {\n"
+ " X x1 = X::X1;\n"
+ " Y y1 = Y::Y1;\n"
+ " Y y2 = Y2;\n"
+ " Y y3 = Y3;\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, EnumsAndAliases) {
+ std::string Code = "namespace ns {\n"
+ "enum class X { X1 };\n"
+ "enum Y { Y1, Y2, Y3 };\n"
+ "} // namespace ns\n"
+ "typedef ns::X TX;\n"
+ "typedef ns::Y TY;\n"
+ "using UX = ns::X;\n"
+ "using UY = ns::Y;\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() {\n"
+ " ns::X x1 = ns::X::X1;\n"
+ " TX tx1 = TX::X1;\n"
+ " UX ux1 = UX::X1;\n"
+ " ns::Y y1 = ns::Y::Y1;\n"
+ " TY ty1 = TY::Y1;\n"
+ " UY uy1 = UY::Y1;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace ns {\n"
+ "enum class X { X1 };\n"
+ "enum Y { Y1, Y2, Y3 };\n"
+ "} // namespace ns\n"
+ "typedef ns::X TX;\n"
+ "typedef ns::Y TY;\n"
+ "using UX = ns::X;\n"
+ "using UY = ns::Y;\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() {\n"
+ " ns::X x1 = ns::X::X1;\n"
+ " TX tx1 = TX::X1;\n"
+ " UX ux1 = UX::X1;\n"
+ " ns::Y y1 = ns::Y::Y1;\n"
+ " TY ty1 = TY::Y1;\n"
+ " UY uy1 = UY::Y1;\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, EnumInClass) {
+ std::string Code = "namespace na {\n"
+ "struct X { enum E { E1 }; };\n"
+ "namespace nb {\n"
+ "void f() {\n"
+ " X::E e = X::E1;\n"
+ " X::E ee = X::E::E1;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "struct X { enum E { E1 }; };\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "void f() {\n"
+ " na::X::E e = na::X::E1;\n"
+ " na::X::E ee = na::X::E::E1;\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, TypeAsTemplateParameter) {
+ std::string Code = "namespace na {\n"
+ "struct X {};\n"
+ "namespace nb {\n"
+ "template <typename TT>\n"
+ "void TempTemp(const TT& t) {\n"
+ " TT tmp;\n"
+ "}\n"
+ "template <typename T>\n"
+ "void Temp(const T& t) {\n"
+ " T tmp = t;\n"
+ " TempTemp(tmp);\n"
+ " TempTemp(t);\n"
+ "}\n"
+ "void f() {\n"
+ " X x;\n"
+ " Temp(x);\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "struct X {};\n"
+ "\n"
+ "} // namespace na\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "template <typename TT>\n"
+ "void TempTemp(const TT& t) {\n"
+ " TT tmp;\n"
+ "}\n"
+ "template <typename T>\n"
+ "void Temp(const T& t) {\n"
+ " T tmp = t;\n"
+ " TempTemp(tmp);\n"
+ " TempTemp(t);\n"
+ "}\n"
+ "void f() {\n"
+ " na::X x;\n"
+ " Temp(x);\n"
+ "}\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, DefaultMoveConstructors) {
+ std::string Code = "namespace na {\n"
+ "class B {\n"
+ " public:\n"
+ " B() = default;\n"
+ " // Allow move only.\n"
+ " B(B&&) = default;\n"
+ " B& operator=(B&&) = default;\n"
+ " B(const B&) = delete;\n"
+ " B& operator=(const B&) = delete;\n"
+ " private:\n"
+ " int ref_;\n"
+ "};\n"
+ "} // namespace na\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "class A {\n"
+ "public:\n"
+ " A() = default;\n"
+ " A(A&&) = default;\n"
+ " A& operator=(A&&) = default;\n"
+ "private:\n"
+ " B b;\n"
+ " A(const A&) = delete;\n"
+ " A& operator=(const A&) = delete;\n"
+ "};\n"
+ "void f() { A a; a = A(); A aa = A(); }\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace na {\n"
+ "class B {\n"
+ " public:\n"
+ " B() = default;\n"
+ " // Allow move only.\n"
+ " B(B&&) = default;\n"
+ " B& operator=(B&&) = default;\n"
+ " B(const B&) = delete;\n"
+ " B& operator=(const B&) = delete;\n"
+ " private:\n"
+ " int ref_;\n"
+ "};\n"
+ "} // namespace na\n"
+ "\n"
+ "namespace x {\n"
+ "namespace y {\n"
+ "class A {\n"
+ "public:\n"
+ " A() = default;\n"
+ " A(A&&) = default;\n"
+ " A& operator=(A&&) = default;\n"
+ "private:\n"
+ " na::B b;\n"
+ " A(const A&) = delete;\n"
+ " A& operator=(const A&) = delete;\n"
+ "};\n"
+ "void f() { A a; a = A(); A aa = A(); }\n"
+ "} // namespace y\n"
+ "} // namespace x\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, InjectedClassNameInFriendDecl) {
+ OldNamespace = "d";
+ NewNamespace = "e";
+ std::string Code = "namespace a{\n"
+ "template <typename T>\n"
+ "class Base {\n"
+ " public:\n"
+ " void f() {\n"
+ " T t;\n"
+ " t.priv();\n"
+ " }\n"
+ "};\n"
+ "} // namespace a\n"
+ "namespace d {\n"
+ "class D : public a::Base<D> {\n"
+ " private:\n"
+ " friend class Base<D>;\n"
+ " void priv() {}\n"
+ " Base b;\n"
+ "};\n"
+ "\n"
+ "void f() {\n"
+ " D d;\n"
+ " a:: Base<D> b;\n"
+ " b.f();\n"
+ "}\n"
+ "} // namespace d\n";
+ std::string Expected = "namespace a{\n"
+ "template <typename T>\n"
+ "class Base {\n"
+ " public:\n"
+ " void f() {\n"
+ " T t;\n"
+ " t.priv();\n"
+ " }\n"
+ "};\n"
+ "} // namespace a\n"
+ "\n"
+ "namespace e {\n"
+ "class D : public a::Base<D> {\n"
+ " private:\n"
+ " friend class Base<D>;\n"
+ " void priv() {}\n"
+ " a::Base b;\n"
+ "};\n"
+ "\n"
+ "void f() {\n"
+ " D d;\n"
+ " a::Base<D> b;\n"
+ " b.f();\n"
+ "}\n"
+ "} // namespace e\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+} // anonymous namespace
+} // namespace change_namespace
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
new file mode 100644
index 0000000..85aaebf
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
@@ -0,0 +1,55 @@
+//===- clang-apply-replacements/ApplyReplacementsTest.cpp
+//----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang-apply-replacements/Tooling/ApplyReplacements.h"
+#include "clang/Format/Format.h"
+#include "gtest/gtest.h"
+
+using namespace clang::replace;
+using namespace llvm;
+
+namespace clang {
+namespace tooling {
+
+static TUDiagnostics
+makeTUDiagnostics(const std::string &MainSourceFile, StringRef DiagnosticName,
+ const DiagnosticMessage &Message,
+ const StringMap<Replacements> &Replacements,
+ StringRef BuildDirectory) {
+ TUDiagnostics TUs;
+ TUs.push_back({MainSourceFile,
+ {{DiagnosticName,
+ Message,
+ Replacements,
+ {},
+ Diagnostic::Warning,
+ BuildDirectory}}});
+ return TUs;
+}
+
+// Test to ensure diagnostics with no fixes, will be merged correctly
+// before applying.
+TEST(ApplyReplacementsTest, mergeDiagnosticsWithNoFixes) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts.get());
+ FileManager Files((FileSystemOptions()));
+ SourceManager SM(Diagnostics, Files);
+ TUReplacements TURs;
+ TUDiagnostics TUs =
+ makeTUDiagnostics("path/to/source.cpp", "diagnostic", {}, {}, "path/to");
+ FileToChangesMap ReplacementsMap;
+
+ EXPECT_TRUE(mergeAndDeduplicate(TURs, TUs, ReplacementsMap, SM));
+ EXPECT_TRUE(ReplacementsMap.empty());
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-apply-replacements/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-apply-replacements/CMakeLists.txt
new file mode 100644
index 0000000..9e5fac2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-apply-replacements/CMakeLists.txt
@@ -0,0 +1,20 @@
+get_filename_component(ClangApplyReplacementsLocation
+ "${CMAKE_CURRENT_SOURCE_DIR}/../../clang-apply-replacements/include" REALPATH)
+get_filename_component(CommonIncLocation
+ "${CMAKE_CURRENT_SOURCE_DIR}/../include" REALPATH)
+include_directories(
+ ${ClangApplyReplacementsLocation}
+ ${CommonIncLocation}
+ )
+
+add_extra_unittest(ClangApplyReplacementsTests
+ ApplyReplacementsTest.cpp
+ )
+
+target_link_libraries(ClangApplyReplacementsTests
+ PRIVATE
+ clangApplyReplacements
+ clangBasic
+ clangToolingCore
+ clangToolingRefactor
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-move/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-move/CMakeLists.txt
new file mode 100644
index 0000000..fea15e1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-move/CMakeLists.txt
@@ -0,0 +1,29 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+get_filename_component(INCLUDE_FIXER_SOURCE_DIR
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../clang-move REALPATH)
+include_directories(
+ ${INCLUDE_FIXER_SOURCE_DIR}
+ )
+
+# We'd like to clang/unittests/Tooling/RewriterTestContext.h in the test.
+include_directories(${CLANG_SOURCE_DIR})
+
+add_extra_unittest(ClangMoveTests
+ ClangMoveTests.cpp
+ )
+
+target_link_libraries(ClangMoveTests
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFormat
+ clangFrontend
+ clangMove
+ clangRewrite
+ clangTooling
+ clangToolingCore
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-move/ClangMoveTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-move/ClangMoveTests.cpp
new file mode 100644
index 0000000..45e3f68
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-move/ClangMoveTests.cpp
@@ -0,0 +1,635 @@
+//===-- ClangMoveTest.cpp - clang-move unit tests -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangMove.h"
+#include "unittests/Tooling/RewriterTestContext.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/StringRef.h"
+#include "gtest/gtest.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace move {
+namespace {
+
+const char TestHeader[] = "namespace a {\n"
+ "class C1; // test\n"
+ "template <typename T> class C2;\n"
+ "namespace b {\n"
+ "// This is a Foo class\n"
+ "// which is used in\n"
+ "// test.\n"
+ "class Foo {\n"
+ "public:\n"
+ " void f();\n"
+ "\n"
+ "private:\n"
+ " C1 *c1;\n"
+ " static int b;\n"
+ "}; // abc\n"
+ "\n"
+ "class Foo2 {\n"
+ "public:\n"
+ " int f();\n"
+ "};\n"
+ "} // namespace b\n"
+ "} // namespace a\n";
+
+const char TestCC[] = "#include \"foo.h\"\n"
+ "namespace a {\n"
+ "namespace b {\n"
+ "namespace {\n"
+ "// comment1.\n"
+ "void f1() {}\n"
+ "/// comment2.\n"
+ "int kConstInt1 = 0;\n"
+ "} // namespace\n"
+ "\n"
+ "/* comment 3*/\n"
+ "static int kConstInt2 = 1;\n"
+ "\n"
+ "/** comment4\n"
+ " */\n"
+ "static int help() {\n"
+ " int a = 0;\n"
+ " return a;\n"
+ "}\n"
+ "\n"
+ "// comment5\n"
+ "// comment5\n"
+ "void Foo::f() {\n"
+ " f1();\n"
+ " kConstInt1;\n"
+ " kConstInt2;\n"
+ " help();\n"
+ "}\n"
+ "\n"
+ "/////////////\n"
+ "// comment //\n"
+ "/////////////\n"
+ "int Foo::b = 2;\n"
+ "int Foo2::f() {\n"
+ " kConstInt1;\n"
+ " kConstInt2;\n"
+ " help();\n"
+ " f1();\n"
+ " return 1;\n"
+ "}\n"
+ "} // namespace b\n"
+ "} // namespace a\n";
+
+const char ExpectedTestHeader[] = "namespace a {\n"
+ "class C1; // test\n"
+ "template <typename T> class C2;\n"
+ "namespace b {\n"
+ "\n"
+ "class Foo2 {\n"
+ "public:\n"
+ " int f();\n"
+ "};\n"
+ "} // namespace b\n"
+ "} // namespace a\n";
+
+const char ExpectedTestCC[] = "#include \"foo.h\"\n"
+ "namespace a {\n"
+ "namespace b {\n"
+ "namespace {\n"
+ "// comment1.\n"
+ "void f1() {}\n"
+ "/// comment2.\n"
+ "int kConstInt1 = 0;\n"
+ "} // namespace\n"
+ "\n"
+ "/* comment 3*/\n"
+ "static int kConstInt2 = 1;\n"
+ "\n"
+ "/** comment4\n"
+ " */\n"
+ "static int help() {\n"
+ " int a = 0;\n"
+ " return a;\n"
+ "}\n"
+ "\n"
+ "int Foo2::f() {\n"
+ " kConstInt1;\n"
+ " kConstInt2;\n"
+ " help();\n"
+ " f1();\n"
+ " return 1;\n"
+ "}\n"
+ "} // namespace b\n"
+ "} // namespace a\n";
+
+const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
+ "#define NEW_FOO_H\n"
+ "\n"
+ "namespace a {\n"
+ "class C1; // test\n"
+ "\n"
+ "template <typename T> class C2;\n"
+ "namespace b {\n"
+ "// This is a Foo class\n"
+ "// which is used in\n"
+ "// test.\n"
+ "class Foo {\n"
+ "public:\n"
+ " void f();\n"
+ "\n"
+ "private:\n"
+ " C1 *c1;\n"
+ " static int b;\n"
+ "}; // abc\n"
+ "} // namespace b\n"
+ "} // namespace a\n"
+ "\n"
+ "#endif // NEW_FOO_H\n";
+
+const char ExpectedNewCC[] = "namespace a {\n"
+ "namespace b {\n"
+ "namespace {\n"
+ "// comment1.\n"
+ "void f1() {}\n"
+ "\n"
+ "/// comment2.\n"
+ "int kConstInt1 = 0;\n"
+ "} // namespace\n"
+ "\n"
+ "/* comment 3*/\n"
+ "static int kConstInt2 = 1;\n"
+ "\n"
+ "/** comment4\n"
+ " */\n"
+ "static int help() {\n"
+ " int a = 0;\n"
+ " return a;\n"
+ "}\n"
+ "\n"
+ "// comment5\n"
+ "// comment5\n"
+ "void Foo::f() {\n"
+ " f1();\n"
+ " kConstInt1;\n"
+ " kConstInt2;\n"
+ " help();\n"
+ "}\n"
+ "\n"
+ "/////////////\n"
+ "// comment //\n"
+ "/////////////\n"
+ "int Foo::b = 2;\n"
+ "} // namespace b\n"
+ "} // namespace a\n";
+
+#ifdef _WIN32
+const char WorkingDir[] = "C:\\test";
+#else
+const char WorkingDir[] = "/test";
+#endif
+
+const char TestHeaderName[] = "foo.h";
+const char TestCCName[] = "foo.cc";
+
+std::map<std::string, std::string>
+runClangMoveOnCode(const move::MoveDefinitionSpec &Spec,
+ const char *const Header = TestHeader,
+ const char *const CC = TestCC,
+ DeclarationReporter *const Reporter = nullptr) {
+ clang::RewriterTestContext Context;
+
+ Context.InMemoryFileSystem->setCurrentWorkingDirectory(WorkingDir);
+
+ std::map<llvm::StringRef, clang::FileID> FileToFileID;
+
+ auto CreateFiles = [&Context, &FileToFileID](llvm::StringRef Name,
+ llvm::StringRef Code) {
+ if (!Name.empty()) {
+ FileToFileID[Name] = Context.createInMemoryFile(Name, Code);
+ }
+ };
+ CreateFiles(Spec.NewCC, "");
+ CreateFiles(Spec.NewHeader, "");
+ CreateFiles(TestHeaderName, Header);
+ CreateFiles(TestCCName, CC);
+
+ std::map<std::string, tooling::Replacements> FileToReplacements;
+ ClangMoveContext MoveContext = {Spec, FileToReplacements, WorkingDir, "LLVM",
+ Reporter != nullptr};
+
+ auto Factory = llvm::make_unique<clang::move::ClangMoveActionFactory>(
+ &MoveContext, Reporter);
+
+ // std::string IncludeArg = Twine("-I" + WorkingDir;
+ tooling::runToolOnCodeWithArgs(
+ Factory->create(), CC, Context.InMemoryFileSystem,
+ {"-std=c++11", "-fparse-all-comments", "-I."}, TestCCName, "clang-move",
+ std::make_shared<PCHContainerOperations>());
+ formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite, "llvm");
+ // The Key is file name, value is the new code after moving the class.
+ std::map<std::string, std::string> Results;
+ for (const auto &It : FileToReplacements) {
+ // The path may come out as "./foo.h", normalize to "foo.h".
+ SmallString<32> FilePath (It.first);
+ llvm::sys::path::remove_dots(FilePath);
+ Results[FilePath.str().str()] = Context.getRewrittenText(FileToFileID[FilePath]);
+ }
+ return Results;
+}
+
+TEST(ClangMove, MoveHeaderAndCC) {
+ move::MoveDefinitionSpec Spec;
+ Spec.Names = {std::string("a::b::Foo")};
+ Spec.OldHeader = "foo.h";
+ Spec.OldCC = "foo.cc";
+ Spec.NewHeader = "new_foo.h";
+ Spec.NewCC = "new_foo.cc";
+ std::string ExpectedHeader = "#include \"" + Spec.NewHeader + "\"\n\n";
+ auto Results = runClangMoveOnCode(Spec);
+ EXPECT_EQ(ExpectedTestHeader, Results[Spec.OldHeader]);
+ EXPECT_EQ(ExpectedTestCC, Results[Spec.OldCC]);
+ EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
+ EXPECT_EQ(ExpectedHeader + ExpectedNewCC, Results[Spec.NewCC]);
+}
+
+TEST(ClangMove, MoveHeaderOnly) {
+ move::MoveDefinitionSpec Spec;
+ Spec.Names = {std::string("a::b::Foo")};
+ Spec.OldHeader = "foo.h";
+ Spec.NewHeader = "new_foo.h";
+ auto Results = runClangMoveOnCode(Spec);
+ EXPECT_EQ(2u, Results.size());
+ EXPECT_EQ(ExpectedTestHeader, Results[Spec.OldHeader]);
+ EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
+}
+
+TEST(ClangMove, MoveCCOnly) {
+ move::MoveDefinitionSpec Spec;
+ Spec.Names = {std::string("a::b::Foo")};
+ Spec.OldCC = "foo.cc";
+ Spec.NewCC = "new_foo.cc";
+ std::string ExpectedHeader = "#include \"foo.h\"\n\n";
+ auto Results = runClangMoveOnCode(Spec);
+ EXPECT_EQ(2u, Results.size());
+ EXPECT_EQ(ExpectedTestCC, Results[Spec.OldCC]);
+ EXPECT_EQ(ExpectedHeader + ExpectedNewCC, Results[Spec.NewCC]);
+}
+
+TEST(ClangMove, MoveNonExistClass) {
+ move::MoveDefinitionSpec Spec;
+ Spec.Names = {std::string("NonExistFoo")};
+ Spec.OldHeader = "foo.h";
+ Spec.OldCC = "foo.cc";
+ Spec.NewHeader = "new_foo.h";
+ Spec.NewCC = "new_foo.cc";
+ auto Results = runClangMoveOnCode(Spec);
+ EXPECT_EQ(0u, Results.size());
+}
+
+TEST(ClangMove, HeaderIncludeSelf) {
+ move::MoveDefinitionSpec Spec;
+ Spec.Names = {std::string("Foo")};
+ Spec.OldHeader = "foo.h";
+ Spec.OldCC = "foo.cc";
+ Spec.NewHeader = "new_foo.h";
+ Spec.NewCC = "new_foo.cc";
+
+ const char TestHeader[] = "#ifndef FOO_H\n"
+ "#define FOO_H\n"
+ "#include \"foo.h\"\n"
+ "class Foo {};\n"
+ "#endif\n";
+ const char TestCode[] = "#include \"foo.h\"";
+ const char ExpectedNewHeader[] = "#ifndef FOO_H\n"
+ "#define FOO_H\n"
+ "#include \"new_foo.h\"\n"
+ "class Foo {};\n"
+ "#endif\n";
+ const char ExpectedNewCC[] = "#include \"new_foo.h\"";
+ auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
+ EXPECT_EQ("", Results[Spec.OldHeader]);
+ EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
+ EXPECT_EQ(ExpectedNewCC, Results[Spec.NewCC]);
+}
+
+TEST(ClangMove, MoveAll) {
+ std::vector<std::string> TestHeaders = {
+ "class A {\npublic:\n int f();\n};",
+ // forward declaration.
+ "class B;\nclass A {\npublic:\n int f();\n};",
+ // template forward declaration.
+ "template <typename T> class B;\nclass A {\npublic:\n int f();\n};",
+ "namespace a {}\nclass A {\npublic:\n int f();\n};",
+ "namespace a {}\nusing namespace a;\nclass A {\npublic:\n int f();\n};",
+ };
+ const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
+ move::MoveDefinitionSpec Spec;
+ Spec.Names.push_back("A");
+ Spec.OldHeader = "foo.h";
+ Spec.OldCC = "foo.cc";
+ Spec.NewHeader = "new_foo.h";
+ Spec.NewCC = "new_foo.cc";
+ for (const auto& Header : TestHeaders) {
+ auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
+ EXPECT_EQ(Header, Results[Spec.NewHeader]);
+ EXPECT_EQ("", Results[Spec.OldHeader]);
+ EXPECT_EQ("", Results[Spec.OldCC]);
+ }
+}
+
+TEST(ClangMove, MoveAllMultipleClasses) {
+ move::MoveDefinitionSpec Spec;
+ std::vector<std::string> TestHeaders = {
+ "class C;\nclass A {\npublic:\n int f();\n};\nclass B {};",
+ "class C;\nclass B;\nclass A {\npublic:\n int f();\n};\nclass B {};",
+ };
+ const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
+ Spec.Names = {std::string("A"), std::string("B")};
+ Spec.OldHeader = "foo.h";
+ Spec.OldCC = "foo.cc";
+ Spec.NewHeader = "new_foo.h";
+ Spec.NewCC = "new_foo.cc";
+ for (const auto& Header : TestHeaders) {
+ auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
+ EXPECT_EQ(Header, Results[Spec.NewHeader]);
+ EXPECT_EQ("", Results[Spec.OldHeader]);
+ EXPECT_EQ("", Results[Spec.OldCC]);
+ }
+}
+
+TEST(ClangMove, DontMoveAll) {
+ const char ExpectedHeader[] = "#ifndef NEW_FOO_H\n"
+ "#define NEW_FOO_H\n"
+ "\n"
+ "class A {\npublic:\n int f();\n};\n"
+ "\n"
+ "#endif // NEW_FOO_H\n";
+ const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }";
+ std::vector<std::string> TestHeaders = {
+ "class B {};\nclass A {\npublic:\n int f();\n};\n",
+ "void f() {};\nclass A {\npublic:\n int f();\n};\n",
+ };
+ move::MoveDefinitionSpec Spec;
+ Spec.Names.push_back("A");
+ Spec.OldHeader = "foo.h";
+ Spec.OldCC = "foo.cc";
+ Spec.NewHeader = "new_foo.h";
+ Spec.NewCC = "new_foo.cc";
+ for (const auto& Header : TestHeaders) {
+ auto Results = runClangMoveOnCode(Spec, Header.c_str(), Code);
+ EXPECT_EQ(ExpectedHeader, Results[Spec.NewHeader]);
+ // The expected old header should not contain class A definition.
+ std::string ExpectedOldHeader = Header.substr(0, Header.size() - 32);
+ EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
+ }
+}
+
+TEST(ClangMove, IgnoreMacroSymbolsAndMoveAll) {
+ const char TestCode[] = "#include \"foo.h\"";
+ std::vector<std::string> TestHeaders = {
+ "#define DEFINE_Foo int Foo = 1;\nDEFINE_Foo;\nclass Bar {};\n",
+ "#define DEFINE(x) int var_##x = 1;\nDEFINE(foo);\nclass Bar {};\n",
+ };
+ move::MoveDefinitionSpec Spec;
+ Spec.Names.push_back("Bar");
+ Spec.OldHeader = "foo.h";
+ Spec.OldCC = "foo.cc";
+ Spec.NewHeader = "new_foo.h";
+ Spec.NewCC = "new_foo.cc";
+
+ for (const auto& Header : TestHeaders) {
+ auto Results = runClangMoveOnCode(Spec, Header.c_str(), TestCode);
+ EXPECT_EQ("", Results[Spec.OldHeader]);
+ EXPECT_EQ(Header, Results[Spec.NewHeader]);
+ }
+}
+
+TEST(ClangMove, MacroInFunction) {
+ const char TestHeader[] = "#define INT int\n"
+ "class A {\npublic:\n int f();\n};\n"
+ "class B {};\n";
+ const char TestCode[] = "#include \"foo.h\"\n"
+ "INT A::f() { return 0; }\n";
+ const char ExpectedNewCode[] = "#include \"new_foo.h\"\n\n"
+ "INT A::f() { return 0; }\n";
+ move::MoveDefinitionSpec Spec;
+ Spec.Names.push_back("A");
+ Spec.OldHeader = "foo.h";
+ Spec.OldCC = "foo.cc";
+ Spec.NewHeader = "new_foo.h";
+ Spec.NewCC = "new_foo.cc";
+ auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
+ EXPECT_EQ(ExpectedNewCode, Results[Spec.NewCC]);
+}
+
+TEST(ClangMove, DefinitionInMacro) {
+ const char TestHeader[] = "#define DEF(CLASS) void CLASS##_::f() {}\n"
+ "#define DEF2(CLASS, ...) void CLASS##_::f2() {}\n"
+ "class A_ {\nvoid f();\nvoid f2();\n};\n"
+ "class B {};\n";
+ const char TestCode[] = "#include \"foo.h\"\n"
+ "DEF(A)\n\n"
+ "DEF2(A,\n"
+ " 123)\n";
+ const char ExpectedNewCode[] = "#include \"new_foo.h\"\n\n"
+ "DEF(A)\n\n"
+ "DEF2(A, 123)\n";
+ move::MoveDefinitionSpec Spec;
+ Spec.Names.push_back("A_");
+ Spec.OldHeader = "foo.h";
+ Spec.OldCC = "foo.cc";
+ Spec.NewHeader = "new_foo.h";
+ Spec.NewCC = "new_foo.cc";
+ auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
+ EXPECT_EQ(ExpectedNewCode, Results[Spec.NewCC]);
+}
+
+TEST(ClangMove, WellFormattedCode) {
+ const std::string CommonHeader =
+ "namespace a {\n"
+ "namespace b {\n"
+ "namespace c {\n"
+ "class C;\n"
+ "\n"
+ "class A {\npublic:\n void f();\n void f2();\n};\n"
+ "} // namespace c\n"
+ "} // namespace b\n"
+ "\n"
+ "namespace d {\n"
+ "namespace e {\n"
+ "class B {\npublic:\n void f();\n};\n"
+ "} // namespace e\n"
+ "} // namespace d\n"
+ "} // namespace a\n";
+ const std::string CommonCode = "\n"
+ "namespace a {\n"
+ "namespace b {\n"
+ "namespace c {\n"
+ "void A::f() {}\n"
+ "\n"
+ "void A::f2() {}\n"
+ "} // namespace c\n"
+ "} // namespace b\n"
+ "\n"
+ "namespace d {\n"
+ "namespace e {\n"
+ "void B::f() {}\n"
+ "} // namespace e\n"
+ "} // namespace d\n"
+ "} // namespace a\n";
+ // Add dummy class to prevent behavior of moving all declarations from header.
+ const std::string TestHeader = CommonHeader + "class D {};\n";
+ const std::string TestCode = "#include \"foo.h\"\n" + CommonCode;
+ const std::string ExpectedNewHeader = "#ifndef NEW_FOO_H\n"
+ "#define NEW_FOO_H\n"
+ "\n" +
+ CommonHeader +
+ "\n"
+ "#endif // NEW_FOO_H\n";
+ const std::string ExpectedNewCC = "#include \"new_foo.h\"\n" + CommonCode;
+ move::MoveDefinitionSpec Spec;
+ Spec.Names.push_back("a::b::c::A");
+ Spec.Names.push_back("a::d::e::B");
+ Spec.OldHeader = "foo.h";
+ Spec.OldCC = "foo.cc";
+ Spec.NewHeader = "new_foo.h";
+ Spec.NewCC = "new_foo.cc";
+ auto Results = runClangMoveOnCode(Spec, TestHeader.c_str(), TestCode.c_str());
+ EXPECT_EQ(ExpectedNewCC, Results[Spec.NewCC]);
+ EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
+}
+
+TEST(ClangMove, AddDependentNewHeader) {
+ const char TestHeader[] = "class A {};\n"
+ "class B {};\n";
+ const char TestCode[] = "#include \"foo.h\"\n";
+ const char ExpectedOldHeader[] = "#include \"new_foo.h\"\nclass B {};\n";
+ const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
+ "#define NEW_FOO_H\n"
+ "\n"
+ "class A {};\n"
+ "\n"
+ "#endif // NEW_FOO_H\n";
+ move::MoveDefinitionSpec Spec;
+ Spec.Names.push_back("A");
+ Spec.OldHeader = "foo.h";
+ Spec.OldCC = "foo.cc";
+ Spec.NewHeader = "new_foo.h";
+ Spec.NewCC = "new_foo.cc";
+ Spec.OldDependOnNew = true;
+ auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
+ EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
+ EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
+}
+
+TEST(ClangMove, AddDependentOldHeader) {
+ const char TestHeader[] = "class A {};\n"
+ "class B {};\n";
+ const char TestCode[] = "#include \"foo.h\"\n";
+ const char ExpectedNewHeader[] = "#ifndef NEW_FOO_H\n"
+ "#define NEW_FOO_H\n"
+ "\n"
+ "#include \"foo.h\"\n"
+ "\n"
+ "class B {};\n"
+ "\n"
+ "#endif // NEW_FOO_H\n";
+ const char ExpectedOldHeader[] = "class A {};\n";
+ move::MoveDefinitionSpec Spec;
+ Spec.Names.push_back("B");
+ Spec.OldHeader = "foo.h";
+ Spec.OldCC = "foo.cc";
+ Spec.NewHeader = "new_foo.h";
+ Spec.NewCC = "new_foo.cc";
+ Spec.NewDependOnOld = true;
+ auto Results = runClangMoveOnCode(Spec, TestHeader, TestCode);
+ EXPECT_EQ(ExpectedNewHeader, Results[Spec.NewHeader]);
+ EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]);
+}
+
+TEST(ClangMove, DumpDecls) {
+ const char TestHeader[] = "template <typename T>\n"
+ "class A {\n"
+ " public:\n"
+ " void f();\n"
+ " template <typename U> void h();\n"
+ " static int b;\n"
+ "};\n"
+ "\n"
+ "template <typename T> void A<T>::f() {}\n"
+ "\n"
+ "template <typename T>\n"
+ "template <typename U>\n"
+ "void A<T>::h() {}\n"
+ "\n"
+ "template <typename T> int A<T>::b = 2;\n"
+ "\n"
+ "template <> class A<int> {};\n"
+ "\n"
+ "class B {};\n"
+ "\n"
+ "namespace a {\n"
+ "class Move1 {};\n"
+ "void f1() {}\n"
+ "void f2();\n"
+ "} // namespace a\n"
+ "\n"
+ "class ForwardClass;\n"
+ "namespace a {\n"
+ "namespace b {\n"
+ "class Move1 { public : void f(); };\n"
+ "void f() {}\n"
+ "enum E1 { Green };\n"
+ "enum class E2 { Red };\n"
+ "typedef int Int2;\n"
+ "typedef A<double> A_d;"
+ "using Int = int;\n"
+ "extern int kGlobalInt;\n"
+ "extern const char* const kGlobalStr;\n"
+ "} // namespace b\n"
+ "} // namespace a\n"
+ "#define DEFINE_FOO class Foo {};\n"
+ "DEFINE_FOO\n";
+ const char TestCode[] = "#include \"foo.h\"\n";
+ move::MoveDefinitionSpec Spec;
+ Spec.Names.push_back("B");
+ Spec.OldHeader = "foo.h";
+ Spec.OldCC = "foo.cc";
+ Spec.NewHeader = "new_foo.h";
+ Spec.NewCC = "new_foo.cc";
+ DeclarationReporter Reporter;
+ std::set<DeclarationReporter::DeclarationPair> ExpectedDeclarations = {
+ {"A", "Class"},
+ {"B", "Class"},
+ {"a::Move1", "Class"},
+ {"a::f1", "Function"},
+ {"a::f2", "Function"},
+ {"a::b::Move1", "Class"},
+ {"a::b::f", "Function"},
+ {"a::b::E1", "Enum"},
+ {"a::b::E2", "Enum"},
+ {"a::b::Int2", "TypeAlias"},
+ {"a::b::A_d", "TypeAlias"},
+ {"a::b::Int", "TypeAlias"},
+ {"a::b::kGlobalInt", "Variable"},
+ {"a::b::kGlobalStr", "Variable"}};
+ runClangMoveOnCode(Spec, TestHeader, TestCode, &Reporter);
+ std::set<DeclarationReporter::DeclarationPair> Results;
+ for (const auto& DelPair : Reporter.getDeclarationList())
+ Results.insert(DelPair);
+ EXPECT_EQ(ExpectedDeclarations, Results);
+}
+
+} // namespace
+} // namespce move
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-query/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-query/CMakeLists.txt
new file mode 100644
index 0000000..21d82b7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-query/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../clang-query
+ )
+
+add_extra_unittest(ClangQueryTests
+ QueryEngineTest.cpp
+ QueryParserTest.cpp
+ )
+
+target_link_libraries(ClangQueryTests
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangDynamicASTMatchers
+ clangFrontend
+ clangQuery
+ clangTooling
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-query/QueryEngineTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-query/QueryEngineTest.cpp
new file mode 100644
index 0000000..631a53e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-query/QueryEngineTest.cpp
@@ -0,0 +1,146 @@
+//===---- QueryTest.cpp - clang-query test --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Query.h"
+#include "QueryParser.h"
+#include "QuerySession.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/Dynamic/VariantValue.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+#include <string>
+
+using namespace clang;
+using namespace clang::ast_matchers;
+using namespace clang::ast_matchers::dynamic;
+using namespace clang::query;
+using namespace clang::tooling;
+
+class QueryEngineTest : public ::testing::Test {
+ ArrayRef<std::unique_ptr<ASTUnit>> mkASTUnit2(std::unique_ptr<ASTUnit> a,
+ std::unique_ptr<ASTUnit> b) {
+ ASTs[0] = std::move(a);
+ ASTs[1] = std::move(b);
+ return ArrayRef<std::unique_ptr<ASTUnit>>(ASTs);
+ }
+
+protected:
+ QueryEngineTest()
+ : S(mkASTUnit2(buildASTFromCode("void foo1(void) {}\nvoid foo2(void) {}",
+ "foo.cc"),
+ buildASTFromCode("void bar1(void) {}\nvoid bar2(void) {}",
+ "bar.cc"))),
+ OS(Str) {}
+
+ std::unique_ptr<ASTUnit> ASTs[2];
+ QuerySession S;
+
+ std::string Str;
+ llvm::raw_string_ostream OS;
+};
+
+TEST_F(QueryEngineTest, Basic) {
+ DynTypedMatcher FnMatcher = functionDecl();
+ DynTypedMatcher FooMatcher = functionDecl(hasName("foo1"));
+
+ EXPECT_TRUE(NoOpQuery().run(OS, S));
+
+ EXPECT_EQ("", OS.str());
+
+ Str.clear();
+
+ EXPECT_FALSE(InvalidQuery("Parse error").run(OS, S));
+
+ EXPECT_EQ("Parse error\n", OS.str());
+
+ Str.clear();
+
+ EXPECT_TRUE(HelpQuery().run(OS, S));
+
+ EXPECT_TRUE(OS.str().find("Available commands:") != std::string::npos);
+
+ Str.clear();
+
+ EXPECT_TRUE(MatchQuery(FnMatcher).run(OS, S));
+
+ EXPECT_TRUE(OS.str().find("foo.cc:1:1: note: \"root\" binds here") !=
+ std::string::npos);
+ EXPECT_TRUE(OS.str().find("foo.cc:2:1: note: \"root\" binds here") !=
+ std::string::npos);
+ EXPECT_TRUE(OS.str().find("bar.cc:1:1: note: \"root\" binds here") !=
+ std::string::npos);
+ EXPECT_TRUE(OS.str().find("bar.cc:2:1: note: \"root\" binds here") !=
+ std::string::npos);
+ EXPECT_TRUE(OS.str().find("4 matches.") != std::string::npos);
+
+ Str.clear();
+
+ EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S));
+
+ EXPECT_TRUE(OS.str().find("foo.cc:1:1: note: \"root\" binds here") !=
+ std::string::npos);
+ EXPECT_TRUE(OS.str().find("1 match.") != std::string::npos);
+
+ Str.clear();
+
+ EXPECT_TRUE(
+ SetQuery<OutputKind>(&QuerySession::OutKind, OK_Print).run(OS, S));
+ EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S));
+
+ EXPECT_TRUE(OS.str().find("Binding for \"root\":\nvoid foo1()") !=
+ std::string::npos);
+
+ Str.clear();
+
+ EXPECT_TRUE(SetQuery<OutputKind>(&QuerySession::OutKind, OK_Dump).run(OS, S));
+ EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S));
+
+ EXPECT_TRUE(OS.str().find("FunctionDecl") != std::string::npos);
+
+ Str.clear();
+
+ EXPECT_TRUE(SetQuery<bool>(&QuerySession::BindRoot, false).run(OS, S));
+ EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S));
+
+ EXPECT_TRUE(OS.str().find("No bindings.") != std::string::npos);
+
+ Str.clear();
+
+ EXPECT_FALSE(MatchQuery(isArrow()).run(OS, S));
+
+ EXPECT_EQ("Not a valid top-level matcher.\n", OS.str());
+}
+
+TEST_F(QueryEngineTest, LetAndMatch) {
+ EXPECT_TRUE(QueryParser::parse("let x \"foo1\"", S)->run(OS, S));
+ EXPECT_EQ("", OS.str());
+ Str.clear();
+
+ EXPECT_TRUE(QueryParser::parse("let y hasName(x)", S)->run(OS, S));
+ EXPECT_EQ("", OS.str());
+ Str.clear();
+
+ EXPECT_TRUE(QueryParser::parse("match functionDecl(y)", S)->run(OS, S));
+ EXPECT_TRUE(OS.str().find("foo.cc:1:1: note: \"root\" binds here") !=
+ std::string::npos);
+ EXPECT_TRUE(OS.str().find("1 match.") != std::string::npos);
+ Str.clear();
+
+ EXPECT_TRUE(QueryParser::parse("unlet x", S)->run(OS, S));
+ EXPECT_EQ("", OS.str());
+ Str.clear();
+
+ EXPECT_FALSE(QueryParser::parse("let y hasName(x)", S)->run(OS, S));
+ EXPECT_EQ("1:2: Error parsing argument 1 for matcher hasName.\n"
+ "1:10: Value not found: x\n", OS.str());
+ Str.clear();
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp
new file mode 100644
index 0000000..5588ea3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp
@@ -0,0 +1,158 @@
+//===---- QueryParserTest.cpp - clang-query test --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "QueryParser.h"
+#include "Query.h"
+#include "QuerySession.h"
+#include "llvm/LineEditor/LineEditor.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace clang::query;
+
+class QueryParserTest : public ::testing::Test {
+protected:
+ QueryParserTest() : QS(llvm::ArrayRef<std::unique_ptr<ASTUnit>>()) {}
+ QueryRef parse(StringRef Code) { return QueryParser::parse(Code, QS); }
+
+ QuerySession QS;
+};
+
+TEST_F(QueryParserTest, NoOp) {
+ QueryRef Q = parse("");
+ EXPECT_TRUE(isa<NoOpQuery>(Q));
+
+ Q = parse("\n");
+ EXPECT_TRUE(isa<NoOpQuery>(Q));
+}
+
+TEST_F(QueryParserTest, Invalid) {
+ QueryRef Q = parse("foo");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("unknown command: foo", cast<InvalidQuery>(Q)->ErrStr);
+}
+
+TEST_F(QueryParserTest, Help) {
+ QueryRef Q = parse("help");
+ ASSERT_TRUE(isa<HelpQuery>(Q));
+
+ Q = parse("help me");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("unexpected extra input: ' me'", cast<InvalidQuery>(Q)->ErrStr);
+}
+
+TEST_F(QueryParserTest, Set) {
+ QueryRef Q = parse("set");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
+
+ Q = parse("set foo bar");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("unknown variable: 'foo'", cast<InvalidQuery>(Q)->ErrStr);
+
+ Q = parse("set output");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("expected 'diag', 'print' or 'dump', got ''",
+ cast<InvalidQuery>(Q)->ErrStr);
+
+ Q = parse("set bind-root true foo");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("unexpected extra input: ' foo'", cast<InvalidQuery>(Q)->ErrStr);
+
+ Q = parse("set output foo");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("expected 'diag', 'print' or 'dump', got 'foo'",
+ cast<InvalidQuery>(Q)->ErrStr);
+
+ Q = parse("set output dump");
+ ASSERT_TRUE(isa<SetQuery<OutputKind> >(Q));
+ EXPECT_EQ(&QuerySession::OutKind, cast<SetQuery<OutputKind> >(Q)->Var);
+ EXPECT_EQ(OK_Dump, cast<SetQuery<OutputKind> >(Q)->Value);
+
+ Q = parse("set bind-root foo");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("expected 'true' or 'false', got 'foo'",
+ cast<InvalidQuery>(Q)->ErrStr);
+
+ Q = parse("set bind-root true");
+ ASSERT_TRUE(isa<SetQuery<bool> >(Q));
+ EXPECT_EQ(&QuerySession::BindRoot, cast<SetQuery<bool> >(Q)->Var);
+ EXPECT_EQ(true, cast<SetQuery<bool> >(Q)->Value);
+}
+
+TEST_F(QueryParserTest, Match) {
+ QueryRef Q = parse("match decl()");
+ ASSERT_TRUE(isa<MatchQuery>(Q));
+ EXPECT_TRUE(cast<MatchQuery>(Q)->Matcher.canConvertTo<Decl>());
+
+ Q = parse("m stmt()");
+ ASSERT_TRUE(isa<MatchQuery>(Q));
+ EXPECT_TRUE(cast<MatchQuery>(Q)->Matcher.canConvertTo<Stmt>());
+}
+
+TEST_F(QueryParserTest, LetUnlet) {
+ QueryRef Q = parse("let foo decl()");
+ ASSERT_TRUE(isa<LetQuery>(Q));
+ EXPECT_EQ("foo", cast<LetQuery>(Q)->Name);
+ EXPECT_TRUE(cast<LetQuery>(Q)->Value.isMatcher());
+ EXPECT_TRUE(cast<LetQuery>(Q)->Value.getMatcher().hasTypedMatcher<Decl>());
+
+ Q = parse("let bar \"str\"");
+ ASSERT_TRUE(isa<LetQuery>(Q));
+ EXPECT_EQ("bar", cast<LetQuery>(Q)->Name);
+ EXPECT_TRUE(cast<LetQuery>(Q)->Value.isString());
+ EXPECT_EQ("str", cast<LetQuery>(Q)->Value.getString());
+
+ Q = parse("let");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
+
+ Q = parse("unlet x");
+ ASSERT_TRUE(isa<LetQuery>(Q));
+ EXPECT_EQ("x", cast<LetQuery>(Q)->Name);
+ EXPECT_FALSE(cast<LetQuery>(Q)->Value.hasValue());
+
+ Q = parse("unlet");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
+
+ Q = parse("unlet x bad_data");
+ ASSERT_TRUE(isa<InvalidQuery>(Q));
+ EXPECT_EQ("unexpected extra input: ' bad_data'",
+ cast<InvalidQuery>(Q)->ErrStr);
+}
+
+TEST_F(QueryParserTest, Complete) {
+ std::vector<llvm::LineEditor::Completion> Comps =
+ QueryParser::complete("", 0, QS);
+ ASSERT_EQ(6u, Comps.size());
+ EXPECT_EQ("help ", Comps[0].TypedText);
+ EXPECT_EQ("help", Comps[0].DisplayText);
+ EXPECT_EQ("let ", Comps[1].TypedText);
+ EXPECT_EQ("let", Comps[1].DisplayText);
+ EXPECT_EQ("match ", Comps[2].TypedText);
+ EXPECT_EQ("match", Comps[2].DisplayText);
+ EXPECT_EQ("set ", Comps[3].TypedText);
+ EXPECT_EQ("set", Comps[3].DisplayText);
+ EXPECT_EQ("unlet ", Comps[4].TypedText);
+ EXPECT_EQ("unlet", Comps[4].DisplayText);
+ EXPECT_EQ("quit", Comps[5].DisplayText);
+ EXPECT_EQ("quit ", Comps[5].TypedText);
+
+ Comps = QueryParser::complete("set o", 5, QS);
+ ASSERT_EQ(1u, Comps.size());
+ EXPECT_EQ("utput ", Comps[0].TypedText);
+ EXPECT_EQ("output", Comps[0].DisplayText);
+
+ Comps = QueryParser::complete("match while", 11, QS);
+ ASSERT_EQ(1u, Comps.size());
+ EXPECT_EQ("Stmt(", Comps[0].TypedText);
+ EXPECT_EQ("Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)",
+ Comps[0].DisplayText);
+}
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
new file mode 100644
index 0000000..a678e59
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
@@ -0,0 +1,38 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+get_filename_component(CLANG_LINT_SOURCE_DIR
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../clang-tidy REALPATH)
+include_directories(${CLANG_LINT_SOURCE_DIR})
+
+add_extra_unittest(ClangTidyTests
+ ClangTidyDiagnosticConsumerTest.cpp
+ ClangTidyOptionsTest.cpp
+ ExprMutationAnalyzerTest.cpp
+ IncludeInserterTest.cpp
+ GoogleModuleTest.cpp
+ LLVMModuleTest.cpp
+ NamespaceAliaserTest.cpp
+ ObjCModuleTest.cpp
+ OverlappingReplacementsTest.cpp
+ UsingInserterTest.cpp
+ ReadabilityModuleTest.cpp)
+
+target_link_libraries(ClangTidyTests
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFrontend
+ clangLex
+ clangTidy
+ clangTidyAndroidModule
+ clangTidyGoogleModule
+ clangTidyLLVMModule
+ clangTidyObjCModule
+ clangTidyReadabilityModule
+ clangTidyUtils
+ clangTooling
+ clangToolingCore
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ClangTidyDiagnosticConsumerTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ClangTidyDiagnosticConsumerTest.cpp
new file mode 100644
index 0000000..5547f98
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ClangTidyDiagnosticConsumerTest.cpp
@@ -0,0 +1,94 @@
+#include "ClangTidy.h"
+#include "ClangTidyTest.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tidy {
+namespace test {
+
+class TestCheck : public ClangTidyCheck {
+public:
+ TestCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override {
+ Finder->addMatcher(ast_matchers::varDecl().bind("var"), this);
+ }
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override {
+ const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var");
+ // Add diagnostics in the wrong order.
+ diag(Var->getLocation(), "variable");
+ diag(Var->getTypeSpecStartLoc(), "type specifier");
+ }
+};
+
+TEST(ClangTidyDiagnosticConsumer, SortsErrors) {
+ std::vector<ClangTidyError> Errors;
+ runCheckOnCode<TestCheck>("int a;", &Errors);
+ EXPECT_EQ(2ul, Errors.size());
+ EXPECT_EQ("type specifier", Errors[0].Message.Message);
+ EXPECT_EQ("variable", Errors[1].Message.Message);
+}
+
+TEST(GlobList, Empty) {
+ GlobList Filter("");
+
+ EXPECT_TRUE(Filter.contains(""));
+ EXPECT_FALSE(Filter.contains("aaa"));
+}
+
+TEST(GlobList, Nothing) {
+ GlobList Filter("-*");
+
+ EXPECT_FALSE(Filter.contains(""));
+ EXPECT_FALSE(Filter.contains("a"));
+ EXPECT_FALSE(Filter.contains("-*"));
+ EXPECT_FALSE(Filter.contains("-"));
+ EXPECT_FALSE(Filter.contains("*"));
+}
+
+TEST(GlobList, Everything) {
+ GlobList Filter("*");
+
+ EXPECT_TRUE(Filter.contains(""));
+ EXPECT_TRUE(Filter.contains("aaaa"));
+ EXPECT_TRUE(Filter.contains("-*"));
+ EXPECT_TRUE(Filter.contains("-"));
+ EXPECT_TRUE(Filter.contains("*"));
+}
+
+TEST(GlobList, Simple) {
+ GlobList Filter("aaa");
+
+ EXPECT_TRUE(Filter.contains("aaa"));
+ EXPECT_FALSE(Filter.contains(""));
+ EXPECT_FALSE(Filter.contains("aa"));
+ EXPECT_FALSE(Filter.contains("aaaa"));
+ EXPECT_FALSE(Filter.contains("bbb"));
+}
+
+TEST(GlobList, WhitespacesAtBegin) {
+ GlobList Filter("-*, a.b.*");
+
+ EXPECT_TRUE(Filter.contains("a.b.c"));
+ EXPECT_FALSE(Filter.contains("b.c"));
+}
+
+TEST(GlobList, Complex) {
+ GlobList Filter("*,-a.*, -b.*, \r \n a.1.* ,-a.1.A.*,-..,-...,-..+,-*$, -*qwe* ");
+
+ EXPECT_TRUE(Filter.contains("aaa"));
+ EXPECT_TRUE(Filter.contains("qqq"));
+ EXPECT_FALSE(Filter.contains("a."));
+ EXPECT_FALSE(Filter.contains("a.b"));
+ EXPECT_FALSE(Filter.contains("b."));
+ EXPECT_FALSE(Filter.contains("b.b"));
+ EXPECT_TRUE(Filter.contains("a.1.b"));
+ EXPECT_FALSE(Filter.contains("a.1.A.a"));
+ EXPECT_FALSE(Filter.contains("qwe"));
+ EXPECT_FALSE(Filter.contains("asdfqweasdf"));
+ EXPECT_TRUE(Filter.contains("asdfqwEasdf"));
+}
+
+} // namespace test
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
new file mode 100644
index 0000000..f50672c
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
@@ -0,0 +1,102 @@
+#include "ClangTidyOptions.h"
+#include "gtest/gtest.h"
+#include "llvm/ADT/StringExtras.h"
+
+namespace clang {
+namespace tidy {
+namespace test {
+
+TEST(ParseLineFilter, EmptyFilter) {
+ ClangTidyGlobalOptions Options;
+ EXPECT_FALSE(parseLineFilter("", Options));
+ EXPECT_TRUE(Options.LineFilter.empty());
+ EXPECT_FALSE(parseLineFilter("[]", Options));
+ EXPECT_TRUE(Options.LineFilter.empty());
+}
+
+TEST(ParseLineFilter, InvalidFilter) {
+ ClangTidyGlobalOptions Options;
+ EXPECT_TRUE(!!parseLineFilter("asdf", Options));
+ EXPECT_TRUE(Options.LineFilter.empty());
+
+ EXPECT_TRUE(!!parseLineFilter("[{}]", Options));
+ EXPECT_TRUE(!!parseLineFilter("[{\"name\":\"\"}]", Options));
+ EXPECT_TRUE(
+ !!parseLineFilter("[{\"name\":\"test\",\"lines\":[[1]]}]", Options));
+ EXPECT_TRUE(
+ !!parseLineFilter("[{\"name\":\"test\",\"lines\":[[1,2,3]]}]", Options));
+ EXPECT_TRUE(
+ !!parseLineFilter("[{\"name\":\"test\",\"lines\":[[1,-1]]}]", Options));
+}
+
+TEST(ParseLineFilter, ValidFilter) {
+ ClangTidyGlobalOptions Options;
+ std::error_code Error = parseLineFilter(
+ "[{\"name\":\"file1.cpp\",\"lines\":[[3,15],[20,30],[42,42]]},"
+ "{\"name\":\"file2.h\"},"
+ "{\"name\":\"file3.cc\",\"lines\":[[100,1000]]}]",
+ Options);
+ EXPECT_FALSE(Error);
+ EXPECT_EQ(3u, Options.LineFilter.size());
+ EXPECT_EQ("file1.cpp", Options.LineFilter[0].Name);
+ EXPECT_EQ(3u, Options.LineFilter[0].LineRanges.size());
+ EXPECT_EQ(3u, Options.LineFilter[0].LineRanges[0].first);
+ EXPECT_EQ(15u, Options.LineFilter[0].LineRanges[0].second);
+ EXPECT_EQ(20u, Options.LineFilter[0].LineRanges[1].first);
+ EXPECT_EQ(30u, Options.LineFilter[0].LineRanges[1].second);
+ EXPECT_EQ(42u, Options.LineFilter[0].LineRanges[2].first);
+ EXPECT_EQ(42u, Options.LineFilter[0].LineRanges[2].second);
+ EXPECT_EQ("file2.h", Options.LineFilter[1].Name);
+ EXPECT_EQ(0u, Options.LineFilter[1].LineRanges.size());
+ EXPECT_EQ("file3.cc", Options.LineFilter[2].Name);
+ EXPECT_EQ(1u, Options.LineFilter[2].LineRanges.size());
+ EXPECT_EQ(100u, Options.LineFilter[2].LineRanges[0].first);
+ EXPECT_EQ(1000u, Options.LineFilter[2].LineRanges[0].second);
+}
+
+TEST(ParseConfiguration, ValidConfiguration) {
+ llvm::ErrorOr<ClangTidyOptions> Options =
+ parseConfiguration("Checks: \"-*,misc-*\"\n"
+ "HeaderFilterRegex: \".*\"\n"
+ "AnalyzeTemporaryDtors: true\n"
+ "User: some.user");
+ EXPECT_TRUE(!!Options);
+ EXPECT_EQ("-*,misc-*", *Options->Checks);
+ EXPECT_EQ(".*", *Options->HeaderFilterRegex);
+ EXPECT_EQ("some.user", *Options->User);
+}
+
+TEST(ParseConfiguration, MergeConfigurations) {
+ llvm::ErrorOr<ClangTidyOptions> Options1 = parseConfiguration(R"(
+ Checks: "check1,check2"
+ HeaderFilterRegex: "filter1"
+ AnalyzeTemporaryDtors: true
+ User: user1
+ ExtraArgs: ['arg1', 'arg2']
+ ExtraArgsBefore: ['arg-before1', 'arg-before2']
+ )");
+ ASSERT_TRUE(!!Options1);
+ llvm::ErrorOr<ClangTidyOptions> Options2 = parseConfiguration(R"(
+ Checks: "check3,check4"
+ HeaderFilterRegex: "filter2"
+ AnalyzeTemporaryDtors: false
+ User: user2
+ ExtraArgs: ['arg3', 'arg4']
+ ExtraArgsBefore: ['arg-before3', 'arg-before4']
+ )");
+ ASSERT_TRUE(!!Options2);
+ ClangTidyOptions Options = Options1->mergeWith(*Options2);
+ EXPECT_EQ("check1,check2,check3,check4", *Options.Checks);
+ EXPECT_EQ("filter2", *Options.HeaderFilterRegex);
+ EXPECT_EQ("user2", *Options.User);
+ ASSERT_TRUE(Options.ExtraArgs.hasValue());
+ EXPECT_EQ("arg1,arg2,arg3,arg4", llvm::join(Options.ExtraArgs->begin(),
+ Options.ExtraArgs->end(), ","));
+ ASSERT_TRUE(Options.ExtraArgsBefore.hasValue());
+ EXPECT_EQ("arg-before1,arg-before2,arg-before3,arg-before4",
+ llvm::join(Options.ExtraArgsBefore->begin(),
+ Options.ExtraArgsBefore->end(), ","));
+}
+} // namespace test
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
new file mode 100644
index 0000000..197c137
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
@@ -0,0 +1,159 @@
+//===--- ClangTidyTest.h - clang-tidy ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_TIDY_CLANGTIDYTEST_H
+#define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_TIDY_CLANGTIDYTEST_H
+
+#include "ClangTidy.h"
+#include "ClangTidyDiagnosticConsumer.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/Path.h"
+#include <map>
+#include <memory>
+
+namespace clang {
+namespace tidy {
+namespace test {
+
+class TestClangTidyAction : public ASTFrontendAction {
+public:
+ TestClangTidyAction(SmallVectorImpl<std::unique_ptr<ClangTidyCheck>> &Checks,
+ ast_matchers::MatchFinder &Finder,
+ ClangTidyContext &Context)
+ : Checks(Checks), Finder(Finder), Context(Context) {}
+
+private:
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef File) override {
+ Context.setSourceManager(&Compiler.getSourceManager());
+ Context.setCurrentFile(File);
+ Context.setASTContext(&Compiler.getASTContext());
+
+ for (auto &Check : Checks) {
+ Check->registerMatchers(&Finder);
+ Check->registerPPCallbacks(Compiler);
+ }
+ return Finder.newASTConsumer();
+ }
+
+ SmallVectorImpl<std::unique_ptr<ClangTidyCheck>> &Checks;
+ ast_matchers::MatchFinder &Finder;
+ ClangTidyContext &Context;
+};
+
+template <typename Check, typename... Checks> struct CheckFactory {
+ static void
+ createChecks(ClangTidyContext *Context,
+ SmallVectorImpl<std::unique_ptr<ClangTidyCheck>> &Result) {
+ CheckFactory<Check>::createChecks(Context, Result);
+ CheckFactory<Checks...>::createChecks(Context, Result);
+ }
+};
+
+template <typename Check> struct CheckFactory<Check> {
+ static void
+ createChecks(ClangTidyContext *Context,
+ SmallVectorImpl<std::unique_ptr<ClangTidyCheck>> &Result) {
+ Result.emplace_back(llvm::make_unique<Check>(
+ "test-check-" + std::to_string(Result.size()), Context));
+ }
+};
+
+template <typename... CheckList>
+std::string
+runCheckOnCode(StringRef Code, std::vector<ClangTidyError> *Errors = nullptr,
+ const Twine &Filename = "input.cc",
+ ArrayRef<std::string> ExtraArgs = None,
+ const ClangTidyOptions &ExtraOptions = ClangTidyOptions(),
+ std::map<StringRef, StringRef> PathsToContent =
+ std::map<StringRef, StringRef>()) {
+ ClangTidyOptions Options = ExtraOptions;
+ Options.Checks = "*";
+ ClangTidyContext Context(llvm::make_unique<DefaultOptionsProvider>(
+ ClangTidyGlobalOptions(), Options));
+ ClangTidyDiagnosticConsumer DiagConsumer(Context);
+
+ std::vector<std::string> Args(1, "clang-tidy");
+ Args.push_back("-fsyntax-only");
+ std::string extension(llvm::sys::path::extension(Filename.str()));
+ if (extension == ".m" || extension == ".mm") {
+ Args.push_back("-fobjc-abi-version=2");
+ Args.push_back("-fobjc-arc");
+ }
+ if (extension == ".cc" || extension == ".cpp" || extension == ".mm") {
+ Args.push_back("-std=c++11");
+ }
+ Args.push_back("-Iinclude");
+ Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
+ Args.push_back(Filename.str());
+
+ ast_matchers::MatchFinder Finder;
+ llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
+ new vfs::InMemoryFileSystem);
+ llvm::IntrusiveRefCntPtr<FileManager> Files(
+ new FileManager(FileSystemOptions(), InMemoryFileSystem));
+
+ SmallVector<std::unique_ptr<ClangTidyCheck>, 1> Checks;
+ CheckFactory<CheckList...>::createChecks(&Context, Checks);
+ tooling::ToolInvocation Invocation(
+ Args, new TestClangTidyAction(Checks, Finder, Context), Files.get());
+ InMemoryFileSystem->addFile(Filename, 0,
+ llvm::MemoryBuffer::getMemBuffer(Code));
+ for (const auto &FileContent : PathsToContent) {
+ InMemoryFileSystem->addFile(
+ Twine("include/") + FileContent.first, 0,
+ llvm::MemoryBuffer::getMemBuffer(FileContent.second));
+ }
+ Invocation.setDiagnosticConsumer(&DiagConsumer);
+ if (!Invocation.run()) {
+ std::string ErrorText;
+ for (const auto &Error : Context.getErrors()) {
+ ErrorText += Error.Message.Message + "\n";
+ }
+ llvm::report_fatal_error(ErrorText);
+ }
+
+ DiagConsumer.finish();
+ tooling::Replacements Fixes;
+ for (const ClangTidyError &Error : Context.getErrors()) {
+ for (const auto &FileAndFixes : Error.Fix) {
+ for (const auto &Fix : FileAndFixes.second) {
+ auto Err = Fixes.add(Fix);
+ // FIXME: better error handling. Keep the behavior for now.
+ if (Err) {
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ return "";
+ }
+ }
+ }
+ }
+ if (Errors)
+ *Errors = Context.getErrors();
+ auto Result = tooling::applyAllReplacements(Code, Fixes);
+ if (!Result) {
+ // FIXME: propogate the error.
+ llvm::consumeError(Result.takeError());
+ return "";
+ }
+ return *Result;
+}
+
+#define EXPECT_NO_CHANGES(Check, Code) \
+ EXPECT_EQ(Code, runCheckOnCode<Check>(Code))
+
+} // namespace test
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_TIDY_CLANGTIDYTEST_H
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ExprMutationAnalyzerTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ExprMutationAnalyzerTest.cpp
new file mode 100644
index 0000000..042d4cb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ExprMutationAnalyzerTest.cpp
@@ -0,0 +1,611 @@
+//===---------- ExprMutationAnalyzerTest.cpp - clang-tidy -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../clang-tidy/utils/ExprMutationAnalyzer.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <cctype>
+
+namespace clang {
+namespace tidy {
+namespace test {
+
+using namespace clang::ast_matchers;
+using ::testing::ElementsAre;
+using ::testing::IsEmpty;
+using ::testing::ResultOf;
+using ::testing::StartsWith;
+using ::testing::Values;
+
+namespace {
+
+using ExprMatcher = internal::Matcher<Expr>;
+using StmtMatcher = internal::Matcher<Stmt>;
+
+ExprMatcher declRefTo(StringRef Name) {
+ return declRefExpr(to(namedDecl(hasName(Name))));
+}
+
+StmtMatcher withEnclosingCompound(ExprMatcher Matcher) {
+ return expr(Matcher, hasAncestor(compoundStmt().bind("stmt"))).bind("expr");
+}
+
+bool isMutated(const SmallVectorImpl<BoundNodes> &Results, ASTUnit *AST) {
+ const auto *const S = selectFirst<Stmt>("stmt", Results);
+ const auto *const E = selectFirst<Expr>("expr", Results);
+ return utils::ExprMutationAnalyzer(S, &AST->getASTContext()).isMutated(E);
+}
+
+SmallVector<std::string, 1>
+mutatedBy(const SmallVectorImpl<BoundNodes> &Results, ASTUnit *AST) {
+ const auto *const S = selectFirst<Stmt>("stmt", Results);
+ SmallVector<std::string, 1> Chain;
+ utils::ExprMutationAnalyzer Analyzer(S, &AST->getASTContext());
+ for (const auto *E = selectFirst<Expr>("expr", Results); E != nullptr;) {
+ const Stmt *By = Analyzer.findMutation(E);
+ std::string buffer;
+ llvm::raw_string_ostream stream(buffer);
+ By->printPretty(stream, nullptr, AST->getASTContext().getPrintingPolicy());
+ Chain.push_back(StringRef(stream.str()).trim().str());
+ E = dyn_cast<DeclRefExpr>(By);
+ }
+ return Chain;
+}
+
+std::string removeSpace(std::string s) {
+ s.erase(std::remove_if(s.begin(), s.end(),
+ [](char c) { return std::isspace(c); }),
+ s.end());
+ return s;
+}
+
+} // namespace
+
+TEST(ExprMutationAnalyzerTest, Trivial) {
+ const auto AST = tooling::buildASTFromCode("void f() { int x; x; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+class AssignmentTest : public ::testing::TestWithParam<std::string> {};
+
+TEST_P(AssignmentTest, AssignmentModifies) {
+ const std::string ModExpr = "x " + GetParam() + " 10";
+ const auto AST =
+ tooling::buildASTFromCode("void f() { int x; " + ModExpr + "; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr));
+}
+
+INSTANTIATE_TEST_CASE_P(AllAssignmentOperators, AssignmentTest,
+ Values("=", "+=", "-=", "*=", "/=", "%=", "&=", "|=",
+ "^=", "<<=", ">>="), );
+
+class IncDecTest : public ::testing::TestWithParam<std::string> {};
+
+TEST_P(IncDecTest, IncDecModifies) {
+ const std::string ModExpr = GetParam();
+ const auto AST =
+ tooling::buildASTFromCode("void f() { int x; " + ModExpr + "; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre(ModExpr));
+}
+
+INSTANTIATE_TEST_CASE_P(AllIncDecOperators, IncDecTest,
+ Values("++x", "--x", "x++", "x--"), );
+
+TEST(ExprMutationAnalyzerTest, NonConstMemberFunc) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { struct Foo { void mf(); }; Foo x; x.mf(); }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.mf()"));
+}
+
+TEST(ExprMutationAnalyzerTest, ConstMemberFunc) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { struct Foo { void mf() const; }; Foo x; x.mf(); }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, NonConstOperator) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { struct Foo { Foo& operator=(int); }; Foo x; x = 10; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x = 10"));
+}
+
+TEST(ExprMutationAnalyzerTest, ConstOperator) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { struct Foo { int operator()() const; }; Foo x; x(); }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, ByValueArgument) {
+ auto AST =
+ tooling::buildASTFromCode("void g(int); void f() { int x; g(x); }");
+ auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode(
+ "void f() { struct A {}; A operator+(A, int); A x; x + 1; }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode(
+ "void f() { struct A { A(int); }; int x; A y(x); }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode(
+ "void f() { struct A { A(); A(A); }; A x; A y(x); }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, ByNonConstRefArgument) {
+ auto AST =
+ tooling::buildASTFromCode("void g(int&); void f() { int x; g(x); }");
+ auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)"));
+
+ AST = tooling::buildASTFromCode(
+ "void f() { struct A {}; A operator+(A&, int); A x; x + 1; }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x + 1"));
+
+ AST = tooling::buildASTFromCode(
+ "void f() { struct A { A(int&); }; int x; A y(x); }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
+
+ AST = tooling::buildASTFromCode(
+ "void f() { struct A { A(); A(A&); }; A x; A y(x); }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
+}
+
+TEST(ExprMutationAnalyzerTest, ByConstRefArgument) {
+ auto AST = tooling::buildASTFromCode(
+ "void g(const int&); void f() { int x; g(x); }");
+ auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode(
+ "void f() { struct A {}; A operator+(const A&, int); A x; x + 1; }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode(
+ "void f() { struct A { A(const int&); }; int x; A y(x); }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode(
+ "void f() { struct A { A(); A(const A&); }; A x; A y(x); }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, ByNonConstRRefArgument) {
+ auto AST = tooling::buildASTFromCode(
+ "void g(int&&); void f() { int x; g(static_cast<int &&>(x)); }");
+ auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()),
+ ElementsAre("g(static_cast<int &&>(x))"));
+
+ AST = tooling::buildASTFromCode(
+ "void f() { struct A {}; A operator+(A&&, int); "
+ "A x; static_cast<A &&>(x) + 1; }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()),
+ ElementsAre("static_cast<A &&>(x) + 1"));
+
+ AST = tooling::buildASTFromCode("void f() { struct A { A(int&&); }; "
+ "int x; A y(static_cast<int &&>(x)); }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()),
+ ElementsAre("static_cast<int &&>(x)"));
+
+ AST = tooling::buildASTFromCode("void f() { struct A { A(); A(A&&); }; "
+ "A x; A y(static_cast<A &&>(x)); }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()),
+ ElementsAre("static_cast<A &&>(x)"));
+}
+
+TEST(ExprMutationAnalyzerTest, ByConstRRefArgument) {
+ auto AST = tooling::buildASTFromCode(
+ "void g(const int&&); void f() { int x; g(static_cast<int&&>(x)); }");
+ auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode(
+ "void f() { struct A {}; A operator+(const A&&, int); "
+ "A x; static_cast<A&&>(x) + 1; }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode("void f() { struct A { A(const int&&); }; "
+ "int x; A y(static_cast<int&&>(x)); }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode("void f() { struct A { A(); A(const A&&); }; "
+ "A x; A y(static_cast<A&&>(x)); }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, Move) {
+ // Technically almost the same as ByNonConstRRefArgument, just double checking
+ const auto AST = tooling::buildASTFromCode(
+ "namespace std {"
+ "template<class T> struct remove_reference { typedef T type; };"
+ "template<class T> struct remove_reference<T&> { typedef T type; };"
+ "template<class T> struct remove_reference<T&&> { typedef T type; };"
+ "template<class T> typename std::remove_reference<T>::type&& "
+ "move(T&& t) noexcept; }"
+ "void f() { struct A {}; A x; std::move(x); }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("std::move(x)"));
+}
+
+TEST(ExprMutationAnalyzerTest, Forward) {
+ // Technically almost the same as ByNonConstRefArgument, just double checking
+ const auto AST = tooling::buildASTFromCode(
+ "namespace std {"
+ "template<class T> struct remove_reference { typedef T type; };"
+ "template<class T> struct remove_reference<T&> { typedef T type; };"
+ "template<class T> struct remove_reference<T&&> { typedef T type; };"
+ "template<class T> T&& "
+ "forward(typename std::remove_reference<T>::type&) noexcept;"
+ "template<class T> T&& "
+ "forward(typename std::remove_reference<T>::type&&) noexcept;"
+ "void f() { struct A {}; A x; std::forward<A &>(x); }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()),
+ ElementsAre("std::forward<A &>(x)"));
+}
+
+TEST(ExprMutationAnalyzerTest, ReturnAsValue) {
+ const auto AST = tooling::buildASTFromCode("int f() { int x; return x; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, ReturnAsNonConstRef) {
+ const auto AST = tooling::buildASTFromCode("int& f() { int x; return x; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("return x;"));
+}
+
+TEST(ExprMutationAnalyzerTest, ReturnAsConstRef) {
+ const auto AST =
+ tooling::buildASTFromCode("const int& f() { int x; return x; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, ReturnAsNonConstRRef) {
+ const auto AST = tooling::buildASTFromCode(
+ "int&& f() { int x; return static_cast<int &&>(x); }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()),
+ ElementsAre("return static_cast<int &&>(x);"));
+}
+
+TEST(ExprMutationAnalyzerTest, ReturnAsConstRRef) {
+ const auto AST = tooling::buildASTFromCode(
+ "const int&& f() { int x; return static_cast<int&&>(x); }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, TakeAddress) {
+ const auto AST =
+ tooling::buildASTFromCode("void g(int*); void f() { int x; g(&x); }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("&x"));
+}
+
+TEST(ExprMutationAnalyzerTest, ArrayToPointerDecay) {
+ const auto AST =
+ tooling::buildASTFromCode("void g(int*); void f() { int x[2]; g(x); }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x"));
+}
+
+TEST(ExprMutationAnalyzerTest, FollowRefModified) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; "
+ "int& r3 = r2; r3 = 10; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()),
+ ElementsAre("r0", "r1", "r2", "r3", "r3 = 10"));
+}
+
+TEST(ExprMutationAnalyzerTest, FollowRefNotModified) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; "
+ "int& r3 = r2; int& r4 = r3; int& r5 = r4;}");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, FollowConditionalRefModified) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { int x, y; bool b; int &r = b ? x : y; r = 10; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("r", "r = 10"));
+}
+
+TEST(ExprMutationAnalyzerTest, FollowConditionalRefNotModified) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { int x, y; bool b; int& r = b ? x : y; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, ArrayElementModified) {
+ const auto AST =
+ tooling::buildASTFromCode("void f() { int x[2]; x[0] = 10; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x[0] = 10"));
+}
+
+TEST(ExprMutationAnalyzerTest, ArrayElementNotModified) {
+ const auto AST = tooling::buildASTFromCode("void f() { int x[2]; x[0]; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, NestedMemberModified) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { struct A { int vi; }; struct B { A va; }; "
+ "struct C { B vb; }; C x; x.vb.va.vi = 10; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.vb.va.vi = 10"));
+}
+
+TEST(ExprMutationAnalyzerTest, NestedMemberNotModified) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { struct A { int vi; }; struct B { A va; }; "
+ "struct C { B vb; }; C x; x.vb.va.vi; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CastToValue) {
+ const auto AST =
+ tooling::buildASTFromCode("void f() { int x; static_cast<double>(x); }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CastToRefModified) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { int x; static_cast<int &>(x) = 10; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()),
+ ElementsAre("static_cast<int &>(x) = 10"));
+}
+
+TEST(ExprMutationAnalyzerTest, CastToRefNotModified) {
+ const auto AST =
+ tooling::buildASTFromCode("void f() { int x; static_cast<int&>(x); }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CastToConstRef) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { int x; static_cast<const int&>(x); }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByValue) {
+ const auto AST =
+ tooling::buildASTFromCode("void f() { int x; [=]() { x = 10; }; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByValue) {
+ const auto AST =
+ tooling::buildASTFromCode("void f() { int x; [x]() { x = 10; }; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByRef) {
+ const auto AST =
+ tooling::buildASTFromCode("void f() { int x; [&]() { x = 10; }; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()),
+ ElementsAre(ResultOf(removeSpace, "[&](){x=10;}")));
+}
+
+TEST(ExprMutationAnalyzerTest, LambdaExplicitCaptureByRef) {
+ const auto AST =
+ tooling::buildASTFromCode("void f() { int x; [&x]() { x = 10; }; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()),
+ ElementsAre(ResultOf(removeSpace, "[&x](){x=10;}")));
+}
+
+TEST(ExprMutationAnalyzerTest, RangeForArrayByRefModified) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { int x[2]; for (int& e : x) e = 10; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10"));
+}
+
+TEST(ExprMutationAnalyzerTest, RangeForArrayByRefNotModified) {
+ const auto AST =
+ tooling::buildASTFromCode("void f() { int x[2]; for (int& e : x) e; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, RangeForArrayByValue) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { int x[2]; for (int e : x) e = 10; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, RangeForArrayByConstRef) {
+ const auto AST = tooling::buildASTFromCode(
+ "void f() { int x[2]; for (const int& e : x) e; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefModified) {
+ const auto AST =
+ tooling::buildASTFromCode("struct V { int* begin(); int* end(); };"
+ "void f() { V x; for (int& e : x) e = 10; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10"));
+}
+
+TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefNotModified) {
+ const auto AST =
+ tooling::buildASTFromCode("struct V { int* begin(); int* end(); };"
+ "void f() { V x; for (int& e : x) e; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, RangeForNonArrayByValue) {
+ const auto AST = tooling::buildASTFromCode(
+ "struct V { const int* begin() const; const int* end() const; };"
+ "void f() { V x; for (int e : x) e; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, RangeForNonArrayByConstRef) {
+ const auto AST = tooling::buildASTFromCode(
+ "struct V { const int* begin() const; const int* end() const; };"
+ "void f() { V x; for (const int& e : x) e; }");
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, UnevaluatedExpressions) {
+ auto AST = tooling::buildASTFromCode(
+ "void f() { int x, y; decltype(x = 10) z = y; }");
+ auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode(
+ "void f() { int x, y; __typeof(x = 10) z = y; }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode(
+ "void f() { int x, y; __typeof__(x = 10) z = y; }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode("void f() { int x; sizeof(x = 10); }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode("void f() { int x; alignof(x = 10); }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode("void f() { int x; noexcept(x = 10); }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCodeWithArgs("namespace std { class type_info; }"
+ "void f() { int x; typeid(x = 10); }",
+ {"-frtti"});
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+
+ AST = tooling::buildASTFromCode(
+ "void f() { int x; _Generic(x = 10, int: 0, default: 1); }");
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, NotUnevaluatedExpressions) {
+ auto AST = tooling::buildASTFromCode("void f() { int x; sizeof(int[x++]); }");
+ auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x++"));
+
+ AST = tooling::buildASTFromCodeWithArgs(
+ "namespace std { class type_info; }"
+ "struct A { virtual ~A(); }; struct B : A {};"
+ "struct X { A& f(); }; void f() { X x; typeid(x.f()); }",
+ {"-frtti"});
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x.f()"));
+}
+
+} // namespace test
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/GoogleModuleTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/GoogleModuleTest.cpp
new file mode 100644
index 0000000..feb7ae9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/GoogleModuleTest.cpp
@@ -0,0 +1,110 @@
+#include "ClangTidyTest.h"
+#include "google/ExplicitConstructorCheck.h"
+#include "google/GlobalNamesInHeadersCheck.h"
+#include "gtest/gtest.h"
+
+using namespace clang::tidy::google;
+
+namespace clang {
+namespace tidy {
+namespace test {
+
+TEST(ExplicitConstructorCheckTest, SingleArgumentConstructorsOnly) {
+ EXPECT_NO_CHANGES(ExplicitConstructorCheck, "class C { C(); };");
+ EXPECT_NO_CHANGES(ExplicitConstructorCheck, "class C { C(int i, int j); };");
+ EXPECT_NO_CHANGES(ExplicitConstructorCheck, "class C { C(const C&); };");
+ EXPECT_NO_CHANGES(ExplicitConstructorCheck, "class C { C(C&&); };");
+ EXPECT_NO_CHANGES(ExplicitConstructorCheck,
+ "class C { C(const C&) = delete; };");
+ EXPECT_NO_CHANGES(ExplicitConstructorCheck,
+ "class C { C(int) = delete; };");
+}
+
+TEST(ExplicitConstructorCheckTest, Basic) {
+ EXPECT_EQ("class C { explicit C(int i); };",
+ runCheckOnCode<ExplicitConstructorCheck>("class C { C(int i); };"));
+}
+
+TEST(ExplicitConstructorCheckTest, DefaultParameters) {
+ EXPECT_EQ("class C { explicit C(int i, int j = 0); };",
+ runCheckOnCode<ExplicitConstructorCheck>(
+ "class C { C(int i, int j = 0); };"));
+}
+
+TEST(ExplicitConstructorCheckTest, OutOfLineDefinitions) {
+ EXPECT_EQ("class C { explicit C(int i); }; C::C(int i) {}",
+ runCheckOnCode<ExplicitConstructorCheck>(
+ "class C { C(int i); }; C::C(int i) {}"));
+}
+
+TEST(ExplicitConstructorCheckTest, RemoveExplicit) {
+ EXPECT_EQ("class A { A(const A&); };\n"
+ "class B { /*asdf*/ B(B&&); };\n"
+ "class C { /*asdf*/ C(const C&, int i = 0); };",
+ runCheckOnCode<ExplicitConstructorCheck>(
+ "class A { explicit A(const A&); };\n"
+ "class B { explicit /*asdf*/ B(B&&); };\n"
+ "class C { explicit/*asdf*/ C(const C&, int i = 0); };"));
+}
+
+TEST(ExplicitConstructorCheckTest, RemoveExplicitWithMacros) {
+ EXPECT_EQ(
+ "#define A(T) class T##Bar { explicit T##Bar(const T##Bar &b) {} };\n"
+ "A(Foo);",
+ runCheckOnCode<ExplicitConstructorCheck>(
+ "#define A(T) class T##Bar { explicit T##Bar(const T##Bar &b) {} };\n"
+ "A(Foo);"));
+}
+
+class GlobalNamesInHeadersCheckTest : public ::testing::Test {
+protected:
+ bool runCheckOnCode(const std::string &Code, const std::string &Filename) {
+ static const char *const Header = "namespace std {\n"
+ "class string {};\n"
+ "} // namespace std\n"
+ "\n"
+ "#define SOME_MACRO(x) using x\n";
+ std::vector<ClangTidyError> Errors;
+ std::vector<std::string> Args;
+ if (!StringRef(Filename).endswith(".cpp")) {
+ Args.emplace_back("-xc++-header");
+ }
+ test::runCheckOnCode<readability::GlobalNamesInHeadersCheck>(
+ Header + Code, &Errors, Filename, Args);
+ if (Errors.empty())
+ return false;
+ assert(Errors.size() == 1);
+ assert(
+ Errors[0].Message.Message ==
+ "using declarations in the global namespace in headers are prohibited");
+ return true;
+ }
+};
+
+TEST_F(GlobalNamesInHeadersCheckTest, UsingDeclarations) {
+ EXPECT_TRUE(runCheckOnCode("using std::string;", "foo.h"));
+ EXPECT_FALSE(runCheckOnCode("using std::string;", "foo.cpp"));
+ EXPECT_FALSE(runCheckOnCode("namespace my_namespace {\n"
+ "using std::string;\n"
+ "} // my_namespace\n",
+ "foo.h"));
+ EXPECT_FALSE(runCheckOnCode("SOME_MACRO(std::string);", "foo.h"));
+}
+
+TEST_F(GlobalNamesInHeadersCheckTest, UsingDirectives) {
+ EXPECT_TRUE(runCheckOnCode("using namespace std;", "foo.h"));
+ EXPECT_FALSE(runCheckOnCode("using namespace std;", "foo.cpp"));
+ EXPECT_FALSE(runCheckOnCode("namespace my_namespace {\n"
+ "using namespace std;\n"
+ "} // my_namespace\n",
+ "foo.h"));
+ EXPECT_FALSE(runCheckOnCode("SOME_MACRO(namespace std);", "foo.h"));
+}
+
+TEST_F(GlobalNamesInHeadersCheckTest, RegressionAnonymousNamespace) {
+ EXPECT_FALSE(runCheckOnCode("namespace {}", "foo.h"));
+}
+
+} // namespace test
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/IncludeInserterTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/IncludeInserterTest.cpp
new file mode 100644
index 0000000..a5f5898
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/IncludeInserterTest.cpp
@@ -0,0 +1,612 @@
+//===---- IncludeInserterTest.cpp - clang-tidy ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../clang-tidy/utils/IncludeInserter.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "ClangTidyTest.h"
+#include "gtest/gtest.h"
+
+// FIXME: Canonicalize paths correctly on windows.
+// Currently, adding virtual files will canonicalize the paths before
+// storing the virtual entries.
+// When resolving virtual entries in the FileManager, the paths (for
+// example coming from a #include directive) are not canonicalized
+// to native paths; thus, the virtual file is not found.
+// This needs to be fixed in the FileManager before we can make
+// clang-tidy tests work.
+#if !defined(_WIN32)
+
+namespace clang {
+namespace tidy {
+namespace {
+
+class IncludeInserterCheckBase : public ClangTidyCheck {
+public:
+ IncludeInserterCheckBase(StringRef CheckName, ClangTidyContext *Context)
+ : ClangTidyCheck(CheckName, Context) {}
+
+ void registerPPCallbacks(CompilerInstance &Compiler) override {
+ Inserter.reset(new utils::IncludeInserter(
+ Compiler.getSourceManager(),
+ Compiler.getLangOpts(),
+ utils::IncludeSorter::IS_Google));
+ Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
+ }
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override {
+ Finder->addMatcher(ast_matchers::declStmt().bind("stmt"), this);
+ }
+
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override {
+ auto Diag = diag(Result.Nodes.getNodeAs<DeclStmt>("stmt")->getLocStart(),
+ "foo, bar");
+ for (StringRef header : HeadersToInclude()) {
+ auto Fixit = Inserter->CreateIncludeInsertion(
+ Result.SourceManager->getMainFileID(), header, IsAngledInclude());
+ if (Fixit) {
+ Diag << *Fixit;
+ }
+ }
+ }
+
+ virtual std::vector<StringRef> HeadersToInclude() const = 0;
+ virtual bool IsAngledInclude() const = 0;
+
+ std::unique_ptr<utils::IncludeInserter> Inserter;
+};
+
+class NonSystemHeaderInserterCheck : public IncludeInserterCheckBase {
+public:
+ NonSystemHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context)
+ : IncludeInserterCheckBase(CheckName, Context) {}
+
+ std::vector<StringRef> HeadersToInclude() const override {
+ return {"path/to/header.h"};
+ }
+ bool IsAngledInclude() const override { return false; }
+};
+
+class EarlyInAlphabetHeaderInserterCheck : public IncludeInserterCheckBase {
+public:
+ EarlyInAlphabetHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context)
+ : IncludeInserterCheckBase(CheckName, Context) {}
+
+ std::vector<StringRef> HeadersToInclude() const override {
+ return {"a/header.h"};
+ }
+ bool IsAngledInclude() const override { return false; }
+};
+
+class MultipleHeaderInserterCheck : public IncludeInserterCheckBase {
+public:
+ MultipleHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context)
+ : IncludeInserterCheckBase(CheckName, Context) {}
+
+ std::vector<StringRef> HeadersToInclude() const override {
+ return {"path/to/header.h", "path/to/header2.h", "path/to/header.h"};
+ }
+ bool IsAngledInclude() const override { return false; }
+};
+
+class CSystemIncludeInserterCheck : public IncludeInserterCheckBase {
+public:
+ CSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
+ : IncludeInserterCheckBase(CheckName, Context) {}
+
+ std::vector<StringRef> HeadersToInclude() const override {
+ return {"stdlib.h"};
+ }
+ bool IsAngledInclude() const override { return true; }
+};
+
+class CXXSystemIncludeInserterCheck : public IncludeInserterCheckBase {
+public:
+ CXXSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
+ : IncludeInserterCheckBase(CheckName, Context) {}
+
+ std::vector<StringRef> HeadersToInclude() const override { return {"set"}; }
+ bool IsAngledInclude() const override { return true; }
+};
+
+template <typename Check>
+std::string runCheckOnCode(StringRef Code, StringRef Filename) {
+ std::vector<ClangTidyError> Errors;
+ return test::runCheckOnCode<Check>(Code, &Errors, Filename, None,
+ ClangTidyOptions(),
+ {// Main file include
+ {"clang_tidy/tests/"
+ "insert_includes_test_header.h",
+ "\n"},
+ // Non system headers
+ {"a/header.h", "\n"},
+ {"path/to/a/header.h", "\n"},
+ {"path/to/z/header.h", "\n"},
+ {"path/to/header.h", "\n"},
+ {"path/to/header2.h", "\n"},
+ // Fake system headers.
+ {"stdlib.h", "\n"},
+ {"unistd.h", "\n"},
+ {"list", "\n"},
+ {"map", "\n"},
+ {"set", "\n"},
+ {"vector", "\n"}});
+}
+
+TEST(IncludeInserterTest, InsertAfterLastNonSystemInclude) {
+ const char *PreCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <list>
+#include <map>
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+ const char *PostCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <list>
+#include <map>
+
+#include "path/to/a/header.h"
+#include "path/to/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
+ PreCode, "clang_tidy/tests/"
+ "insert_includes_test_input2.cc"));
+}
+
+TEST(IncludeInserterTest, InsertMultipleIncludesAndDeduplicate) {
+ const char *PreCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <list>
+#include <map>
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+ const char *PostCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <list>
+#include <map>
+
+#include "path/to/a/header.h"
+#include "path/to/header.h"
+#include "path/to/header2.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<MultipleHeaderInserterCheck>(
+ PreCode, "clang_tidy/tests/"
+ "insert_includes_test_input2.cc"));
+}
+
+TEST(IncludeInserterTest, InsertBeforeFirstNonSystemInclude) {
+ const char *PreCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <list>
+#include <map>
+
+#include "path/to/z/header.h"
+
+void foo() {
+ int a = 0;
+})";
+ const char *PostCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <list>
+#include <map>
+
+#include "path/to/header.h"
+#include "path/to/z/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
+ PreCode, "clang_tidy/tests/"
+ "insert_includes_test_input2.cc"));
+}
+
+TEST(IncludeInserterTest, InsertBetweenNonSystemIncludes) {
+ const char *PreCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <list>
+#include <map>
+
+#include "path/to/a/header.h"
+#include "path/to/z/header.h"
+
+void foo() {
+ int a = 0;
+})";
+ const char *PostCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <list>
+#include <map>
+
+#include "path/to/a/header.h"
+#include "path/to/header.h"
+#include "path/to/z/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
+ PreCode, "clang_tidy/tests/"
+ "insert_includes_test_input2.cc"));
+}
+
+TEST(IncludeInserterTest, NonSystemIncludeAlreadyIncluded) {
+ const char *PreCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <list>
+#include <map>
+
+#include "path/to/a/header.h"
+#include "path/to/header.h"
+#include "path/to/z/header.h"
+
+void foo() {
+ int a = 0;
+})";
+ EXPECT_EQ(PreCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
+ PreCode, "clang_tidy/tests/"
+ "insert_includes_test_input2.cc"));
+}
+
+TEST(IncludeInserterTest, InsertNonSystemIncludeAfterLastCXXSystemInclude) {
+ const char *PreCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <list>
+#include <map>
+
+void foo() {
+ int a = 0;
+})";
+ const char *PostCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <list>
+#include <map>
+
+#include "path/to/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
+ PreCode, "clang_tidy/tests/"
+ "insert_includes_test_header.cc"));
+}
+
+TEST(IncludeInserterTest, InsertNonSystemIncludeAfterMainFileInclude) {
+ const char *PreCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+void foo() {
+ int a = 0;
+})";
+ const char *PostCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include "path/to/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
+ PreCode, "clang_tidy/tests/"
+ "insert_includes_test_header.cc"));
+}
+
+TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterLastCXXSystemInclude) {
+ const char *PreCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <list>
+#include <map>
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+ const char *PostCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <list>
+#include <map>
+#include <set>
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
+ PreCode, "clang_tidy/tests/"
+ "insert_includes_test_header.cc"));
+}
+
+TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeFirstCXXSystemInclude) {
+ const char *PreCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <vector>
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+ const char *PostCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <set>
+#include <vector>
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
+ PreCode, "clang_tidy/tests/"
+ "insert_includes_test_header.cc"));
+}
+
+TEST(IncludeInserterTest, InsertCXXSystemIncludeBetweenCXXSystemIncludes) {
+ const char *PreCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <map>
+#include <vector>
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+ const char *PostCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
+ PreCode, "clang_tidy/tests/"
+ "insert_includes_test_header.cc"));
+}
+
+TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterMainFileInclude) {
+ const char *PreCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+ const char *PostCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <set>
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
+ PreCode, "clang_tidy/tests/"
+ "insert_includes_test_header.cc"));
+}
+
+TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterCSystemInclude) {
+ const char *PreCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <stdlib.h>
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+ const char *PostCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <stdlib.h>
+
+#include <set>
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
+ PreCode, "clang_tidy/tests/"
+ "insert_includes_test_header.cc"));
+}
+
+TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeNonSystemInclude) {
+ const char *PreCode = R"(
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+ const char *PostCode = R"(
+#include <set>
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
+ PreCode, "devtools/cymbal/clang_tidy/tests/"
+ "insert_includes_test_header.cc"));
+}
+
+TEST(IncludeInserterTest, InsertCSystemIncludeBeforeCXXSystemInclude) {
+ const char *PreCode = R"(
+#include <set>
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+ const char *PostCode = R"(
+#include <stdlib.h>
+
+#include <set>
+
+#include "path/to/a/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<CSystemIncludeInserterCheck>(
+ PreCode, "devtools/cymbal/clang_tidy/tests/"
+ "insert_includes_test_header.cc"));
+}
+
+TEST(IncludeInserterTest, InsertIncludeIfThereWasNoneBefore) {
+ const char *PreCode = R"(
+void foo() {
+ int a = 0;
+})";
+ const char *PostCode = R"(#include <set>
+
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
+ PreCode, "devtools/cymbal/clang_tidy/tests/"
+ "insert_includes_test_header.cc"));
+}
+
+TEST(IncludeInserterTest, DontInsertDuplicateIncludeEvenIfMiscategorized) {
+ const char *PreCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "a/header.h"
+#include "path/to/a/header.h"
+#include "path/to/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ const char *PostCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "a/header.h"
+#include "path/to/a/header.h"
+#include "path/to/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<EarlyInAlphabetHeaderInserterCheck>(
+ PreCode, "workspace_folder/clang_tidy/tests/"
+ "insert_includes_test_header.cc"));
+}
+
+TEST(IncludeInserterTest, HandleOrderInSubdirectory) {
+ const char *PreCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "path/to/a/header.h"
+#include "path/to/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ const char *PostCode = R"(
+#include "clang_tidy/tests/insert_includes_test_header.h"
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "a/header.h"
+#include "path/to/a/header.h"
+#include "path/to/header.h"
+
+void foo() {
+ int a = 0;
+})";
+
+ EXPECT_EQ(PostCode, runCheckOnCode<EarlyInAlphabetHeaderInserterCheck>(
+ PreCode, "workspace_folder/clang_tidy/tests/"
+ "insert_includes_test_header.cc"));
+}
+
+} // anonymous namespace
+} // namespace tidy
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/LLVMModuleTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/LLVMModuleTest.cpp
new file mode 100644
index 0000000..8ab207d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/LLVMModuleTest.cpp
@@ -0,0 +1,219 @@
+#include "ClangTidyTest.h"
+#include "llvm/HeaderGuardCheck.h"
+#include "llvm/IncludeOrderCheck.h"
+#include "gtest/gtest.h"
+
+using namespace clang::tidy::llvm;
+
+namespace clang {
+namespace tidy {
+namespace test {
+
+// FIXME: It seems this might be incompatible to dos path. Investigating.
+#if !defined(_WIN32)
+static std::string runHeaderGuardCheck(StringRef Code, const Twine &Filename,
+ Optional<StringRef> ExpectedWarning) {
+ std::vector<ClangTidyError> Errors;
+ std::string Result = test::runCheckOnCode<LLVMHeaderGuardCheck>(
+ Code, &Errors, Filename, std::string("-xc++-header"));
+ if (Errors.size() != (size_t)ExpectedWarning.hasValue())
+ return "invalid error count";
+ if (ExpectedWarning && *ExpectedWarning != Errors.back().Message.Message)
+ return "expected: '" + ExpectedWarning->str() + "', saw: '" +
+ Errors.back().Message.Message + "'";
+ return Result;
+}
+
+namespace {
+struct WithEndifComment : public LLVMHeaderGuardCheck {
+ WithEndifComment(StringRef Name, ClangTidyContext *Context)
+ : LLVMHeaderGuardCheck(Name, Context) {}
+ bool shouldSuggestEndifComment(StringRef Filename) override { return true; }
+};
+} // namespace
+
+static std::string
+runHeaderGuardCheckWithEndif(StringRef Code, const Twine &Filename,
+ Optional<StringRef> ExpectedWarning) {
+ std::vector<ClangTidyError> Errors;
+ std::string Result = test::runCheckOnCode<WithEndifComment>(
+ Code, &Errors, Filename, std::string("-xc++-header"));
+ if (Errors.size() != (size_t)ExpectedWarning.hasValue())
+ return "invalid error count";
+ if (ExpectedWarning && *ExpectedWarning != Errors.back().Message.Message)
+ return "expected: '" + ExpectedWarning->str() + "', saw: '" +
+ Errors.back().Message.Message + "'";
+ return Result;
+}
+
+TEST(LLVMHeaderGuardCheckTest, FixHeaderGuards) {
+ EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
+ "#define LLVM_ADT_FOO_H\n"
+ "#endif\n",
+ runHeaderGuardCheck(
+ "#ifndef FOO\n"
+ "#define FOO\n"
+ "#endif\n",
+ "include/llvm/ADT/foo.h",
+ StringRef("header guard does not follow preferred style")));
+
+ // Allow trailing underscores.
+ EXPECT_EQ("#ifndef LLVM_ADT_FOO_H_\n"
+ "#define LLVM_ADT_FOO_H_\n"
+ "#endif\n",
+ runHeaderGuardCheck("#ifndef LLVM_ADT_FOO_H_\n"
+ "#define LLVM_ADT_FOO_H_\n"
+ "#endif\n",
+ "include/llvm/ADT/foo.h", None));
+
+ EXPECT_EQ("#ifndef LLVM_CLANG_C_BAR_H\n"
+ "#define LLVM_CLANG_C_BAR_H\n"
+ "\n"
+ "\n"
+ "#endif\n",
+ runHeaderGuardCheck("", "./include/clang-c/bar.h",
+ StringRef("header is missing header guard")));
+
+ EXPECT_EQ("#ifndef LLVM_CLANG_LIB_CODEGEN_C_H\n"
+ "#define LLVM_CLANG_LIB_CODEGEN_C_H\n"
+ "\n"
+ "\n"
+ "#endif\n",
+ runHeaderGuardCheck("", "tools/clang/lib/CodeGen/c.h",
+ StringRef("header is missing header guard")));
+
+ EXPECT_EQ("#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_X_H\n"
+ "#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_X_H\n"
+ "\n"
+ "\n"
+ "#endif\n",
+ runHeaderGuardCheck("", "tools/clang/tools/extra/clang-tidy/x.h",
+ StringRef("header is missing header guard")));
+
+ EXPECT_EQ(
+ "int foo;\n"
+ "#ifndef LLVM_CLANG_BAR_H\n"
+ "#define LLVM_CLANG_BAR_H\n"
+ "#endif\n",
+ runHeaderGuardCheck("int foo;\n"
+ "#ifndef LLVM_CLANG_BAR_H\n"
+ "#define LLVM_CLANG_BAR_H\n"
+ "#endif\n",
+ "include/clang/bar.h",
+ StringRef("code/includes outside of area guarded by "
+ "header guard; consider moving it")));
+
+ EXPECT_EQ(
+ "#ifndef LLVM_CLANG_BAR_H\n"
+ "#define LLVM_CLANG_BAR_H\n"
+ "#endif\n"
+ "int foo;\n",
+ runHeaderGuardCheck("#ifndef LLVM_CLANG_BAR_H\n"
+ "#define LLVM_CLANG_BAR_H\n"
+ "#endif\n"
+ "int foo;\n",
+ "include/clang/bar.h",
+ StringRef("code/includes outside of area guarded by "
+ "header guard; consider moving it")));
+
+ EXPECT_EQ("#ifndef LLVM_CLANG_BAR_H\n"
+ "#define LLVM_CLANG_BAR_H\n"
+ "\n"
+ "int foo;\n"
+ "#ifndef FOOLOLO\n"
+ "#define FOOLOLO\n"
+ "#endif\n"
+ "\n"
+ "#endif\n",
+ runHeaderGuardCheck("int foo;\n"
+ "#ifndef FOOLOLO\n"
+ "#define FOOLOLO\n"
+ "#endif\n",
+ "include/clang/bar.h",
+ StringRef("header is missing header guard")));
+
+ // Fix incorrect #endif comments even if we shouldn't add new ones.
+ EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
+ "#define LLVM_ADT_FOO_H\n"
+ "#endif // LLVM_ADT_FOO_H\n",
+ runHeaderGuardCheck(
+ "#ifndef FOO\n"
+ "#define FOO\n"
+ "#endif // FOO\n",
+ "include/llvm/ADT/foo.h",
+ StringRef("header guard does not follow preferred style")));
+
+ EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
+ "#define LLVM_ADT_FOO_H\n"
+ "#endif // LLVM_ADT_FOO_H\n",
+ runHeaderGuardCheckWithEndif(
+ "#ifndef FOO\n"
+ "#define FOO\n"
+ "#endif\n",
+ "include/llvm/ADT/foo.h",
+ StringRef("header guard does not follow preferred style")));
+
+ EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
+ "#define LLVM_ADT_FOO_H\n"
+ "#endif // LLVM_ADT_FOO_H\n",
+ runHeaderGuardCheckWithEndif(
+ "#ifndef LLVM_ADT_FOO_H\n"
+ "#define LLVM_ADT_FOO_H\n"
+ "#endif // LLVM_H\n",
+ "include/llvm/ADT/foo.h",
+ StringRef("#endif for a header guard should reference the "
+ "guard macro in a comment")));
+
+ EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
+ "#define LLVM_ADT_FOO_H\n"
+ "#endif /* LLVM_ADT_FOO_H */\n",
+ runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H\n"
+ "#define LLVM_ADT_FOO_H\n"
+ "#endif /* LLVM_ADT_FOO_H */\n",
+ "include/llvm/ADT/foo.h", None));
+
+ EXPECT_EQ("#ifndef LLVM_ADT_FOO_H_\n"
+ "#define LLVM_ADT_FOO_H_\n"
+ "#endif // LLVM_ADT_FOO_H_\n",
+ runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H_\n"
+ "#define LLVM_ADT_FOO_H_\n"
+ "#endif // LLVM_ADT_FOO_H_\n",
+ "include/llvm/ADT/foo.h", None));
+
+ EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
+ "#define LLVM_ADT_FOO_H\n"
+ "#endif // LLVM_ADT_FOO_H\n",
+ runHeaderGuardCheckWithEndif(
+ "#ifndef LLVM_ADT_FOO_H_\n"
+ "#define LLVM_ADT_FOO_H_\n"
+ "#endif // LLVM\n",
+ "include/llvm/ADT/foo.h",
+ StringRef("header guard does not follow preferred style")));
+
+ EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
+ "#define LLVM_ADT_FOO_H\n"
+ "#endif \\ \n"
+ "// LLVM_ADT_FOO_H\n",
+ runHeaderGuardCheckWithEndif(
+ "#ifndef LLVM_ADT_FOO_H\n"
+ "#define LLVM_ADT_FOO_H\n"
+ "#endif \\ \n"
+ "// LLVM_ADT_FOO_H\n",
+ "include/llvm/ADT/foo.h",
+ StringRef("backslash and newline separated by space")));
+
+ EXPECT_EQ("#ifndef LLVM_ADT_FOO_H\n"
+ "#define LLVM_ADT_FOO_H\n"
+ "#endif /* LLVM_ADT_FOO_H\\ \n"
+ " FOO */",
+ runHeaderGuardCheckWithEndif("#ifndef LLVM_ADT_FOO_H\n"
+ "#define LLVM_ADT_FOO_H\n"
+ "#endif /* LLVM_ADT_FOO_H\\ \n"
+ " FOO */",
+ "include/llvm/ADT/foo.h", None));
+}
+#endif
+
+} // namespace test
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/NamespaceAliaserTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/NamespaceAliaserTest.cpp
new file mode 100644
index 0000000..71286e2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/NamespaceAliaserTest.cpp
@@ -0,0 +1,123 @@
+//===---- NamespaceAliaserTest.cpp - clang-tidy
+//----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../clang-tidy/utils/NamespaceAliaser.h"
+
+#include "ClangTidyTest.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+// This checker is for testing only. It can only run on one test case
+// (e.g. with one SourceManager).
+class InsertAliasCheck : public ClangTidyCheck {
+public:
+ InsertAliasCheck(StringRef Name, ClangTidyContext *Context)
+ :ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override {
+ Finder->addMatcher(ast_matchers::callExpr().bind("foo"), this);
+ }
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override {
+ if (!Aliaser)
+ Aliaser.reset(new NamespaceAliaser(*Result.SourceManager));
+
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("foo");
+ assert(Call != nullptr && "Did not find node \"foo\"");
+ auto Hint = Aliaser->createAlias(*Result.Context, *Call, "::foo::bar",
+ {"b", "some_alias"});
+ if (Hint.hasValue())
+ diag(Call->getLocStart(), "Fix for testing") << Hint.getValue();
+
+ diag(Call->getLocStart(), "insert call")
+ << FixItHint::CreateInsertion(
+ Call->getLocStart(),
+ Aliaser->getNamespaceName(*Result.Context, *Call, "::foo::bar") +
+ "::");
+ }
+
+private:
+ std::unique_ptr<NamespaceAliaser> Aliaser;
+};
+
+template <typename Check>
+std::string runChecker(StringRef Code, unsigned ExpectedWarningCount) {
+ std::map<StringRef, StringRef> AdditionalFileContents = {{"foo.h",
+ "namespace foo {\n"
+ "namespace bar {\n"
+ "}\n"
+ "void func() { }\n"
+ "}"}};
+ std::vector<ClangTidyError> errors;
+
+ std::string result =
+ test::runCheckOnCode<Check>(Code, &errors, "foo.cc", None,
+ ClangTidyOptions(), AdditionalFileContents);
+
+ EXPECT_EQ(ExpectedWarningCount, errors.size());
+ return result;
+}
+
+TEST(NamespaceAliaserTest, AddNewAlias) {
+ EXPECT_EQ("#include \"foo.h\"\n"
+ "void f() {\n"
+ "namespace b = ::foo::bar;"
+ " b::f(); }",
+ runChecker<InsertAliasCheck>("#include \"foo.h\"\n"
+ "void f() { f(); }",
+ 2));
+}
+
+TEST(NamespaceAliaserTest, ReuseAlias) {
+ EXPECT_EQ(
+ "#include \"foo.h\"\n"
+ "void f() { namespace x = foo::bar; x::f(); }",
+ runChecker<InsertAliasCheck>("#include \"foo.h\"\n"
+ "void f() { namespace x = foo::bar; f(); }",
+ 1));
+}
+
+TEST(NamespaceAliaserTest, AddsOnlyOneAlias) {
+ EXPECT_EQ("#include \"foo.h\"\n"
+ "void f() {\n"
+ "namespace b = ::foo::bar;"
+ " b::f(); b::f(); }",
+ runChecker<InsertAliasCheck>("#include \"foo.h\"\n"
+ "void f() { f(); f(); }",
+ 3));
+}
+
+TEST(NamespaceAliaserTest, LocalConflict) {
+ EXPECT_EQ("#include \"foo.h\"\n"
+ "void f() {\n"
+ "namespace some_alias = ::foo::bar;"
+ " namespace b = foo; some_alias::f(); }",
+ runChecker<InsertAliasCheck>("#include \"foo.h\"\n"
+ "void f() { namespace b = foo; f(); }",
+ 2));
+}
+
+TEST(NamespaceAliaserTest, GlobalConflict) {
+ EXPECT_EQ("#include \"foo.h\"\n"
+ "namespace b = foo;\n"
+ "void f() {\n"
+ "namespace some_alias = ::foo::bar;"
+ " some_alias::f(); }",
+ runChecker<InsertAliasCheck>("#include \"foo.h\"\n"
+ "namespace b = foo;\n"
+ "void f() { f(); }",
+ 2));
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ObjCModuleTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ObjCModuleTest.cpp
new file mode 100644
index 0000000..92ae8e1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ObjCModuleTest.cpp
@@ -0,0 +1,49 @@
+//===---- ObjCModuleTest.cpp - clang-tidy ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangTidyTest.h"
+#include "gtest/gtest.h"
+#include "objc/ForbiddenSubclassingCheck.h"
+
+using namespace clang::tidy::objc;
+
+namespace clang {
+namespace tidy {
+namespace test {
+
+TEST(ObjCForbiddenSubclassing, AllowedSubclass) {
+ std::vector<ClangTidyError> Errors;
+ runCheckOnCode<ForbiddenSubclassingCheck>(
+ "@interface Foo\n"
+ "@end\n"
+ "@interface Bar : Foo\n"
+ "@end\n",
+ &Errors,
+ "input.m");
+ EXPECT_EQ(0ul, Errors.size());
+}
+
+TEST(ObjCForbiddenSubclassing, ForbiddenSubclass) {
+ std::vector<ClangTidyError> Errors;
+ runCheckOnCode<ForbiddenSubclassingCheck>(
+ "@interface UIImagePickerController\n"
+ "@end\n"
+ "@interface Foo : UIImagePickerController\n"
+ "@end\n",
+ &Errors,
+ "input.m");
+ EXPECT_EQ(1ul, Errors.size());
+ EXPECT_EQ(
+ "Objective-C interface 'Foo' subclasses 'UIImagePickerController', which is not intended to be subclassed",
+ Errors[0].Message.Message);
+}
+
+} // namespace test
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/OverlappingReplacementsTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/OverlappingReplacementsTest.cpp
new file mode 100644
index 0000000..b7c4805
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/OverlappingReplacementsTest.cpp
@@ -0,0 +1,409 @@
+//===---- OverlappingReplacementsTest.cpp - clang-tidy --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangTidyTest.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tidy {
+namespace test {
+namespace {
+
+const char BoundDecl[] = "decl";
+const char BoundIf[] = "if";
+
+// We define a reduced set of very small checks that allow to test different
+// overlapping situations (no overlapping, replacements partially overlap, etc),
+// as well as different kinds of diagnostics (one check produces several errors,
+// several replacement ranges in an error, etc).
+class UseCharCheck : public ClangTidyCheck {
+public:
+ UseCharCheck(StringRef CheckName, ClangTidyContext *Context)
+ : ClangTidyCheck(CheckName, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override {
+ using namespace ast_matchers;
+ Finder->addMatcher(varDecl(hasType(isInteger())).bind(BoundDecl), this);
+ }
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override {
+ auto *VD = Result.Nodes.getNodeAs<VarDecl>(BoundDecl);
+ diag(VD->getLocStart(), "use char") << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(VD->getLocStart(), VD->getLocStart()),
+ "char");
+ }
+};
+
+class IfFalseCheck : public ClangTidyCheck {
+public:
+ IfFalseCheck(StringRef CheckName, ClangTidyContext *Context)
+ : ClangTidyCheck(CheckName, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override {
+ using namespace ast_matchers;
+ Finder->addMatcher(ifStmt().bind(BoundIf), this);
+ }
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override {
+ auto *If = Result.Nodes.getNodeAs<IfStmt>(BoundIf);
+ auto *Cond = If->getCond();
+ SourceRange Range = Cond->getSourceRange();
+ if (auto *D = If->getConditionVariable()) {
+ Range = SourceRange(D->getLocStart(), D->getLocEnd());
+ }
+ diag(Range.getBegin(), "the cake is a lie") << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(Range), "false");
+ }
+};
+
+class RefactorCheck : public ClangTidyCheck {
+public:
+ RefactorCheck(StringRef CheckName, ClangTidyContext *Context)
+ : ClangTidyCheck(CheckName, Context), NamePattern("::$") {}
+ RefactorCheck(StringRef CheckName, ClangTidyContext *Context,
+ StringRef NamePattern)
+ : ClangTidyCheck(CheckName, Context), NamePattern(NamePattern) {}
+ virtual std::string newName(StringRef OldName) = 0;
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder) final {
+ using namespace ast_matchers;
+ Finder->addMatcher(varDecl(matchesName(NamePattern)).bind(BoundDecl), this);
+ }
+
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) final {
+ auto *VD = Result.Nodes.getNodeAs<VarDecl>(BoundDecl);
+ std::string NewName = newName(VD->getName());
+
+ auto Diag = diag(VD->getLocation(), "refactor %0 into %1")
+ << VD->getName() << NewName
+ << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(VD->getLocation(),
+ VD->getLocation()),
+ NewName);
+
+ class UsageVisitor : public RecursiveASTVisitor<UsageVisitor> {
+ public:
+ UsageVisitor(const ValueDecl *VD, StringRef NewName,
+ DiagnosticBuilder &Diag)
+ : VD(VD), NewName(NewName), Diag(Diag) {}
+ bool VisitDeclRefExpr(DeclRefExpr *E) {
+ if (const ValueDecl *D = E->getDecl()) {
+ if (VD->getCanonicalDecl() == D->getCanonicalDecl()) {
+ Diag << FixItHint::CreateReplacement(
+ CharSourceRange::getTokenRange(E->getSourceRange()), NewName);
+ }
+ }
+ return RecursiveASTVisitor<UsageVisitor>::VisitDeclRefExpr(E);
+ }
+
+ private:
+ const ValueDecl *VD;
+ StringRef NewName;
+ DiagnosticBuilder &Diag;
+ };
+
+ UsageVisitor(VD, NewName, Diag)
+ .TraverseDecl(Result.Context->getTranslationUnitDecl());
+ }
+
+protected:
+ const std::string NamePattern;
+};
+
+class StartsWithPotaCheck : public RefactorCheck {
+public:
+ StartsWithPotaCheck(StringRef CheckName, ClangTidyContext *Context)
+ : RefactorCheck(CheckName, Context, "::pota") {}
+
+ std::string newName(StringRef OldName) override {
+ return "toma" + OldName.substr(4).str();
+ }
+};
+
+class EndsWithTatoCheck : public RefactorCheck {
+public:
+ EndsWithTatoCheck(StringRef CheckName, ClangTidyContext *Context)
+ : RefactorCheck(CheckName, Context, "tato$") {}
+
+ std::string newName(StringRef OldName) override {
+ return OldName.substr(0, OldName.size() - 4).str() + "melo";
+ }
+};
+
+} // namespace
+
+TEST(OverlappingReplacementsTest, UseCharCheckTest) {
+ const char Code[] =
+ R"(void f() {
+ int a = 0;
+ if (int b = 0) {
+ int c = a;
+ }
+})";
+
+ const char CharFix[] =
+ R"(void f() {
+ char a = 0;
+ if (char b = 0) {
+ char c = a;
+ }
+})";
+ EXPECT_EQ(CharFix, runCheckOnCode<UseCharCheck>(Code));
+}
+
+TEST(OverlappingReplacementsTest, IfFalseCheckTest) {
+ const char Code[] =
+ R"(void f() {
+ int potato = 0;
+ if (int b = 0) {
+ int c = potato;
+ } else if (true) {
+ int d = 0;
+ }
+})";
+
+ const char IfFix[] =
+ R"(void f() {
+ int potato = 0;
+ if (false) {
+ int c = potato;
+ } else if (false) {
+ int d = 0;
+ }
+})";
+ EXPECT_EQ(IfFix, runCheckOnCode<IfFalseCheck>(Code));
+}
+
+TEST(OverlappingReplacementsTest, StartsWithCheckTest) {
+ const char Code[] =
+ R"(void f() {
+ int a = 0;
+ int potato = 0;
+ if (int b = 0) {
+ int c = potato;
+ } else if (true) {
+ int d = 0;
+ }
+})";
+
+ const char StartsFix[] =
+ R"(void f() {
+ int a = 0;
+ int tomato = 0;
+ if (int b = 0) {
+ int c = tomato;
+ } else if (true) {
+ int d = 0;
+ }
+})";
+ EXPECT_EQ(StartsFix, runCheckOnCode<StartsWithPotaCheck>(Code));
+}
+
+TEST(OverlappingReplacementsTest, EndsWithCheckTest) {
+ const char Code[] =
+ R"(void f() {
+ int a = 0;
+ int potato = 0;
+ if (int b = 0) {
+ int c = potato;
+ } else if (true) {
+ int d = 0;
+ }
+})";
+
+ const char EndsFix[] =
+ R"(void f() {
+ int a = 0;
+ int pomelo = 0;
+ if (int b = 0) {
+ int c = pomelo;
+ } else if (true) {
+ int d = 0;
+ }
+})";
+ EXPECT_EQ(EndsFix, runCheckOnCode<EndsWithTatoCheck>(Code));
+}
+
+TEST(OverlappingReplacementTest, ReplacementsDoNotOverlap) {
+ std::string Res;
+ const char Code[] =
+ R"(void f() {
+ int potassium = 0;
+ if (true) {
+ int Potato = potassium;
+ }
+})";
+
+ const char CharIfFix[] =
+ R"(void f() {
+ char potassium = 0;
+ if (false) {
+ char Potato = potassium;
+ }
+})";
+ Res = runCheckOnCode<UseCharCheck, IfFalseCheck>(Code);
+ EXPECT_EQ(CharIfFix, Res);
+
+ const char StartsEndsFix[] =
+ R"(void f() {
+ int tomassium = 0;
+ if (true) {
+ int Pomelo = tomassium;
+ }
+})";
+ Res = runCheckOnCode<StartsWithPotaCheck, EndsWithTatoCheck>(Code);
+ EXPECT_EQ(StartsEndsFix, Res);
+
+ const char CharIfStartsEndsFix[] =
+ R"(void f() {
+ char tomassium = 0;
+ if (false) {
+ char Pomelo = tomassium;
+ }
+})";
+ Res = runCheckOnCode<UseCharCheck, IfFalseCheck, StartsWithPotaCheck,
+ EndsWithTatoCheck>(Code);
+ EXPECT_EQ(CharIfStartsEndsFix, Res);
+}
+
+TEST(OverlappingReplacementsTest, ReplacementInsideOtherReplacement) {
+ std::string Res;
+ const char Code[] =
+ R"(void f() {
+ if (char potato = 0) {
+ } else if (int a = 0) {
+ char potato = 0;
+ if (potato) potato;
+ }
+})";
+
+ // Apply the UseCharCheck together with the IfFalseCheck.
+ //
+ // The 'If' fix contains the other, so that is the one that has to be applied.
+ // } else if (int a = 0) {
+ // ^^^ -> char
+ // ~~~~~~~~~ -> false
+ const char CharIfFix[] =
+ R"(void f() {
+ if (false) {
+ } else if (false) {
+ char potato = 0;
+ if (false) potato;
+ }
+})";
+ Res = runCheckOnCode<UseCharCheck, IfFalseCheck>(Code);
+ EXPECT_EQ(CharIfFix, Res);
+ Res = runCheckOnCode<IfFalseCheck, UseCharCheck>(Code);
+ EXPECT_EQ(CharIfFix, Res);
+
+ // Apply the IfFalseCheck with the StartsWithPotaCheck.
+ //
+ // The 'If' replacement is bigger here.
+ // if (char potato = 0) {
+ // ^^^^^^ -> tomato
+ // ~~~~~~~~~~~~~~~ -> false
+ //
+ // But the refactoring is the one that contains the other here:
+ // char potato = 0;
+ // ^^^^^^ -> tomato
+ // if (potato) potato;
+ // ^^^^^^ ^^^^^^ -> tomato, tomato
+ // ~~~~~~ -> false
+ const char IfStartsFix[] =
+ R"(void f() {
+ if (false) {
+ } else if (false) {
+ char tomato = 0;
+ if (tomato) tomato;
+ }
+})";
+ Res = runCheckOnCode<IfFalseCheck, StartsWithPotaCheck>(Code);
+ EXPECT_EQ(IfStartsFix, Res);
+ Res = runCheckOnCode<StartsWithPotaCheck, IfFalseCheck>(Code);
+ EXPECT_EQ(IfStartsFix, Res);
+}
+
+TEST(OverlappingReplacements, TwoReplacementsInsideOne) {
+ std::string Res;
+ const char Code[] =
+ R"(void f() {
+ if (int potato = 0) {
+ int a = 0;
+ }
+})";
+
+ // The two smallest replacements should not be applied.
+ // if (int potato = 0) {
+ // ^^^^^^ -> tomato
+ // *** -> char
+ // ~~~~~~~~~~~~~~ -> false
+ // But other errors from the same checks should not be affected.
+ // int a = 0;
+ // *** -> char
+ const char Fix[] =
+ R"(void f() {
+ if (false) {
+ char a = 0;
+ }
+})";
+ Res = runCheckOnCode<UseCharCheck, IfFalseCheck, StartsWithPotaCheck>(Code);
+ EXPECT_EQ(Fix, Res);
+ Res = runCheckOnCode<StartsWithPotaCheck, IfFalseCheck, UseCharCheck>(Code);
+ EXPECT_EQ(Fix, Res);
+}
+
+TEST(OverlappingReplacementsTest,
+ ApplyAtMostOneOfTheChangesWhenPartialOverlapping) {
+ std::string Res;
+ const char Code[] =
+ R"(void f() {
+ if (int potato = 0) {
+ int a = potato;
+ }
+})";
+
+ // These two replacements overlap, but none of them is completely contained
+ // inside the other.
+ // if (int potato = 0) {
+ // ^^^^^^ -> tomato
+ // ~~~~~~~~~~~~~~ -> false
+ // int a = potato;
+ // ^^^^^^ -> tomato
+ //
+ // The 'StartsWithPotaCheck' fix has endpoints inside the 'IfFalseCheck' fix,
+ // so it is going to be set as inapplicable. The 'if' fix will be applied.
+ const char IfFix[] =
+ R"(void f() {
+ if (false) {
+ int a = potato;
+ }
+})";
+ Res = runCheckOnCode<IfFalseCheck, StartsWithPotaCheck>(Code);
+ EXPECT_EQ(IfFix, Res);
+}
+
+TEST(OverlappingReplacementsTest, TwoErrorsHavePerfectOverlapping) {
+ std::string Res;
+ const char Code[] =
+ R"(void f() {
+ int potato = 0;
+ potato += potato * potato;
+ if (char a = potato) potato;
+})";
+
+ // StartsWithPotaCheck will try to refactor 'potato' into 'tomato', and
+ // EndsWithTatoCheck will try to use 'pomelo'. Both fixes have the same set of
+ // ranges. This is a corner case of one error completely containing another:
+ // the other completely contains the first one as well. Both errors are
+ // discarded.
+
+ Res = runCheckOnCode<StartsWithPotaCheck, EndsWithTatoCheck>(Code);
+ EXPECT_EQ(Code, Res);
+}
+
+} // namespace test
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ReadabilityModuleTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ReadabilityModuleTest.cpp
new file mode 100644
index 0000000..a0eca16
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/ReadabilityModuleTest.cpp
@@ -0,0 +1,505 @@
+#include "ClangTidyTest.h"
+#include "readability/BracesAroundStatementsCheck.h"
+#include "readability/NamespaceCommentCheck.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tidy {
+namespace test {
+
+using readability::BracesAroundStatementsCheck;
+using readability::NamespaceCommentCheck;
+
+TEST(NamespaceCommentCheckTest, Basic) {
+ EXPECT_EQ("namespace i {\n} // namespace i",
+ runCheckOnCode<NamespaceCommentCheck>("namespace i {\n}"));
+ EXPECT_EQ("namespace {\n} // namespace",
+ runCheckOnCode<NamespaceCommentCheck>("namespace {\n}"));
+ EXPECT_EQ("namespace i { namespace j {\n} // namespace j\n } // namespace i",
+ runCheckOnCode<NamespaceCommentCheck>(
+ "namespace i { namespace j {\n} }"));
+}
+
+TEST(NamespaceCommentCheckTest, SingleLineNamespaces) {
+ EXPECT_EQ(
+ "namespace i { namespace j { } }",
+ runCheckOnCode<NamespaceCommentCheck>("namespace i { namespace j { } }"));
+}
+
+TEST(NamespaceCommentCheckTest, CheckExistingComments) {
+ EXPECT_EQ("namespace i { namespace j {\n"
+ "} /* namespace j */ } // namespace i\n"
+ " /* random comment */",
+ runCheckOnCode<NamespaceCommentCheck>(
+ "namespace i { namespace j {\n"
+ "} /* namespace j */ } /* random comment */"));
+ EXPECT_EQ("namespace {\n"
+ "} // namespace",
+ runCheckOnCode<NamespaceCommentCheck>("namespace {\n"
+ "} // namespace"));
+ EXPECT_EQ("namespace {\n"
+ "} //namespace",
+ runCheckOnCode<NamespaceCommentCheck>("namespace {\n"
+ "} //namespace"));
+ EXPECT_EQ("namespace {\n"
+ "} // anonymous namespace",
+ runCheckOnCode<NamespaceCommentCheck>("namespace {\n"
+ "} // anonymous namespace"));
+ EXPECT_EQ("namespace {\n"
+ "} // Anonymous namespace.",
+ runCheckOnCode<NamespaceCommentCheck>("namespace {\n"
+ "} // Anonymous namespace."));
+ EXPECT_EQ(
+ "namespace q {\n"
+ "} // namespace q",
+ runCheckOnCode<NamespaceCommentCheck>("namespace q {\n"
+ "} // anonymous namespace q"));
+ EXPECT_EQ(
+ "namespace My_NameSpace123 {\n"
+ "} // namespace My_NameSpace123",
+ runCheckOnCode<NamespaceCommentCheck>("namespace My_NameSpace123 {\n"
+ "} // namespace My_NameSpace123"));
+ EXPECT_EQ(
+ "namespace My_NameSpace123 {\n"
+ "} //namespace My_NameSpace123",
+ runCheckOnCode<NamespaceCommentCheck>("namespace My_NameSpace123 {\n"
+ "} //namespace My_NameSpace123"));
+ EXPECT_EQ("namespace My_NameSpace123 {\n"
+ "} // end namespace My_NameSpace123",
+ runCheckOnCode<NamespaceCommentCheck>(
+ "namespace My_NameSpace123 {\n"
+ "} // end namespace My_NameSpace123"));
+ // Understand comments only on the same line.
+ EXPECT_EQ("namespace {\n"
+ "} // namespace\n"
+ "// namespace",
+ runCheckOnCode<NamespaceCommentCheck>("namespace {\n"
+ "}\n"
+ "// namespace"));
+}
+
+TEST(NamespaceCommentCheckTest, FixWrongComments) {
+ EXPECT_EQ("namespace i { namespace jJ0_ {\n"
+ "} // namespace jJ0_\n"
+ " } // namespace i\n"
+ " /* random comment */",
+ runCheckOnCode<NamespaceCommentCheck>(
+ "namespace i { namespace jJ0_ {\n"
+ "} /* namespace qqq */ } /* random comment */"));
+ EXPECT_EQ("namespace {\n"
+ "} // namespace",
+ runCheckOnCode<NamespaceCommentCheck>("namespace {\n"
+ "} // namespace asdf"));
+ // Remove unknown line comments. These are likely to be an unrecognized form
+ // of a namespace ending comment.
+ EXPECT_EQ("namespace {\n"
+ "} // namespace",
+ runCheckOnCode<NamespaceCommentCheck>("namespace {\n"
+ "} // random text"));
+}
+
+TEST(BracesAroundStatementsCheckTest, IfWithComments) {
+ EXPECT_EQ("int main() {\n"
+ " if (false /*dummy token*/) {\n"
+ " // comment\n"
+ " return -1; /**/\n"
+ "}\n"
+ " if (false) {\n"
+ " return -1; // comment\n"
+ "}\n"
+ " if (false) {\n"
+ " return -1; \n"
+ "}/* multi-line \n comment */\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>(
+ "int main() {\n"
+ " if (false /*dummy token*/)\n"
+ " // comment\n"
+ " return -1; /**/\n"
+ " if (false)\n"
+ " return -1; // comment\n"
+ " if (false)\n"
+ " return -1; /* multi-line \n comment */\n"
+ "}"));
+ EXPECT_EQ("int main() {\n"
+ " if (false /*dummy token*/) {\n"
+ " // comment\n"
+ " return -1 /**/ ;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>(
+ "int main() {\n"
+ " if (false /*dummy token*/)\n"
+ " // comment\n"
+ " return -1 /**/ ;\n"
+ "}"));
+}
+
+TEST(BracesAroundStatementsCheckTest, If) {
+ EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n"
+ " if (false) {\n"
+ " return -1;\n"
+ " }\n"
+ "}");
+ EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n"
+ " if (auto Cond = false) {\n"
+ " return -1;\n"
+ " }\n"
+ "}");
+ EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n"
+ " if (false) {\n"
+ " return -1;\n"
+ " } else {\n"
+ " return -2;\n"
+ " }\n"
+ "}");
+ EXPECT_EQ("int main() {\n"
+ " if (false) {\n"
+ " return -1;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+ " if (false)\n"
+ " return -1;\n"
+ "}"));
+ EXPECT_EQ("int main() {\n"
+ " if (auto Cond = false /**/ ) {\n"
+ " return -1;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>(
+ "int main() {\n"
+ " if (auto Cond = false /**/ )\n"
+ " return -1;\n"
+ "}"));
+ // FIXME: Consider adding braces before EMPTY_MACRO and after the statement.
+ EXPECT_NO_CHANGES(BracesAroundStatementsCheck,
+ "#define EMPTY_MACRO\n"
+ "int main() {\n"
+ " if (auto Cond = false EMPTY_MACRO /**/ ) EMPTY_MACRO\n"
+ " return -1;\n"
+ "}");
+ EXPECT_EQ("int main() {\n"
+ " if (true) { return -1/**/ ;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>(
+ "int main() {\n"
+ " if (true) return -1/**/ ;\n"
+ "}"));
+ EXPECT_EQ("int main() {\n"
+ " if (false) {\n"
+ " return -1;\n"
+ " } else {\n"
+ " return -2;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+ " if (false)\n"
+ " return -1;\n"
+ " else\n"
+ " return -2;\n"
+ "}"));
+ EXPECT_EQ("int main() {\n"
+ " if (false) {\n"
+ " return -1;\n"
+ " } else if (1 == 2) {\n"
+ " return -2;\n"
+ " } else {\n"
+ " return -3;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+ " if (false)\n"
+ " return -1;\n"
+ " else if (1 == 2)\n"
+ " return -2;\n"
+ " else\n"
+ " return -3;\n"
+ "}"));
+ EXPECT_EQ("int main() {\n"
+ " if (false) {\n"
+ " return -1;\n"
+ " } else if (1 == 2) {\n"
+ " return -2;\n"
+ " } else {\n"
+ " return -3;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+ " if (false)\n"
+ " return -1;\n"
+ " else if (1 == 2) {\n"
+ " return -2;\n"
+ " } else\n"
+ " return -3;\n"
+ "}"));
+}
+
+TEST(BracesAroundStatementsCheckTest, IfElseWithShortStatements) {
+ ClangTidyOptions Options;
+ Options.CheckOptions["test-check-0.ShortStatementLines"] = "1";
+
+ EXPECT_EQ("int main() {\n"
+ " if (true) return 1;\n"
+ " if (false) { return -1;\n"
+ " } else if (1 == 2) { return -2;\n"
+ " } else { return -3;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>(
+ "int main() {\n"
+ " if (true) return 1;\n"
+ " if (false) return -1;\n"
+ " else if (1 == 2) return -2;\n"
+ " else return -3;\n"
+ "}",
+ nullptr, "input.cc", None, Options));
+
+ // If the last else is an else-if, we also force it.
+ EXPECT_EQ("int main() {\n"
+ " if (false) { return -1;\n"
+ " } else if (1 == 2) { return -2;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>(
+ "int main() {\n"
+ " if (false) return -1;\n"
+ " else if (1 == 2) return -2;\n"
+ "}",
+ nullptr, "input.cc", None, Options));
+}
+
+TEST(BracesAroundStatementsCheckTest, For) {
+ EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n"
+ " for (;;) {\n"
+ " ;\n"
+ " }\n"
+ "}");
+ EXPECT_EQ("int main() {\n"
+ " for (;;) {\n"
+ " ;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+ " for (;;)\n"
+ " ;\n"
+ "}"));
+ EXPECT_EQ("int main() {\n"
+ " for (;;) {\n"
+ " /**/ ;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+ " for (;;)\n"
+ " /**/ ;\n"
+ "}"));
+ EXPECT_EQ("int main() {\n"
+ " for (;;) {\n"
+ " return -1 /**/ ;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+ " for (;;)\n"
+ " return -1 /**/ ;\n"
+ "}"));
+}
+
+TEST(BracesAroundStatementsCheckTest, ForRange) {
+ EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n"
+ " int arr[4];\n"
+ " for (int i : arr) {\n"
+ " ;\n"
+ " }\n"
+ "}");
+ EXPECT_EQ("int main() {\n"
+ " int arr[4];\n"
+ " for (int i : arr) {\n"
+ " ;\n"
+ "}\n"
+ " for (int i : arr) {\n"
+ " return -1 ;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+ " int arr[4];\n"
+ " for (int i : arr)\n"
+ " ;\n"
+ " for (int i : arr)\n"
+ " return -1 ;\n"
+ "}"));
+}
+
+TEST(BracesAroundStatementsCheckTest, DoWhile) {
+ EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n"
+ " do {\n"
+ " ;\n"
+ " } while (false);\n"
+ "}");
+ EXPECT_EQ("int main() {\n"
+ " do {\n"
+ " ;\n"
+ " } while (false);\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+ " do\n"
+ " ;\n"
+ " while (false);\n"
+ "}"));
+}
+
+TEST(BracesAroundStatementsCheckTest, While) {
+ EXPECT_NO_CHANGES(BracesAroundStatementsCheck, "int main() {\n"
+ " while (false) {\n"
+ " ;\n"
+ " }\n"
+ "}");
+ EXPECT_EQ("int main() {\n"
+ " while (false) {\n"
+ " ;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+ " while (false)\n"
+ " ;\n"
+ "}"));
+ EXPECT_EQ("int main() {\n"
+ " while (auto Cond = false) {\n"
+ " ;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>(
+ "int main() {\n"
+ " while (auto Cond = false)\n"
+ " ;\n"
+ "}"));
+ EXPECT_EQ("int main() {\n"
+ " while (false /*dummy token*/) {\n"
+ " ;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>(
+ "int main() {\n"
+ " while (false /*dummy token*/)\n"
+ " ;\n"
+ "}"));
+ EXPECT_EQ("int main() {\n"
+ " while (false) {\n"
+ " break;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+ " while (false)\n"
+ " break;\n"
+ "}"));
+ EXPECT_EQ("int main() {\n"
+ " while (false) {\n"
+ " break /**/;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+ " while (false)\n"
+ " break /**/;\n"
+ "}"));
+ EXPECT_EQ("int main() {\n"
+ " while (false) {\n"
+ " /**/;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+ " while (false)\n"
+ " /**/;\n"
+ "}"));
+}
+
+TEST(BracesAroundStatementsCheckTest, Nested) {
+ EXPECT_EQ("int main() {\n"
+ " do { if (true) {}} while (false);\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>(
+ "int main() {\n"
+ " do if (true) {}while (false);\n"
+ "}"));
+ EXPECT_EQ("int main() {\n"
+ " do { if (true) {}} while (false);\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>(
+ "int main() {\n"
+ " do if (true) {}while (false);\n"
+ "}"));
+ EXPECT_EQ(
+ "int main() {\n"
+ " if (true) {\n"
+ " // comment\n"
+ " if (false) {\n"
+ " // comment\n"
+ " /**/ ; // comment\n"
+ " }\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("int main() {\n"
+ " if (true)\n"
+ " // comment\n"
+ " if (false) {\n"
+ " // comment\n"
+ " /**/ ; // comment\n"
+ " }\n"
+ "}"));
+}
+
+TEST(BracesAroundStatementsCheckTest, Macros) {
+ EXPECT_NO_CHANGES(BracesAroundStatementsCheck,
+ "#define IF(COND) if (COND) return -1;\n"
+ "int main() {\n"
+ " IF(false)\n"
+ "}");
+ EXPECT_NO_CHANGES(BracesAroundStatementsCheck,
+ "#define FOR(COND) for (COND) return -1;\n"
+ "int main() {\n"
+ " FOR(;;)\n"
+ "}");
+ EXPECT_EQ("#define DO_IT ++i\n"
+ "int i = 0;\n"
+ "int main() {\n"
+ " if (false) {\n"
+ " DO_IT;\n"
+ " } else if (1 == 2) {\n"
+ " DO_IT;\n"
+ " } else {\n"
+ " DO_IT;\n"
+ "}\n"
+ "}",
+ runCheckOnCode<BracesAroundStatementsCheck>("#define DO_IT ++i\n"
+ "int i = 0;\n"
+ "int main() {\n"
+ " if (false)\n"
+ " DO_IT;\n"
+ " else if (1 == 2)\n"
+ " DO_IT;\n"
+ " else\n"
+ " DO_IT;\n"
+ "}"));
+}
+
+#define EXPECT_NO_CHANGES_WITH_OPTS(Check, Opts, Code) \
+ EXPECT_EQ(Code, runCheckOnCode<Check>(Code, nullptr, "input.cc", None, Opts))
+TEST(BracesAroundStatementsCheckTest, ImplicitCastInReturn) {
+ ClangTidyOptions Opts;
+ Opts.CheckOptions["test-check-0.ShortStatementLines"] = "1";
+
+ StringRef Input = "const char *f() {\n"
+ " if (true) return \"\";\n"
+ " return \"abc\";\n"
+ "}\n";
+ EXPECT_NO_CHANGES_WITH_OPTS(BracesAroundStatementsCheck, Opts, Input);
+ EXPECT_EQ("const char *f() {\n"
+ " if (true) { return \"\";\n"
+ "}\n"
+ " return \"abc\";\n"
+ "}\n",
+ runCheckOnCode<BracesAroundStatementsCheck>(Input));
+}
+
+} // namespace test
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/UsingInserterTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/UsingInserterTest.cpp
new file mode 100644
index 0000000..9e465a0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clang-tidy/UsingInserterTest.cpp
@@ -0,0 +1,114 @@
+//===---- UsingInserterTest.cpp - clang-tidy ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../clang-tidy/utils/UsingInserter.h"
+
+#include "ClangTidyTest.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+// Replace all function calls with calls to foo::func. Inserts using
+// declarations as necessary. This checker is for testing only. It
+// can only run on one test case (e.g. wih one SourceManager).
+class InsertUsingCheck : public clang::tidy::ClangTidyCheck {
+public:
+ InsertUsingCheck(StringRef Name, ClangTidyContext *Context)
+ :ClangTidyCheck(Name, Context) {}
+ void registerMatchers(clang::ast_matchers::MatchFinder *Finder) override {
+ Finder->addMatcher(clang::ast_matchers::callExpr().bind("foo"), this);
+ }
+ void
+ check(const clang::ast_matchers::MatchFinder::MatchResult &Result) override {
+ if (!Inserter)
+ Inserter.reset(new UsingInserter(*Result.SourceManager));
+
+ const auto *Call = Result.Nodes.getNodeAs<clang::CallExpr>("foo");
+ assert(Call != nullptr && "Did not find node \"foo\"");
+ auto Hint =
+ Inserter->createUsingDeclaration(*Result.Context, *Call, "::foo::func");
+
+ if (Hint.hasValue())
+ diag(Call->getLocStart(), "Fix for testing") << Hint.getValue();
+
+ diag(Call->getLocStart(), "insert call")
+ << clang::FixItHint::CreateReplacement(
+ Call->getCallee()->getSourceRange(),
+ Inserter->getShortName(*Result.Context, *Call, "::foo::func"));
+ }
+
+private:
+ std::unique_ptr<UsingInserter> Inserter;
+};
+
+template <typename Check>
+std::string runChecker(StringRef Code, unsigned ExpectedWarningCount) {
+ std::map<StringRef, StringRef> AdditionalFileContents = {{"foo.h",
+ "namespace foo {\n"
+ "namespace bar {\n"
+ "}\n"
+ "void func() { }\n"
+ "}"}};
+ std::vector<ClangTidyError> errors;
+
+ std::string result =
+ test::runCheckOnCode<Check>(Code, &errors, "foo.cc", None,
+ ClangTidyOptions(), AdditionalFileContents);
+
+ EXPECT_EQ(ExpectedWarningCount, errors.size());
+ return result;
+}
+
+TEST(UsingInserterTest, ReusesExisting) {
+ EXPECT_EQ("#include \"foo.h\"\n"
+ "namespace {"
+ "using ::foo::func;\n"
+ "void f() { func(); }"
+ "}",
+ runChecker<InsertUsingCheck>("#include \"foo.h\"\n"
+ "namespace {"
+ "using ::foo::func;\n"
+ "void f() { f(); }"
+ "}",
+ 1));
+}
+
+TEST(UsingInserterTest, ReusesExistingGlobal) {
+ EXPECT_EQ("#include \"foo.h\"\n"
+ "using ::foo::func;\n"
+ "namespace {"
+ "void f() { func(); }"
+ "}",
+ runChecker<InsertUsingCheck>("#include \"foo.h\"\n"
+ "using ::foo::func;\n"
+ "namespace {"
+ "void f() { f(); }"
+ "}",
+ 1));
+}
+
+TEST(UsingInserterTest, AvoidsConflict) {
+ EXPECT_EQ("#include \"foo.h\"\n"
+ "namespace {"
+ "void f() { int func; ::foo::func(); }"
+ "}",
+ runChecker<InsertUsingCheck>("#include \"foo.h\"\n"
+ "namespace {"
+ "void f() { int func; f(); }"
+ "}",
+ 1));
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/Annotations.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/Annotations.cpp
new file mode 100644
index 0000000..6bd81c8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/Annotations.cpp
@@ -0,0 +1,87 @@
+//===--- Annotations.cpp - Annotated source code for unit tests -*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#include "Annotations.h"
+#include "SourceCode.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+// Crash if the assertion fails, printing the message and testcase.
+// More elegant error handling isn't needed for unit tests.
+static void require(bool Assertion, const char *Msg, llvm::StringRef Code) {
+ if (!Assertion) {
+ llvm::errs() << "Annotated testcase: " << Msg << "\n" << Code << "\n";
+ llvm_unreachable("Annotated testcase assertion failed!");
+ }
+}
+
+Annotations::Annotations(StringRef Text) {
+ auto Here = [this] { return offsetToPosition(Code, Code.size()); };
+ auto Require = [Text](bool Assertion, const char *Msg) {
+ require(Assertion, Msg, Text);
+ };
+ Optional<StringRef> Name;
+ SmallVector<std::pair<StringRef, Position>, 8> OpenRanges;
+
+ Code.reserve(Text.size());
+ while (!Text.empty()) {
+ if (Text.consume_front("^")) {
+ Points[Name.getValueOr("")].push_back(Here());
+ Name = None;
+ continue;
+ }
+ if (Text.consume_front("[[")) {
+ OpenRanges.emplace_back(Name.getValueOr(""), Here());
+ Name = None;
+ continue;
+ }
+ Require(!Name, "$name should be followed by ^ or [[");
+ if (Text.consume_front("]]")) {
+ Require(!OpenRanges.empty(), "unmatched ]]");
+ Ranges[OpenRanges.back().first].push_back(
+ {OpenRanges.back().second, Here()});
+ OpenRanges.pop_back();
+ continue;
+ }
+ if (Text.consume_front("$")) {
+ Name = Text.take_while(llvm::isAlnum);
+ Text = Text.drop_front(Name->size());
+ continue;
+ }
+ Code.push_back(Text.front());
+ Text = Text.drop_front();
+ }
+ Require(!Name, "unterminated $name");
+ Require(OpenRanges.empty(), "unmatched [[");
+}
+
+Position Annotations::point(llvm::StringRef Name) const {
+ auto I = Points.find(Name);
+ require(I != Points.end() && I->getValue().size() == 1,
+ "expected exactly one point", Code);
+ return I->getValue()[0];
+}
+std::vector<Position> Annotations::points(llvm::StringRef Name) const {
+ auto P = Points.lookup(Name);
+ return {P.begin(), P.end()};
+}
+Range Annotations::range(llvm::StringRef Name) const {
+ auto I = Ranges.find(Name);
+ require(I != Ranges.end() && I->getValue().size() == 1,
+ "expected exactly one range", Code);
+ return I->getValue()[0];
+}
+std::vector<Range> Annotations::ranges(llvm::StringRef Name) const {
+ auto R = Ranges.lookup(Name);
+ return {R.begin(), R.end()};
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/Annotations.h b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/Annotations.h
new file mode 100644
index 0000000..549a21e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/Annotations.h
@@ -0,0 +1,69 @@
+//===--- Annotations.h - Annotated source code for tests --------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// Annotations lets you mark points and ranges inside source code, for tests:
+//
+// Annotations Example(R"cpp(
+// int complete() { x.pri^ } // ^ indicates a point
+// void err() { [["hello" == 42]]; } // [[this is a range]]
+// $definition^class Foo{}; // points can be named: "definition"
+// $fail[[static_assert(false, "")]] // ranges can be named too: "fail"
+// )cpp");
+//
+// StringRef Code = Example.code(); // annotations stripped.
+// std::vector<Position> PP = Example.points(); // all unnamed points
+// Position P = Example.point(); // there must be exactly one
+// Range R = Example.range("fail"); // find named ranges
+//
+// Points/ranges are coordinates into `code()` which is stripped of annotations.
+//
+// Ranges may be nested (and points can be inside ranges), but there's no way
+// to define general overlapping ranges.
+//
+//===---------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_ANNOTATIONS_H
+#define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_ANNOTATIONS_H
+#include "Protocol.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace clangd {
+
+class Annotations {
+public:
+ // Parses the annotations from Text. Crashes if it's malformed.
+ Annotations(llvm::StringRef Text);
+
+ // The input text with all annotations stripped.
+ // All points and ranges are relative to this stripped text.
+ llvm::StringRef code() const { return Code; }
+
+ // Returns the position of the point marked by ^ (or $name^) in the text.
+ // Crashes if there isn't exactly one.
+ Position point(llvm::StringRef Name = "") const;
+ // Returns the position of all points marked by ^ (or $name^) in the text.
+ std::vector<Position> points(llvm::StringRef Name = "") const;
+
+ // Returns the location of the range marked by [[ ]] (or $name[[ ]]).
+ // Crashes if there isn't exactly one.
+ Range range(llvm::StringRef Name = "") const;
+ // Returns the location of all ranges marked by [[ ]] (or $name[[ ]]).
+ std::vector<Range> ranges(llvm::StringRef Name = "") const;
+
+private:
+ std::string Code;
+ llvm::StringMap<llvm::SmallVector<Position, 1>> Points;
+ llvm::StringMap<llvm::SmallVector<Range, 1>> Ranges;
+};
+
+} // namespace clangd
+} // namespace clang
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/CMakeLists.txt
new file mode 100644
index 0000000..516060e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/CMakeLists.txt
@@ -0,0 +1,55 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+get_filename_component(CLANGD_SOURCE_DIR
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../clangd REALPATH)
+include_directories(
+ ${CLANGD_SOURCE_DIR}
+ )
+
+add_extra_unittest(ClangdTests
+ Annotations.cpp
+ ClangdTests.cpp
+ ClangdUnitTests.cpp
+ CodeCompleteTests.cpp
+ CodeCompletionStringsTests.cpp
+ ContextTests.cpp
+ DexIndexTests.cpp
+ DraftStoreTests.cpp
+ FileDistanceTests.cpp
+ FileIndexTests.cpp
+ FindSymbolsTests.cpp
+ FuzzyMatchTests.cpp
+ GlobalCompilationDatabaseTests.cpp
+ HeadersTests.cpp
+ IndexTests.cpp
+ QualityTests.cpp
+ SourceCodeTests.cpp
+ SymbolCollectorTests.cpp
+ SyncAPI.cpp
+ TUSchedulerTests.cpp
+ TestFS.cpp
+ TestTU.cpp
+ ThreadingTests.cpp
+ TraceTests.cpp
+ URITests.cpp
+ XRefsTests.cpp
+ )
+
+target_link_libraries(ClangdTests
+ PRIVATE
+ clangAST
+ clangBasic
+ clangDaemon
+ clangFormat
+ clangFrontend
+ clangIndex
+ clangLex
+ clangSema
+ clangTooling
+ clangToolingCore
+ clangToolingInclusions
+ LLVMSupport
+ LLVMTestingSupport
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/ClangdTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/ClangdTests.cpp
new file mode 100644
index 0000000..ace2cef
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/ClangdTests.cpp
@@ -0,0 +1,968 @@
+//===-- ClangdTests.cpp - Clangd unit tests ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Annotations.h"
+#include "ClangdLSPServer.h"
+#include "ClangdServer.h"
+#include "Matchers.h"
+#include "SyncAPI.h"
+#include "TestFS.h"
+#include "URI.h"
+#include "clang/Config/config.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Regex.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <algorithm>
+#include <chrono>
+#include <iostream>
+#include <random>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace clang {
+namespace clangd {
+
+using ::testing::ElementsAre;
+using ::testing::Eq;
+using ::testing::Field;
+using ::testing::Gt;
+using ::testing::IsEmpty;
+using ::testing::Pair;
+using ::testing::UnorderedElementsAre;
+
+namespace {
+
+bool diagsContainErrors(const std::vector<Diag> &Diagnostics) {
+ for (auto D : Diagnostics) {
+ if (D.Severity == DiagnosticsEngine::Error ||
+ D.Severity == DiagnosticsEngine::Fatal)
+ return true;
+ }
+ return false;
+}
+
+class ErrorCheckingDiagConsumer : public DiagnosticsConsumer {
+public:
+ void onDiagnosticsReady(PathRef File,
+ std::vector<Diag> Diagnostics) override {
+ bool HadError = diagsContainErrors(Diagnostics);
+ std::lock_guard<std::mutex> Lock(Mutex);
+ HadErrorInLastDiags = HadError;
+ }
+
+ bool hadErrorInLastDiags() {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ return HadErrorInLastDiags;
+ }
+
+private:
+ std::mutex Mutex;
+ bool HadErrorInLastDiags = false;
+};
+
+/// For each file, record whether the last published diagnostics contained at
+/// least one error.
+class MultipleErrorCheckingDiagConsumer : public DiagnosticsConsumer {
+public:
+ void onDiagnosticsReady(PathRef File,
+ std::vector<Diag> Diagnostics) override {
+ bool HadError = diagsContainErrors(Diagnostics);
+
+ std::lock_guard<std::mutex> Lock(Mutex);
+ LastDiagsHadError[File] = HadError;
+ }
+
+ /// Exposes all files consumed by onDiagnosticsReady in an unspecified order.
+ /// For each file, a bool value indicates whether the last diagnostics
+ /// contained an error.
+ std::vector<std::pair<Path, bool>> filesWithDiags() const {
+ std::vector<std::pair<Path, bool>> Result;
+ std::lock_guard<std::mutex> Lock(Mutex);
+
+ for (const auto &it : LastDiagsHadError) {
+ Result.emplace_back(it.first(), it.second);
+ }
+
+ return Result;
+ }
+
+ void clear() {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ LastDiagsHadError.clear();
+ }
+
+private:
+ mutable std::mutex Mutex;
+ llvm::StringMap<bool> LastDiagsHadError;
+};
+
+/// Replaces all patterns of the form 0x123abc with spaces
+std::string replacePtrsInDump(std::string const &Dump) {
+ llvm::Regex RE("0x[0-9a-fA-F]+");
+ llvm::SmallVector<StringRef, 1> Matches;
+ llvm::StringRef Pending = Dump;
+
+ std::string Result;
+ while (RE.match(Pending, &Matches)) {
+ assert(Matches.size() == 1 && "Exactly one match expected");
+ auto MatchPos = Matches[0].data() - Pending.data();
+
+ Result += Pending.take_front(MatchPos);
+ Pending = Pending.drop_front(MatchPos + Matches[0].size());
+ }
+ Result += Pending;
+
+ return Result;
+}
+
+std::string dumpASTWithoutMemoryLocs(ClangdServer &Server, PathRef File) {
+ auto DumpWithMemLocs = runDumpAST(Server, File);
+ return replacePtrsInDump(DumpWithMemLocs);
+}
+
+class ClangdVFSTest : public ::testing::Test {
+protected:
+ std::string parseSourceAndDumpAST(
+ PathRef SourceFileRelPath, StringRef SourceContents,
+ std::vector<std::pair<PathRef, StringRef>> ExtraFiles = {},
+ bool ExpectErrors = false) {
+ MockFSProvider FS;
+ ErrorCheckingDiagConsumer DiagConsumer;
+ MockCompilationDatabase CDB;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ for (const auto &FileWithContents : ExtraFiles)
+ FS.Files[testPath(FileWithContents.first)] = FileWithContents.second;
+
+ auto SourceFilename = testPath(SourceFileRelPath);
+ Server.addDocument(SourceFilename, SourceContents);
+ auto Result = dumpASTWithoutMemoryLocs(Server, SourceFilename);
+ EXPECT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
+ EXPECT_EQ(ExpectErrors, DiagConsumer.hadErrorInLastDiags());
+ return Result;
+ }
+};
+
+TEST_F(ClangdVFSTest, Parse) {
+ // FIXME: figure out a stable format for AST dumps, so that we can check the
+ // output of the dump itself is equal to the expected one, not just that it's
+ // different.
+ auto Empty = parseSourceAndDumpAST("foo.cpp", "", {});
+ auto OneDecl = parseSourceAndDumpAST("foo.cpp", "int a;", {});
+ auto SomeDecls = parseSourceAndDumpAST("foo.cpp", "int a; int b; int c;", {});
+ EXPECT_NE(Empty, OneDecl);
+ EXPECT_NE(Empty, SomeDecls);
+ EXPECT_NE(SomeDecls, OneDecl);
+
+ auto Empty2 = parseSourceAndDumpAST("foo.cpp", "");
+ auto OneDecl2 = parseSourceAndDumpAST("foo.cpp", "int a;");
+ auto SomeDecls2 = parseSourceAndDumpAST("foo.cpp", "int a; int b; int c;");
+ EXPECT_EQ(Empty, Empty2);
+ EXPECT_EQ(OneDecl, OneDecl2);
+ EXPECT_EQ(SomeDecls, SomeDecls2);
+}
+
+TEST_F(ClangdVFSTest, ParseWithHeader) {
+ parseSourceAndDumpAST("foo.cpp", "#include \"foo.h\"", {},
+ /*ExpectErrors=*/true);
+ parseSourceAndDumpAST("foo.cpp", "#include \"foo.h\"", {{"foo.h", ""}},
+ /*ExpectErrors=*/false);
+
+ const auto SourceContents = R"cpp(
+#include "foo.h"
+int b = a;
+)cpp";
+ parseSourceAndDumpAST("foo.cpp", SourceContents, {{"foo.h", ""}},
+ /*ExpectErrors=*/true);
+ parseSourceAndDumpAST("foo.cpp", SourceContents, {{"foo.h", "int a;"}},
+ /*ExpectErrors=*/false);
+}
+
+TEST_F(ClangdVFSTest, Reparse) {
+ MockFSProvider FS;
+ ErrorCheckingDiagConsumer DiagConsumer;
+ MockCompilationDatabase CDB;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ const auto SourceContents = R"cpp(
+#include "foo.h"
+int b = a;
+)cpp";
+
+ auto FooCpp = testPath("foo.cpp");
+
+ FS.Files[testPath("foo.h")] = "int a;";
+ FS.Files[FooCpp] = SourceContents;
+
+ Server.addDocument(FooCpp, SourceContents);
+ auto DumpParse1 = dumpASTWithoutMemoryLocs(Server, FooCpp);
+ ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
+ EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
+
+ Server.addDocument(FooCpp, "");
+ auto DumpParseEmpty = dumpASTWithoutMemoryLocs(Server, FooCpp);
+ ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
+ EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
+
+ Server.addDocument(FooCpp, SourceContents);
+ auto DumpParse2 = dumpASTWithoutMemoryLocs(Server, FooCpp);
+ ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
+ EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
+
+ EXPECT_EQ(DumpParse1, DumpParse2);
+ EXPECT_NE(DumpParse1, DumpParseEmpty);
+}
+
+TEST_F(ClangdVFSTest, ReparseOnHeaderChange) {
+ MockFSProvider FS;
+ ErrorCheckingDiagConsumer DiagConsumer;
+ MockCompilationDatabase CDB;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ const auto SourceContents = R"cpp(
+#include "foo.h"
+int b = a;
+)cpp";
+
+ auto FooCpp = testPath("foo.cpp");
+ auto FooH = testPath("foo.h");
+
+ FS.Files[FooH] = "int a;";
+ FS.Files[FooCpp] = SourceContents;
+
+ Server.addDocument(FooCpp, SourceContents);
+ auto DumpParse1 = dumpASTWithoutMemoryLocs(Server, FooCpp);
+ ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
+ EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
+
+ FS.Files[FooH] = "";
+ Server.addDocument(FooCpp, SourceContents);
+ auto DumpParseDifferent = dumpASTWithoutMemoryLocs(Server, FooCpp);
+ ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
+ EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
+
+ FS.Files[FooH] = "int a;";
+ Server.addDocument(FooCpp, SourceContents);
+ auto DumpParse2 = dumpASTWithoutMemoryLocs(Server, FooCpp);
+ ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
+ EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
+
+ EXPECT_EQ(DumpParse1, DumpParse2);
+ EXPECT_NE(DumpParse1, DumpParseDifferent);
+}
+
+TEST_F(ClangdVFSTest, PropagatesContexts) {
+ static Key<int> Secret;
+ struct FSProvider : public FileSystemProvider {
+ IntrusiveRefCntPtr<vfs::FileSystem> getFileSystem() override {
+ Got = Context::current().getExisting(Secret);
+ return buildTestFS({});
+ }
+ int Got;
+ } FS;
+ struct DiagConsumer : public DiagnosticsConsumer {
+ void onDiagnosticsReady(PathRef File,
+ std::vector<Diag> Diagnostics) override {
+ Got = Context::current().getExisting(Secret);
+ }
+ int Got;
+ } DiagConsumer;
+ MockCompilationDatabase CDB;
+
+ // Verify that the context is plumbed to the FS provider and diagnostics.
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ {
+ WithContextValue Entrypoint(Secret, 42);
+ Server.addDocument(testPath("foo.cpp"), "void main(){}");
+ }
+ ASSERT_TRUE(Server.blockUntilIdleForTest());
+ EXPECT_EQ(FS.Got, 42);
+ EXPECT_EQ(DiagConsumer.Got, 42);
+}
+
+// Only enable this test on Unix
+#ifdef LLVM_ON_UNIX
+TEST_F(ClangdVFSTest, SearchLibDir) {
+ // Checks that searches for GCC installation is done through vfs.
+ MockFSProvider FS;
+ ErrorCheckingDiagConsumer DiagConsumer;
+ MockCompilationDatabase CDB;
+ CDB.ExtraClangFlags.insert(CDB.ExtraClangFlags.end(),
+ {"-xc++", "-target", "x86_64-linux-unknown",
+ "-m64", "--gcc-toolchain=/randomusr",
+ "-stdlib=libstdc++"});
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ // Just a random gcc version string
+ SmallString<8> Version("4.9.3");
+
+ // A lib dir for gcc installation
+ SmallString<64> LibDir("/randomusr/lib/gcc/x86_64-linux-gnu");
+ llvm::sys::path::append(LibDir, Version);
+
+ // Put crtbegin.o into LibDir/64 to trick clang into thinking there's a gcc
+ // installation there.
+ SmallString<64> DummyLibFile;
+ llvm::sys::path::append(DummyLibFile, LibDir, "64", "crtbegin.o");
+ FS.Files[DummyLibFile] = "";
+
+ SmallString<64> IncludeDir("/randomusr/include/c++");
+ llvm::sys::path::append(IncludeDir, Version);
+
+ SmallString<64> StringPath;
+ llvm::sys::path::append(StringPath, IncludeDir, "string");
+ FS.Files[StringPath] = "class mock_string {};";
+
+ auto FooCpp = testPath("foo.cpp");
+ const auto SourceContents = R"cpp(
+#include <string>
+mock_string x;
+)cpp";
+ FS.Files[FooCpp] = SourceContents;
+
+ runAddDocument(Server, FooCpp, SourceContents);
+ EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
+
+ const auto SourceContentsWithError = R"cpp(
+#include <string>
+std::string x;
+)cpp";
+ runAddDocument(Server, FooCpp, SourceContentsWithError);
+ EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
+}
+#endif // LLVM_ON_UNIX
+
+TEST_F(ClangdVFSTest, ForceReparseCompileCommand) {
+ MockFSProvider FS;
+ ErrorCheckingDiagConsumer DiagConsumer;
+ MockCompilationDatabase CDB;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ auto FooCpp = testPath("foo.cpp");
+ const auto SourceContents1 = R"cpp(
+template <class T>
+struct foo { T x; };
+)cpp";
+ const auto SourceContents2 = R"cpp(
+template <class T>
+struct bar { T x; };
+)cpp";
+
+ FS.Files[FooCpp] = "";
+
+ // First parse files in C mode and check they produce errors.
+ CDB.ExtraClangFlags = {"-xc"};
+ runAddDocument(Server, FooCpp, SourceContents1);
+ EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
+ runAddDocument(Server, FooCpp, SourceContents2);
+ EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
+
+ // Now switch to C++ mode.
+ CDB.ExtraClangFlags = {"-xc++"};
+ runAddDocument(Server, FooCpp, SourceContents2, WantDiagnostics::Auto);
+ EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
+ // Subsequent addDocument calls should finish without errors too.
+ runAddDocument(Server, FooCpp, SourceContents1);
+ EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
+ runAddDocument(Server, FooCpp, SourceContents2);
+ EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
+}
+
+TEST_F(ClangdVFSTest, ForceReparseCompileCommandDefines) {
+ MockFSProvider FS;
+ ErrorCheckingDiagConsumer DiagConsumer;
+ MockCompilationDatabase CDB;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ auto FooCpp = testPath("foo.cpp");
+ const auto SourceContents = R"cpp(
+#ifdef WITH_ERROR
+this
+#endif
+
+int main() { return 0; }
+)cpp";
+ FS.Files[FooCpp] = "";
+
+ // Parse with define, we expect to see the errors.
+ CDB.ExtraClangFlags = {"-DWITH_ERROR"};
+ runAddDocument(Server, FooCpp, SourceContents);
+ EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
+
+ // Parse without the define, no errors should be produced.
+ CDB.ExtraClangFlags = {};
+ runAddDocument(Server, FooCpp, SourceContents, WantDiagnostics::Auto);
+ ASSERT_TRUE(Server.blockUntilIdleForTest());
+ EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
+ // Subsequent addDocument call should finish without errors too.
+ runAddDocument(Server, FooCpp, SourceContents);
+ EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
+}
+
+// Test ClangdServer.reparseOpenedFiles.
+TEST_F(ClangdVFSTest, ReparseOpenedFiles) {
+ Annotations FooSource(R"cpp(
+#ifdef MACRO
+static void $one[[bob]]() {}
+#else
+static void $two[[bob]]() {}
+#endif
+
+int main () { bo^b (); return 0; }
+)cpp");
+
+ Annotations BarSource(R"cpp(
+#ifdef MACRO
+this is an error
+#endif
+)cpp");
+
+ Annotations BazSource(R"cpp(
+int hello;
+)cpp");
+
+ MockFSProvider FS;
+ MockCompilationDatabase CDB;
+ MultipleErrorCheckingDiagConsumer DiagConsumer;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ auto FooCpp = testPath("foo.cpp");
+ auto BarCpp = testPath("bar.cpp");
+ auto BazCpp = testPath("baz.cpp");
+
+ FS.Files[FooCpp] = "";
+ FS.Files[BarCpp] = "";
+ FS.Files[BazCpp] = "";
+
+ CDB.ExtraClangFlags = {"-DMACRO=1"};
+ Server.addDocument(FooCpp, FooSource.code());
+ Server.addDocument(BarCpp, BarSource.code());
+ Server.addDocument(BazCpp, BazSource.code());
+ ASSERT_TRUE(Server.blockUntilIdleForTest());
+
+ EXPECT_THAT(DiagConsumer.filesWithDiags(),
+ UnorderedElementsAre(Pair(FooCpp, false), Pair(BarCpp, true),
+ Pair(BazCpp, false)));
+
+ auto Locations = runFindDefinitions(Server, FooCpp, FooSource.point());
+ EXPECT_TRUE(bool(Locations));
+ EXPECT_THAT(*Locations, ElementsAre(Location{URIForFile{FooCpp},
+ FooSource.range("one")}));
+
+ // Undefine MACRO, close baz.cpp.
+ CDB.ExtraClangFlags.clear();
+ DiagConsumer.clear();
+ Server.removeDocument(BazCpp);
+ Server.addDocument(FooCpp, FooSource.code(), WantDiagnostics::Auto);
+ Server.addDocument(BarCpp, BarSource.code(), WantDiagnostics::Auto);
+ ASSERT_TRUE(Server.blockUntilIdleForTest());
+
+ EXPECT_THAT(DiagConsumer.filesWithDiags(),
+ UnorderedElementsAre(Pair(FooCpp, false), Pair(BarCpp, false)));
+
+ Locations = runFindDefinitions(Server, FooCpp, FooSource.point());
+ EXPECT_TRUE(bool(Locations));
+ EXPECT_THAT(*Locations, ElementsAre(Location{URIForFile{FooCpp},
+ FooSource.range("two")}));
+}
+
+TEST_F(ClangdVFSTest, MemoryUsage) {
+ MockFSProvider FS;
+ ErrorCheckingDiagConsumer DiagConsumer;
+ MockCompilationDatabase CDB;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ Path FooCpp = testPath("foo.cpp");
+ const auto SourceContents = R"cpp(
+struct Something {
+ int method();
+};
+)cpp";
+ Path BarCpp = testPath("bar.cpp");
+
+ FS.Files[FooCpp] = "";
+ FS.Files[BarCpp] = "";
+
+ EXPECT_THAT(Server.getUsedBytesPerFile(), IsEmpty());
+
+ Server.addDocument(FooCpp, SourceContents);
+ Server.addDocument(BarCpp, SourceContents);
+ ASSERT_TRUE(Server.blockUntilIdleForTest());
+
+ EXPECT_THAT(Server.getUsedBytesPerFile(),
+ UnorderedElementsAre(Pair(FooCpp, Gt(0u)), Pair(BarCpp, Gt(0u))));
+
+ Server.removeDocument(FooCpp);
+ ASSERT_TRUE(Server.blockUntilIdleForTest());
+ EXPECT_THAT(Server.getUsedBytesPerFile(), ElementsAre(Pair(BarCpp, Gt(0u))));
+
+ Server.removeDocument(BarCpp);
+ ASSERT_TRUE(Server.blockUntilIdleForTest());
+ EXPECT_THAT(Server.getUsedBytesPerFile(), IsEmpty());
+}
+
+TEST_F(ClangdVFSTest, InvalidCompileCommand) {
+ MockFSProvider FS;
+ ErrorCheckingDiagConsumer DiagConsumer;
+ MockCompilationDatabase CDB;
+
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ auto FooCpp = testPath("foo.cpp");
+ // clang cannot create CompilerInvocation if we pass two files in the
+ // CompileCommand. We pass the file in ExtraFlags once and CDB adds another
+ // one in getCompileCommand().
+ CDB.ExtraClangFlags.push_back(FooCpp);
+
+ // Clang can't parse command args in that case, but we shouldn't crash.
+ runAddDocument(Server, FooCpp, "int main() {}");
+
+ EXPECT_EQ(runDumpAST(Server, FooCpp), "<no-ast>");
+ EXPECT_ERROR(runFindDefinitions(Server, FooCpp, Position()));
+ EXPECT_ERROR(runFindDocumentHighlights(Server, FooCpp, Position()));
+ EXPECT_ERROR(runRename(Server, FooCpp, Position(), "new_name"));
+ // FIXME: codeComplete and signatureHelp should also return errors when they
+ // can't parse the file.
+ EXPECT_THAT(cantFail(runCodeComplete(Server, FooCpp, Position(),
+ clangd::CodeCompleteOptions()))
+ .Completions,
+ IsEmpty());
+ auto SigHelp = runSignatureHelp(Server, FooCpp, Position());
+ ASSERT_TRUE(bool(SigHelp)) << "signatureHelp returned an error";
+ EXPECT_THAT(SigHelp->signatures, IsEmpty());
+}
+
+class ClangdThreadingTest : public ClangdVFSTest {};
+
+TEST_F(ClangdThreadingTest, StressTest) {
+ // Without 'static' clang gives an error for a usage inside TestDiagConsumer.
+ static const unsigned FilesCount = 5;
+ const unsigned RequestsCount = 500;
+ // Blocking requests wait for the parsing to complete, they slow down the test
+ // dramatically, so they are issued rarely. Each
+ // BlockingRequestInterval-request will be a blocking one.
+ const unsigned BlockingRequestInterval = 40;
+
+ const auto SourceContentsWithoutErrors = R"cpp(
+int a;
+int b;
+int c;
+int d;
+)cpp";
+
+ const auto SourceContentsWithErrors = R"cpp(
+int a = x;
+int b;
+int c;
+int d;
+)cpp";
+
+ // Giving invalid line and column number should not crash ClangdServer, but
+ // just to make sure we're sometimes hitting the bounds inside the file we
+ // limit the intervals of line and column number that are generated.
+ unsigned MaxLineForFileRequests = 7;
+ unsigned MaxColumnForFileRequests = 10;
+
+ std::vector<std::string> FilePaths;
+ MockFSProvider FS;
+ for (unsigned I = 0; I < FilesCount; ++I) {
+ std::string Name = std::string("Foo") + std::to_string(I) + ".cpp";
+ FS.Files[Name] = "";
+ FilePaths.push_back(testPath(Name));
+ }
+
+ struct FileStat {
+ unsigned HitsWithoutErrors = 0;
+ unsigned HitsWithErrors = 0;
+ bool HadErrorsInLastDiags = false;
+ };
+
+ class TestDiagConsumer : public DiagnosticsConsumer {
+ public:
+ TestDiagConsumer() : Stats(FilesCount, FileStat()) {}
+
+ void onDiagnosticsReady(PathRef File,
+ std::vector<Diag> Diagnostics) override {
+ StringRef FileIndexStr = llvm::sys::path::stem(File);
+ ASSERT_TRUE(FileIndexStr.consume_front("Foo"));
+
+ unsigned long FileIndex = std::stoul(FileIndexStr.str());
+
+ bool HadError = diagsContainErrors(Diagnostics);
+
+ std::lock_guard<std::mutex> Lock(Mutex);
+ if (HadError)
+ Stats[FileIndex].HitsWithErrors++;
+ else
+ Stats[FileIndex].HitsWithoutErrors++;
+ Stats[FileIndex].HadErrorsInLastDiags = HadError;
+ }
+
+ std::vector<FileStat> takeFileStats() {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ return std::move(Stats);
+ }
+
+ private:
+ std::mutex Mutex;
+ std::vector<FileStat> Stats;
+ };
+
+ struct RequestStats {
+ unsigned RequestsWithoutErrors = 0;
+ unsigned RequestsWithErrors = 0;
+ bool LastContentsHadErrors = false;
+ bool FileIsRemoved = true;
+ };
+
+ std::vector<RequestStats> ReqStats;
+ ReqStats.reserve(FilesCount);
+ for (unsigned FileIndex = 0; FileIndex < FilesCount; ++FileIndex)
+ ReqStats.emplace_back();
+
+ TestDiagConsumer DiagConsumer;
+ {
+ MockCompilationDatabase CDB;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ // Prepare some random distributions for the test.
+ std::random_device RandGen;
+
+ std::uniform_int_distribution<unsigned> FileIndexDist(0, FilesCount - 1);
+ // Pass a text that contains compiler errors to addDocument in about 20% of
+ // all requests.
+ std::bernoulli_distribution ShouldHaveErrorsDist(0.2);
+ // Line and Column numbers for requests that need them.
+ std::uniform_int_distribution<int> LineDist(0, MaxLineForFileRequests);
+ std::uniform_int_distribution<int> ColumnDist(0, MaxColumnForFileRequests);
+
+ // Some helpers.
+ auto UpdateStatsOnAddDocument = [&](unsigned FileIndex, bool HadErrors) {
+ auto &Stats = ReqStats[FileIndex];
+
+ if (HadErrors)
+ ++Stats.RequestsWithErrors;
+ else
+ ++Stats.RequestsWithoutErrors;
+ Stats.LastContentsHadErrors = HadErrors;
+ Stats.FileIsRemoved = false;
+ };
+
+ auto UpdateStatsOnRemoveDocument = [&](unsigned FileIndex) {
+ auto &Stats = ReqStats[FileIndex];
+
+ Stats.FileIsRemoved = true;
+ };
+
+ auto AddDocument = [&](unsigned FileIndex, bool SkipCache) {
+ bool ShouldHaveErrors = ShouldHaveErrorsDist(RandGen);
+ Server.addDocument(FilePaths[FileIndex],
+ ShouldHaveErrors ? SourceContentsWithErrors
+ : SourceContentsWithoutErrors,
+ WantDiagnostics::Auto);
+ UpdateStatsOnAddDocument(FileIndex, ShouldHaveErrors);
+ };
+
+ // Various requests that we would randomly run.
+ auto AddDocumentRequest = [&]() {
+ unsigned FileIndex = FileIndexDist(RandGen);
+ AddDocument(FileIndex, /*SkipCache=*/false);
+ };
+
+ auto ForceReparseRequest = [&]() {
+ unsigned FileIndex = FileIndexDist(RandGen);
+ AddDocument(FileIndex, /*SkipCache=*/true);
+ };
+
+ auto RemoveDocumentRequest = [&]() {
+ unsigned FileIndex = FileIndexDist(RandGen);
+ // Make sure we don't violate the ClangdServer's contract.
+ if (ReqStats[FileIndex].FileIsRemoved)
+ AddDocument(FileIndex, /*SkipCache=*/false);
+
+ Server.removeDocument(FilePaths[FileIndex]);
+ UpdateStatsOnRemoveDocument(FileIndex);
+ };
+
+ auto CodeCompletionRequest = [&]() {
+ unsigned FileIndex = FileIndexDist(RandGen);
+ // Make sure we don't violate the ClangdServer's contract.
+ if (ReqStats[FileIndex].FileIsRemoved)
+ AddDocument(FileIndex, /*SkipCache=*/false);
+
+ Position Pos;
+ Pos.line = LineDist(RandGen);
+ Pos.character = ColumnDist(RandGen);
+ // FIXME(ibiryukov): Also test async completion requests.
+ // Simply putting CodeCompletion into async requests now would make
+ // tests slow, since there's no way to cancel previous completion
+ // requests as opposed to AddDocument/RemoveDocument, which are implicitly
+ // cancelled by any subsequent AddDocument/RemoveDocument request to the
+ // same file.
+ cantFail(runCodeComplete(Server, FilePaths[FileIndex], Pos,
+ clangd::CodeCompleteOptions()));
+ };
+
+ auto FindDefinitionsRequest = [&]() {
+ unsigned FileIndex = FileIndexDist(RandGen);
+ // Make sure we don't violate the ClangdServer's contract.
+ if (ReqStats[FileIndex].FileIsRemoved)
+ AddDocument(FileIndex, /*SkipCache=*/false);
+
+ Position Pos;
+ Pos.line = LineDist(RandGen);
+ Pos.character = ColumnDist(RandGen);
+
+ ASSERT_TRUE(!!runFindDefinitions(Server, FilePaths[FileIndex], Pos));
+ };
+
+ std::vector<std::function<void()>> AsyncRequests = {
+ AddDocumentRequest, ForceReparseRequest, RemoveDocumentRequest};
+ std::vector<std::function<void()>> BlockingRequests = {
+ CodeCompletionRequest, FindDefinitionsRequest};
+
+ // Bash requests to ClangdServer in a loop.
+ std::uniform_int_distribution<int> AsyncRequestIndexDist(
+ 0, AsyncRequests.size() - 1);
+ std::uniform_int_distribution<int> BlockingRequestIndexDist(
+ 0, BlockingRequests.size() - 1);
+ for (unsigned I = 1; I <= RequestsCount; ++I) {
+ if (I % BlockingRequestInterval != 0) {
+ // Issue an async request most of the time. It should be fast.
+ unsigned RequestIndex = AsyncRequestIndexDist(RandGen);
+ AsyncRequests[RequestIndex]();
+ } else {
+ // Issue a blocking request once in a while.
+ auto RequestIndex = BlockingRequestIndexDist(RandGen);
+ BlockingRequests[RequestIndex]();
+ }
+ }
+ } // Wait for ClangdServer to shutdown before proceeding.
+
+ // Check some invariants about the state of the program.
+ std::vector<FileStat> Stats = DiagConsumer.takeFileStats();
+ for (unsigned I = 0; I < FilesCount; ++I) {
+ if (!ReqStats[I].FileIsRemoved) {
+ ASSERT_EQ(Stats[I].HadErrorsInLastDiags,
+ ReqStats[I].LastContentsHadErrors);
+ }
+
+ ASSERT_LE(Stats[I].HitsWithErrors, ReqStats[I].RequestsWithErrors);
+ ASSERT_LE(Stats[I].HitsWithoutErrors, ReqStats[I].RequestsWithoutErrors);
+ }
+}
+
+TEST_F(ClangdVFSTest, CheckSourceHeaderSwitch) {
+ MockFSProvider FS;
+ ErrorCheckingDiagConsumer DiagConsumer;
+ MockCompilationDatabase CDB;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ auto SourceContents = R"cpp(
+ #include "foo.h"
+ int b = a;
+ )cpp";
+
+ auto FooCpp = testPath("foo.cpp");
+ auto FooH = testPath("foo.h");
+ auto Invalid = testPath("main.cpp");
+
+ FS.Files[FooCpp] = SourceContents;
+ FS.Files[FooH] = "int a;";
+ FS.Files[Invalid] = "int main() { \n return 0; \n }";
+
+ llvm::Optional<Path> PathResult = Server.switchSourceHeader(FooCpp);
+ EXPECT_TRUE(PathResult.hasValue());
+ ASSERT_EQ(PathResult.getValue(), FooH);
+
+ PathResult = Server.switchSourceHeader(FooH);
+ EXPECT_TRUE(PathResult.hasValue());
+ ASSERT_EQ(PathResult.getValue(), FooCpp);
+
+ SourceContents = R"c(
+ #include "foo.HH"
+ int b = a;
+ )c";
+
+ // Test with header file in capital letters and different extension, source
+ // file with different extension
+ auto FooC = testPath("bar.c");
+ auto FooHH = testPath("bar.HH");
+
+ FS.Files[FooC] = SourceContents;
+ FS.Files[FooHH] = "int a;";
+
+ PathResult = Server.switchSourceHeader(FooC);
+ EXPECT_TRUE(PathResult.hasValue());
+ ASSERT_EQ(PathResult.getValue(), FooHH);
+
+ // Test with both capital letters
+ auto Foo2C = testPath("foo2.C");
+ auto Foo2HH = testPath("foo2.HH");
+ FS.Files[Foo2C] = SourceContents;
+ FS.Files[Foo2HH] = "int a;";
+
+ PathResult = Server.switchSourceHeader(Foo2C);
+ EXPECT_TRUE(PathResult.hasValue());
+ ASSERT_EQ(PathResult.getValue(), Foo2HH);
+
+ // Test with source file as capital letter and .hxx header file
+ auto Foo3C = testPath("foo3.C");
+ auto Foo3HXX = testPath("foo3.hxx");
+
+ SourceContents = R"c(
+ #include "foo3.hxx"
+ int b = a;
+ )c";
+
+ FS.Files[Foo3C] = SourceContents;
+ FS.Files[Foo3HXX] = "int a;";
+
+ PathResult = Server.switchSourceHeader(Foo3C);
+ EXPECT_TRUE(PathResult.hasValue());
+ ASSERT_EQ(PathResult.getValue(), Foo3HXX);
+
+ // Test if asking for a corresponding file that doesn't exist returns an empty
+ // string.
+ PathResult = Server.switchSourceHeader(Invalid);
+ EXPECT_FALSE(PathResult.hasValue());
+}
+
+TEST_F(ClangdThreadingTest, NoConcurrentDiagnostics) {
+ class NoConcurrentAccessDiagConsumer : public DiagnosticsConsumer {
+ public:
+ std::atomic<int> Count = {0};
+
+ NoConcurrentAccessDiagConsumer(std::promise<void> StartSecondReparse)
+ : StartSecondReparse(std::move(StartSecondReparse)) {}
+
+ void onDiagnosticsReady(PathRef, std::vector<Diag>) override {
+ ++Count;
+ std::unique_lock<std::mutex> Lock(Mutex, std::try_to_lock_t());
+ ASSERT_TRUE(Lock.owns_lock())
+ << "Detected concurrent onDiagnosticsReady calls for the same file.";
+
+ // If we started the second parse immediately, it might cancel the first.
+ // So we don't allow it to start until the first has delivered diags...
+ if (FirstRequest) {
+ FirstRequest = false;
+ StartSecondReparse.set_value();
+ // ... but then we wait long enough that the callbacks would overlap.
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ }
+ }
+
+ private:
+ std::mutex Mutex;
+ bool FirstRequest = true;
+ std::promise<void> StartSecondReparse;
+ };
+
+ const auto SourceContentsWithoutErrors = R"cpp(
+int a;
+int b;
+int c;
+int d;
+)cpp";
+
+ const auto SourceContentsWithErrors = R"cpp(
+int a = x;
+int b;
+int c;
+int d;
+)cpp";
+
+ auto FooCpp = testPath("foo.cpp");
+ MockFSProvider FS;
+ FS.Files[FooCpp] = "";
+
+ std::promise<void> StartSecondPromise;
+ std::future<void> StartSecond = StartSecondPromise.get_future();
+
+ NoConcurrentAccessDiagConsumer DiagConsumer(std::move(StartSecondPromise));
+ MockCompilationDatabase CDB;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ Server.addDocument(FooCpp, SourceContentsWithErrors);
+ StartSecond.wait();
+ Server.addDocument(FooCpp, SourceContentsWithoutErrors);
+ ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
+ ASSERT_EQ(DiagConsumer.Count, 2); // Sanity check - we actually ran both?
+}
+
+TEST_F(ClangdVFSTest, FormatCode) {
+ MockFSProvider FS;
+ ErrorCheckingDiagConsumer DiagConsumer;
+ MockCompilationDatabase CDB;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ auto Path = testPath("foo.cpp");
+ std::string Code = R"cpp(
+#include "x.h"
+#include "y.h"
+
+void f( ) {}
+)cpp";
+ std::string Expected = R"cpp(
+#include "x.h"
+#include "y.h"
+
+void f() {}
+)cpp";
+ FS.Files[Path] = Code;
+ runAddDocument(Server, Path, Code);
+
+ auto Replaces = Server.formatFile(Code, Path);
+ EXPECT_TRUE(static_cast<bool>(Replaces));
+ auto Changed = tooling::applyAllReplacements(Code, *Replaces);
+ EXPECT_TRUE(static_cast<bool>(Changed));
+ EXPECT_EQ(Expected, *Changed);
+}
+
+TEST_F(ClangdVFSTest, ChangedHeaderFromISystem) {
+ MockFSProvider FS;
+ ErrorCheckingDiagConsumer DiagConsumer;
+ MockCompilationDatabase CDB;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ auto SourcePath = testPath("source/foo.cpp");
+ auto HeaderPath = testPath("headers/foo.h");
+ FS.Files[HeaderPath] = "struct X { int bar; };";
+ Annotations Code(R"cpp(
+ #include "foo.h"
+
+ int main() {
+ X().ba^
+ })cpp");
+ CDB.ExtraClangFlags.push_back("-xc++");
+ CDB.ExtraClangFlags.push_back("-isystem" + testPath("headers"));
+
+ runAddDocument(Server, SourcePath, Code.code());
+ auto Completions = cantFail(runCodeComplete(Server, SourcePath, Code.point(),
+ clangd::CodeCompleteOptions()))
+ .Completions;
+ EXPECT_THAT(Completions, ElementsAre(Field(&CodeCompletion::Name, "bar")));
+ // Update the header and rerun addDocument to make sure we get the updated
+ // files.
+ FS.Files[HeaderPath] = "struct X { int bar; int baz; };";
+ runAddDocument(Server, SourcePath, Code.code());
+ Completions = cantFail(runCodeComplete(Server, SourcePath, Code.point(),
+ clangd::CodeCompleteOptions()))
+ .Completions;
+ // We want to make sure we see the updated version.
+ EXPECT_THAT(Completions, ElementsAre(Field(&CodeCompletion::Name, "bar"),
+ Field(&CodeCompletion::Name, "baz")));
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/ClangdUnitTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/ClangdUnitTests.cpp
new file mode 100644
index 0000000..6843c9e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/ClangdUnitTests.cpp
@@ -0,0 +1,225 @@
+//===-- ClangdUnitTests.cpp - ClangdUnit tests ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Annotations.h"
+#include "ClangdUnit.h"
+#include "SourceCode.h"
+#include "TestTU.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+namespace {
+using testing::ElementsAre;
+using testing::Field;
+using testing::IsEmpty;
+using testing::Pair;
+
+testing::Matcher<const Diag &> WithFix(testing::Matcher<Fix> FixMatcher) {
+ return Field(&Diag::Fixes, ElementsAre(FixMatcher));
+}
+
+testing::Matcher<const Diag &> WithNote(testing::Matcher<Note> NoteMatcher) {
+ return Field(&Diag::Notes, ElementsAre(NoteMatcher));
+}
+
+MATCHER_P2(Diag, Range, Message,
+ "Diag at " + llvm::to_string(Range) + " = [" + Message + "]") {
+ return arg.Range == Range && arg.Message == Message;
+}
+
+MATCHER_P3(Fix, Range, Replacement, Message,
+ "Fix " + llvm::to_string(Range) + " => " +
+ testing::PrintToString(Replacement) + " = [" + Message + "]") {
+ return arg.Message == Message && arg.Edits.size() == 1 &&
+ arg.Edits[0].range == Range && arg.Edits[0].newText == Replacement;
+}
+
+MATCHER_P(EqualToLSPDiag, LSPDiag,
+ "LSP diagnostic " + llvm::to_string(LSPDiag)) {
+ return std::tie(arg.range, arg.severity, arg.message) ==
+ std::tie(LSPDiag.range, LSPDiag.severity, LSPDiag.message);
+}
+
+MATCHER_P(EqualToFix, Fix, "LSP fix " + llvm::to_string(Fix)) {
+ if (arg.Message != Fix.Message)
+ return false;
+ if (arg.Edits.size() != Fix.Edits.size())
+ return false;
+ for (std::size_t I = 0; I < arg.Edits.size(); ++I) {
+ if (arg.Edits[I].range != Fix.Edits[I].range ||
+ arg.Edits[I].newText != Fix.Edits[I].newText)
+ return false;
+ }
+ return true;
+}
+
+// Helper function to make tests shorter.
+Position pos(int line, int character) {
+ Position Res;
+ Res.line = line;
+ Res.character = character;
+ return Res;
+}
+
+TEST(DiagnosticsTest, DiagnosticRanges) {
+ // Check we report correct ranges, including various edge-cases.
+ Annotations Test(R"cpp(
+ void $decl[[foo]]();
+ int main() {
+ $typo[[go\
+o]]();
+ foo()$semicolon[[]]
+ $unk[[unknown]]();
+ }
+ )cpp");
+ EXPECT_THAT(
+ TestTU::withCode(Test.code()).build().getDiagnostics(),
+ ElementsAre(
+ // This range spans lines.
+ AllOf(Diag(Test.range("typo"),
+ "use of undeclared identifier 'goo'; did you mean 'foo'?"),
+ WithFix(
+ Fix(Test.range("typo"), "foo", "change 'go\\ o' to 'foo'")),
+ // This is a pretty normal range.
+ WithNote(Diag(Test.range("decl"), "'foo' declared here"))),
+ // This range is zero-width, and at the end of a line.
+ AllOf(Diag(Test.range("semicolon"), "expected ';' after expression"),
+ WithFix(Fix(Test.range("semicolon"), ";", "insert ';'"))),
+ // This range isn't provided by clang, we expand to the token.
+ Diag(Test.range("unk"), "use of undeclared identifier 'unknown'")));
+}
+
+TEST(DiagnosticsTest, FlagsMatter) {
+ Annotations Test("[[void]] main() {}");
+ auto TU = TestTU::withCode(Test.code());
+ EXPECT_THAT(TU.build().getDiagnostics(),
+ ElementsAre(AllOf(Diag(Test.range(), "'main' must return 'int'"),
+ WithFix(Fix(Test.range(), "int",
+ "change 'void' to 'int'")))));
+ // Same code built as C gets different diagnostics.
+ TU.Filename = "Plain.c";
+ EXPECT_THAT(
+ TU.build().getDiagnostics(),
+ ElementsAre(AllOf(
+ Diag(Test.range(), "return type of 'main' is not 'int'"),
+ WithFix(Fix(Test.range(), "int", "change return type to 'int'")))));
+}
+
+TEST(DiagnosticsTest, Preprocessor) {
+ // This looks like a preamble, but there's an #else in the middle!
+ // Check that:
+ // - the #else doesn't generate diagnostics (we had this bug)
+ // - we get diagnostics from the taken branch
+ // - we get no diagnostics from the not taken branch
+ Annotations Test(R"cpp(
+ #ifndef FOO
+ #define FOO
+ int a = [[b]];
+ #else
+ int x = y;
+ #endif
+ )cpp");
+ EXPECT_THAT(
+ TestTU::withCode(Test.code()).build().getDiagnostics(),
+ ElementsAre(Diag(Test.range(), "use of undeclared identifier 'b'")));
+}
+
+TEST(DiagnosticsTest, ToLSP) {
+ clangd::Diag D;
+ D.Message = "something terrible happened";
+ D.Range = {pos(1, 2), pos(3, 4)};
+ D.InsideMainFile = true;
+ D.Severity = DiagnosticsEngine::Error;
+ D.File = "foo/bar/main.cpp";
+
+ clangd::Note NoteInMain;
+ NoteInMain.Message = "declared somewhere in the main file";
+ NoteInMain.Range = {pos(5, 6), pos(7, 8)};
+ NoteInMain.Severity = DiagnosticsEngine::Remark;
+ NoteInMain.File = "../foo/bar/main.cpp";
+ NoteInMain.InsideMainFile = true;
+ D.Notes.push_back(NoteInMain);
+
+ clangd::Note NoteInHeader;
+ NoteInHeader.Message = "declared somewhere in the header file";
+ NoteInHeader.Range = {pos(9, 10), pos(11, 12)};
+ NoteInHeader.Severity = DiagnosticsEngine::Note;
+ NoteInHeader.File = "../foo/baz/header.h";
+ NoteInHeader.InsideMainFile = false;
+ D.Notes.push_back(NoteInHeader);
+
+ clangd::Fix F;
+ F.Message = "do something";
+ D.Fixes.push_back(F);
+
+ auto MatchingLSP = [](const DiagBase &D, llvm::StringRef Message) {
+ clangd::Diagnostic Res;
+ Res.range = D.Range;
+ Res.severity = getSeverity(D.Severity);
+ Res.message = Message;
+ return Res;
+ };
+
+ // Diagnostics should turn into these:
+ clangd::Diagnostic MainLSP = MatchingLSP(D, R"(something terrible happened
+
+main.cpp:6:7: remark: declared somewhere in the main file
+
+../foo/baz/header.h:10:11:
+note: declared somewhere in the header file)");
+
+ clangd::Diagnostic NoteInMainLSP =
+ MatchingLSP(NoteInMain, R"(declared somewhere in the main file
+
+main.cpp:2:3: error: something terrible happened)");
+
+ // Transform dianostics and check the results.
+ std::vector<std::pair<clangd::Diagnostic, std::vector<clangd::Fix>>> LSPDiags;
+ toLSPDiags(D, [&](clangd::Diagnostic LSPDiag,
+ llvm::ArrayRef<clangd::Fix> Fixes) {
+ LSPDiags.push_back({std::move(LSPDiag),
+ std::vector<clangd::Fix>(Fixes.begin(), Fixes.end())});
+ });
+
+ EXPECT_THAT(
+ LSPDiags,
+ ElementsAre(Pair(EqualToLSPDiag(MainLSP), ElementsAre(EqualToFix(F))),
+ Pair(EqualToLSPDiag(NoteInMainLSP), IsEmpty())));
+}
+
+TEST(ClangdUnitTest, GetBeginningOfIdentifier) {
+ // First ^ is the expected beginning, last is the search position.
+ for (const char *Text : {
+ "int ^f^oo();", // inside identifier
+ "int ^foo();", // beginning of identifier
+ "int ^foo^();", // end of identifier
+ "int foo(^);", // non-identifier
+ "^int foo();", // beginning of file (can't back up)
+ "int ^f0^0();", // after a digit (lexing at N-1 is wrong)
+ "int ^λλ^λ();", // UTF-8 handled properly when backing up
+ }) {
+ Annotations TestCase(Text);
+ auto AST = TestTU::withCode(TestCase.code()).build();
+ const auto &SourceMgr = AST.getASTContext().getSourceManager();
+ SourceLocation Actual = getBeginningOfIdentifier(
+ AST, TestCase.points().back(), SourceMgr.getMainFileID());
+ Position ActualPos =
+ offsetToPosition(TestCase.code(), SourceMgr.getFileOffset(Actual));
+ EXPECT_EQ(TestCase.points().front(), ActualPos) << Text;
+ }
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp
new file mode 100644
index 0000000..2f04bef
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp
@@ -0,0 +1,1343 @@
+//===-- CodeCompleteTests.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Annotations.h"
+#include "ClangdServer.h"
+#include "CodeComplete.h"
+#include "Compiler.h"
+#include "Matchers.h"
+#include "Protocol.h"
+#include "Quality.h"
+#include "SourceCode.h"
+#include "SyncAPI.h"
+#include "TestFS.h"
+#include "index/MemIndex.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+
+namespace {
+using namespace llvm;
+using ::testing::AllOf;
+using ::testing::Contains;
+using ::testing::Each;
+using ::testing::ElementsAre;
+using ::testing::Field;
+using ::testing::HasSubstr;
+using ::testing::IsEmpty;
+using ::testing::Not;
+using ::testing::UnorderedElementsAre;
+
+class IgnoreDiagnostics : public DiagnosticsConsumer {
+ void onDiagnosticsReady(PathRef File,
+ std::vector<Diag> Diagnostics) override {}
+};
+
+// GMock helpers for matching completion items.
+MATCHER_P(Named, Name, "") { return arg.Name == Name; }
+MATCHER_P(Scope, S, "") { return arg.Scope == S; }
+MATCHER_P(Qualifier, Q, "") { return arg.RequiredQualifier == Q; }
+MATCHER_P(Labeled, Label, "") {
+ return arg.RequiredQualifier + arg.Name + arg.Signature == Label;
+}
+MATCHER_P(SigHelpLabeled, Label, "") { return arg.label == Label; }
+MATCHER_P(Kind, K, "") { return arg.Kind == K; }
+MATCHER_P(Doc, D, "") { return arg.Documentation == D; }
+MATCHER_P(ReturnType, D, "") { return arg.ReturnType == D; }
+MATCHER_P(InsertInclude, IncludeHeader, "") {
+ return arg.Header == IncludeHeader && bool(arg.HeaderInsertion);
+}
+MATCHER(InsertInclude, "") { return bool(arg.HeaderInsertion); }
+MATCHER_P(SnippetSuffix, Text, "") { return arg.SnippetSuffix == Text; }
+MATCHER_P(Origin, OriginSet, "") { return arg.Origin == OriginSet; }
+
+// Shorthand for Contains(Named(Name)).
+Matcher<const std::vector<CodeCompletion> &> Has(std::string Name) {
+ return Contains(Named(std::move(Name)));
+}
+Matcher<const std::vector<CodeCompletion> &> Has(std::string Name,
+ CompletionItemKind K) {
+ return Contains(AllOf(Named(std::move(Name)), Kind(K)));
+}
+MATCHER(IsDocumented, "") { return !arg.Documentation.empty(); }
+
+std::unique_ptr<SymbolIndex> memIndex(std::vector<Symbol> Symbols) {
+ SymbolSlab::Builder Slab;
+ for (const auto &Sym : Symbols)
+ Slab.insert(Sym);
+ return MemIndex::build(std::move(Slab).build());
+}
+
+CodeCompleteResult completions(ClangdServer &Server, StringRef Text,
+ std::vector<Symbol> IndexSymbols = {},
+ clangd::CodeCompleteOptions Opts = {}) {
+ std::unique_ptr<SymbolIndex> OverrideIndex;
+ if (!IndexSymbols.empty()) {
+ assert(!Opts.Index && "both Index and IndexSymbols given!");
+ OverrideIndex = memIndex(std::move(IndexSymbols));
+ Opts.Index = OverrideIndex.get();
+ }
+
+ auto File = testPath("foo.cpp");
+ Annotations Test(Text);
+ runAddDocument(Server, File, Test.code());
+ auto CompletionList =
+ cantFail(runCodeComplete(Server, File, Test.point(), Opts));
+ return CompletionList;
+}
+
+// Builds a server and runs code completion.
+// If IndexSymbols is non-empty, an index will be built and passed to opts.
+CodeCompleteResult completions(StringRef Text,
+ std::vector<Symbol> IndexSymbols = {},
+ clangd::CodeCompleteOptions Opts = {}) {
+ MockFSProvider FS;
+ MockCompilationDatabase CDB;
+ IgnoreDiagnostics DiagConsumer;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ return completions(Server, Text, std::move(IndexSymbols), std::move(Opts));
+}
+
+std::string replace(StringRef Haystack, StringRef Needle, StringRef Repl) {
+ std::string Result;
+ raw_string_ostream OS(Result);
+ std::pair<StringRef, StringRef> Split;
+ for (Split = Haystack.split(Needle); !Split.second.empty();
+ Split = Split.first.split(Needle))
+ OS << Split.first << Repl;
+ Result += Split.first;
+ OS.flush();
+ return Result;
+}
+
+// Helpers to produce fake index symbols for memIndex() or completions().
+// USRFormat is a regex replacement string for the unqualified part of the USR.
+Symbol sym(StringRef QName, index::SymbolKind Kind, StringRef USRFormat) {
+ Symbol Sym;
+ std::string USR = "c:"; // We synthesize a few simple cases of USRs by hand!
+ size_t Pos = QName.rfind("::");
+ if (Pos == llvm::StringRef::npos) {
+ Sym.Name = QName;
+ Sym.Scope = "";
+ } else {
+ Sym.Name = QName.substr(Pos + 2);
+ Sym.Scope = QName.substr(0, Pos + 2);
+ USR += "@N@" + replace(QName.substr(0, Pos), "::", "@N@"); // ns:: -> @N@ns
+ }
+ USR += Regex("^.*$").sub(USRFormat, Sym.Name); // e.g. func -> @F@func#
+ Sym.ID = SymbolID(USR);
+ Sym.SymInfo.Kind = Kind;
+ Sym.IsIndexedForCodeCompletion = true;
+ Sym.Origin = SymbolOrigin::Static;
+ return Sym;
+}
+Symbol func(StringRef Name) { // Assumes the function has no args.
+ return sym(Name, index::SymbolKind::Function, "@F@\\0#"); // no args
+}
+Symbol cls(StringRef Name) {
+ return sym(Name, index::SymbolKind::Class, "@S@\\0");
+}
+Symbol var(StringRef Name) {
+ return sym(Name, index::SymbolKind::Variable, "@\\0");
+}
+Symbol ns(StringRef Name) {
+ return sym(Name, index::SymbolKind::Namespace, "@N@\\0");
+}
+Symbol withReferences(int N, Symbol S) {
+ S.References = N;
+ return S;
+}
+
+TEST(CompletionTest, Limit) {
+ clangd::CodeCompleteOptions Opts;
+ Opts.Limit = 2;
+ auto Results = completions(R"cpp(
+struct ClassWithMembers {
+ int AAA();
+ int BBB();
+ int CCC();
+}
+int main() { ClassWithMembers().^ }
+ )cpp",
+ /*IndexSymbols=*/{}, Opts);
+
+ EXPECT_TRUE(Results.HasMore);
+ EXPECT_THAT(Results.Completions, ElementsAre(Named("AAA"), Named("BBB")));
+}
+
+TEST(CompletionTest, Filter) {
+ std::string Body = R"cpp(
+ #define MotorCar
+ int Car;
+ struct S {
+ int FooBar;
+ int FooBaz;
+ int Qux;
+ };
+ )cpp";
+
+ // Only items matching the fuzzy query are returned.
+ EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").Completions,
+ AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
+
+ // Macros require prefix match.
+ EXPECT_THAT(completions(Body + "int main() { C^ }").Completions,
+ AllOf(Has("Car"), Not(Has("MotorCar"))));
+}
+
+void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
+ auto Results = completions(
+ R"cpp(
+ #define MACRO X
+
+ int global_var;
+
+ int global_func();
+
+ struct GlobalClass {};
+
+ struct ClassWithMembers {
+ /// Doc for method.
+ int method();
+
+ int field;
+ private:
+ int private_field;
+ };
+
+ int test() {
+ struct LocalClass {};
+
+ /// Doc for local_var.
+ int local_var;
+
+ ClassWithMembers().^
+ }
+ )cpp",
+ {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
+
+ // Class members. The only items that must be present in after-dot
+ // completion.
+ EXPECT_THAT(Results.Completions,
+ AllOf(Has("method"), Has("field"), Not(Has("ClassWithMembers")),
+ Not(Has("operator=")), Not(Has("~ClassWithMembers"))));
+ EXPECT_IFF(Opts.IncludeIneligibleResults, Results.Completions,
+ Has("private_field"));
+ // Global items.
+ EXPECT_THAT(
+ Results.Completions,
+ Not(AnyOf(Has("global_var"), Has("index_var"), Has("global_func"),
+ Has("global_func()"), Has("index_func"), Has("GlobalClass"),
+ Has("IndexClass"), Has("MACRO"), Has("LocalClass"))));
+ // There should be no code patterns (aka snippets) in after-dot
+ // completion. At least there aren't any we're aware of.
+ EXPECT_THAT(Results.Completions,
+ Not(Contains(Kind(CompletionItemKind::Snippet))));
+ // Check documentation.
+ EXPECT_IFF(Opts.IncludeComments, Results.Completions,
+ Contains(IsDocumented()));
+}
+
+void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
+ auto Results = completions(
+ R"cpp(
+ #define MACRO X
+
+ int global_var;
+ int global_func();
+
+ struct GlobalClass {};
+
+ struct ClassWithMembers {
+ /// Doc for method.
+ int method();
+ };
+
+ int test() {
+ struct LocalClass {};
+
+ /// Doc for local_var.
+ int local_var;
+
+ ^
+ }
+ )cpp",
+ {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);
+
+ // Class members. Should never be present in global completions.
+ EXPECT_THAT(Results.Completions,
+ Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
+ // Global items.
+ EXPECT_THAT(Results.Completions,
+ AllOf(Has("global_var"), Has("index_var"), Has("global_func"),
+ Has("index_func" /* our fake symbol doesn't include () */),
+ Has("GlobalClass"), Has("IndexClass")));
+ // A macro.
+ EXPECT_IFF(Opts.IncludeMacros, Results.Completions, Has("MACRO"));
+ // Local items. Must be present always.
+ EXPECT_THAT(Results.Completions,
+ AllOf(Has("local_var"), Has("LocalClass"),
+ Contains(Kind(CompletionItemKind::Snippet))));
+ // Check documentation.
+ EXPECT_IFF(Opts.IncludeComments, Results.Completions,
+ Contains(IsDocumented()));
+}
+
+TEST(CompletionTest, CompletionOptions) {
+ auto Test = [&](const clangd::CodeCompleteOptions &Opts) {
+ TestAfterDotCompletion(Opts);
+ TestGlobalScopeCompletion(Opts);
+ };
+ // We used to test every combination of options, but that got too slow (2^N).
+ auto Flags = {
+ &clangd::CodeCompleteOptions::IncludeMacros,
+ &clangd::CodeCompleteOptions::IncludeComments,
+ &clangd::CodeCompleteOptions::IncludeCodePatterns,
+ &clangd::CodeCompleteOptions::IncludeIneligibleResults,
+ };
+ // Test default options.
+ Test({});
+ // Test with one flag flipped.
+ for (auto &F : Flags) {
+ clangd::CodeCompleteOptions O;
+ O.*F ^= true;
+ Test(O);
+ }
+}
+
+TEST(CompletionTest, Priorities) {
+ auto Internal = completions(R"cpp(
+ class Foo {
+ public: void pub();
+ protected: void prot();
+ private: void priv();
+ };
+ void Foo::pub() { this->^ }
+ )cpp");
+ EXPECT_THAT(Internal.Completions,
+ HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
+
+ auto External = completions(R"cpp(
+ class Foo {
+ public: void pub();
+ protected: void prot();
+ private: void priv();
+ };
+ void test() {
+ Foo F;
+ F.^
+ }
+ )cpp");
+ EXPECT_THAT(External.Completions,
+ AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
+}
+
+TEST(CompletionTest, Qualifiers) {
+ auto Results = completions(R"cpp(
+ class Foo {
+ public: int foo() const;
+ int bar() const;
+ };
+ class Bar : public Foo {
+ int foo() const;
+ };
+ void test() { Bar().^ }
+ )cpp");
+ EXPECT_THAT(Results.Completions,
+ HasSubsequence(AllOf(Qualifier(""), Named("bar")),
+ AllOf(Qualifier("Foo::"), Named("foo"))));
+ EXPECT_THAT(Results.Completions,
+ Not(Contains(AllOf(Qualifier(""), Named("foo"))))); // private
+}
+
+TEST(CompletionTest, InjectedTypename) {
+ // These are suppressed when accessed as a member...
+ EXPECT_THAT(completions("struct X{}; void foo(){ X().^ }").Completions,
+ Not(Has("X")));
+ EXPECT_THAT(completions("struct X{ void foo(){ this->^ } };").Completions,
+ Not(Has("X")));
+ // ...but accessible in other, more useful cases.
+ EXPECT_THAT(completions("struct X{ void foo(){ ^ } };").Completions,
+ Has("X"));
+ EXPECT_THAT(
+ completions("struct Y{}; struct X:Y{ void foo(){ ^ } };").Completions,
+ Has("Y"));
+ EXPECT_THAT(
+ completions(
+ "template<class> struct Y{}; struct X:Y<int>{ void foo(){ ^ } };")
+ .Completions,
+ Has("Y"));
+ // This case is marginal (`using X::X` is useful), we allow it for now.
+ EXPECT_THAT(completions("struct X{}; void foo(){ X::^ }").Completions,
+ Has("X"));
+}
+
+TEST(CompletionTest, Snippets) {
+ clangd::CodeCompleteOptions Opts;
+ auto Results = completions(
+ R"cpp(
+ struct fake {
+ int a;
+ int f(int i, const float f) const;
+ };
+ int main() {
+ fake f;
+ f.^
+ }
+ )cpp",
+ /*IndexSymbols=*/{}, Opts);
+ EXPECT_THAT(
+ Results.Completions,
+ HasSubsequence(Named("a"),
+ SnippetSuffix("(${1:int i}, ${2:const float f})")));
+}
+
+TEST(CompletionTest, Kinds) {
+ auto Results = completions(
+ R"cpp(
+ #define MACRO X
+ int variable;
+ struct Struct {};
+ int function();
+ int X = ^
+ )cpp",
+ {func("indexFunction"), var("indexVariable"), cls("indexClass")});
+ EXPECT_THAT(Results.Completions,
+ AllOf(Has("function", CompletionItemKind::Function),
+ Has("variable", CompletionItemKind::Variable),
+ Has("int", CompletionItemKind::Keyword),
+ Has("Struct", CompletionItemKind::Class),
+ Has("MACRO", CompletionItemKind::Text),
+ Has("indexFunction", CompletionItemKind::Function),
+ Has("indexVariable", CompletionItemKind::Variable),
+ Has("indexClass", CompletionItemKind::Class)));
+
+ Results = completions("nam^");
+ EXPECT_THAT(Results.Completions,
+ Has("namespace", CompletionItemKind::Snippet));
+}
+
+TEST(CompletionTest, NoDuplicates) {
+ auto Results = completions(
+ R"cpp(
+ class Adapter {
+ };
+
+ void f() {
+ Adapter^
+ }
+ )cpp",
+ {cls("Adapter")});
+
+ // Make sure there are no duplicate entries of 'Adapter'.
+ EXPECT_THAT(Results.Completions, ElementsAre(Named("Adapter")));
+}
+
+TEST(CompletionTest, ScopedNoIndex) {
+ auto Results = completions(
+ R"cpp(
+ namespace fake { int BigBang, Babble, Box; };
+ int main() { fake::ba^ }
+ ")cpp");
+ // Babble is a better match than BigBang. Box doesn't match at all.
+ EXPECT_THAT(Results.Completions,
+ ElementsAre(Named("Babble"), Named("BigBang")));
+}
+
+TEST(CompletionTest, Scoped) {
+ auto Results = completions(
+ R"cpp(
+ namespace fake { int Babble, Box; };
+ int main() { fake::ba^ }
+ ")cpp",
+ {var("fake::BigBang")});
+ EXPECT_THAT(Results.Completions,
+ ElementsAre(Named("Babble"), Named("BigBang")));
+}
+
+TEST(CompletionTest, ScopedWithFilter) {
+ auto Results = completions(
+ R"cpp(
+ void f() { ns::x^ }
+ )cpp",
+ {cls("ns::XYZ"), func("ns::foo")});
+ EXPECT_THAT(Results.Completions, UnorderedElementsAre(Named("XYZ")));
+}
+
+TEST(CompletionTest, ReferencesAffectRanking) {
+ auto Results = completions("int main() { abs^ }", {ns("absl"), func("absb")});
+ EXPECT_THAT(Results.Completions, HasSubsequence(Named("absb"), Named("absl")));
+ Results = completions("int main() { abs^ }",
+ {withReferences(10000, ns("absl")), func("absb")});
+ EXPECT_THAT(Results.Completions,
+ HasSubsequence(Named("absl"), Named("absb")));
+}
+
+TEST(CompletionTest, GlobalQualified) {
+ auto Results = completions(
+ R"cpp(
+ void f() { ::^ }
+ )cpp",
+ {cls("XYZ")});
+ EXPECT_THAT(Results.Completions,
+ AllOf(Has("XYZ", CompletionItemKind::Class),
+ Has("f", CompletionItemKind::Function)));
+}
+
+TEST(CompletionTest, FullyQualified) {
+ auto Results = completions(
+ R"cpp(
+ namespace ns { void bar(); }
+ void f() { ::ns::^ }
+ )cpp",
+ {cls("ns::XYZ")});
+ EXPECT_THAT(Results.Completions,
+ AllOf(Has("XYZ", CompletionItemKind::Class),
+ Has("bar", CompletionItemKind::Function)));
+}
+
+TEST(CompletionTest, SemaIndexMerge) {
+ auto Results = completions(
+ R"cpp(
+ namespace ns { int local; void both(); }
+ void f() { ::ns::^ }
+ )cpp",
+ {func("ns::both"), cls("ns::Index")});
+ // We get results from both index and sema, with no duplicates.
+ EXPECT_THAT(Results.Completions,
+ UnorderedElementsAre(
+ AllOf(Named("local"), Origin(SymbolOrigin::AST)),
+ AllOf(Named("Index"), Origin(SymbolOrigin::Static)),
+ AllOf(Named("both"),
+ Origin(SymbolOrigin::AST | SymbolOrigin::Static))));
+}
+
+TEST(CompletionTest, SemaIndexMergeWithLimit) {
+ clangd::CodeCompleteOptions Opts;
+ Opts.Limit = 1;
+ auto Results = completions(
+ R"cpp(
+ namespace ns { int local; void both(); }
+ void f() { ::ns::^ }
+ )cpp",
+ {func("ns::both"), cls("ns::Index")}, Opts);
+ EXPECT_EQ(Results.Completions.size(), Opts.Limit);
+ EXPECT_TRUE(Results.HasMore);
+}
+
+TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
+ MockFSProvider FS;
+ MockCompilationDatabase CDB;
+ std::string Subdir = testPath("sub");
+ std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
+ CDB.ExtraClangFlags = {SearchDirArg.c_str()};
+ std::string BarHeader = testPath("sub/bar.h");
+ FS.Files[BarHeader] = "";
+
+ IgnoreDiagnostics DiagConsumer;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ Symbol::Details Scratch;
+ auto BarURI = URI::createFile(BarHeader).toString();
+ Symbol Sym = cls("ns::X");
+ Sym.CanonicalDeclaration.FileURI = BarURI;
+ Scratch.IncludeHeader = BarURI;
+ Sym.Detail = &Scratch;
+ // Shoten include path based on search dirctory and insert.
+ auto Results = completions(Server,
+ R"cpp(
+ int main() { ns::^ }
+ )cpp",
+ {Sym});
+ EXPECT_THAT(Results.Completions,
+ ElementsAre(AllOf(Named("X"), InsertInclude("\"bar.h\""))));
+ // Duplicate based on inclusions in preamble.
+ Results = completions(Server,
+ R"cpp(
+ #include "sub/bar.h" // not shortest, so should only match resolved.
+ int main() { ns::^ }
+ )cpp",
+ {Sym});
+ EXPECT_THAT(Results.Completions, ElementsAre(AllOf(Named("X"), Labeled("X"),
+ Not(InsertInclude()))));
+}
+
+TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
+ MockFSProvider FS;
+ MockCompilationDatabase CDB;
+
+ IgnoreDiagnostics DiagConsumer;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ Symbol::Details Scratch;
+ Symbol SymX = cls("ns::X");
+ Symbol SymY = cls("ns::Y");
+ std::string BarHeader = testPath("bar.h");
+ auto BarURI = URI::createFile(BarHeader).toString();
+ SymX.CanonicalDeclaration.FileURI = BarURI;
+ SymY.CanonicalDeclaration.FileURI = BarURI;
+ Scratch.IncludeHeader = "<bar>";
+ SymX.Detail = &Scratch;
+ SymY.Detail = &Scratch;
+ // Shoten include path based on search dirctory and insert.
+ auto Results = completions(Server,
+ R"cpp(
+ namespace ns {
+ class X;
+ class Y {}
+ }
+ int main() { ns::^ }
+ )cpp",
+ {SymX, SymY});
+ EXPECT_THAT(Results.Completions,
+ ElementsAre(AllOf(Named("X"), Not(InsertInclude())),
+ AllOf(Named("Y"), Not(InsertInclude()))));
+}
+
+TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
+ MockFSProvider FS;
+ MockCompilationDatabase CDB;
+ IgnoreDiagnostics DiagConsumer;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ FS.Files[testPath("bar.h")] =
+ R"cpp(namespace ns { struct preamble { int member; }; })cpp";
+ auto File = testPath("foo.cpp");
+ Annotations Test(R"cpp(
+ #include "bar.h"
+ namespace ns { int local; }
+ void f() { ns::^; }
+ void f() { ns::preamble().$2^; }
+ )cpp");
+ runAddDocument(Server, File, Test.code());
+ clangd::CodeCompleteOptions Opts = {};
+
+ auto I = memIndex({var("ns::index")});
+ Opts.Index = I.get();
+ auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
+ EXPECT_THAT(WithIndex.Completions,
+ UnorderedElementsAre(Named("local"), Named("index")));
+ auto ClassFromPreamble =
+ cantFail(runCodeComplete(Server, File, Test.point("2"), Opts));
+ EXPECT_THAT(ClassFromPreamble.Completions, Contains(Named("member")));
+
+ Opts.Index = nullptr;
+ auto WithoutIndex =
+ cantFail(runCodeComplete(Server, File, Test.point(), Opts));
+ EXPECT_THAT(WithoutIndex.Completions,
+ UnorderedElementsAre(Named("local"), Named("preamble")));
+}
+
+TEST(CompletionTest, DynamicIndexMultiFile) {
+ MockFSProvider FS;
+ MockCompilationDatabase CDB;
+ IgnoreDiagnostics DiagConsumer;
+ auto Opts = ClangdServer::optsForTest();
+ Opts.BuildDynamicSymbolIndex = true;
+ ClangdServer Server(CDB, FS, DiagConsumer, Opts);
+
+ FS.Files[testPath("foo.h")] = R"cpp(
+ namespace ns { class XYZ {}; void foo(int x) {} }
+ )cpp";
+ runAddDocument(Server, testPath("foo.cpp"), R"cpp(
+ #include "foo.h"
+ )cpp");
+
+ auto File = testPath("bar.cpp");
+ Annotations Test(R"cpp(
+ namespace ns {
+ class XXX {};
+ /// Doooc
+ void fooooo() {}
+ }
+ void f() { ns::^ }
+ )cpp");
+ runAddDocument(Server, File, Test.code());
+
+ auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
+ // "XYZ" and "foo" are not included in the file being completed but are still
+ // visible through the index.
+ EXPECT_THAT(Results.Completions, Has("XYZ", CompletionItemKind::Class));
+ EXPECT_THAT(Results.Completions, Has("foo", CompletionItemKind::Function));
+ EXPECT_THAT(Results.Completions, Has("XXX", CompletionItemKind::Class));
+ EXPECT_THAT(Results.Completions,
+ Contains((Named("fooooo"), Kind(CompletionItemKind::Function),
+ Doc("Doooc"), ReturnType("void"))));
+}
+
+TEST(CompletionTest, Documentation) {
+ auto Results = completions(
+ R"cpp(
+ // Non-doxygen comment.
+ int foo();
+ /// Doxygen comment.
+ /// \param int a
+ int bar(int a);
+ /* Multi-line
+ block comment
+ */
+ int baz();
+
+ int x = ^
+ )cpp");
+ EXPECT_THAT(Results.Completions,
+ Contains(AllOf(Named("foo"), Doc("Non-doxygen comment."))));
+ EXPECT_THAT(
+ Results.Completions,
+ Contains(AllOf(Named("bar"), Doc("Doxygen comment.\n\\param int a"))));
+ EXPECT_THAT(Results.Completions,
+ Contains(AllOf(Named("baz"), Doc("Multi-line\nblock comment"))));
+}
+
+TEST(CompletionTest, GlobalCompletionFiltering) {
+
+ Symbol Class = cls("XYZ");
+ Class.IsIndexedForCodeCompletion = false;
+ Symbol Func = func("XYZ::foooo");
+ Func.IsIndexedForCodeCompletion = false;
+
+ auto Results = completions(R"(// void f() {
+ XYZ::foooo^
+ })",
+ {Class, Func});
+ EXPECT_THAT(Results.Completions, IsEmpty());
+}
+
+TEST(CodeCompleteTest, DisableTypoCorrection) {
+ auto Results = completions(R"cpp(
+ namespace clang { int v; }
+ void f() { clangd::^
+ )cpp");
+ EXPECT_TRUE(Results.Completions.empty());
+}
+
+TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
+ auto Results = completions(R"cpp(
+ namespace clang { }
+ void f() {
+ clan^
+ }
+ )cpp");
+
+ EXPECT_THAT(Results.Completions, Contains(Labeled("clang")));
+ EXPECT_THAT(Results.Completions, Not(Contains(Labeled("clang::"))));
+}
+
+TEST(CompletionTest, BacktrackCrashes) {
+ // Sema calls code completion callbacks twice in these cases.
+ auto Results = completions(R"cpp(
+ namespace ns {
+ struct FooBarBaz {};
+ } // namespace ns
+
+ int foo(ns::FooBar^
+ )cpp");
+
+ EXPECT_THAT(Results.Completions, ElementsAre(Labeled("FooBarBaz")));
+
+ // Check we don't crash in that case too.
+ completions(R"cpp(
+ struct FooBarBaz {};
+ void test() {
+ if (FooBarBaz * x^) {}
+ }
+)cpp");
+}
+
+TEST(CompletionTest, CompleteInMacroWithStringification) {
+ auto Results = completions(R"cpp(
+void f(const char *, int x);
+#define F(x) f(#x, x)
+
+namespace ns {
+int X;
+int Y;
+} // namespace ns
+
+int f(int input_num) {
+ F(ns::^)
+}
+)cpp");
+
+ EXPECT_THAT(Results.Completions,
+ UnorderedElementsAre(Named("X"), Named("Y")));
+}
+
+TEST(CompletionTest, CompleteInMacroAndNamespaceWithStringification) {
+ auto Results = completions(R"cpp(
+void f(const char *, int x);
+#define F(x) f(#x, x)
+
+namespace ns {
+int X;
+
+int f(int input_num) {
+ F(^)
+}
+} // namespace ns
+)cpp");
+
+ EXPECT_THAT(Results.Completions, Contains(Named("X")));
+}
+
+TEST(CompletionTest, IgnoreCompleteInExcludedPPBranchWithRecoveryContext) {
+ auto Results = completions(R"cpp(
+ int bar(int param_in_bar) {
+ }
+
+ int foo(int param_in_foo) {
+#if 0
+ // In recorvery mode, "param_in_foo" will also be suggested among many other
+ // unrelated symbols; however, this is really a special case where this works.
+ // If the #if block is outside of the function, "param_in_foo" is still
+ // suggested, but "bar" and "foo" are missing. So the recovery mode doesn't
+ // really provide useful results in excluded branches.
+ par^
+#endif
+ }
+)cpp");
+
+ EXPECT_TRUE(Results.Completions.empty());
+}
+
+SignatureHelp signatures(StringRef Text) {
+ MockFSProvider FS;
+ MockCompilationDatabase CDB;
+ IgnoreDiagnostics DiagConsumer;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ auto File = testPath("foo.cpp");
+ Annotations Test(Text);
+ runAddDocument(Server, File, Test.code());
+ return cantFail(runSignatureHelp(Server, File, Test.point()));
+}
+
+MATCHER_P(ParamsAre, P, "") {
+ if (P.size() != arg.parameters.size())
+ return false;
+ for (unsigned I = 0; I < P.size(); ++I)
+ if (P[I] != arg.parameters[I].label)
+ return false;
+ return true;
+}
+
+Matcher<SignatureInformation> Sig(std::string Label,
+ std::vector<std::string> Params) {
+ return AllOf(SigHelpLabeled(Label), ParamsAre(Params));
+}
+
+TEST(SignatureHelpTest, Overloads) {
+ auto Results = signatures(R"cpp(
+ void foo(int x, int y);
+ void foo(int x, float y);
+ void foo(float x, int y);
+ void foo(float x, float y);
+ void bar(int x, int y = 0);
+ int main() { foo(^); }
+ )cpp");
+ EXPECT_THAT(Results.signatures,
+ UnorderedElementsAre(
+ Sig("foo(float x, float y) -> void", {"float x", "float y"}),
+ Sig("foo(float x, int y) -> void", {"float x", "int y"}),
+ Sig("foo(int x, float y) -> void", {"int x", "float y"}),
+ Sig("foo(int x, int y) -> void", {"int x", "int y"})));
+ // We always prefer the first signature.
+ EXPECT_EQ(0, Results.activeSignature);
+ EXPECT_EQ(0, Results.activeParameter);
+}
+
+TEST(SignatureHelpTest, DefaultArgs) {
+ auto Results = signatures(R"cpp(
+ void bar(int x, int y = 0);
+ void bar(float x = 0, int y = 42);
+ int main() { bar(^
+ )cpp");
+ EXPECT_THAT(Results.signatures,
+ UnorderedElementsAre(
+ Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
+ Sig("bar(float x = 0, int y = 42) -> void",
+ {"float x = 0", "int y = 42"})));
+ EXPECT_EQ(0, Results.activeSignature);
+ EXPECT_EQ(0, Results.activeParameter);
+}
+
+TEST(SignatureHelpTest, ActiveArg) {
+ auto Results = signatures(R"cpp(
+ int baz(int a, int b, int c);
+ int main() { baz(baz(1,2,3), ^); }
+ )cpp");
+ EXPECT_THAT(Results.signatures,
+ ElementsAre(Sig("baz(int a, int b, int c) -> int",
+ {"int a", "int b", "int c"})));
+ EXPECT_EQ(0, Results.activeSignature);
+ EXPECT_EQ(1, Results.activeParameter);
+}
+
+class IndexRequestCollector : public SymbolIndex {
+public:
+ bool
+ fuzzyFind(const FuzzyFindRequest &Req,
+ llvm::function_ref<void(const Symbol &)> Callback) const override {
+ Requests.push_back(Req);
+ return true;
+ }
+
+ void lookup(const LookupRequest &,
+ llvm::function_ref<void(const Symbol &)>) const override {}
+
+ const std::vector<FuzzyFindRequest> allRequests() const { return Requests; }
+
+private:
+ mutable std::vector<FuzzyFindRequest> Requests;
+};
+
+std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code) {
+ clangd::CodeCompleteOptions Opts;
+ IndexRequestCollector Requests;
+ Opts.Index = &Requests;
+ completions(Code, {}, Opts);
+ return Requests.allRequests();
+}
+
+TEST(CompletionTest, UnqualifiedIdQuery) {
+ auto Requests = captureIndexRequests(R"cpp(
+ namespace std {}
+ using namespace std;
+ namespace ns {
+ void f() {
+ vec^
+ }
+ }
+ )cpp");
+
+ EXPECT_THAT(Requests,
+ ElementsAre(Field(&FuzzyFindRequest::Scopes,
+ UnorderedElementsAre("", "ns::", "std::"))));
+}
+
+TEST(CompletionTest, ResolvedQualifiedIdQuery) {
+ auto Requests = captureIndexRequests(R"cpp(
+ namespace ns1 {}
+ namespace ns2 {} // ignore
+ namespace ns3 { namespace nns3 {} }
+ namespace foo {
+ using namespace ns1;
+ using namespace ns3::nns3;
+ }
+ namespace ns {
+ void f() {
+ foo::^
+ }
+ }
+ )cpp");
+
+ EXPECT_THAT(Requests,
+ ElementsAre(Field(
+ &FuzzyFindRequest::Scopes,
+ UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));
+}
+
+TEST(CompletionTest, UnresolvedQualifierIdQuery) {
+ auto Requests = captureIndexRequests(R"cpp(
+ namespace a {}
+ using namespace a;
+ namespace ns {
+ void f() {
+ bar::^
+ }
+ } // namespace ns
+ )cpp");
+
+ EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
+ UnorderedElementsAre("bar::"))));
+}
+
+TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {
+ auto Requests = captureIndexRequests(R"cpp(
+ namespace a {}
+ using namespace a;
+ namespace ns {
+ void f() {
+ ::a::bar::^
+ }
+ } // namespace ns
+ )cpp");
+
+ EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
+ UnorderedElementsAre("a::bar::"))));
+}
+
+TEST(CompletionTest, EmptyQualifiedQuery) {
+ auto Requests = captureIndexRequests(R"cpp(
+ namespace ns {
+ void f() {
+ ^
+ }
+ } // namespace ns
+ )cpp");
+
+ EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
+ UnorderedElementsAre("", "ns::"))));
+}
+
+TEST(CompletionTest, GlobalQualifiedQuery) {
+ auto Requests = captureIndexRequests(R"cpp(
+ namespace ns {
+ void f() {
+ ::^
+ }
+ } // namespace ns
+ )cpp");
+
+ EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
+ UnorderedElementsAre(""))));
+}
+
+TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
+ auto Completions = completions(
+ R"cpp(
+ struct Foo {
+ int SomeNameOfField;
+ typedef int SomeNameOfTypedefField;
+ };
+
+ Foo::^)cpp",
+ {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});
+
+ EXPECT_THAT(Completions.Completions,
+ AllOf(Contains(Labeled("SomeNameOfField")),
+ Contains(Labeled("SomeNameOfTypedefField")),
+ Not(Contains(Labeled("SomeNameInTheIndex")))));
+}
+
+TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
+ {
+ auto Completions = completions(
+ R"cpp(
+ template <class T>
+ void foo() {
+ T::^
+ }
+ )cpp",
+ {func("::SomeNameInTheIndex")});
+
+ EXPECT_THAT(Completions.Completions,
+ Not(Contains(Labeled("SomeNameInTheIndex"))));
+ }
+
+ {
+ auto Completions = completions(
+ R"cpp(
+ template <class T>
+ void foo() {
+ T::template Y<int>::^
+ }
+ )cpp",
+ {func("::SomeNameInTheIndex")});
+
+ EXPECT_THAT(Completions.Completions,
+ Not(Contains(Labeled("SomeNameInTheIndex"))));
+ }
+
+ {
+ auto Completions = completions(
+ R"cpp(
+ template <class T>
+ void foo() {
+ T::foo::^
+ }
+ )cpp",
+ {func("::SomeNameInTheIndex")});
+
+ EXPECT_THAT(Completions.Completions,
+ Not(Contains(Labeled("SomeNameInTheIndex"))));
+ }
+}
+
+TEST(CompletionTest, OverloadBundling) {
+ clangd::CodeCompleteOptions Opts;
+ Opts.BundleOverloads = true;
+
+ std::string Context = R"cpp(
+ struct X {
+ // Overload with int
+ int a(int);
+ // Overload with bool
+ int a(bool);
+ int b(float);
+ };
+ int GFuncC(int);
+ int GFuncD(int);
+ )cpp";
+
+ // Member completions are bundled.
+ EXPECT_THAT(completions(Context + "int y = X().^", {}, Opts).Completions,
+ UnorderedElementsAre(Labeled("a(…)"), Labeled("b(float)")));
+
+ // Non-member completions are bundled, including index+sema.
+ Symbol NoArgsGFunc = func("GFuncC");
+ EXPECT_THAT(
+ completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
+ UnorderedElementsAre(Labeled("GFuncC(…)"), Labeled("GFuncD(int)")));
+
+ // Differences in header-to-insert suppress bundling.
+ Symbol::Details Detail;
+ std::string DeclFile = URI::createFile(testPath("foo")).toString();
+ NoArgsGFunc.CanonicalDeclaration.FileURI = DeclFile;
+ Detail.IncludeHeader = "<foo>";
+ NoArgsGFunc.Detail = &Detail;
+ EXPECT_THAT(
+ completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
+ UnorderedElementsAre(AllOf(Named("GFuncC"), InsertInclude("<foo>")),
+ Labeled("GFuncC(int)"), Labeled("GFuncD(int)")));
+
+ // Examine a bundled completion in detail.
+ auto A =
+ completions(Context + "int y = X().a^", {}, Opts).Completions.front();
+ EXPECT_EQ(A.Name, "a");
+ EXPECT_EQ(A.Signature, "(…)");
+ EXPECT_EQ(A.BundleSize, 2u);
+ EXPECT_EQ(A.Kind, CompletionItemKind::Method);
+ EXPECT_EQ(A.ReturnType, "int"); // All overloads return int.
+ // For now we just return one of the doc strings arbitrarily.
+ EXPECT_THAT(A.Documentation, AnyOf(HasSubstr("Overload with int"),
+ HasSubstr("Overload with bool")));
+ EXPECT_EQ(A.SnippetSuffix, "(${0})");
+}
+
+TEST(CompletionTest, DocumentationFromChangedFileCrash) {
+ MockFSProvider FS;
+ auto FooH = testPath("foo.h");
+ auto FooCpp = testPath("foo.cpp");
+ FS.Files[FooH] = R"cpp(
+ // this is my documentation comment.
+ int func();
+ )cpp";
+ FS.Files[FooCpp] = "";
+
+ MockCompilationDatabase CDB;
+ IgnoreDiagnostics DiagConsumer;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ Annotations Source(R"cpp(
+ #include "foo.h"
+ int func() {
+ // This makes sure we have func from header in the AST.
+ }
+ int a = fun^
+ )cpp");
+ Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
+ // We need to wait for preamble to build.
+ ASSERT_TRUE(Server.blockUntilIdleForTest());
+
+ // Change the header file. Completion will reuse the old preamble!
+ FS.Files[FooH] = R"cpp(
+ int func();
+ )cpp";
+
+ clangd::CodeCompleteOptions Opts;
+ Opts.IncludeComments = true;
+ CodeCompleteResult Completions =
+ cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));
+ // We shouldn't crash. Unfortunately, current workaround is to not produce
+ // comments for symbols from headers.
+ EXPECT_THAT(Completions.Completions,
+ Contains(AllOf(Not(IsDocumented()), Named("func"))));
+}
+
+TEST(CompletionTest, NonDocComments) {
+ MockFSProvider FS;
+ auto FooCpp = testPath("foo.cpp");
+ FS.Files[FooCpp] = "";
+
+ MockCompilationDatabase CDB;
+ IgnoreDiagnostics DiagConsumer;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ Annotations Source(R"cpp(
+ // We ignore namespace comments, for rationale see CodeCompletionStrings.h.
+ namespace comments_ns {
+ }
+
+ // ------------------
+ int comments_foo();
+
+ // A comment and a decl are separated by newlines.
+ // Therefore, the comment shouldn't show up as doc comment.
+
+ int comments_bar();
+
+ // this comment should be in the results.
+ int comments_baz();
+
+
+ template <class T>
+ struct Struct {
+ int comments_qux();
+ int comments_quux();
+ };
+
+
+ // This comment should not be there.
+
+ template <class T>
+ int Struct<T>::comments_qux() {
+ }
+
+ // This comment **should** be in results.
+ template <class T>
+ int Struct<T>::comments_quux() {
+ int a = comments^;
+ }
+ )cpp");
+ // FIXME: Auto-completion in a template requires disabling delayed template
+ // parsing.
+ CDB.ExtraClangFlags.push_back("-fno-delayed-template-parsing");
+ Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
+ CodeCompleteResult Completions = cantFail(runCodeComplete(
+ Server, FooCpp, Source.point(), clangd::CodeCompleteOptions()));
+
+ // We should not get any of those comments in completion.
+ EXPECT_THAT(
+ Completions.Completions,
+ UnorderedElementsAre(AllOf(Not(IsDocumented()), Named("comments_foo")),
+ AllOf(IsDocumented(), Named("comments_baz")),
+ AllOf(IsDocumented(), Named("comments_quux")),
+ AllOf(Not(IsDocumented()), Named("comments_ns")),
+ // FIXME(ibiryukov): the following items should have
+ // empty documentation, since they are separated from
+ // a comment with an empty line. Unfortunately, I
+ // couldn't make Sema tests pass if we ignore those.
+ AllOf(IsDocumented(), Named("comments_bar")),
+ AllOf(IsDocumented(), Named("comments_qux"))));
+}
+
+TEST(CompletionTest, CompleteOnInvalidLine) {
+ auto FooCpp = testPath("foo.cpp");
+
+ MockCompilationDatabase CDB;
+ IgnoreDiagnostics DiagConsumer;
+ MockFSProvider FS;
+ FS.Files[FooCpp] = "// empty file";
+
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+ // Run completion outside the file range.
+ Position Pos;
+ Pos.line = 100;
+ Pos.character = 0;
+ EXPECT_THAT_EXPECTED(
+ runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),
+ Failed());
+}
+
+TEST(CompletionTest, QualifiedNames) {
+ auto Results = completions(
+ R"cpp(
+ namespace ns { int local; void both(); }
+ void f() { ::ns::^ }
+ )cpp",
+ {func("ns::both"), cls("ns::Index")});
+ // We get results from both index and sema, with no duplicates.
+ EXPECT_THAT(
+ Results.Completions,
+ UnorderedElementsAre(Scope("ns::"), Scope("ns::"), Scope("ns::")));
+}
+
+TEST(CompletionTest, Render) {
+ CodeCompletion C;
+ C.Name = "x";
+ C.Signature = "(bool) const";
+ C.SnippetSuffix = "(${0:bool})";
+ C.ReturnType = "int";
+ C.RequiredQualifier = "Foo::";
+ C.Scope = "ns::Foo::";
+ C.Documentation = "This is x().";
+ C.Header = "\"foo.h\"";
+ C.Kind = CompletionItemKind::Method;
+ C.Score.Total = 1.0;
+ C.Origin = SymbolOrigin::AST | SymbolOrigin::Static;
+
+ CodeCompleteOptions Opts;
+ Opts.IncludeIndicator.Insert = "^";
+ Opts.IncludeIndicator.NoInsert = "";
+ Opts.EnableSnippets = false;
+
+ auto R = C.render(Opts);
+ EXPECT_EQ(R.label, "Foo::x(bool) const");
+ EXPECT_EQ(R.insertText, "Foo::x");
+ EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText);
+ EXPECT_EQ(R.filterText, "x");
+ EXPECT_EQ(R.detail, "int\n\"foo.h\"");
+ EXPECT_EQ(R.documentation, "This is x().");
+ EXPECT_THAT(R.additionalTextEdits, IsEmpty());
+ EXPECT_EQ(R.sortText, sortText(1.0, "x"));
+
+ Opts.EnableSnippets = true;
+ R = C.render(Opts);
+ EXPECT_EQ(R.insertText, "Foo::x(${0:bool})");
+ EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet);
+
+ C.HeaderInsertion.emplace();
+ R = C.render(Opts);
+ EXPECT_EQ(R.label, "^Foo::x(bool) const");
+ EXPECT_THAT(R.additionalTextEdits, Not(IsEmpty()));
+
+ Opts.ShowOrigins = true;
+ R = C.render(Opts);
+ EXPECT_EQ(R.label, "^[AS]Foo::x(bool) const");
+
+ C.BundleSize = 2;
+ R = C.render(Opts);
+ EXPECT_EQ(R.detail, "[2 overloads]\n\"foo.h\"");
+}
+
+TEST(CompletionTest, IgnoreRecoveryResults) {
+ auto Results = completions(
+ R"cpp(
+ namespace ns { int NotRecovered() { return 0; } }
+ void f() {
+ // Sema enters recovery mode first and then normal mode.
+ if (auto x = ns::NotRecover^)
+ }
+ )cpp");
+ EXPECT_THAT(Results.Completions, UnorderedElementsAre(Named("NotRecovered")));
+}
+
+TEST(CompletionTest, ScopeOfClassFieldInConstructorInitializer) {
+ auto Results = completions(
+ R"cpp(
+ namespace ns {
+ class X { public: X(); int x_; };
+ X::X() : x_^(0) {}
+ }
+ )cpp");
+ EXPECT_THAT(Results.Completions,
+ UnorderedElementsAre(AllOf(Scope("ns::X::"), Named("x_"))));
+}
+
+TEST(CompletionTest, CodeCompletionContext) {
+ auto Results = completions(
+ R"cpp(
+ namespace ns {
+ class X { public: X(); int x_; };
+ void f() {
+ X x;
+ x.^;
+ }
+ }
+ )cpp");
+
+ EXPECT_THAT(Results.Context, CodeCompletionContext::CCC_DotMemberAccess);
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/CodeCompletionStringsTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/CodeCompletionStringsTests.cpp
new file mode 100644
index 0000000..a6038a7
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/CodeCompletionStringsTests.cpp
@@ -0,0 +1,114 @@
+//===-- CodeCompletionStringsTests.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeCompletionStrings.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+class CompletionStringTest : public ::testing::Test {
+public:
+ CompletionStringTest()
+ : Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
+ CCTUInfo(Allocator), Builder(*Allocator, CCTUInfo) {}
+
+protected:
+ void computeSignature(const CodeCompletionString &CCS) {
+ Signature.clear();
+ Snippet.clear();
+ getSignature(CCS, &Signature, &Snippet);
+ }
+
+ std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
+ CodeCompletionTUInfo CCTUInfo;
+ CodeCompletionBuilder Builder;
+ std::string Signature;
+ std::string Snippet;
+};
+
+TEST_F(CompletionStringTest, ReturnType) {
+ Builder.AddResultTypeChunk("result");
+ Builder.AddResultTypeChunk("redundant result no no");
+ EXPECT_EQ(getReturnType(*Builder.TakeString()), "result");
+}
+
+TEST_F(CompletionStringTest, Documentation) {
+ Builder.addBriefComment("This is ignored");
+ EXPECT_EQ(formatDocumentation(*Builder.TakeString(), "Is this brief?"),
+ "Is this brief?");
+}
+
+TEST_F(CompletionStringTest, DocumentationWithAnnotation) {
+ Builder.addBriefComment("This is ignored");
+ Builder.AddAnnotation("Ano");
+ EXPECT_EQ(formatDocumentation(*Builder.TakeString(), "Is this brief?"),
+ "Annotation: Ano\n\nIs this brief?");
+}
+
+TEST_F(CompletionStringTest, MultipleAnnotations) {
+ Builder.AddAnnotation("Ano1");
+ Builder.AddAnnotation("Ano2");
+ Builder.AddAnnotation("Ano3");
+
+ EXPECT_EQ(formatDocumentation(*Builder.TakeString(), ""),
+ "Annotations: Ano1 Ano2 Ano3\n");
+}
+
+TEST_F(CompletionStringTest, EmptySignature) {
+ Builder.AddTypedTextChunk("X");
+ Builder.AddResultTypeChunk("result no no");
+ computeSignature(*Builder.TakeString());
+ EXPECT_EQ(Signature, "");
+ EXPECT_EQ(Snippet, "");
+}
+
+TEST_F(CompletionStringTest, Function) {
+ Builder.AddResultTypeChunk("result no no");
+ Builder.addBriefComment("This comment is ignored");
+ Builder.AddTypedTextChunk("Foo");
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+ Builder.AddPlaceholderChunk("p1");
+ Builder.AddChunk(CodeCompletionString::CK_Comma);
+ Builder.AddPlaceholderChunk("p2");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+
+ auto *CCS = Builder.TakeString();
+ computeSignature(*CCS);
+ EXPECT_EQ(Signature, "(p1, p2)");
+ EXPECT_EQ(Snippet, "(${1:p1}, ${2:p2})");
+ EXPECT_EQ(formatDocumentation(*CCS, "Foo's comment"), "Foo's comment");
+}
+
+TEST_F(CompletionStringTest, EscapeSnippet) {
+ Builder.AddTypedTextChunk("Foo");
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+ Builder.AddPlaceholderChunk("$p}1\\");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+
+ computeSignature(*Builder.TakeString());
+ EXPECT_EQ(Signature, "($p}1\\)");
+ EXPECT_EQ(Snippet, "(${1:\\$p\\}1\\\\})");
+}
+
+TEST_F(CompletionStringTest, IgnoreInformativeQualifier) {
+ Builder.AddTypedTextChunk("X");
+ Builder.AddInformativeChunk("info ok");
+ Builder.AddInformativeChunk("info no no::");
+ computeSignature(*Builder.TakeString());
+ EXPECT_EQ(Signature, "info ok");
+ EXPECT_EQ(Snippet, "");
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/ContextTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/ContextTests.cpp
new file mode 100644
index 0000000..d5cb3ce
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/ContextTests.cpp
@@ -0,0 +1,57 @@
+//===-- ContextTests.cpp - Context tests ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Context.h"
+
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+
+TEST(ContextTests, Simple) {
+ Key<int> IntParam;
+ Key<int> ExtraIntParam;
+
+ Context Ctx = Context::empty().derive(IntParam, 10).derive(ExtraIntParam, 20);
+
+ EXPECT_EQ(*Ctx.get(IntParam), 10);
+ EXPECT_EQ(*Ctx.get(ExtraIntParam), 20);
+}
+
+TEST(ContextTests, MoveOps) {
+ Key<std::unique_ptr<int>> Param;
+
+ Context Ctx = Context::empty().derive(Param, llvm::make_unique<int>(10));
+ EXPECT_EQ(**Ctx.get(Param), 10);
+
+ Context NewCtx = std::move(Ctx);
+ EXPECT_EQ(**NewCtx.get(Param), 10);
+}
+
+TEST(ContextTests, Builders) {
+ Key<int> ParentParam;
+ Key<int> ParentAndChildParam;
+ Key<int> ChildParam;
+
+ Context ParentCtx =
+ Context::empty().derive(ParentParam, 10).derive(ParentAndChildParam, 20);
+ Context ChildCtx =
+ ParentCtx.derive(ParentAndChildParam, 30).derive(ChildParam, 40);
+
+ EXPECT_EQ(*ParentCtx.get(ParentParam), 10);
+ EXPECT_EQ(*ParentCtx.get(ParentAndChildParam), 20);
+ EXPECT_EQ(ParentCtx.get(ChildParam), nullptr);
+
+ EXPECT_EQ(*ChildCtx.get(ParentParam), 10);
+ EXPECT_EQ(*ChildCtx.get(ParentAndChildParam), 30);
+ EXPECT_EQ(*ChildCtx.get(ChildParam), 40);
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/DexIndexTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/DexIndexTests.cpp
new file mode 100644
index 0000000..906d62a
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/DexIndexTests.cpp
@@ -0,0 +1,317 @@
+//===-- DexIndexTests.cpp ----------------------------*- C++ -*-----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "index/dex/Iterator.h"
+#include "index/dex/Token.h"
+#include "index/dex/Trigram.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace clangd {
+namespace dex {
+
+using ::testing::ElementsAre;
+
+TEST(DexIndexIterators, DocumentIterator) {
+ const PostingList L = {4, 7, 8, 20, 42, 100};
+ auto DocIterator = create(L);
+
+ EXPECT_EQ(DocIterator->peek(), 4U);
+ EXPECT_EQ(DocIterator->reachedEnd(), false);
+
+ DocIterator->advance();
+ EXPECT_EQ(DocIterator->peek(), 7U);
+ EXPECT_EQ(DocIterator->reachedEnd(), false);
+
+ DocIterator->advanceTo(20);
+ EXPECT_EQ(DocIterator->peek(), 20U);
+ EXPECT_EQ(DocIterator->reachedEnd(), false);
+
+ DocIterator->advanceTo(65);
+ EXPECT_EQ(DocIterator->peek(), 100U);
+ EXPECT_EQ(DocIterator->reachedEnd(), false);
+
+ DocIterator->advanceTo(420);
+ EXPECT_EQ(DocIterator->reachedEnd(), true);
+}
+
+TEST(DexIndexIterators, AndWithEmpty) {
+ const PostingList L0;
+ const PostingList L1 = {0, 5, 7, 10, 42, 320, 9000};
+
+ auto AndEmpty = createAnd(create(L0));
+ EXPECT_EQ(AndEmpty->reachedEnd(), true);
+
+ auto AndWithEmpty = createAnd(create(L0), create(L1));
+ EXPECT_EQ(AndWithEmpty->reachedEnd(), true);
+
+ EXPECT_THAT(consume(*AndWithEmpty), ElementsAre());
+}
+
+TEST(DexIndexIterators, AndTwoLists) {
+ const PostingList L0 = {0, 5, 7, 10, 42, 320, 9000};
+ const PostingList L1 = {0, 4, 7, 10, 30, 60, 320, 9000};
+
+ auto And = createAnd(create(L1), create(L0));
+
+ EXPECT_EQ(And->reachedEnd(), false);
+ EXPECT_THAT(consume(*And), ElementsAre(0U, 7U, 10U, 320U, 9000U));
+
+ And = createAnd(create(L0), create(L1));
+
+ And->advanceTo(0);
+ EXPECT_EQ(And->peek(), 0U);
+ And->advanceTo(5);
+ EXPECT_EQ(And->peek(), 7U);
+ And->advanceTo(10);
+ EXPECT_EQ(And->peek(), 10U);
+ And->advanceTo(42);
+ EXPECT_EQ(And->peek(), 320U);
+ And->advanceTo(8999);
+ EXPECT_EQ(And->peek(), 9000U);
+ And->advanceTo(9001);
+}
+
+TEST(DexIndexIterators, AndThreeLists) {
+ const PostingList L0 = {0, 5, 7, 10, 42, 320, 9000};
+ const PostingList L1 = {0, 4, 7, 10, 30, 60, 320, 9000};
+ const PostingList L2 = {1, 4, 7, 11, 30, 60, 320, 9000};
+
+ auto And = createAnd(create(L0), create(L1), create(L2));
+ EXPECT_EQ(And->peek(), 7U);
+ And->advanceTo(300);
+ EXPECT_EQ(And->peek(), 320U);
+ And->advanceTo(100000);
+
+ EXPECT_EQ(And->reachedEnd(), true);
+}
+
+TEST(DexIndexIterators, OrWithEmpty) {
+ const PostingList L0;
+ const PostingList L1 = {0, 5, 7, 10, 42, 320, 9000};
+
+ auto OrEmpty = createOr(create(L0));
+ EXPECT_EQ(OrEmpty->reachedEnd(), true);
+
+ auto OrWithEmpty = createOr(create(L0), create(L1));
+ EXPECT_EQ(OrWithEmpty->reachedEnd(), false);
+
+ EXPECT_THAT(consume(*OrWithEmpty),
+ ElementsAre(0U, 5U, 7U, 10U, 42U, 320U, 9000U));
+}
+
+TEST(DexIndexIterators, OrTwoLists) {
+ const PostingList L0 = {0, 5, 7, 10, 42, 320, 9000};
+ const PostingList L1 = {0, 4, 7, 10, 30, 60, 320, 9000};
+
+ auto Or = createOr(create(L0), create(L1));
+
+ EXPECT_EQ(Or->reachedEnd(), false);
+ EXPECT_EQ(Or->peek(), 0U);
+ Or->advance();
+ EXPECT_EQ(Or->peek(), 4U);
+ Or->advance();
+ EXPECT_EQ(Or->peek(), 5U);
+ Or->advance();
+ EXPECT_EQ(Or->peek(), 7U);
+ Or->advance();
+ EXPECT_EQ(Or->peek(), 10U);
+ Or->advance();
+ EXPECT_EQ(Or->peek(), 30U);
+ Or->advanceTo(42);
+ EXPECT_EQ(Or->peek(), 42U);
+ Or->advanceTo(300);
+ EXPECT_EQ(Or->peek(), 320U);
+ Or->advanceTo(9000);
+ EXPECT_EQ(Or->peek(), 9000U);
+ Or->advanceTo(9001);
+ EXPECT_EQ(Or->reachedEnd(), true);
+
+ Or = createOr(create(L0), create(L1));
+
+ EXPECT_THAT(consume(*Or),
+ ElementsAre(0U, 4U, 5U, 7U, 10U, 30U, 42U, 60U, 320U, 9000U));
+}
+
+TEST(DexIndexIterators, OrThreeLists) {
+ const PostingList L0 = {0, 5, 7, 10, 42, 320, 9000};
+ const PostingList L1 = {0, 4, 7, 10, 30, 60, 320, 9000};
+ const PostingList L2 = {1, 4, 7, 11, 30, 60, 320, 9000};
+
+ auto Or = createOr(create(L0), create(L1), create(L2));
+
+ EXPECT_EQ(Or->reachedEnd(), false);
+ EXPECT_EQ(Or->peek(), 0U);
+
+ Or->advance();
+ EXPECT_EQ(Or->peek(), 1U);
+
+ Or->advance();
+ EXPECT_EQ(Or->peek(), 4U);
+
+ Or->advanceTo(7);
+
+ Or->advanceTo(59);
+ EXPECT_EQ(Or->peek(), 60U);
+
+ Or->advanceTo(9001);
+ EXPECT_EQ(Or->reachedEnd(), true);
+}
+
+// FIXME(kbobyrev): The testcase below is similar to what is expected in real
+// queries. It should be updated once new iterators (such as boosting, limiting,
+// etc iterators) appear. However, it is not exhaustive and it would be
+// beneficial to implement automatic generation of query trees for more
+// comprehensive testing.
+TEST(DexIndexIterators, QueryTree) {
+ // An example of more complicated query
+ //
+ // +-----------------+
+ // |And Iterator:1, 5|
+ // +--------+--------+
+ // |
+ // |
+ // +------------------------------------+
+ // | |
+ // | |
+ // +----------v----------+ +----------v---------+
+ // |And Iterator: 1, 5, 9| |Or Iterator: 0, 1, 5|
+ // +----------+----------+ +----------+---------+
+ // | |
+ // +------+-----+ +---------+-----------+
+ // | | | | |
+ // +-------v-----+ +----v-----+ +--v--+ +-V--+ +---v---+
+ // |1, 3, 5, 8, 9| |1, 5, 7, 9| |Empty| |0, 5| |0, 1, 5|
+ // +-------------+ +----------+ +-----+ +----+ +-------+
+
+ const PostingList L0 = {1, 3, 5, 8, 9};
+ const PostingList L1 = {1, 5, 7, 9};
+ const PostingList L2 = {0, 5};
+ const PostingList L3 = {0, 1, 5};
+ const PostingList L4;
+
+ // Root of the query tree: [1, 5]
+ auto Root = createAnd(
+ // Lower And Iterator: [1, 5, 9]
+ createAnd(create(L0), create(L1)),
+ // Lower Or Iterator: [0, 1, 5]
+ createOr(create(L2), create(L3), create(L4)));
+
+ EXPECT_EQ(Root->reachedEnd(), false);
+ EXPECT_EQ(Root->peek(), 1U);
+ Root->advanceTo(0);
+ // Advance multiple times. Shouldn't do anything.
+ Root->advanceTo(1);
+ Root->advanceTo(0);
+ EXPECT_EQ(Root->peek(), 1U);
+ Root->advance();
+ EXPECT_EQ(Root->peek(), 5U);
+ Root->advanceTo(5);
+ EXPECT_EQ(Root->peek(), 5U);
+ Root->advanceTo(9000);
+ EXPECT_EQ(Root->reachedEnd(), true);
+}
+
+TEST(DexIndexIterators, StringRepresentation) {
+ const PostingList L0 = {4, 7, 8, 20, 42, 100};
+ const PostingList L1 = {1, 3, 5, 8, 9};
+ const PostingList L2 = {1, 5, 7, 9};
+ const PostingList L3 = {0, 5};
+ const PostingList L4 = {0, 1, 5};
+ const PostingList L5;
+
+ EXPECT_EQ(llvm::to_string(*(create(L0))), "[4, 7, 8, 20, 42, 100]");
+
+ auto Nested = createAnd(createAnd(create(L1), create(L2)),
+ createOr(create(L3), create(L4), create(L5)));
+
+ EXPECT_EQ(llvm::to_string(*Nested),
+ "(& (& [1, 3, 5, 8, 9] [1, 5, 7, 9]) (| [0, 5] [0, 1, 5] []))");
+}
+
+testing::Matcher<std::vector<Token>>
+trigramsAre(std::initializer_list<std::string> Trigrams) {
+ std::vector<Token> Tokens;
+ for (const auto &Symbols : Trigrams) {
+ Tokens.push_back(Token(Token::Kind::Trigram, Symbols));
+ }
+ return testing::UnorderedElementsAreArray(Tokens);
+}
+
+TEST(DexIndexTrigrams, IdentifierTrigrams) {
+ EXPECT_THAT(generateIdentifierTrigrams("X86"), trigramsAre({"x86"}));
+
+ EXPECT_THAT(generateIdentifierTrigrams("nl"), trigramsAre({}));
+
+ EXPECT_THAT(generateIdentifierTrigrams("clangd"),
+ trigramsAre({"cla", "lan", "ang", "ngd"}));
+
+ EXPECT_THAT(generateIdentifierTrigrams("abc_def"),
+ trigramsAre({"abc", "abd", "ade", "bcd", "bde", "cde", "def"}));
+
+ EXPECT_THAT(
+ generateIdentifierTrigrams("a_b_c_d_e_"),
+ trigramsAre({"abc", "abd", "acd", "ace", "bcd", "bce", "bde", "cde"}));
+
+ EXPECT_THAT(
+ generateIdentifierTrigrams("unique_ptr"),
+ trigramsAre({"uni", "unp", "upt", "niq", "nip", "npt", "iqu", "iqp",
+ "ipt", "que", "qup", "qpt", "uep", "ept", "ptr"}));
+
+ EXPECT_THAT(generateIdentifierTrigrams("TUDecl"),
+ trigramsAre({"tud", "tde", "ude", "dec", "ecl"}));
+
+ EXPECT_THAT(generateIdentifierTrigrams("IsOK"),
+ trigramsAre({"iso", "iok", "sok"}));
+
+ EXPECT_THAT(generateIdentifierTrigrams("abc_defGhij__klm"),
+ trigramsAre({
+ "abc", "abd", "abg", "ade", "adg", "adk", "agh", "agk", "bcd",
+ "bcg", "bde", "bdg", "bdk", "bgh", "bgk", "cde", "cdg", "cdk",
+ "cgh", "cgk", "def", "deg", "dek", "dgh", "dgk", "dkl", "efg",
+ "efk", "egh", "egk", "ekl", "fgh", "fgk", "fkl", "ghi", "ghk",
+ "gkl", "hij", "hik", "hkl", "ijk", "ikl", "jkl", "klm",
+ }));
+}
+
+TEST(DexIndexTrigrams, QueryTrigrams) {
+ EXPECT_THAT(generateQueryTrigrams("X86"), trigramsAre({"x86"}));
+
+ EXPECT_THAT(generateQueryTrigrams("nl"), trigramsAre({}));
+
+ EXPECT_THAT(generateQueryTrigrams("clangd"),
+ trigramsAre({"cla", "lan", "ang", "ngd"}));
+
+ EXPECT_THAT(generateQueryTrigrams("abc_def"),
+ trigramsAre({"abc", "bcd", "cde", "def"}));
+
+ EXPECT_THAT(generateQueryTrigrams("a_b_c_d_e_"),
+ trigramsAre({"abc", "bcd", "cde"}));
+
+ EXPECT_THAT(generateQueryTrigrams("unique_ptr"),
+ trigramsAre({"uni", "niq", "iqu", "que", "uep", "ept", "ptr"}));
+
+ EXPECT_THAT(generateQueryTrigrams("TUDecl"),
+ trigramsAre({"tud", "ude", "dec", "ecl"}));
+
+ EXPECT_THAT(generateQueryTrigrams("IsOK"), trigramsAre({"iso", "sok"}));
+
+ EXPECT_THAT(generateQueryTrigrams("abc_defGhij__klm"),
+ trigramsAre({"abc", "bcd", "cde", "def", "efg", "fgh", "ghi",
+ "hij", "ijk", "jkl", "klm"}));
+}
+
+} // namespace dex
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/DraftStoreTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/DraftStoreTests.cpp
new file mode 100644
index 0000000..ad723a3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/DraftStoreTests.cpp
@@ -0,0 +1,350 @@
+//===-- DraftStoreTests.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Annotations.h"
+#include "DraftStore.h"
+#include "SourceCode.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+struct IncrementalTestStep {
+ StringRef Src;
+ StringRef Contents;
+};
+
+int rangeLength(StringRef Code, const Range &Rng) {
+ llvm::Expected<size_t> Start = positionToOffset(Code, Rng.start);
+ llvm::Expected<size_t> End = positionToOffset(Code, Rng.end);
+ assert(Start);
+ assert(End);
+ return *End - *Start;
+}
+
+/// Send the changes one by one to updateDraft, verify the intermediate results.
+void stepByStep(llvm::ArrayRef<IncrementalTestStep> Steps) {
+ DraftStore DS;
+ Annotations InitialSrc(Steps.front().Src);
+ constexpr llvm::StringLiteral Path("/hello.cpp");
+
+ // Set the initial content.
+ DS.addDraft(Path, InitialSrc.code());
+
+ for (size_t i = 1; i < Steps.size(); i++) {
+ Annotations SrcBefore(Steps[i - 1].Src);
+ Annotations SrcAfter(Steps[i].Src);
+ StringRef Contents = Steps[i - 1].Contents;
+ TextDocumentContentChangeEvent Event{
+ SrcBefore.range(),
+ rangeLength(SrcBefore.code(), SrcBefore.range()),
+ Contents.str(),
+ };
+
+ llvm::Expected<std::string> Result = DS.updateDraft(Path, {Event});
+ ASSERT_TRUE(!!Result);
+ EXPECT_EQ(*Result, SrcAfter.code());
+ EXPECT_EQ(*DS.getDraft(Path), SrcAfter.code());
+ }
+}
+
+/// Send all the changes at once to updateDraft, check only the final result.
+void allAtOnce(llvm::ArrayRef<IncrementalTestStep> Steps) {
+ DraftStore DS;
+ Annotations InitialSrc(Steps.front().Src);
+ Annotations FinalSrc(Steps.back().Src);
+ constexpr llvm::StringLiteral Path("/hello.cpp");
+ std::vector<TextDocumentContentChangeEvent> Changes;
+
+ for (size_t i = 0; i < Steps.size() - 1; i++) {
+ Annotations Src(Steps[i].Src);
+ StringRef Contents = Steps[i].Contents;
+
+ Changes.push_back({
+ Src.range(),
+ rangeLength(Src.code(), Src.range()),
+ Contents.str(),
+ });
+ }
+
+ // Set the initial content.
+ DS.addDraft(Path, InitialSrc.code());
+
+ llvm::Expected<std::string> Result = DS.updateDraft(Path, Changes);
+
+ ASSERT_TRUE(!!Result) << llvm::toString(Result.takeError());
+ EXPECT_EQ(*Result, FinalSrc.code());
+ EXPECT_EQ(*DS.getDraft(Path), FinalSrc.code());
+}
+
+TEST(DraftStoreIncrementalUpdateTest, Simple) {
+ // clang-format off
+ IncrementalTestStep Steps[] =
+ {
+ // Replace a range
+ {
+R"cpp(static int
+hello[[World]]()
+{})cpp",
+ "Universe"
+ },
+ // Delete a range
+ {
+R"cpp(static int
+hello[[Universe]]()
+{})cpp",
+ ""
+ },
+ // Add a range
+ {
+R"cpp(static int
+hello[[]]()
+{})cpp",
+ "Monde"
+ },
+ {
+R"cpp(static int
+helloMonde()
+{})cpp",
+ ""
+ }
+ };
+ // clang-format on
+
+ stepByStep(Steps);
+ allAtOnce(Steps);
+}
+
+TEST(DraftStoreIncrementalUpdateTest, MultiLine) {
+ // clang-format off
+ IncrementalTestStep Steps[] =
+ {
+ // Replace a range
+ {
+R"cpp(static [[int
+helloWorld]]()
+{})cpp",
+R"cpp(char
+welcome)cpp"
+ },
+ // Delete a range
+ {
+R"cpp(static char[[
+welcome]]()
+{})cpp",
+ ""
+ },
+ // Add a range
+ {
+R"cpp(static char[[]]()
+{})cpp",
+ R"cpp(
+cookies)cpp"
+ },
+ // Replace the whole file
+ {
+R"cpp([[static char
+cookies()
+{}]])cpp",
+ R"cpp(#include <stdio.h>
+)cpp"
+ },
+ // Delete the whole file
+ {
+ R"cpp([[#include <stdio.h>
+]])cpp",
+ "",
+ },
+ // Add something to an empty file
+ {
+ "[[]]",
+ R"cpp(int main() {
+)cpp",
+ },
+ {
+ R"cpp(int main() {
+)cpp",
+ ""
+ }
+ };
+ // clang-format on
+
+ stepByStep(Steps);
+ allAtOnce(Steps);
+}
+
+TEST(DraftStoreIncrementalUpdateTest, WrongRangeLength) {
+ DraftStore DS;
+ Path File = "foo.cpp";
+
+ DS.addDraft(File, "int main() {}\n");
+
+ TextDocumentContentChangeEvent Change;
+ Change.range.emplace();
+ Change.range->start.line = 0;
+ Change.range->start.character = 0;
+ Change.range->end.line = 0;
+ Change.range->end.character = 2;
+ Change.rangeLength = 10;
+
+ llvm::Expected<std::string> Result = DS.updateDraft(File, {Change});
+
+ EXPECT_TRUE(!Result);
+ EXPECT_EQ(
+ llvm::toString(Result.takeError()),
+ "Change's rangeLength (10) doesn't match the computed range length (2).");
+}
+
+TEST(DraftStoreIncrementalUpdateTest, EndBeforeStart) {
+ DraftStore DS;
+ Path File = "foo.cpp";
+
+ DS.addDraft(File, "int main() {}\n");
+
+ TextDocumentContentChangeEvent Change;
+ Change.range.emplace();
+ Change.range->start.line = 0;
+ Change.range->start.character = 5;
+ Change.range->end.line = 0;
+ Change.range->end.character = 3;
+
+ llvm::Expected<std::string> Result = DS.updateDraft(File, {Change});
+
+ EXPECT_TRUE(!Result);
+ EXPECT_EQ(llvm::toString(Result.takeError()),
+ "Range's end position (0:3) is before start position (0:5)");
+}
+
+TEST(DraftStoreIncrementalUpdateTest, StartCharOutOfRange) {
+ DraftStore DS;
+ Path File = "foo.cpp";
+
+ DS.addDraft(File, "int main() {}\n");
+
+ TextDocumentContentChangeEvent Change;
+ Change.range.emplace();
+ Change.range->start.line = 0;
+ Change.range->start.character = 100;
+ Change.range->end.line = 0;
+ Change.range->end.character = 100;
+ Change.text = "foo";
+
+ llvm::Expected<std::string> Result = DS.updateDraft(File, {Change});
+
+ EXPECT_TRUE(!Result);
+ EXPECT_EQ(llvm::toString(Result.takeError()),
+ "UTF-16 offset 100 is invalid for line 0");
+}
+
+TEST(DraftStoreIncrementalUpdateTest, EndCharOutOfRange) {
+ DraftStore DS;
+ Path File = "foo.cpp";
+
+ DS.addDraft(File, "int main() {}\n");
+
+ TextDocumentContentChangeEvent Change;
+ Change.range.emplace();
+ Change.range->start.line = 0;
+ Change.range->start.character = 0;
+ Change.range->end.line = 0;
+ Change.range->end.character = 100;
+ Change.text = "foo";
+
+ llvm::Expected<std::string> Result = DS.updateDraft(File, {Change});
+
+ EXPECT_TRUE(!Result);
+ EXPECT_EQ(llvm::toString(Result.takeError()),
+ "UTF-16 offset 100 is invalid for line 0");
+}
+
+TEST(DraftStoreIncrementalUpdateTest, StartLineOutOfRange) {
+ DraftStore DS;
+ Path File = "foo.cpp";
+
+ DS.addDraft(File, "int main() {}\n");
+
+ TextDocumentContentChangeEvent Change;
+ Change.range.emplace();
+ Change.range->start.line = 100;
+ Change.range->start.character = 0;
+ Change.range->end.line = 100;
+ Change.range->end.character = 0;
+ Change.text = "foo";
+
+ llvm::Expected<std::string> Result = DS.updateDraft(File, {Change});
+
+ EXPECT_TRUE(!Result);
+ EXPECT_EQ(llvm::toString(Result.takeError()),
+ "Line value is out of range (100)");
+}
+
+TEST(DraftStoreIncrementalUpdateTest, EndLineOutOfRange) {
+ DraftStore DS;
+ Path File = "foo.cpp";
+
+ DS.addDraft(File, "int main() {}\n");
+
+ TextDocumentContentChangeEvent Change;
+ Change.range.emplace();
+ Change.range->start.line = 0;
+ Change.range->start.character = 0;
+ Change.range->end.line = 100;
+ Change.range->end.character = 0;
+ Change.text = "foo";
+
+ llvm::Expected<std::string> Result = DS.updateDraft(File, {Change});
+
+ EXPECT_TRUE(!Result);
+ EXPECT_EQ(llvm::toString(Result.takeError()),
+ "Line value is out of range (100)");
+}
+
+/// Check that if a valid change is followed by an invalid change, the original
+/// version of the document (prior to all changes) is kept.
+TEST(DraftStoreIncrementalUpdateTest, InvalidRangeInASequence) {
+ DraftStore DS;
+ Path File = "foo.cpp";
+
+ StringRef OriginalContents = "int main() {}\n";
+ DS.addDraft(File, OriginalContents);
+
+ // The valid change
+ TextDocumentContentChangeEvent Change1;
+ Change1.range.emplace();
+ Change1.range->start.line = 0;
+ Change1.range->start.character = 0;
+ Change1.range->end.line = 0;
+ Change1.range->end.character = 0;
+ Change1.text = "Hello ";
+
+ // The invalid change
+ TextDocumentContentChangeEvent Change2;
+ Change2.range.emplace();
+ Change2.range->start.line = 0;
+ Change2.range->start.character = 5;
+ Change2.range->end.line = 0;
+ Change2.range->end.character = 100;
+ Change2.text = "something";
+
+ llvm::Expected<std::string> Result = DS.updateDraft(File, {Change1, Change2});
+
+ EXPECT_TRUE(!Result);
+ EXPECT_EQ(llvm::toString(Result.takeError()),
+ "UTF-16 offset 100 is invalid for line 0");
+
+ llvm::Optional<std::string> Contents = DS.getDraft(File);
+ EXPECT_TRUE(Contents);
+ EXPECT_EQ(*Contents, OriginalContents);
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/FileDistanceTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/FileDistanceTests.cpp
new file mode 100644
index 0000000..0d5afc9
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/FileDistanceTests.cpp
@@ -0,0 +1,99 @@
+//===-- FileDistanceTests.cpp ------------------------*- C++ -*-----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FileDistance.h"
+#include "TestFS.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+TEST(FileDistanceTests, Distance) {
+ FileDistanceOptions Opts;
+ Opts.UpCost = 5;
+ Opts.DownCost = 3;
+ SourceParams CostTwo;
+ CostTwo.Cost = 2;
+ FileDistance D(
+ {{"tools/clang/lib/Format/FormatToken.cpp", SourceParams()},
+ {"tools/clang/include/clang/Format/FormatToken.h", SourceParams()},
+ {"include/llvm/ADT/StringRef.h", CostTwo}},
+ Opts);
+
+ // Source
+ EXPECT_EQ(D.distance("tools/clang/lib/Format/FormatToken.cpp"), 0u);
+ EXPECT_EQ(D.distance("include/llvm/ADT/StringRef.h"), 2u);
+ // Parent
+ EXPECT_EQ(D.distance("tools/clang/lib/Format/"), 5u);
+ // Child
+ EXPECT_EQ(D.distance("tools/clang/lib/Format/FormatToken.cpp/Oops"), 3u);
+ // Ancestor (up+up+up+up)
+ EXPECT_EQ(D.distance("/"), 22u);
+ // Sibling (up+down)
+ EXPECT_EQ(D.distance("tools/clang/lib/Format/AnotherFile.cpp"), 8u);
+ // Cousin (up+up+down+down)
+ EXPECT_EQ(D.distance("include/llvm/Support/Allocator.h"), 18u);
+ // First cousin, once removed (up+up+up+down+down)
+ EXPECT_EQ(D.distance("include/llvm-c/Core.h"), 23u);
+}
+
+TEST(FileDistanceTests, BadSource) {
+ // We mustn't assume that paths above sources are best reached via them.
+ FileDistanceOptions Opts;
+ Opts.UpCost = 5;
+ Opts.DownCost = 3;
+ SourceParams CostLots;
+ CostLots.Cost = 100;
+ FileDistance D({{"a", SourceParams()}, {"b/b/b", CostLots}}, Opts);
+ EXPECT_EQ(D.distance("b"), 8u); // a+up+down, not b+up+up
+ EXPECT_EQ(D.distance("b/b/b"), 14u); // a+up+down+down+down, not b
+ EXPECT_EQ(D.distance("b/b/b/c"), 17u); // a+up+down+down+down+down, not b+down
+}
+
+auto UseUnittestScheme = UnittestSchemeAnchorSource;
+
+TEST(FileDistanceTests, URI) {
+ FileDistanceOptions Opts;
+ Opts.UpCost = 5;
+ Opts.DownCost = 3;
+ SourceParams CostLots;
+ CostLots.Cost = 1000;
+
+ URIDistance D({{testPath("foo"), CostLots},
+ {"/not/a/testpath", SourceParams()},
+ {"C:\\not\\a\\testpath", SourceParams()}},
+ Opts);
+#ifdef _WIN32
+ EXPECT_EQ(D.distance("file:///C%3a/not/a/testpath/either"), 3u);
+#else
+ EXPECT_EQ(D.distance("file:///not/a/testpath/either"), 3u);
+#endif
+ EXPECT_EQ(D.distance("unittest:///foo"), 1000u);
+ EXPECT_EQ(D.distance("unittest:///bar"), 1008u);
+}
+
+TEST(FileDistance, LimitUpTraversals) {
+ FileDistanceOptions Opts;
+ Opts.UpCost = Opts.DownCost = 1;
+ SourceParams CheapButLimited, CostLots;
+ CheapButLimited.MaxUpTraversals = 1;
+ CostLots.Cost = 100;
+
+ FileDistance D({{"/", CostLots}, {"/a/b/c", CheapButLimited}}, Opts);
+ EXPECT_EQ(D.distance("/a"), 101u);
+ EXPECT_EQ(D.distance("/a/z"), 102u);
+ EXPECT_EQ(D.distance("/a/b"), 1u);
+ EXPECT_EQ(D.distance("/a/b/z"), 2u);
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/FileIndexTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/FileIndexTests.cpp
new file mode 100644
index 0000000..08e8568
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/FileIndexTests.cpp
@@ -0,0 +1,275 @@
+//===-- FileIndexTests.cpp ---------------------------*- C++ -*-----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangdUnit.h"
+#include "TestFS.h"
+#include "TestTU.h"
+#include "index/FileIndex.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/PCHContainerOperations.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using testing::UnorderedElementsAre;
+
+namespace clang {
+namespace clangd {
+
+namespace {
+
+Symbol symbol(llvm::StringRef ID) {
+ Symbol Sym;
+ Sym.ID = SymbolID(ID);
+ Sym.Name = ID;
+ return Sym;
+}
+
+std::unique_ptr<SymbolSlab> numSlab(int Begin, int End) {
+ SymbolSlab::Builder Slab;
+ for (int i = Begin; i <= End; i++)
+ Slab.insert(symbol(std::to_string(i)));
+ return llvm::make_unique<SymbolSlab>(std::move(Slab).build());
+}
+
+std::vector<std::string>
+getSymbolNames(const std::vector<const Symbol *> &Symbols) {
+ std::vector<std::string> Names;
+ for (const Symbol *Sym : Symbols)
+ Names.push_back(Sym->Name);
+ return Names;
+}
+
+TEST(FileSymbolsTest, UpdateAndGet) {
+ FileSymbols FS;
+ EXPECT_THAT(getSymbolNames(*FS.allSymbols()), UnorderedElementsAre());
+
+ FS.update("f1", numSlab(1, 3));
+ EXPECT_THAT(getSymbolNames(*FS.allSymbols()),
+ UnorderedElementsAre("1", "2", "3"));
+}
+
+TEST(FileSymbolsTest, Overlap) {
+ FileSymbols FS;
+ FS.update("f1", numSlab(1, 3));
+ FS.update("f2", numSlab(3, 5));
+ EXPECT_THAT(getSymbolNames(*FS.allSymbols()),
+ UnorderedElementsAre("1", "2", "3", "3", "4", "5"));
+}
+
+TEST(FileSymbolsTest, SnapshotAliveAfterRemove) {
+ FileSymbols FS;
+
+ FS.update("f1", numSlab(1, 3));
+
+ auto Symbols = FS.allSymbols();
+ EXPECT_THAT(getSymbolNames(*Symbols), UnorderedElementsAre("1", "2", "3"));
+
+ FS.update("f1", nullptr);
+ EXPECT_THAT(getSymbolNames(*FS.allSymbols()), UnorderedElementsAre());
+ EXPECT_THAT(getSymbolNames(*Symbols), UnorderedElementsAre("1", "2", "3"));
+}
+
+std::vector<std::string> match(const SymbolIndex &I,
+ const FuzzyFindRequest &Req) {
+ std::vector<std::string> Matches;
+ I.fuzzyFind(Req, [&](const Symbol &Sym) {
+ Matches.push_back((Sym.Scope + Sym.Name).str());
+ });
+ return Matches;
+}
+
+// Adds Basename.cpp, which includes Basename.h, which contains Code.
+void update(FileIndex &M, llvm::StringRef Basename, llvm::StringRef Code) {
+ TestTU File;
+ File.Filename = (Basename + ".cpp").str();
+ File.HeaderFilename = (Basename + ".h").str();
+ File.HeaderCode = Code;
+ auto AST = File.build();
+ M.update(File.Filename, &AST.getASTContext(), AST.getPreprocessorPtr());
+}
+
+TEST(FileIndexTest, CustomizedURIScheme) {
+ FileIndex M({"unittest"});
+ update(M, "f", "class string {};");
+
+ FuzzyFindRequest Req;
+ Req.Query = "";
+ bool SeenSymbol = false;
+ M.fuzzyFind(Req, [&](const Symbol &Sym) {
+ EXPECT_EQ(Sym.CanonicalDeclaration.FileURI, "unittest:///f.h");
+ SeenSymbol = true;
+ });
+ EXPECT_TRUE(SeenSymbol);
+}
+
+TEST(FileIndexTest, IndexAST) {
+ FileIndex M;
+ update(M, "f1", "namespace ns { void f() {} class X {}; }");
+
+ FuzzyFindRequest Req;
+ Req.Query = "";
+ Req.Scopes = {"ns::"};
+ EXPECT_THAT(match(M, Req), UnorderedElementsAre("ns::f", "ns::X"));
+}
+
+TEST(FileIndexTest, NoLocal) {
+ FileIndex M;
+ update(M, "f1", "namespace ns { void f() { int local = 0; } class X {}; }");
+
+ FuzzyFindRequest Req;
+ Req.Query = "";
+ EXPECT_THAT(match(M, Req), UnorderedElementsAre("ns", "ns::f", "ns::X"));
+}
+
+TEST(FileIndexTest, IndexMultiASTAndDeduplicate) {
+ FileIndex M;
+ update(M, "f1", "namespace ns { void f() {} class X {}; }");
+ update(M, "f2", "namespace ns { void ff() {} class X {}; }");
+
+ FuzzyFindRequest Req;
+ Req.Query = "";
+ Req.Scopes = {"ns::"};
+ EXPECT_THAT(match(M, Req), UnorderedElementsAre("ns::f", "ns::X", "ns::ff"));
+}
+
+TEST(FileIndexTest, RemoveAST) {
+ FileIndex M;
+ update(M, "f1", "namespace ns { void f() {} class X {}; }");
+
+ FuzzyFindRequest Req;
+ Req.Query = "";
+ Req.Scopes = {"ns::"};
+ EXPECT_THAT(match(M, Req), UnorderedElementsAre("ns::f", "ns::X"));
+
+ M.update("f1.cpp", nullptr, nullptr);
+ EXPECT_THAT(match(M, Req), UnorderedElementsAre());
+}
+
+TEST(FileIndexTest, RemoveNonExisting) {
+ FileIndex M;
+ M.update("no.cpp", nullptr, nullptr);
+ EXPECT_THAT(match(M, FuzzyFindRequest()), UnorderedElementsAre());
+}
+
+TEST(FileIndexTest, ClassMembers) {
+ FileIndex M;
+ update(M, "f1", "class X { static int m1; int m2; static void f(); };");
+
+ FuzzyFindRequest Req;
+ Req.Query = "";
+ EXPECT_THAT(match(M, Req),
+ UnorderedElementsAre("X", "X::m1", "X::m2", "X::f"));
+}
+
+TEST(FileIndexTest, NoIncludeCollected) {
+ FileIndex M;
+ update(M, "f", "class string {};");
+
+ FuzzyFindRequest Req;
+ Req.Query = "";
+ bool SeenSymbol = false;
+ M.fuzzyFind(Req, [&](const Symbol &Sym) {
+ EXPECT_TRUE(Sym.Detail->IncludeHeader.empty());
+ SeenSymbol = true;
+ });
+ EXPECT_TRUE(SeenSymbol);
+}
+
+TEST(FileIndexTest, TemplateParamsInLabel) {
+ auto Source = R"cpp(
+template <class Ty>
+class vector {
+};
+
+template <class Ty, class Arg>
+vector<Ty> make_vector(Arg A) {}
+)cpp";
+
+ FileIndex M;
+ update(M, "f", Source);
+
+ FuzzyFindRequest Req;
+ Req.Query = "";
+ bool SeenVector = false;
+ bool SeenMakeVector = false;
+ M.fuzzyFind(Req, [&](const Symbol &Sym) {
+ if (Sym.Name == "vector") {
+ EXPECT_EQ(Sym.Signature, "<class Ty>");
+ EXPECT_EQ(Sym.CompletionSnippetSuffix, "<${1:class Ty}>");
+ SeenVector = true;
+ return;
+ }
+
+ if (Sym.Name == "make_vector") {
+ EXPECT_EQ(Sym.Signature, "<class Ty>(Arg A)");
+ EXPECT_EQ(Sym.CompletionSnippetSuffix, "<${1:class Ty}>(${2:Arg A})");
+ SeenMakeVector = true;
+ }
+ });
+ EXPECT_TRUE(SeenVector);
+ EXPECT_TRUE(SeenMakeVector);
+}
+
+TEST(FileIndexTest, RebuildWithPreamble) {
+ auto FooCpp = testPath("foo.cpp");
+ auto FooH = testPath("foo.h");
+ // Preparse ParseInputs.
+ ParseInputs PI;
+ PI.CompileCommand.Directory = testRoot();
+ PI.CompileCommand.Filename = FooCpp;
+ PI.CompileCommand.CommandLine = {"clang", "-xc++", FooCpp};
+
+ llvm::StringMap<std::string> Files;
+ Files[FooCpp] = "";
+ Files[FooH] = R"cpp(
+ namespace ns_in_header {
+ int func_in_header();
+ }
+ )cpp";
+ PI.FS = buildTestFS(std::move(Files));
+
+ PI.Contents = R"cpp(
+ #include "foo.h"
+ namespace ns_in_source {
+ int func_in_source();
+ }
+ )cpp";
+
+ // Rebuild the file.
+ auto CI = buildCompilerInvocation(PI);
+
+ FileIndex Index;
+ bool IndexUpdated = false;
+ buildPreamble(
+ FooCpp, *CI, /*OldPreamble=*/nullptr, tooling::CompileCommand(), PI,
+ std::make_shared<PCHContainerOperations>(), /*StoreInMemory=*/true,
+ [&Index, &IndexUpdated](PathRef FilePath, ASTContext &Ctx,
+ std::shared_ptr<Preprocessor> PP) {
+ EXPECT_FALSE(IndexUpdated) << "Expected only a single index update";
+ IndexUpdated = true;
+ Index.update(FilePath, &Ctx, std::move(PP));
+ });
+ ASSERT_TRUE(IndexUpdated);
+
+ // Check the index contains symbols from the preamble, but not from the main
+ // file.
+ FuzzyFindRequest Req;
+ Req.Query = "";
+ Req.Scopes = {"", "ns_in_header::"};
+
+ EXPECT_THAT(
+ match(Index, Req),
+ UnorderedElementsAre("ns_in_header", "ns_in_header::func_in_header"));
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/FindSymbolsTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/FindSymbolsTests.cpp
new file mode 100644
index 0000000..068660d
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/FindSymbolsTests.cpp
@@ -0,0 +1,562 @@
+//===-- FindSymbolsTests.cpp -------------------------*- C++ -*------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "Annotations.h"
+#include "ClangdServer.h"
+#include "FindSymbols.h"
+#include "SyncAPI.h"
+#include "TestFS.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+
+namespace {
+
+using ::testing::AllOf;
+using ::testing::AnyOf;
+using ::testing::ElementsAre;
+using ::testing::ElementsAreArray;
+using ::testing::IsEmpty;
+using ::testing::UnorderedElementsAre;
+
+class IgnoreDiagnostics : public DiagnosticsConsumer {
+ void onDiagnosticsReady(PathRef File,
+ std::vector<Diag> Diagnostics) override {}
+};
+
+// GMock helpers for matching SymbolInfos items.
+MATCHER_P(QName, Name, "") {
+ if (arg.containerName.empty())
+ return arg.name == Name;
+ return (arg.containerName + "::" + arg.name) == Name;
+}
+MATCHER_P(WithKind, Kind, "") { return arg.kind == Kind; }
+MATCHER_P(SymRange, Range, "") { return arg.location.range == Range; }
+
+ClangdServer::Options optsForTests() {
+ auto ServerOpts = ClangdServer::optsForTest();
+ ServerOpts.BuildDynamicSymbolIndex = true;
+ ServerOpts.URISchemes = {"unittest", "file"};
+ return ServerOpts;
+}
+
+class WorkspaceSymbolsTest : public ::testing::Test {
+public:
+ WorkspaceSymbolsTest()
+ : Server(CDB, FSProvider, DiagConsumer, optsForTests()) {
+ // Make sure the test root directory is created.
+ FSProvider.Files[testPath("unused")] = "";
+ Server.setRootPath(testRoot());
+ }
+
+protected:
+ MockFSProvider FSProvider;
+ MockCompilationDatabase CDB;
+ IgnoreDiagnostics DiagConsumer;
+ ClangdServer Server;
+ int Limit = 0;
+
+ std::vector<SymbolInformation> getSymbols(StringRef Query) {
+ EXPECT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for preamble";
+ auto SymbolInfos = runWorkspaceSymbols(Server, Query, Limit);
+ EXPECT_TRUE(bool(SymbolInfos)) << "workspaceSymbols returned an error";
+ return *SymbolInfos;
+ }
+
+ void addFile(StringRef FileName, StringRef Contents) {
+ auto Path = testPath(FileName);
+ FSProvider.Files[Path] = Contents;
+ Server.addDocument(Path, Contents);
+ }
+};
+
+} // namespace
+
+TEST_F(WorkspaceSymbolsTest, NoMacro) {
+ addFile("foo.cpp", R"cpp(
+ #define MACRO X
+ )cpp");
+
+ // Macros are not in the index.
+ EXPECT_THAT(getSymbols("macro"), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, NoLocals) {
+ addFile("foo.cpp", R"cpp(
+ void test(int FirstParam, int SecondParam) {
+ struct LocalClass {};
+ int local_var;
+ })cpp");
+ EXPECT_THAT(getSymbols("l"), IsEmpty());
+ EXPECT_THAT(getSymbols("p"), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, Globals) {
+ addFile("foo.h", R"cpp(
+ int global_var;
+
+ int global_func();
+
+ struct GlobalStruct {};)cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("global"),
+ UnorderedElementsAre(
+ AllOf(QName("GlobalStruct"), WithKind(SymbolKind::Struct)),
+ AllOf(QName("global_func"), WithKind(SymbolKind::Function)),
+ AllOf(QName("global_var"), WithKind(SymbolKind::Variable))));
+}
+
+TEST_F(WorkspaceSymbolsTest, Unnamed) {
+ addFile("foo.h", R"cpp(
+ struct {
+ int InUnnamed;
+ } UnnamedStruct;)cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("UnnamedStruct"),
+ ElementsAre(AllOf(QName("UnnamedStruct"),
+ WithKind(SymbolKind::Variable))));
+ EXPECT_THAT(getSymbols("InUnnamed"),
+ ElementsAre(AllOf(QName("(anonymous struct)::InUnnamed"),
+ WithKind(SymbolKind::Field))));
+}
+
+TEST_F(WorkspaceSymbolsTest, InMainFile) {
+ addFile("foo.cpp", R"cpp(
+ int test() {
+ }
+ )cpp");
+ EXPECT_THAT(getSymbols("test"), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, Namespaces) {
+ addFile("foo.h", R"cpp(
+ namespace ans1 {
+ int ai1;
+ namespace ans2 {
+ int ai2;
+ }
+ }
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("a"),
+ UnorderedElementsAre(QName("ans1"), QName("ans1::ai1"),
+ QName("ans1::ans2"),
+ QName("ans1::ans2::ai2")));
+ EXPECT_THAT(getSymbols("::"), ElementsAre(QName("ans1")));
+ EXPECT_THAT(getSymbols("::a"), ElementsAre(QName("ans1")));
+ EXPECT_THAT(getSymbols("ans1::"),
+ UnorderedElementsAre(QName("ans1::ai1"), QName("ans1::ans2")));
+ EXPECT_THAT(getSymbols("::ans1"), ElementsAre(QName("ans1")));
+ EXPECT_THAT(getSymbols("::ans1::"),
+ UnorderedElementsAre(QName("ans1::ai1"), QName("ans1::ans2")));
+ EXPECT_THAT(getSymbols("::ans1::ans2"), ElementsAre(QName("ans1::ans2")));
+ EXPECT_THAT(getSymbols("::ans1::ans2::"),
+ ElementsAre(QName("ans1::ans2::ai2")));
+}
+
+TEST_F(WorkspaceSymbolsTest, AnonymousNamespace) {
+ addFile("foo.h", R"cpp(
+ namespace {
+ void test() {}
+ }
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("test"), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, MultiFile) {
+ addFile("foo.h", R"cpp(
+ int foo() {
+ }
+ )cpp");
+ addFile("foo2.h", R"cpp(
+ int foo2() {
+ }
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ #include "foo2.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("foo"),
+ UnorderedElementsAre(QName("foo"), QName("foo2")));
+}
+
+TEST_F(WorkspaceSymbolsTest, GlobalNamespaceQueries) {
+ addFile("foo.h", R"cpp(
+ int foo() {
+ }
+ class Foo {
+ int a;
+ };
+ namespace ns {
+ int foo2() {
+ }
+ }
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("::"),
+ UnorderedElementsAre(
+ AllOf(QName("Foo"), WithKind(SymbolKind::Class)),
+ AllOf(QName("foo"), WithKind(SymbolKind::Function)),
+ AllOf(QName("ns"), WithKind(SymbolKind::Namespace))));
+ EXPECT_THAT(getSymbols(":"), IsEmpty());
+ EXPECT_THAT(getSymbols(""), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, Enums) {
+ addFile("foo.h", R"cpp(
+ enum {
+ Red
+ };
+ enum Color {
+ Green
+ };
+ enum class Color2 {
+ Yellow
+ };
+ namespace ns {
+ enum {
+ Black
+ };
+ enum Color3 {
+ Blue
+ };
+ enum class Color4 {
+ White
+ };
+ }
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("Red"), ElementsAre(QName("Red")));
+ EXPECT_THAT(getSymbols("::Red"), ElementsAre(QName("Red")));
+ EXPECT_THAT(getSymbols("Green"), ElementsAre(QName("Green")));
+ EXPECT_THAT(getSymbols("Green"), ElementsAre(QName("Green")));
+ EXPECT_THAT(getSymbols("Color2::Yellow"),
+ ElementsAre(QName("Color2::Yellow")));
+ EXPECT_THAT(getSymbols("Yellow"), ElementsAre(QName("Color2::Yellow")));
+
+ EXPECT_THAT(getSymbols("ns::Black"), ElementsAre(QName("ns::Black")));
+ EXPECT_THAT(getSymbols("ns::Blue"), ElementsAre(QName("ns::Blue")));
+ EXPECT_THAT(getSymbols("ns::Color4::White"),
+ ElementsAre(QName("ns::Color4::White")));
+}
+
+TEST_F(WorkspaceSymbolsTest, Ranking) {
+ addFile("foo.h", R"cpp(
+ namespace ns{}
+ function func();
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("::"), ElementsAre(QName("func"), QName("ns")));
+}
+
+TEST_F(WorkspaceSymbolsTest, WithLimit) {
+ addFile("foo.h", R"cpp(
+ int foo;
+ int foo2;
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ // Foo is higher ranked because of exact name match.
+ EXPECT_THAT(getSymbols("foo"),
+ UnorderedElementsAre(
+ AllOf(QName("foo"), WithKind(SymbolKind::Variable)),
+ AllOf(QName("foo2"), WithKind(SymbolKind::Variable))));
+
+ Limit = 1;
+ EXPECT_THAT(getSymbols("foo"), ElementsAre(QName("foo")));
+}
+
+namespace {
+class DocumentSymbolsTest : public ::testing::Test {
+public:
+ DocumentSymbolsTest()
+ : Server(CDB, FSProvider, DiagConsumer, optsForTests()) {}
+
+protected:
+ MockFSProvider FSProvider;
+ MockCompilationDatabase CDB;
+ IgnoreDiagnostics DiagConsumer;
+ ClangdServer Server;
+
+ std::vector<SymbolInformation> getSymbols(PathRef File) {
+ EXPECT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for preamble";
+ auto SymbolInfos = runDocumentSymbols(Server, File);
+ EXPECT_TRUE(bool(SymbolInfos)) << "documentSymbols returned an error";
+ return *SymbolInfos;
+ }
+
+ void addFile(StringRef FilePath, StringRef Contents) {
+ FSProvider.Files[FilePath] = Contents;
+ Server.addDocument(FilePath, Contents);
+ }
+};
+} // namespace
+
+TEST_F(DocumentSymbolsTest, BasicSymbols) {
+ std::string FilePath = testPath("foo.cpp");
+ Annotations Main(R"(
+ class Foo;
+ class Foo {
+ Foo() {}
+ Foo(int a) {}
+ void $decl[[f]]();
+ friend void f1();
+ friend class Friend;
+ Foo& operator=(const Foo&);
+ ~Foo();
+ class Nested {
+ void f();
+ };
+ };
+ class Friend {
+ };
+
+ void f1();
+ inline void f2() {}
+ static const int KInt = 2;
+ const char* kStr = "123";
+
+ void f1() {}
+
+ namespace foo {
+ // Type alias
+ typedef int int32;
+ using int32_t = int32;
+
+ // Variable
+ int v1;
+
+ // Namespace
+ namespace bar {
+ int v2;
+ }
+ // Namespace alias
+ namespace baz = bar;
+
+ // FIXME: using declaration is not supported as the IndexAction will ignore
+ // implicit declarations (the implicit using shadow declaration) by default,
+ // and there is no way to customize this behavior at the moment.
+ using bar::v2;
+ } // namespace foo
+ )");
+
+ addFile(FilePath, Main.code());
+ EXPECT_THAT(getSymbols(FilePath),
+ ElementsAreArray(
+ {AllOf(QName("Foo"), WithKind(SymbolKind::Class)),
+ AllOf(QName("Foo"), WithKind(SymbolKind::Class)),
+ AllOf(QName("Foo::Foo"), WithKind(SymbolKind::Method)),
+ AllOf(QName("Foo::Foo"), WithKind(SymbolKind::Method)),
+ AllOf(QName("Foo::f"), WithKind(SymbolKind::Method)),
+ AllOf(QName("f1"), WithKind(SymbolKind::Function)),
+ AllOf(QName("Foo::operator="), WithKind(SymbolKind::Method)),
+ AllOf(QName("Foo::~Foo"), WithKind(SymbolKind::Method)),
+ AllOf(QName("Foo::Nested"), WithKind(SymbolKind::Class)),
+ AllOf(QName("Foo::Nested::f"), WithKind(SymbolKind::Method)),
+ AllOf(QName("Friend"), WithKind(SymbolKind::Class)),
+ AllOf(QName("f1"), WithKind(SymbolKind::Function)),
+ AllOf(QName("f2"), WithKind(SymbolKind::Function)),
+ AllOf(QName("KInt"), WithKind(SymbolKind::Variable)),
+ AllOf(QName("kStr"), WithKind(SymbolKind::Variable)),
+ AllOf(QName("f1"), WithKind(SymbolKind::Function)),
+ AllOf(QName("foo"), WithKind(SymbolKind::Namespace)),
+ AllOf(QName("foo::int32"), WithKind(SymbolKind::Class)),
+ AllOf(QName("foo::int32_t"), WithKind(SymbolKind::Class)),
+ AllOf(QName("foo::v1"), WithKind(SymbolKind::Variable)),
+ AllOf(QName("foo::bar"), WithKind(SymbolKind::Namespace)),
+ AllOf(QName("foo::bar::v2"), WithKind(SymbolKind::Variable)),
+ AllOf(QName("foo::baz"), WithKind(SymbolKind::Namespace))}));
+}
+
+TEST_F(DocumentSymbolsTest, DeclarationDefinition) {
+ std::string FilePath = testPath("foo.cpp");
+ Annotations Main(R"(
+ class Foo {
+ void $decl[[f]]();
+ };
+ void Foo::$def[[f]]() {
+ }
+ )");
+
+ addFile(FilePath, Main.code());
+ EXPECT_THAT(getSymbols(FilePath),
+ ElementsAre(AllOf(QName("Foo"), WithKind(SymbolKind::Class)),
+ AllOf(QName("Foo::f"), WithKind(SymbolKind::Method),
+ SymRange(Main.range("decl"))),
+ AllOf(QName("Foo::f"), WithKind(SymbolKind::Method),
+ SymRange(Main.range("def")))));
+}
+
+TEST_F(DocumentSymbolsTest, ExternSymbol) {
+ std::string FilePath = testPath("foo.cpp");
+ addFile(testPath("foo.h"), R"cpp(
+ extern int var = 2;
+ )cpp");
+ addFile(FilePath, R"cpp(
+ #include "foo.h"
+ )cpp");
+
+ EXPECT_THAT(getSymbols(FilePath), IsEmpty());
+}
+
+TEST_F(DocumentSymbolsTest, NoLocals) {
+ std::string FilePath = testPath("foo.cpp");
+ addFile(FilePath,
+ R"cpp(
+ void test(int FirstParam, int SecondParam) {
+ struct LocalClass {};
+ int local_var;
+ })cpp");
+ EXPECT_THAT(getSymbols(FilePath), ElementsAre(QName("test")));
+}
+
+TEST_F(DocumentSymbolsTest, Unnamed) {
+ std::string FilePath = testPath("foo.h");
+ addFile(FilePath,
+ R"cpp(
+ struct {
+ int InUnnamed;
+ } UnnamedStruct;
+ )cpp");
+ EXPECT_THAT(
+ getSymbols(FilePath),
+ ElementsAre(AllOf(QName("UnnamedStruct"), WithKind(SymbolKind::Variable)),
+ AllOf(QName("(anonymous struct)::InUnnamed"),
+ WithKind(SymbolKind::Field))));
+}
+
+TEST_F(DocumentSymbolsTest, InHeaderFile) {
+ addFile("bar.h", R"cpp(
+ int foo() {
+ }
+ )cpp");
+ std::string FilePath = testPath("foo.h");
+ addFile(FilePath, R"cpp(
+ #include "bar.h"
+ int test() {
+ }
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols(FilePath), ElementsAre(QName("test")));
+}
+
+TEST_F(DocumentSymbolsTest, Template) {
+ std::string FilePath = testPath("foo.cpp");
+ addFile(FilePath, R"(
+ // Primary templates and specializations are included but instantiations
+ // are not.
+ template <class T> struct Tmpl {T x = 0;};
+ template <> struct Tmpl<int> {};
+ extern template struct Tmpl<float>;
+ template struct Tmpl<double>;
+ )");
+ EXPECT_THAT(getSymbols(FilePath),
+ ElementsAre(AllOf(QName("Tmpl"), WithKind(SymbolKind::Struct)),
+ AllOf(QName("Tmpl::x"), WithKind(SymbolKind::Field)),
+ AllOf(QName("Tmpl"), WithKind(SymbolKind::Struct))));
+}
+
+TEST_F(DocumentSymbolsTest, Namespaces) {
+ std::string FilePath = testPath("foo.cpp");
+ addFile(FilePath, R"cpp(
+ namespace ans1 {
+ int ai1;
+ namespace ans2 {
+ int ai2;
+ }
+ }
+ namespace {
+ void test() {}
+ }
+
+ namespace na {
+ inline namespace nb {
+ class Foo {};
+ }
+ }
+ namespace na {
+ // This is still inlined.
+ namespace nb {
+ class Bar {};
+ }
+ }
+ )cpp");
+ EXPECT_THAT(
+ getSymbols(FilePath),
+ ElementsAreArray({QName("ans1"), QName("ans1::ai1"), QName("ans1::ans2"),
+ QName("ans1::ans2::ai2"), QName("test"), QName("na"),
+ QName("na::nb"), QName("na::Foo"), QName("na"),
+ QName("na::nb"), QName("na::Bar")}));
+}
+
+TEST_F(DocumentSymbolsTest, Enums) {
+ std::string FilePath = testPath("foo.cpp");
+ addFile(FilePath, R"(
+ enum {
+ Red
+ };
+ enum Color {
+ Green
+ };
+ enum class Color2 {
+ Yellow
+ };
+ namespace ns {
+ enum {
+ Black
+ };
+ }
+ )");
+ EXPECT_THAT(getSymbols(FilePath),
+ ElementsAre(QName("Red"), QName("Color"), QName("Green"),
+ QName("Color2"), QName("Color2::Yellow"), QName("ns"),
+ QName("ns::Black")));
+}
+
+TEST_F(DocumentSymbolsTest, FromMacro) {
+ std::string FilePath = testPath("foo.cpp");
+ Annotations Main(R"(
+ #define FF(name) \
+ class name##_Test {};
+
+ $expansion[[FF]](abc);
+
+ #define FF2() \
+ class $spelling[[Test]] {};
+
+ FF2();
+ )");
+ addFile(FilePath, Main.code());
+ EXPECT_THAT(
+ getSymbols(FilePath),
+ ElementsAre(AllOf(QName("abc_Test"), SymRange(Main.range("expansion"))),
+ AllOf(QName("Test"), SymRange(Main.range("spelling")))));
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/FuzzyMatchTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/FuzzyMatchTests.cpp
new file mode 100644
index 0000000..c03f8f3
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/FuzzyMatchTests.cpp
@@ -0,0 +1,301 @@
+//===-- FuzzyMatchTests.cpp - String fuzzy matcher tests --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FuzzyMatch.h"
+
+#include "llvm/ADT/StringExtras.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+using namespace llvm;
+using testing::Not;
+
+struct ExpectedMatch {
+ // Annotations are optional, and will not be asserted if absent.
+ ExpectedMatch(StringRef Match) : Word(Match), Annotated(Match) {
+ for (char C : "[]")
+ Word.erase(std::remove(Word.begin(), Word.end(), C), Word.end());
+ if (Word.size() == Annotated->size())
+ Annotated = None;
+ }
+ bool accepts(StringRef ActualAnnotated) const {
+ return !Annotated || ActualAnnotated == *Annotated;
+ }
+
+ friend raw_ostream &operator<<(raw_ostream &OS, const ExpectedMatch &M) {
+ OS << "'" << M.Word;
+ if (M.Annotated)
+ OS << "' as " << *M.Annotated;
+ return OS;
+ }
+
+ std::string Word;
+
+private:
+ Optional<StringRef> Annotated;
+};
+
+struct MatchesMatcher : public testing::MatcherInterface<StringRef> {
+ ExpectedMatch Candidate;
+ Optional<float> Score;
+ MatchesMatcher(ExpectedMatch Candidate, Optional<float> Score)
+ : Candidate(std::move(Candidate)), Score(Score) {}
+
+ void DescribeTo(::std::ostream *OS) const override {
+ raw_os_ostream(*OS) << "Matches " << Candidate;
+ if (Score)
+ *OS << " with score " << *Score;
+ }
+
+ bool MatchAndExplain(StringRef Pattern,
+ testing::MatchResultListener *L) const override {
+ std::unique_ptr<raw_ostream> OS(
+ L->stream() ? (raw_ostream *)(new raw_os_ostream(*L->stream()))
+ : new raw_null_ostream());
+ FuzzyMatcher Matcher(Pattern);
+ auto Result = Matcher.match(Candidate.Word);
+ auto AnnotatedMatch = Matcher.dumpLast(*OS << "\n");
+ return Result && Candidate.accepts(AnnotatedMatch) &&
+ (!Score || testing::Value(*Result, testing::FloatEq(*Score)));
+ }
+};
+
+// Accepts patterns that match a given word, optionally requiring a score.
+// Dumps the debug tables on match failure.
+testing::Matcher<StringRef> matches(StringRef M, Optional<float> Score = {}) {
+ return testing::MakeMatcher<StringRef>(new MatchesMatcher(M, Score));
+}
+
+TEST(FuzzyMatch, Matches) {
+ EXPECT_THAT("", matches("unique_ptr"));
+ EXPECT_THAT("u_p", matches("[u]nique[_p]tr"));
+ EXPECT_THAT("up", matches("[u]nique_[p]tr"));
+ EXPECT_THAT("uq", Not(matches("unique_ptr")));
+ EXPECT_THAT("qp", Not(matches("unique_ptr")));
+ EXPECT_THAT("log", Not(matches("SVGFEMorphologyElement")));
+
+ EXPECT_THAT("tit", matches("win.[tit]"));
+ EXPECT_THAT("title", matches("win.[title]"));
+ EXPECT_THAT("WordCla", matches("[Word]Character[Cla]ssifier"));
+ EXPECT_THAT("WordCCla", matches("[WordC]haracter[Cla]ssifier"));
+
+ EXPECT_THAT("dete", Not(matches("editor.quickSuggestionsDelay")));
+
+ EXPECT_THAT("highlight", matches("editorHover[Highlight]"));
+ EXPECT_THAT("hhighlight", matches("editor[H]over[Highlight]"));
+ EXPECT_THAT("dhhighlight", Not(matches("editorHoverHighlight")));
+
+ EXPECT_THAT("-moz", matches("[-moz]-foo"));
+ EXPECT_THAT("moz", matches("-[moz]-foo"));
+ EXPECT_THAT("moza", matches("-[moz]-[a]nimation"));
+
+ EXPECT_THAT("ab", matches("[ab]A"));
+ EXPECT_THAT("ccm", Not(matches("cacmelCase")));
+ EXPECT_THAT("bti", Not(matches("the_black_knight")));
+ EXPECT_THAT("ccm", Not(matches("camelCase")));
+ EXPECT_THAT("cmcm", Not(matches("camelCase")));
+ EXPECT_THAT("BK", matches("the_[b]lack_[k]night"));
+ EXPECT_THAT("KeyboardLayout=", Not(matches("KeyboardLayout")));
+ EXPECT_THAT("LLL", matches("SVisual[L]ogger[L]ogs[L]ist"));
+ EXPECT_THAT("LLLL", Not(matches("SVilLoLosLi")));
+ EXPECT_THAT("LLLL", Not(matches("SVisualLoggerLogsList")));
+ EXPECT_THAT("TEdit", matches("[T]ext[Edit]"));
+ EXPECT_THAT("TEdit", matches("[T]ext[Edit]or"));
+ EXPECT_THAT("TEdit", Not(matches("[T]ext[edit]")));
+ EXPECT_THAT("TEdit", matches("[t]ext_[edit]"));
+ EXPECT_THAT("TEditDt", matches("[T]ext[Edit]or[D]ecoration[T]ype"));
+ EXPECT_THAT("TEdit", matches("[T]ext[Edit]orDecorationType"));
+ EXPECT_THAT("Tedit", matches("[T]ext[Edit]"));
+ EXPECT_THAT("ba", Not(matches("?AB?")));
+ EXPECT_THAT("bkn", matches("the_[b]lack_[kn]ight"));
+ EXPECT_THAT("bt", Not(matches("the_[b]lack_knigh[t]")));
+ EXPECT_THAT("ccm", Not(matches("[c]amelCase[cm]")));
+ EXPECT_THAT("fdm", Not(matches("[f]in[dM]odel")));
+ EXPECT_THAT("fob", Not(matches("[fo]o[b]ar")));
+ EXPECT_THAT("fobz", Not(matches("foobar")));
+ EXPECT_THAT("foobar", matches("[foobar]"));
+ EXPECT_THAT("form", matches("editor.[form]atOnSave"));
+ EXPECT_THAT("g p", matches("[G]it:[ P]ull"));
+ EXPECT_THAT("g p", matches("[G]it:[ P]ull"));
+ EXPECT_THAT("gip", matches("[Gi]t: [P]ull"));
+ EXPECT_THAT("gip", matches("[Gi]t: [P]ull"));
+ EXPECT_THAT("gp", matches("[G]it: [P]ull"));
+ EXPECT_THAT("gp", matches("[G]it_Git_[P]ull"));
+ EXPECT_THAT("is", matches("[I]mport[S]tatement"));
+ EXPECT_THAT("is", matches("[is]Valid"));
+ EXPECT_THAT("lowrd", Not(matches("[low]Wo[rd]")));
+ EXPECT_THAT("myvable", Not(matches("[myva]ria[ble]")));
+ EXPECT_THAT("no", Not(matches("")));
+ EXPECT_THAT("no", Not(matches("match")));
+ EXPECT_THAT("ob", Not(matches("foobar")));
+ EXPECT_THAT("sl", matches("[S]Visual[L]oggerLogsList"));
+ EXPECT_THAT("sllll", matches("[S]Visua[L]ogger[Ll]ama[L]ist"));
+ EXPECT_THAT("THRE", matches("H[T]ML[HRE]lement"));
+ EXPECT_THAT("b", Not(matches("NDEBUG")));
+ EXPECT_THAT("Three", matches("[Three]"));
+ EXPECT_THAT("fo", Not(matches("barfoo")));
+ EXPECT_THAT("fo", matches("bar_[fo]o"));
+ EXPECT_THAT("fo", matches("bar_[Fo]o"));
+ EXPECT_THAT("fo", matches("bar [fo]o"));
+ EXPECT_THAT("fo", matches("bar.[fo]o"));
+ EXPECT_THAT("fo", matches("bar/[fo]o"));
+ EXPECT_THAT("fo", matches("bar\\[fo]o"));
+
+ EXPECT_THAT(
+ "aaaaaa",
+ matches("[aaaaaa]aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ EXPECT_THAT("baba", Not(matches("ababababab")));
+ EXPECT_THAT("fsfsfs", Not(matches("dsafdsafdsafdsafdsafdsafdsafasdfdsa")));
+ EXPECT_THAT("fsfsfsfsfsfsfsf",
+ Not(matches("dsafdsafdsafdsafdsafdsafdsafasdfdsafdsafdsafdsafdsfd"
+ "safdsfdfdfasdnfdsajfndsjnafjndsajlknfdsa")));
+
+ EXPECT_THAT(" g", matches("[ g]roup"));
+ EXPECT_THAT("g", matches(" [g]roup"));
+ EXPECT_THAT("g g", Not(matches(" groupGroup")));
+ EXPECT_THAT("g g", matches(" [g]roup[ G]roup"));
+ EXPECT_THAT(" g g", matches("[ ] [g]roup[ G]roup"));
+ EXPECT_THAT("zz", matches("[zz]Group"));
+ EXPECT_THAT("zzg", matches("[zzG]roup"));
+ EXPECT_THAT("g", matches("zz[G]roup"));
+
+ EXPECT_THAT("aaaa", matches("_a_[aaaa]")); // Prefer consecutive.
+ // These would ideally match, but would need special segmentation rules.
+ EXPECT_THAT("printf", Not(matches("s[printf]")));
+ EXPECT_THAT("str", Not(matches("o[str]eam")));
+ EXPECT_THAT("strcpy", Not(matches("strncpy")));
+ EXPECT_THAT("std", Not(matches("PTHREAD_MUTEX_STALLED")));
+ EXPECT_THAT("std", Not(matches("pthread_condattr_setpshared")));
+}
+
+struct RankMatcher : public testing::MatcherInterface<StringRef> {
+ std::vector<ExpectedMatch> RankedStrings;
+ RankMatcher(std::initializer_list<ExpectedMatch> RankedStrings)
+ : RankedStrings(RankedStrings) {}
+
+ void DescribeTo(::std::ostream *OS) const override {
+ raw_os_ostream O(*OS);
+ O << "Ranks strings in order: [";
+ for (const auto &Str : RankedStrings)
+ O << "\n\t" << Str;
+ O << "\n]";
+ }
+
+ bool MatchAndExplain(StringRef Pattern,
+ testing::MatchResultListener *L) const override {
+ std::unique_ptr<raw_ostream> OS(
+ L->stream() ? (raw_ostream *)(new raw_os_ostream(*L->stream()))
+ : new raw_null_ostream());
+ FuzzyMatcher Matcher(Pattern);
+ const ExpectedMatch *LastMatch;
+ Optional<float> LastScore;
+ bool Ok = true;
+ for (const auto &Str : RankedStrings) {
+ auto Score = Matcher.match(Str.Word);
+ if (!Score) {
+ *OS << "\nDoesn't match '" << Str.Word << "'";
+ Matcher.dumpLast(*OS << "\n");
+ Ok = false;
+ } else {
+ std::string Buf;
+ llvm::raw_string_ostream Info(Buf);
+ auto AnnotatedMatch = Matcher.dumpLast(Info);
+
+ if (!Str.accepts(AnnotatedMatch)) {
+ *OS << "\nDoesn't match " << Str << ", but " << AnnotatedMatch << "\n"
+ << Info.str();
+ Ok = false;
+ } else if (LastScore && *LastScore < *Score) {
+ *OS << "\nRanks '" << Str.Word << "'=" << *Score << " above '"
+ << LastMatch->Word << "'=" << *LastScore << "\n"
+ << Info.str();
+ Matcher.match(LastMatch->Word);
+ Matcher.dumpLast(*OS << "\n");
+ Ok = false;
+ }
+ }
+ LastMatch = &Str;
+ LastScore = Score;
+ }
+ return Ok;
+ }
+};
+
+// Accepts patterns that match all the strings and rank them in the given order.
+// Dumps the debug tables on match failure.
+template <typename... T> testing::Matcher<StringRef> ranks(T... RankedStrings) {
+ return testing::MakeMatcher<StringRef>(
+ new RankMatcher{ExpectedMatch(RankedStrings)...});
+}
+
+TEST(FuzzyMatch, Ranking) {
+ EXPECT_THAT("cons",
+ ranks("[cons]ole", "[Cons]ole", "ArrayBuffer[Cons]tructor"));
+ EXPECT_THAT("foo", ranks("[foo]", "[Foo]"));
+ EXPECT_THAT("onMes",
+ ranks("[onMes]sage", "[onmes]sage", "[on]This[M]ega[Es]capes"));
+ EXPECT_THAT("CC", ranks("[C]amel[C]ase", "[c]amel[C]ase"));
+ EXPECT_THAT("cC", ranks("[c]amel[C]ase", "[C]amel[C]ase"));
+ EXPECT_THAT("p", ranks("[p]", "[p]arse", "[p]osix", "[p]afdsa", "[p]ath"));
+ EXPECT_THAT("pa", ranks("[pa]rse", "[pa]th", "[pa]fdsa"));
+ EXPECT_THAT("log", ranks("[log]", "Scroll[Log]icalPosition"));
+ EXPECT_THAT("e", ranks("[e]lse", "Abstract[E]lement"));
+ EXPECT_THAT("workbench.sideb",
+ ranks("[workbench.sideB]ar.location",
+ "[workbench.]editor.default[SideB]ySideLayout"));
+ EXPECT_THAT("editor.r", ranks("[editor.r]enderControlCharacter",
+ "[editor.]overview[R]ulerlanes",
+ "diff[Editor.r]enderSideBySide"));
+ EXPECT_THAT("-mo", ranks("[-mo]z-columns", "[-]ms-ime-[mo]de"));
+ EXPECT_THAT("convertModelPosition",
+ ranks("[convertModelPosition]ToViewPosition",
+ "[convert]ViewTo[ModelPosition]"));
+ EXPECT_THAT("is", ranks("[is]ValidViewletId", "[i]mport [s]tatement"));
+ EXPECT_THAT("strcpy", ranks("[strcpy]", "[strcpy]_s"));
+}
+
+// Verify some bounds so we know scores fall in the right range.
+// Testing exact scores is fragile, so we prefer Ranking tests.
+TEST(FuzzyMatch, Scoring) {
+ EXPECT_THAT("abs", matches("[a]w[B]xYz[S]", 0.f));
+ EXPECT_THAT("abs", matches("[abs]l", 1.f));
+ EXPECT_THAT("abs", matches("[abs]", 2.f));
+ EXPECT_THAT("Abs", matches("[abs]", 2.f));
+}
+
+// Returns pretty-printed segmentation of Text.
+// e.g. std::basic_string --> +-- +---- +-----
+std::string segment(StringRef Text) {
+ std::vector<CharRole> Roles(Text.size());
+ calculateRoles(Text, Roles);
+ std::string Printed;
+ for (unsigned I = 0; I < Text.size(); ++I)
+ Printed.push_back("?-+ "[static_cast<unsigned>(Roles[I])]);
+ return Printed;
+}
+
+// this is a no-op hack so clang-format will vertically align our testcases.
+StringRef returns(StringRef Text) { return Text; }
+
+TEST(FuzzyMatch, Segmentation) {
+ EXPECT_THAT(segment("std::basic_string"), //
+ returns("+-- +---- +-----"));
+ EXPECT_THAT(segment("XMLHttpRequest"), //
+ returns("+--+---+------"));
+ EXPECT_THAT(segment("t3h PeNgU1N oF d00m!!!!!!!!"), //
+ returns("+-- +-+-+-+ ++ +--- "));
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/GlobalCompilationDatabaseTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/GlobalCompilationDatabaseTests.cpp
new file mode 100644
index 0000000..18190c2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/GlobalCompilationDatabaseTests.cpp
@@ -0,0 +1,37 @@
+//===-- GlobalCompilationDatabaseTests.cpp ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GlobalCompilationDatabase.h"
+
+#include "TestFS.h"
+#include "llvm/ADT/StringExtras.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+using ::testing::ElementsAre;
+
+TEST(GlobalCompilationDatabaseTest, FallbackCommand) {
+ DirectoryBasedGlobalCompilationDatabase DB(llvm::None);
+ auto Cmd = DB.getFallbackCommand(testPath("foo/bar.cc"));
+ EXPECT_EQ(Cmd.Directory, testPath("foo"));
+ EXPECT_THAT(Cmd.CommandLine, ElementsAre("clang", testPath("foo/bar.cc")));
+ EXPECT_EQ(Cmd.Output, "");
+
+ // .h files have unknown language, so they are parsed liberally as obj-c++.
+ Cmd = DB.getFallbackCommand(testPath("foo/bar.h"));
+ EXPECT_THAT(Cmd.CommandLine, ElementsAre("clang", "-xobjective-c++-header",
+ testPath("foo/bar.h")));
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/HeadersTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/HeadersTests.cpp
new file mode 100644
index 0000000..21046c0
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/HeadersTests.cpp
@@ -0,0 +1,245 @@
+//===-- HeadersTests.cpp - Include headers unit tests -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Headers.h"
+
+#include "Compiler.h"
+#include "TestFS.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+using ::testing::AllOf;
+using ::testing::UnorderedElementsAre;
+
+class HeadersTest : public ::testing::Test {
+public:
+ HeadersTest() {
+ CDB.ExtraClangFlags = {SearchDirArg.c_str()};
+ FS.Files[MainFile] = "";
+ // Make sure directory sub/ exists.
+ FS.Files[testPath("sub/EMPTY")] = "";
+ }
+
+private:
+ std::unique_ptr<CompilerInstance> setupClang() {
+ auto Cmd = CDB.getCompileCommand(MainFile);
+ assert(static_cast<bool>(Cmd));
+ auto VFS = FS.getFileSystem();
+ VFS->setCurrentWorkingDirectory(Cmd->Directory);
+
+ std::vector<const char *> Argv;
+ for (const auto &S : Cmd->CommandLine)
+ Argv.push_back(S.c_str());
+ auto CI = clang::createInvocationFromCommandLine(
+ Argv,
+ CompilerInstance::createDiagnostics(new DiagnosticOptions(),
+ &IgnoreDiags, false),
+ VFS);
+ EXPECT_TRUE(static_cast<bool>(CI));
+ CI->getFrontendOpts().DisableFree = false;
+
+ // The diagnostic options must be set before creating a CompilerInstance.
+ CI->getDiagnosticOpts().IgnoreWarnings = true;
+ auto Clang = prepareCompilerInstance(
+ std::move(CI), /*Preamble=*/nullptr,
+ llvm::MemoryBuffer::getMemBuffer(FS.Files[MainFile], MainFile),
+ std::make_shared<PCHContainerOperations>(), VFS, IgnoreDiags);
+
+ EXPECT_FALSE(Clang->getFrontendOpts().Inputs.empty());
+ return Clang;
+ }
+
+protected:
+ IncludeStructure collectIncludes() {
+ auto Clang = setupClang();
+ PreprocessOnlyAction Action;
+ EXPECT_TRUE(
+ Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]));
+ IncludeStructure Includes;
+ Clang->getPreprocessor().addPPCallbacks(
+ collectIncludeStructureCallback(Clang->getSourceManager(), &Includes));
+ EXPECT_TRUE(Action.Execute());
+ Action.EndSourceFile();
+ return Includes;
+ }
+
+ // Calculates the include path, or returns "" on error or header should not be
+ // inserted.
+ std::string calculate(PathRef Original, PathRef Preferred = "",
+ const std::vector<Inclusion> &Inclusions = {}) {
+ auto Clang = setupClang();
+ PreprocessOnlyAction Action;
+ EXPECT_TRUE(
+ Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]));
+
+ if (Preferred.empty())
+ Preferred = Original;
+ auto ToHeaderFile = [](llvm::StringRef Header) {
+ return HeaderFile{Header,
+ /*Verbatim=*/!llvm::sys::path::is_absolute(Header)};
+ };
+
+ IncludeInserter Inserter(MainFile, /*Code=*/"", format::getLLVMStyle(),
+ CDB.getCompileCommand(MainFile)->Directory,
+ Clang->getPreprocessor().getHeaderSearchInfo());
+ for (const auto &Inc : Inclusions)
+ Inserter.addExisting(Inc);
+ auto Declaring = ToHeaderFile(Original);
+ auto Inserted = ToHeaderFile(Preferred);
+ if (!Inserter.shouldInsertInclude(Declaring, Inserted))
+ return "";
+ std::string Path = Inserter.calculateIncludePath(Declaring, Inserted);
+ Action.EndSourceFile();
+ return Path;
+ }
+
+ Optional<TextEdit> insert(StringRef VerbatimHeader) {
+ auto Clang = setupClang();
+ PreprocessOnlyAction Action;
+ EXPECT_TRUE(
+ Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]));
+
+ IncludeInserter Inserter(MainFile, /*Code=*/"", format::getLLVMStyle(),
+ CDB.getCompileCommand(MainFile)->Directory,
+ Clang->getPreprocessor().getHeaderSearchInfo());
+ auto Edit = Inserter.insert(VerbatimHeader);
+ Action.EndSourceFile();
+ return Edit;
+ }
+
+ MockFSProvider FS;
+ MockCompilationDatabase CDB;
+ std::string MainFile = testPath("main.cpp");
+ std::string Subdir = testPath("sub");
+ std::string SearchDirArg = (llvm::Twine("-I") + Subdir).str();
+ IgnoringDiagConsumer IgnoreDiags;
+};
+
+MATCHER_P(Written, Name, "") { return arg.Written == Name; }
+MATCHER_P(Resolved, Name, "") { return arg.Resolved == Name; }
+
+MATCHER_P2(Distance, File, D, "") {
+ if (arg.getKey() != File)
+ *result_listener << "file =" << arg.getKey().str();
+ if (arg.getValue() != D)
+ *result_listener << "distance =" << arg.getValue();
+ return arg.getKey() == File && arg.getValue() == D;
+}
+
+TEST_F(HeadersTest, CollectRewrittenAndResolved) {
+ FS.Files[MainFile] = R"cpp(
+#include "sub/bar.h" // not shortest
+)cpp";
+ std::string BarHeader = testPath("sub/bar.h");
+ FS.Files[BarHeader] = "";
+
+ EXPECT_THAT(collectIncludes().MainFileIncludes,
+ UnorderedElementsAre(
+ AllOf(Written("\"sub/bar.h\""), Resolved(BarHeader))));
+ EXPECT_THAT(collectIncludes().includeDepth(MainFile),
+ UnorderedElementsAre(Distance(MainFile, 0u),
+ Distance(testPath("sub/bar.h"), 1u)));
+}
+
+TEST_F(HeadersTest, OnlyCollectInclusionsInMain) {
+ std::string BazHeader = testPath("sub/baz.h");
+ FS.Files[BazHeader] = "";
+ std::string BarHeader = testPath("sub/bar.h");
+ FS.Files[BarHeader] = R"cpp(
+#include "baz.h"
+)cpp";
+ FS.Files[MainFile] = R"cpp(
+#include "bar.h"
+)cpp";
+ EXPECT_THAT(
+ collectIncludes().MainFileIncludes,
+ UnorderedElementsAre(AllOf(Written("\"bar.h\""), Resolved(BarHeader))));
+ EXPECT_THAT(collectIncludes().includeDepth(MainFile),
+ UnorderedElementsAre(Distance(MainFile, 0u),
+ Distance(testPath("sub/bar.h"), 1u),
+ Distance(testPath("sub/baz.h"), 2u)));
+ // includeDepth() also works for non-main files.
+ EXPECT_THAT(collectIncludes().includeDepth(testPath("sub/bar.h")),
+ UnorderedElementsAre(Distance(testPath("sub/bar.h"), 0u),
+ Distance(testPath("sub/baz.h"), 1u)));
+}
+
+TEST_F(HeadersTest, UnResolvedInclusion) {
+ FS.Files[MainFile] = R"cpp(
+#include "foo.h"
+)cpp";
+
+ EXPECT_THAT(collectIncludes().MainFileIncludes,
+ UnorderedElementsAre(AllOf(Written("\"foo.h\""), Resolved(""))));
+ EXPECT_THAT(collectIncludes().includeDepth(MainFile),
+ UnorderedElementsAre(Distance(MainFile, 0u)));
+}
+
+TEST_F(HeadersTest, InsertInclude) {
+ std::string Path = testPath("sub/bar.h");
+ FS.Files[Path] = "";
+ EXPECT_EQ(calculate(Path), "\"bar.h\"");
+}
+
+TEST_F(HeadersTest, DoNotInsertIfInSameFile) {
+ MainFile = testPath("main.h");
+ EXPECT_EQ(calculate(MainFile), "");
+}
+
+TEST_F(HeadersTest, ShortenedInclude) {
+ std::string BarHeader = testPath("sub/bar.h");
+ EXPECT_EQ(calculate(BarHeader), "\"bar.h\"");
+}
+
+TEST_F(HeadersTest, NotShortenedInclude) {
+ std::string BarHeader = testPath("sub-2/bar.h");
+ EXPECT_EQ(calculate(BarHeader, ""), "\"" + BarHeader + "\"");
+}
+
+TEST_F(HeadersTest, PreferredHeader) {
+ std::string BarHeader = testPath("sub/bar.h");
+ EXPECT_EQ(calculate(BarHeader, "<bar>"), "<bar>");
+
+ std::string BazHeader = testPath("sub/baz.h");
+ EXPECT_EQ(calculate(BarHeader, BazHeader), "\"baz.h\"");
+}
+
+TEST_F(HeadersTest, DontInsertDuplicatePreferred) {
+ std::vector<Inclusion> Inclusions = {
+ {Range(), /*Written*/ "\"bar.h\"", /*Resolved*/ ""}};
+ EXPECT_EQ(calculate(testPath("sub/bar.h"), "\"bar.h\"", Inclusions), "");
+ EXPECT_EQ(calculate("\"x.h\"", "\"bar.h\"", Inclusions), "");
+}
+
+TEST_F(HeadersTest, DontInsertDuplicateResolved) {
+ std::string BarHeader = testPath("sub/bar.h");
+ std::vector<Inclusion> Inclusions = {
+ {Range(), /*Written*/ "fake-bar.h", /*Resolved*/ BarHeader}};
+ EXPECT_EQ(calculate(BarHeader, "", Inclusions), "");
+ // Do not insert preferred.
+ EXPECT_EQ(calculate(BarHeader, "\"BAR.h\"", Inclusions), "");
+}
+
+TEST_F(HeadersTest, PreferInserted) {
+ auto Edit = insert("<y>");
+ EXPECT_TRUE(Edit.hasValue());
+ EXPECT_TRUE(llvm::StringRef(Edit->newText).contains("<y>"));
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/IndexTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/IndexTests.cpp
new file mode 100644
index 0000000..3ddf2d2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/IndexTests.cpp
@@ -0,0 +1,326 @@
+//===-- IndexTests.cpp -------------------------------*- C++ -*-----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "index/Index.h"
+#include "index/MemIndex.h"
+#include "index/Merge.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using testing::UnorderedElementsAre;
+using testing::Pointee;
+
+namespace clang {
+namespace clangd {
+namespace {
+
+Symbol symbol(llvm::StringRef QName) {
+ Symbol Sym;
+ Sym.ID = SymbolID(QName.str());
+ size_t Pos = QName.rfind("::");
+ if (Pos == llvm::StringRef::npos) {
+ Sym.Name = QName;
+ Sym.Scope = "";
+ } else {
+ Sym.Name = QName.substr(Pos + 2);
+ Sym.Scope = QName.substr(0, Pos + 2);
+ }
+ return Sym;
+}
+
+MATCHER_P(Named, N, "") { return arg.Name == N; }
+
+TEST(SymbolSlab, FindAndIterate) {
+ SymbolSlab::Builder B;
+ B.insert(symbol("Z"));
+ B.insert(symbol("Y"));
+ B.insert(symbol("X"));
+ EXPECT_EQ(nullptr, B.find(SymbolID("W")));
+ for (const char *Sym : {"X", "Y", "Z"})
+ EXPECT_THAT(B.find(SymbolID(Sym)), Pointee(Named(Sym)));
+
+ SymbolSlab S = std::move(B).build();
+ EXPECT_THAT(S, UnorderedElementsAre(Named("X"), Named("Y"), Named("Z")));
+ EXPECT_EQ(S.end(), S.find(SymbolID("W")));
+ for (const char *Sym : {"X", "Y", "Z"})
+ EXPECT_THAT(*S.find(SymbolID(Sym)), Named(Sym));
+}
+
+struct SlabAndPointers {
+ SymbolSlab Slab;
+ std::vector<const Symbol *> Pointers;
+};
+
+// Create a slab of symbols with the given qualified names as both IDs and
+// names. The life time of the slab is managed by the returned shared pointer.
+// If \p WeakSymbols is provided, it will be pointed to the managed object in
+// the returned shared pointer.
+std::shared_ptr<std::vector<const Symbol *>>
+generateSymbols(std::vector<std::string> QualifiedNames,
+ std::weak_ptr<SlabAndPointers> *WeakSymbols = nullptr) {
+ SymbolSlab::Builder Slab;
+ for (llvm::StringRef QName : QualifiedNames)
+ Slab.insert(symbol(QName));
+
+ auto Storage = std::make_shared<SlabAndPointers>();
+ Storage->Slab = std::move(Slab).build();
+ for (const auto &Sym : Storage->Slab)
+ Storage->Pointers.push_back(&Sym);
+ if (WeakSymbols)
+ *WeakSymbols = Storage;
+ auto *Pointers = &Storage->Pointers;
+ return {std::move(Storage), Pointers};
+}
+
+// Create a slab of symbols with IDs and names [Begin, End], otherwise identical
+// to the `generateSymbols` above.
+std::shared_ptr<std::vector<const Symbol *>>
+generateNumSymbols(int Begin, int End,
+ std::weak_ptr<SlabAndPointers> *WeakSymbols = nullptr) {
+ std::vector<std::string> Names;
+ for (int i = Begin; i <= End; i++)
+ Names.push_back(std::to_string(i));
+ return generateSymbols(Names, WeakSymbols);
+}
+
+std::string getQualifiedName(const Symbol &Sym) {
+ return (Sym.Scope + Sym.Name).str();
+}
+
+std::vector<std::string> match(const SymbolIndex &I,
+ const FuzzyFindRequest &Req,
+ bool *Incomplete = nullptr) {
+ std::vector<std::string> Matches;
+ bool IsIncomplete = I.fuzzyFind(Req, [&](const Symbol &Sym) {
+ Matches.push_back(getQualifiedName(Sym));
+ });
+ if (Incomplete)
+ *Incomplete = IsIncomplete;
+ return Matches;
+}
+
+TEST(MemIndexTest, MemIndexSymbolsRecycled) {
+ MemIndex I;
+ std::weak_ptr<SlabAndPointers> Symbols;
+ I.build(generateNumSymbols(0, 10, &Symbols));
+ FuzzyFindRequest Req;
+ Req.Query = "7";
+ EXPECT_THAT(match(I, Req), UnorderedElementsAre("7"));
+
+ EXPECT_FALSE(Symbols.expired());
+ // Release old symbols.
+ I.build(generateNumSymbols(0, 0));
+ EXPECT_TRUE(Symbols.expired());
+}
+
+TEST(MemIndexTest, MemIndexDeduplicate) {
+ auto Symbols = generateNumSymbols(0, 10);
+
+ // Inject some duplicates and make sure we only match the same symbol once.
+ auto Sym = symbol("7");
+ Symbols->push_back(&Sym);
+ Symbols->push_back(&Sym);
+ Symbols->push_back(&Sym);
+
+ FuzzyFindRequest Req;
+ Req.Query = "7";
+ MemIndex I;
+ I.build(std::move(Symbols));
+ auto Matches = match(I, Req);
+ EXPECT_EQ(Matches.size(), 1u);
+}
+
+TEST(MemIndexTest, MemIndexLimitedNumMatches) {
+ MemIndex I;
+ I.build(generateNumSymbols(0, 100));
+ FuzzyFindRequest Req;
+ Req.Query = "5";
+ Req.MaxCandidateCount = 3;
+ bool Incomplete;
+ auto Matches = match(I, Req, &Incomplete);
+ EXPECT_EQ(Matches.size(), Req.MaxCandidateCount);
+ EXPECT_TRUE(Incomplete);
+}
+
+TEST(MemIndexTest, FuzzyMatch) {
+ MemIndex I;
+ I.build(
+ generateSymbols({"LaughingOutLoud", "LionPopulation", "LittleOldLady"}));
+ FuzzyFindRequest Req;
+ Req.Query = "lol";
+ Req.MaxCandidateCount = 2;
+ EXPECT_THAT(match(I, Req),
+ UnorderedElementsAre("LaughingOutLoud", "LittleOldLady"));
+}
+
+TEST(MemIndexTest, MatchQualifiedNamesWithoutSpecificScope) {
+ MemIndex I;
+ I.build(generateSymbols({"a::y1", "b::y2", "y3"}));
+ FuzzyFindRequest Req;
+ Req.Query = "y";
+ EXPECT_THAT(match(I, Req), UnorderedElementsAre("a::y1", "b::y2", "y3"));
+}
+
+TEST(MemIndexTest, MatchQualifiedNamesWithGlobalScope) {
+ MemIndex I;
+ I.build(generateSymbols({"a::y1", "b::y2", "y3"}));
+ FuzzyFindRequest Req;
+ Req.Query = "y";
+ Req.Scopes = {""};
+ EXPECT_THAT(match(I, Req), UnorderedElementsAre("y3"));
+}
+
+TEST(MemIndexTest, MatchQualifiedNamesWithOneScope) {
+ MemIndex I;
+ I.build(generateSymbols({"a::y1", "a::y2", "a::x", "b::y2", "y3"}));
+ FuzzyFindRequest Req;
+ Req.Query = "y";
+ Req.Scopes = {"a::"};
+ EXPECT_THAT(match(I, Req), UnorderedElementsAre("a::y1", "a::y2"));
+}
+
+TEST(MemIndexTest, MatchQualifiedNamesWithMultipleScopes) {
+ MemIndex I;
+ I.build(generateSymbols({"a::y1", "a::y2", "a::x", "b::y3", "y3"}));
+ FuzzyFindRequest Req;
+ Req.Query = "y";
+ Req.Scopes = {"a::", "b::"};
+ EXPECT_THAT(match(I, Req), UnorderedElementsAre("a::y1", "a::y2", "b::y3"));
+}
+
+TEST(MemIndexTest, NoMatchNestedScopes) {
+ MemIndex I;
+ I.build(generateSymbols({"a::y1", "a::b::y2"}));
+ FuzzyFindRequest Req;
+ Req.Query = "y";
+ Req.Scopes = {"a::"};
+ EXPECT_THAT(match(I, Req), UnorderedElementsAre("a::y1"));
+}
+
+TEST(MemIndexTest, IgnoreCases) {
+ MemIndex I;
+ I.build(generateSymbols({"ns::ABC", "ns::abc"}));
+ FuzzyFindRequest Req;
+ Req.Query = "AB";
+ Req.Scopes = {"ns::"};
+ EXPECT_THAT(match(I, Req), UnorderedElementsAre("ns::ABC", "ns::abc"));
+}
+
+// Returns qualified names of symbols with any of IDs in the index.
+std::vector<std::string> lookup(const SymbolIndex &I,
+ llvm::ArrayRef<SymbolID> IDs) {
+ LookupRequest Req;
+ Req.IDs.insert(IDs.begin(), IDs.end());
+ std::vector<std::string> Results;
+ I.lookup(Req, [&](const Symbol &Sym) {
+ Results.push_back(getQualifiedName(Sym));
+ });
+ return Results;
+}
+
+TEST(MemIndexTest, Lookup) {
+ MemIndex I;
+ I.build(generateSymbols({"ns::abc", "ns::xyz"}));
+ EXPECT_THAT(lookup(I, SymbolID("ns::abc")), UnorderedElementsAre("ns::abc"));
+ EXPECT_THAT(lookup(I, {SymbolID("ns::abc"), SymbolID("ns::xyz")}),
+ UnorderedElementsAre("ns::abc", "ns::xyz"));
+ EXPECT_THAT(lookup(I, {SymbolID("ns::nonono"), SymbolID("ns::xyz")}),
+ UnorderedElementsAre("ns::xyz"));
+ EXPECT_THAT(lookup(I, SymbolID("ns::nonono")), UnorderedElementsAre());
+}
+
+TEST(MergeIndexTest, Lookup) {
+ MemIndex I, J;
+ I.build(generateSymbols({"ns::A", "ns::B"}));
+ J.build(generateSymbols({"ns::B", "ns::C"}));
+ EXPECT_THAT(lookup(*mergeIndex(&I, &J), SymbolID("ns::A")),
+ UnorderedElementsAre("ns::A"));
+ EXPECT_THAT(lookup(*mergeIndex(&I, &J), SymbolID("ns::B")),
+ UnorderedElementsAre("ns::B"));
+ EXPECT_THAT(lookup(*mergeIndex(&I, &J), SymbolID("ns::C")),
+ UnorderedElementsAre("ns::C"));
+ EXPECT_THAT(
+ lookup(*mergeIndex(&I, &J), {SymbolID("ns::A"), SymbolID("ns::B")}),
+ UnorderedElementsAre("ns::A", "ns::B"));
+ EXPECT_THAT(
+ lookup(*mergeIndex(&I, &J), {SymbolID("ns::A"), SymbolID("ns::C")}),
+ UnorderedElementsAre("ns::A", "ns::C"));
+ EXPECT_THAT(lookup(*mergeIndex(&I, &J), SymbolID("ns::D")),
+ UnorderedElementsAre());
+ EXPECT_THAT(lookup(*mergeIndex(&I, &J), {}), UnorderedElementsAre());
+}
+
+TEST(MergeIndexTest, FuzzyFind) {
+ MemIndex I, J;
+ I.build(generateSymbols({"ns::A", "ns::B"}));
+ J.build(generateSymbols({"ns::B", "ns::C"}));
+ FuzzyFindRequest Req;
+ Req.Scopes = {"ns::"};
+ EXPECT_THAT(match(*mergeIndex(&I, &J), Req),
+ UnorderedElementsAre("ns::A", "ns::B", "ns::C"));
+}
+
+TEST(MergeTest, Merge) {
+ Symbol L, R;
+ L.ID = R.ID = SymbolID("hello");
+ L.Name = R.Name = "Foo"; // same in both
+ L.CanonicalDeclaration.FileURI = "file:///left.h"; // differs
+ R.CanonicalDeclaration.FileURI = "file:///right.h";
+ L.References = 1;
+ R.References = 2;
+ L.Signature = "()"; // present in left only
+ R.CompletionSnippetSuffix = "{$1:0}"; // present in right only
+ Symbol::Details DetL, DetR;
+ DetL.ReturnType = "DetL";
+ DetR.ReturnType = "DetR";
+ DetR.Documentation = "--doc--";
+ L.Detail = &DetL;
+ R.Detail = &DetR;
+ L.Origin = SymbolOrigin::Dynamic;
+ R.Origin = SymbolOrigin::Static;
+
+ Symbol::Details Scratch;
+ Symbol M = mergeSymbol(L, R, &Scratch);
+ EXPECT_EQ(M.Name, "Foo");
+ EXPECT_EQ(M.CanonicalDeclaration.FileURI, "file:///left.h");
+ EXPECT_EQ(M.References, 3u);
+ EXPECT_EQ(M.Signature, "()");
+ EXPECT_EQ(M.CompletionSnippetSuffix, "{$1:0}");
+ ASSERT_TRUE(M.Detail);
+ EXPECT_EQ(M.Detail->ReturnType, "DetL");
+ EXPECT_EQ(M.Detail->Documentation, "--doc--");
+ EXPECT_EQ(M.Origin,
+ SymbolOrigin::Dynamic | SymbolOrigin::Static | SymbolOrigin::Merge);
+}
+
+TEST(MergeTest, PreferSymbolWithDefn) {
+ Symbol L, R;
+ Symbol::Details Scratch;
+
+ L.ID = R.ID = SymbolID("hello");
+ L.CanonicalDeclaration.FileURI = "file:/left.h";
+ R.CanonicalDeclaration.FileURI = "file:/right.h";
+ L.Name = "left";
+ R.Name = "right";
+
+ Symbol M = mergeSymbol(L, R, &Scratch);
+ EXPECT_EQ(M.CanonicalDeclaration.FileURI, "file:/left.h");
+ EXPECT_EQ(M.Definition.FileURI, "");
+ EXPECT_EQ(M.Name, "left");
+
+ R.Definition.FileURI = "file:/right.cpp"; // Now right will be favored.
+ M = mergeSymbol(L, R, &Scratch);
+ EXPECT_EQ(M.CanonicalDeclaration.FileURI, "file:/right.h");
+ EXPECT_EQ(M.Definition.FileURI, "file:/right.cpp");
+ EXPECT_EQ(M.Name, "right");
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/Matchers.h b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/Matchers.h
new file mode 100644
index 0000000..ed44464
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/Matchers.h
@@ -0,0 +1,135 @@
+//===-- Matchers.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// GMock matchers that aren't specific to particular tests.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_MATCHERS_H
+#define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_MATCHERS_H
+#include "Protocol.h"
+#include "gmock/gmock.h"
+
+namespace clang {
+namespace clangd {
+using ::testing::Matcher;
+
+// EXPECT_IFF expects matcher if condition is true, and Not(matcher) if false.
+// This is hard to write as a function, because matchers may be polymorphic.
+#define EXPECT_IFF(condition, value, matcher) \
+ do { \
+ if (condition) \
+ EXPECT_THAT(value, matcher); \
+ else \
+ EXPECT_THAT(value, ::testing::Not(matcher)); \
+ } while (0)
+
+// HasSubsequence(m1, m2, ...) matches a vector containing elements that match
+// m1, m2 ... in that order.
+//
+// SubsequenceMatcher implements this once the type of vector is known.
+template <typename T>
+class SubsequenceMatcher
+ : public ::testing::MatcherInterface<const std::vector<T> &> {
+ std::vector<Matcher<T>> Matchers;
+
+public:
+ SubsequenceMatcher(std::vector<Matcher<T>> M) : Matchers(M) {}
+
+ void DescribeTo(std::ostream *OS) const override {
+ *OS << "Contains the subsequence [";
+ const char *Sep = "";
+ for (const auto &M : Matchers) {
+ *OS << Sep;
+ M.DescribeTo(OS);
+ Sep = ", ";
+ }
+ *OS << "]";
+ }
+
+ bool MatchAndExplain(const std::vector<T> &V,
+ ::testing::MatchResultListener *L) const override {
+ std::vector<int> Matches(Matchers.size());
+ size_t I = 0;
+ for (size_t J = 0; I < Matchers.size() && J < V.size(); ++J)
+ if (Matchers[I].Matches(V[J]))
+ Matches[I++] = J;
+ if (I == Matchers.size()) // We exhausted all matchers.
+ return true;
+ if (L->IsInterested()) {
+ *L << "\n Matched:";
+ for (size_t K = 0; K < I; ++K) {
+ *L << "\n\t";
+ Matchers[K].DescribeTo(L->stream());
+ *L << " ==> " << ::testing::PrintToString(V[Matches[K]]);
+ }
+ *L << "\n\t";
+ Matchers[I].DescribeTo(L->stream());
+ *L << " ==> no subsequent match";
+ }
+ return false;
+ }
+};
+
+// PolySubsequenceMatcher implements a "polymorphic" SubsequenceMatcher.
+// It captures the types of the element matchers, and can be converted to
+// Matcher<vector<T>> if each matcher can be converted to Matcher<T>.
+// This allows HasSubsequence() to accept polymorphic matchers like Not().
+template <typename... M> class PolySubsequenceMatcher {
+ std::tuple<M...> Matchers;
+
+public:
+ PolySubsequenceMatcher(M &&... Args)
+ : Matchers(std::make_tuple(std::forward<M>(Args)...)) {}
+
+ template <typename T> operator Matcher<const std::vector<T> &>() const {
+ return ::testing::MakeMatcher(new SubsequenceMatcher<T>(
+ TypedMatchers<T>(llvm::index_sequence_for<M...>{})));
+ }
+
+private:
+ template <typename T, size_t... I>
+ std::vector<Matcher<T>> TypedMatchers(llvm::index_sequence<I...>) const {
+ return {std::get<I>(Matchers)...};
+ }
+};
+
+// HasSubsequence(m1, m2, ...) matches a vector containing elements that match
+// m1, m2 ... in that order.
+// The real implementation is in SubsequenceMatcher.
+template <typename... Args>
+PolySubsequenceMatcher<Args...> HasSubsequence(Args &&... M) {
+ return PolySubsequenceMatcher<Args...>(std::forward<Args>(M)...);
+}
+
+// EXPECT_ERROR seems like a pretty generic name, make sure it's not defined
+// already.
+#ifdef EXPECT_ERROR
+#error "Refusing to redefine EXPECT_ERROR"
+#endif
+
+// Consumes llvm::Expected<T>, checks it contains an error and marks it as
+// handled.
+#define EXPECT_ERROR(expectedValue) \
+ do { \
+ auto &&ComputedValue = (expectedValue); \
+ if (ComputedValue) { \
+ ADD_FAILURE() << "expected an error from " << #expectedValue \
+ << " but got " \
+ << ::testing::PrintToString(*ComputedValue); \
+ break; \
+ } \
+ handleAllErrors(ComputedValue.takeError(), \
+ [](const llvm::ErrorInfoBase &) {}); \
+ \
+ } while (false)
+
+} // namespace clangd
+} // namespace clang
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/QualityTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/QualityTests.cpp
new file mode 100644
index 0000000..153eef4
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/QualityTests.cpp
@@ -0,0 +1,351 @@
+//===-- SourceCodeTests.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Evaluating scoring functions isn't a great fit for assert-based tests.
+// For interesting cases, both exact scores and "X beats Y" are too brittle to
+// make good hard assertions.
+//
+// Here we test the signal extraction and sanity-check that signals point in
+// the right direction. This should be supplemented by quality metrics which
+// we can compute from a corpus of queries and preferred rankings.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FileDistance.h"
+#include "Quality.h"
+#include "TestFS.h"
+#include "TestTU.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "llvm/Support/Casting.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+
+// Force the unittest URI scheme to be linked,
+static int LLVM_ATTRIBUTE_UNUSED UnittestSchemeAnchorDest =
+ UnittestSchemeAnchorSource;
+
+namespace {
+
+TEST(QualityTests, SymbolQualitySignalExtraction) {
+ auto Header = TestTU::withHeaderCode(R"cpp(
+ int _X;
+
+ [[deprecated]]
+ int _f() { return _X; }
+ )cpp");
+ auto Symbols = Header.headerSymbols();
+ auto AST = Header.build();
+
+ SymbolQualitySignals Quality;
+ Quality.merge(findSymbol(Symbols, "_X"));
+ EXPECT_FALSE(Quality.Deprecated);
+ EXPECT_TRUE(Quality.ReservedName);
+ EXPECT_EQ(Quality.References, SymbolQualitySignals().References);
+ EXPECT_EQ(Quality.Category, SymbolQualitySignals::Variable);
+
+ Symbol F = findSymbol(Symbols, "_f");
+ F.References = 24; // TestTU doesn't count references, so fake it.
+ Quality = {};
+ Quality.merge(F);
+ EXPECT_FALSE(Quality.Deprecated); // FIXME: Include deprecated bit in index.
+ EXPECT_FALSE(Quality.ReservedName);
+ EXPECT_EQ(Quality.References, 24u);
+ EXPECT_EQ(Quality.Category, SymbolQualitySignals::Function);
+
+ Quality = {};
+ Quality.merge(CodeCompletionResult(&findDecl(AST, "_f"), /*Priority=*/42));
+ EXPECT_TRUE(Quality.Deprecated);
+ EXPECT_FALSE(Quality.ReservedName);
+ EXPECT_EQ(Quality.References, SymbolQualitySignals().References);
+ EXPECT_EQ(Quality.Category, SymbolQualitySignals::Function);
+
+ Quality = {};
+ Quality.merge(CodeCompletionResult("if"));
+ EXPECT_EQ(Quality.Category, SymbolQualitySignals::Keyword);
+}
+
+TEST(QualityTests, SymbolRelevanceSignalExtraction) {
+ TestTU Test;
+ Test.HeaderCode = R"cpp(
+ int header();
+ int header_main();
+
+ namespace hdr { class Bar {}; } // namespace hdr
+
+ #define DEFINE_FLAG(X) \
+ namespace flags { \
+ int FLAGS_##X; \
+ } \
+
+ DEFINE_FLAG(FOO)
+ )cpp";
+ Test.Code = R"cpp(
+ using hdr::Bar;
+
+ using flags::FLAGS_FOO;
+
+ int ::header_main() {}
+ int main();
+
+ [[deprecated]]
+ int deprecated() { return 0; }
+
+ namespace { struct X { void y() { int z; } }; }
+ struct S{}
+ )cpp";
+ auto AST = Test.build();
+
+ SymbolRelevanceSignals Relevance;
+ Relevance.merge(CodeCompletionResult(&findDecl(AST, "deprecated"),
+ /*Priority=*/42, nullptr, false,
+ /*Accessible=*/false));
+ EXPECT_EQ(Relevance.NameMatch, SymbolRelevanceSignals().NameMatch);
+ EXPECT_TRUE(Relevance.Forbidden);
+ EXPECT_EQ(Relevance.Scope, SymbolRelevanceSignals::GlobalScope);
+
+ Relevance = {};
+ Relevance.merge(CodeCompletionResult(&findDecl(AST, "main"), 42));
+ EXPECT_FLOAT_EQ(Relevance.SemaProximityScore, 1.0f) << "Decl in current file";
+ Relevance = {};
+ Relevance.merge(CodeCompletionResult(&findDecl(AST, "header"), 42));
+ EXPECT_FLOAT_EQ(Relevance.SemaProximityScore, 0.6f) << "Decl from header";
+ Relevance = {};
+ Relevance.merge(CodeCompletionResult(&findDecl(AST, "header_main"), 42));
+ EXPECT_FLOAT_EQ(Relevance.SemaProximityScore, 1.0f)
+ << "Current file and header";
+
+ auto constructShadowDeclCompletionResult = [&](const std::string DeclName) {
+ auto *Shadow =
+ *dyn_cast<UsingDecl>(
+ &findAnyDecl(AST,
+ [&](const NamedDecl &ND) {
+ if (const UsingDecl *Using =
+ dyn_cast<UsingDecl>(&ND))
+ if (Using->shadow_size() &&
+ Using->getQualifiedNameAsString() == DeclName)
+ return true;
+ return false;
+ }))
+ ->shadow_begin();
+ CodeCompletionResult Result(Shadow->getTargetDecl(), 42);
+ Result.ShadowDecl = Shadow;
+ return Result;
+ };
+
+ Relevance = {};
+ Relevance.merge(constructShadowDeclCompletionResult("Bar"));
+ EXPECT_FLOAT_EQ(Relevance.SemaProximityScore, 1.0f)
+ << "Using declaration in main file";
+ Relevance.merge(constructShadowDeclCompletionResult("FLAGS_FOO"));
+ EXPECT_FLOAT_EQ(Relevance.SemaProximityScore, 1.0f)
+ << "Using declaration in main file";
+
+ Relevance = {};
+ Relevance.merge(CodeCompletionResult(&findAnyDecl(AST, "X"), 42));
+ EXPECT_EQ(Relevance.Scope, SymbolRelevanceSignals::FileScope);
+ Relevance = {};
+ Relevance.merge(CodeCompletionResult(&findAnyDecl(AST, "y"), 42));
+ EXPECT_EQ(Relevance.Scope, SymbolRelevanceSignals::ClassScope);
+ Relevance = {};
+ Relevance.merge(CodeCompletionResult(&findAnyDecl(AST, "z"), 42));
+ EXPECT_EQ(Relevance.Scope, SymbolRelevanceSignals::FunctionScope);
+ // The injected class name is treated as the outer class name.
+ Relevance = {};
+ Relevance.merge(CodeCompletionResult(&findDecl(AST, "S::S"), 42));
+ EXPECT_EQ(Relevance.Scope, SymbolRelevanceSignals::GlobalScope);
+}
+
+// Do the signals move the scores in the direction we expect?
+TEST(QualityTests, SymbolQualitySignalsSanity) {
+ SymbolQualitySignals Default;
+ EXPECT_EQ(Default.evaluate(), 1);
+
+ SymbolQualitySignals Deprecated;
+ Deprecated.Deprecated = true;
+ EXPECT_LT(Deprecated.evaluate(), Default.evaluate());
+
+ SymbolQualitySignals ReservedName;
+ ReservedName.ReservedName = true;
+ EXPECT_LT(ReservedName.evaluate(), Default.evaluate());
+
+ SymbolQualitySignals WithReferences, ManyReferences;
+ WithReferences.References = 20;
+ ManyReferences.References = 1000;
+ EXPECT_GT(WithReferences.evaluate(), Default.evaluate());
+ EXPECT_GT(ManyReferences.evaluate(), WithReferences.evaluate());
+
+ SymbolQualitySignals Keyword, Variable, Macro, Constructor, Function;
+ Keyword.Category = SymbolQualitySignals::Keyword;
+ Variable.Category = SymbolQualitySignals::Variable;
+ Macro.Category = SymbolQualitySignals::Macro;
+ Constructor.Category = SymbolQualitySignals::Constructor;
+ Function.Category = SymbolQualitySignals::Function;
+ EXPECT_GT(Variable.evaluate(), Default.evaluate());
+ EXPECT_GT(Keyword.evaluate(), Variable.evaluate());
+ EXPECT_LT(Macro.evaluate(), Default.evaluate());
+ EXPECT_LT(Constructor.evaluate(), Function.evaluate());
+}
+
+TEST(QualityTests, SymbolRelevanceSignalsSanity) {
+ SymbolRelevanceSignals Default;
+ EXPECT_EQ(Default.evaluate(), 1);
+
+ SymbolRelevanceSignals Forbidden;
+ Forbidden.Forbidden = true;
+ EXPECT_LT(Forbidden.evaluate(), Default.evaluate());
+
+ SymbolRelevanceSignals PoorNameMatch;
+ PoorNameMatch.NameMatch = 0.2f;
+ EXPECT_LT(PoorNameMatch.evaluate(), Default.evaluate());
+
+ SymbolRelevanceSignals WithSemaProximity;
+ WithSemaProximity.SemaProximityScore = 0.2f;
+ EXPECT_GT(WithSemaProximity.evaluate(), Default.evaluate());
+
+ SymbolRelevanceSignals IndexProximate;
+ IndexProximate.SymbolURI = "unittest:/foo/bar.h";
+ llvm::StringMap<SourceParams> ProxSources;
+ ProxSources.try_emplace(testPath("foo/baz.h"));
+ URIDistance Distance(ProxSources);
+ IndexProximate.FileProximityMatch = &Distance;
+ EXPECT_GT(IndexProximate.evaluate(), Default.evaluate());
+ SymbolRelevanceSignals IndexDistant = IndexProximate;
+ IndexDistant.SymbolURI = "unittest:/elsewhere/path.h";
+ EXPECT_GT(IndexProximate.evaluate(), IndexDistant.evaluate())
+ << IndexProximate << IndexDistant;
+ EXPECT_GT(IndexDistant.evaluate(), Default.evaluate());
+
+ SymbolRelevanceSignals Scoped;
+ Scoped.Scope = SymbolRelevanceSignals::FileScope;
+ EXPECT_EQ(Scoped.evaluate(), Default.evaluate());
+ Scoped.Query = SymbolRelevanceSignals::CodeComplete;
+ EXPECT_GT(Scoped.evaluate(), Default.evaluate());
+
+ SymbolRelevanceSignals Instance;
+ Instance.IsInstanceMember = false;
+ EXPECT_EQ(Instance.evaluate(), Default.evaluate());
+ Instance.Context = CodeCompletionContext::CCC_DotMemberAccess;
+ EXPECT_LT(Instance.evaluate(), Default.evaluate());
+ Instance.IsInstanceMember = true;
+ EXPECT_EQ(Instance.evaluate(), Default.evaluate());
+}
+
+TEST(QualityTests, SortText) {
+ EXPECT_LT(sortText(std::numeric_limits<float>::infinity()),
+ sortText(1000.2f));
+ EXPECT_LT(sortText(1000.2f), sortText(1));
+ EXPECT_LT(sortText(1), sortText(0.3f));
+ EXPECT_LT(sortText(0.3f), sortText(0));
+ EXPECT_LT(sortText(0), sortText(-10));
+ EXPECT_LT(sortText(-10), sortText(-std::numeric_limits<float>::infinity()));
+
+ EXPECT_LT(sortText(1, "z"), sortText(0, "a"));
+ EXPECT_LT(sortText(0, "a"), sortText(0, "z"));
+}
+
+TEST(QualityTests, NoBoostForClassConstructor) {
+ auto Header = TestTU::withHeaderCode(R"cpp(
+ class Foo {
+ public:
+ Foo(int);
+ };
+ )cpp");
+ auto Symbols = Header.headerSymbols();
+ auto AST = Header.build();
+
+ const NamedDecl *Foo = &findDecl(AST, "Foo");
+ SymbolRelevanceSignals Cls;
+ Cls.merge(CodeCompletionResult(Foo, /*Priority=*/0));
+
+ const NamedDecl *CtorDecl = &findAnyDecl(AST, [](const NamedDecl &ND) {
+ return (ND.getQualifiedNameAsString() == "Foo::Foo") &&
+ llvm::isa<CXXConstructorDecl>(&ND);
+ });
+ SymbolRelevanceSignals Ctor;
+ Ctor.merge(CodeCompletionResult(CtorDecl, /*Priority=*/0));
+
+ EXPECT_EQ(Cls.Scope, SymbolRelevanceSignals::GlobalScope);
+ EXPECT_EQ(Ctor.Scope, SymbolRelevanceSignals::GlobalScope);
+}
+
+TEST(QualityTests, IsInstanceMember) {
+ auto Header = TestTU::withHeaderCode(R"cpp(
+ class Foo {
+ public:
+ static void foo() {}
+
+ template <typename T> void tpl(T *t) {}
+
+ void bar() {}
+ };
+ )cpp");
+ auto Symbols = Header.headerSymbols();
+
+ SymbolRelevanceSignals Rel;
+ const Symbol &FooSym = findSymbol(Symbols, "Foo::foo");
+ Rel.merge(FooSym);
+ EXPECT_FALSE(Rel.IsInstanceMember);
+ const Symbol &BarSym = findSymbol(Symbols, "Foo::bar");
+ Rel.merge(BarSym);
+ EXPECT_TRUE(Rel.IsInstanceMember);
+
+ Rel.IsInstanceMember =false;
+ const Symbol &TplSym = findSymbol(Symbols, "Foo::tpl");
+ Rel.merge(TplSym);
+ EXPECT_TRUE(Rel.IsInstanceMember);
+
+ auto AST = Header.build();
+ const NamedDecl *Foo = &findDecl(AST, "Foo::foo");
+ const NamedDecl *Bar = &findDecl(AST, "Foo::bar");
+ const NamedDecl *Tpl = &findDecl(AST, "Foo::tpl");
+
+ Rel.IsInstanceMember = false;
+ Rel.merge(CodeCompletionResult(Foo, /*Priority=*/0));
+ EXPECT_FALSE(Rel.IsInstanceMember);
+ Rel.merge(CodeCompletionResult(Bar, /*Priority=*/0));
+ EXPECT_TRUE(Rel.IsInstanceMember);
+ Rel.IsInstanceMember = false;
+ Rel.merge(CodeCompletionResult(Tpl, /*Priority=*/0));
+ EXPECT_TRUE(Rel.IsInstanceMember);
+}
+
+TEST(QualityTests, ConstructorQuality) {
+ auto Header = TestTU::withHeaderCode(R"cpp(
+ class Foo {
+ public:
+ Foo(int);
+ };
+ )cpp");
+ auto Symbols = Header.headerSymbols();
+ auto AST = Header.build();
+
+ const NamedDecl *CtorDecl = &findAnyDecl(AST, [](const NamedDecl &ND) {
+ return (ND.getQualifiedNameAsString() == "Foo::Foo") &&
+ llvm::isa<CXXConstructorDecl>(&ND);
+ });
+
+ SymbolQualitySignals Q;
+ Q.merge(CodeCompletionResult(CtorDecl, /*Priority=*/0));
+ EXPECT_EQ(Q.Category, SymbolQualitySignals::Constructor);
+
+ Q.Category = SymbolQualitySignals::Unknown;
+ const Symbol &CtorSym = findSymbol(Symbols, "Foo::Foo");
+ Q.merge(CtorSym);
+ EXPECT_EQ(Q.Category, SymbolQualitySignals::Constructor);
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/SourceCodeTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/SourceCodeTests.cpp
new file mode 100644
index 0000000..57276af
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/SourceCodeTests.cpp
@@ -0,0 +1,124 @@
+//===-- SourceCodeTests.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "SourceCode.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_os_ostream.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang{
+namespace clangd {
+namespace {
+
+using llvm::Failed;
+using llvm::HasValue;
+
+MATCHER_P2(Pos, Line, Col, "") {
+ return arg.line == Line && arg.character == Col;
+}
+
+// The = → 🡆 below are ASCII (1 byte), BMP (3 bytes), and astral (4 bytes).
+const char File[] = R"(0:0 = 0
+1:0 → 8
+2:0 🡆 18)";
+
+/// A helper to make tests easier to read.
+Position position(int line, int character) {
+ Position Pos;
+ Pos.line = line;
+ Pos.character = character;
+ return Pos;
+}
+
+TEST(SourceCodeTests, PositionToOffset) {
+ // line out of bounds
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), Failed());
+ // first line
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, -1)),
+ Failed()); // out of range
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 0)),
+ HasValue(0)); // first character
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 3)),
+ HasValue(3)); // middle character
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 6)),
+ HasValue(6)); // last character
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7)),
+ HasValue(7)); // the newline itself
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7), false),
+ HasValue(7));
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8)),
+ HasValue(7)); // out of range
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8), false),
+ Failed()); // out of range
+ // middle line
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, -1)),
+ Failed()); // out of range
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 0)),
+ HasValue(8)); // first character
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3)),
+ HasValue(11)); // middle character
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3), false),
+ HasValue(11));
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 6)),
+ HasValue(16)); // last character
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 7)),
+ HasValue(17)); // the newline itself
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8)),
+ HasValue(17)); // out of range
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8), false),
+ Failed()); // out of range
+ // last line
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, -1)),
+ Failed()); // out of range
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 0)),
+ HasValue(18)); // first character
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 3)),
+ HasValue(21)); // middle character
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 5), false),
+ Failed()); // middle of surrogate pair
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 5)),
+ HasValue(26)); // middle of surrogate pair
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 6), false),
+ HasValue(26)); // end of surrogate pair
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 8)),
+ HasValue(28)); // last character
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 9)),
+ HasValue(29)); // EOF
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 10), false),
+ Failed()); // out of range
+ // line out of bounds
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 0)), Failed());
+ EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 1)), Failed());
+}
+
+TEST(SourceCodeTests, OffsetToPosition) {
+ EXPECT_THAT(offsetToPosition(File, 0), Pos(0, 0)) << "start of file";
+ EXPECT_THAT(offsetToPosition(File, 3), Pos(0, 3)) << "in first line";
+ EXPECT_THAT(offsetToPosition(File, 6), Pos(0, 6)) << "end of first line";
+ EXPECT_THAT(offsetToPosition(File, 7), Pos(0, 7)) << "first newline";
+ EXPECT_THAT(offsetToPosition(File, 8), Pos(1, 0)) << "start of second line";
+ EXPECT_THAT(offsetToPosition(File, 12), Pos(1, 4)) << "before BMP char";
+ EXPECT_THAT(offsetToPosition(File, 13), Pos(1, 5)) << "in BMP char";
+ EXPECT_THAT(offsetToPosition(File, 15), Pos(1, 5)) << "after BMP char";
+ EXPECT_THAT(offsetToPosition(File, 16), Pos(1, 6)) << "end of second line";
+ EXPECT_THAT(offsetToPosition(File, 17), Pos(1, 7)) << "second newline";
+ EXPECT_THAT(offsetToPosition(File, 18), Pos(2, 0)) << "start of last line";
+ EXPECT_THAT(offsetToPosition(File, 21), Pos(2, 3)) << "in last line";
+ EXPECT_THAT(offsetToPosition(File, 22), Pos(2, 4)) << "before astral char";
+ EXPECT_THAT(offsetToPosition(File, 24), Pos(2, 6)) << "in astral char";
+ EXPECT_THAT(offsetToPosition(File, 26), Pos(2, 6)) << "after astral char";
+ EXPECT_THAT(offsetToPosition(File, 28), Pos(2, 8)) << "end of last line";
+ EXPECT_THAT(offsetToPosition(File, 29), Pos(2, 9)) << "EOF";
+ EXPECT_THAT(offsetToPosition(File, 30), Pos(2, 9)) << "out of bounds";
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp
new file mode 100644
index 0000000..666d0bb
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/SymbolCollectorTests.cpp
@@ -0,0 +1,1023 @@
+//===-- SymbolCollectorTests.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Annotations.h"
+#include "TestFS.h"
+#include "TestTU.h"
+#include "index/SymbolCollector.h"
+#include "index/SymbolYAML.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Index/IndexingAction.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include <memory>
+#include <string>
+
+using testing::AllOf;
+using testing::Eq;
+using testing::Field;
+using testing::Not;
+using testing::UnorderedElementsAre;
+using testing::UnorderedElementsAreArray;
+
+// GMock helpers for matching Symbol.
+MATCHER_P(Labeled, Label, "") {
+ return (arg.Name + arg.Signature).str() == Label;
+}
+MATCHER(HasReturnType, "") {
+ return arg.Detail && !arg.Detail->ReturnType.empty();
+}
+MATCHER_P(ReturnType, D, "") {
+ return arg.Detail && arg.Detail->ReturnType == D;
+}
+MATCHER_P(Doc, D, "") { return arg.Detail && arg.Detail->Documentation == D; }
+MATCHER_P(Snippet, S, "") {
+ return (arg.Name + arg.CompletionSnippetSuffix).str() == S;
+}
+MATCHER_P(QName, Name, "") { return (arg.Scope + arg.Name).str() == Name; }
+MATCHER_P(DeclURI, P, "") { return arg.CanonicalDeclaration.FileURI == P; }
+MATCHER_P(DefURI, P, "") { return arg.Definition.FileURI == P; }
+MATCHER_P(IncludeHeader, P, "") {
+ return arg.Detail && arg.Detail->IncludeHeader == P;
+}
+MATCHER_P(DeclRange, Pos, "") {
+ return std::tie(arg.CanonicalDeclaration.Start.Line,
+ arg.CanonicalDeclaration.Start.Column,
+ arg.CanonicalDeclaration.End.Line,
+ arg.CanonicalDeclaration.End.Column) ==
+ std::tie(Pos.start.line, Pos.start.character, Pos.end.line,
+ Pos.end.character);
+}
+MATCHER_P(DefRange, Pos, "") {
+ return std::tie(arg.Definition.Start.Line,
+ arg.Definition.Start.Column, arg.Definition.End.Line,
+ arg.Definition.End.Column) ==
+ std::tie(Pos.start.line, Pos.start.character, Pos.end.line,
+ Pos.end.character);
+}
+MATCHER_P(Refs, R, "") { return int(arg.References) == R; }
+MATCHER_P(ForCodeCompletion, IsIndexedForCodeCompletion, "") {
+ return arg.IsIndexedForCodeCompletion == IsIndexedForCodeCompletion;
+}
+
+namespace clang {
+namespace clangd {
+
+namespace {
+
+class ShouldCollectSymbolTest : public ::testing::Test {
+public:
+ void build(StringRef HeaderCode, StringRef Code = "") {
+ File.HeaderFilename = HeaderName;
+ File.Filename = FileName;
+ File.HeaderCode = HeaderCode;
+ File.Code = Code;
+ AST = File.build();
+ }
+
+ // build() must have been called.
+ bool shouldCollect(StringRef Name, bool Qualified = true) {
+ assert(AST.hasValue());
+ return SymbolCollector::shouldCollectSymbol(
+ Qualified ? findDecl(*AST, Name) : findAnyDecl(*AST, Name),
+ AST->getASTContext(), SymbolCollector::Options());
+ }
+
+protected:
+ std::string HeaderName = "f.h";
+ std::string FileName = "f.cpp";
+ TestTU File;
+ Optional<ParsedAST> AST; // Initialized after build.
+};
+
+TEST_F(ShouldCollectSymbolTest, ShouldCollectSymbol) {
+ build(R"(
+ namespace nx {
+ class X{}
+ void f() { int Local; }
+ struct { int x } var;
+ namespace { class InAnonymous {}; }
+ }
+ )",
+ "class InMain {};");
+ auto AST = File.build();
+ EXPECT_TRUE(shouldCollect("nx"));
+ EXPECT_TRUE(shouldCollect("nx::X"));
+ EXPECT_TRUE(shouldCollect("nx::f"));
+
+ EXPECT_FALSE(shouldCollect("InMain"));
+ EXPECT_FALSE(shouldCollect("Local", /*Qualified=*/false));
+ EXPECT_FALSE(shouldCollect("InAnonymous", /*Qualified=*/false));
+}
+
+TEST_F(ShouldCollectSymbolTest, NoPrivateProtoSymbol) {
+ HeaderName = "f.proto.h";
+ build(
+ R"(// Generated by the protocol buffer compiler. DO NOT EDIT!
+ namespace nx {
+ class Top_Level {};
+ class TopLevel {};
+ enum Kind {
+ KIND_OK,
+ Kind_Not_Ok,
+ };
+ })");
+ EXPECT_TRUE(shouldCollect("nx::TopLevel"));
+ EXPECT_TRUE(shouldCollect("nx::Kind::KIND_OK"));
+ EXPECT_TRUE(shouldCollect("nx::Kind"));
+
+ EXPECT_FALSE(shouldCollect("nx::Top_Level"));
+ EXPECT_FALSE(shouldCollect("nx::Kind::Kind_Not_Ok"));
+}
+
+TEST_F(ShouldCollectSymbolTest, DoubleCheckProtoHeaderComment) {
+ HeaderName = "f.proto.h";
+ build(R"(
+ namespace nx {
+ class Top_Level {};
+ enum Kind {
+ Kind_Fine
+ };
+ }
+ )");
+ EXPECT_TRUE(shouldCollect("nx::Top_Level"));
+ EXPECT_TRUE(shouldCollect("nx::Kind_Fine"));
+}
+
+class SymbolIndexActionFactory : public tooling::FrontendActionFactory {
+public:
+ SymbolIndexActionFactory(SymbolCollector::Options COpts,
+ CommentHandler *PragmaHandler)
+ : COpts(std::move(COpts)), PragmaHandler(PragmaHandler) {}
+
+ clang::FrontendAction *create() override {
+ class WrappedIndexAction : public WrapperFrontendAction {
+ public:
+ WrappedIndexAction(std::shared_ptr<SymbolCollector> C,
+ const index::IndexingOptions &Opts,
+ CommentHandler *PragmaHandler)
+ : WrapperFrontendAction(
+ index::createIndexingAction(C, Opts, nullptr)),
+ PragmaHandler(PragmaHandler) {}
+
+ std::unique_ptr<ASTConsumer>
+ CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
+ if (PragmaHandler)
+ CI.getPreprocessor().addCommentHandler(PragmaHandler);
+ return WrapperFrontendAction::CreateASTConsumer(CI, InFile);
+ }
+
+ private:
+ index::IndexingOptions IndexOpts;
+ CommentHandler *PragmaHandler;
+ };
+ index::IndexingOptions IndexOpts;
+ IndexOpts.SystemSymbolFilter =
+ index::IndexingOptions::SystemSymbolFilterKind::All;
+ IndexOpts.IndexFunctionLocals = false;
+ Collector = std::make_shared<SymbolCollector>(COpts);
+ return new WrappedIndexAction(Collector, std::move(IndexOpts),
+ PragmaHandler);
+ }
+
+ std::shared_ptr<SymbolCollector> Collector;
+ SymbolCollector::Options COpts;
+ CommentHandler *PragmaHandler;
+};
+
+class SymbolCollectorTest : public ::testing::Test {
+public:
+ SymbolCollectorTest()
+ : InMemoryFileSystem(new vfs::InMemoryFileSystem),
+ TestHeaderName(testPath("symbol.h")),
+ TestFileName(testPath("symbol.cc")) {
+ TestHeaderURI = URI::createFile(TestHeaderName).toString();
+ TestFileURI = URI::createFile(TestFileName).toString();
+ }
+
+ bool runSymbolCollector(StringRef HeaderCode, StringRef MainCode,
+ const std::vector<std::string> &ExtraArgs = {}) {
+ llvm::IntrusiveRefCntPtr<FileManager> Files(
+ new FileManager(FileSystemOptions(), InMemoryFileSystem));
+
+ auto Factory = llvm::make_unique<SymbolIndexActionFactory>(
+ CollectorOpts, PragmaHandler.get());
+
+ std::vector<std::string> Args = {
+ "symbol_collector", "-fsyntax-only", "-xc++",
+ "-std=c++11", "-include", TestHeaderName};
+ Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
+ // This allows to override the "-xc++" with something else, i.e.
+ // -xobjective-c++.
+ Args.push_back(TestFileName);
+
+ tooling::ToolInvocation Invocation(
+ Args,
+ Factory->create(), Files.get(),
+ std::make_shared<PCHContainerOperations>());
+
+ InMemoryFileSystem->addFile(TestHeaderName, 0,
+ llvm::MemoryBuffer::getMemBuffer(HeaderCode));
+ InMemoryFileSystem->addFile(TestFileName, 0,
+ llvm::MemoryBuffer::getMemBuffer(MainCode));
+ Invocation.run();
+ Symbols = Factory->Collector->takeSymbols();
+ return true;
+ }
+
+protected:
+ llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem;
+ std::string TestHeaderName;
+ std::string TestHeaderURI;
+ std::string TestFileName;
+ std::string TestFileURI;
+ SymbolSlab Symbols;
+ SymbolCollector::Options CollectorOpts;
+ std::unique_ptr<CommentHandler> PragmaHandler;
+};
+
+TEST_F(SymbolCollectorTest, CollectSymbols) {
+ const std::string Header = R"(
+ class Foo {
+ Foo() {}
+ Foo(int a) {}
+ void f();
+ friend void f1();
+ friend class Friend;
+ Foo& operator=(const Foo&);
+ ~Foo();
+ class Nested {
+ void f();
+ };
+ };
+ class Friend {
+ };
+
+ void f1();
+ inline void f2() {}
+ static const int KInt = 2;
+ const char* kStr = "123";
+
+ namespace {
+ void ff() {} // ignore
+ }
+
+ void f1() {}
+
+ namespace foo {
+ // Type alias
+ typedef int int32;
+ using int32_t = int32;
+
+ // Variable
+ int v1;
+
+ // Namespace
+ namespace bar {
+ int v2;
+ }
+ // Namespace alias
+ namespace baz = bar;
+
+ // FIXME: using declaration is not supported as the IndexAction will ignore
+ // implicit declarations (the implicit using shadow declaration) by default,
+ // and there is no way to customize this behavior at the moment.
+ using bar::v2;
+ } // namespace foo
+ )";
+ runSymbolCollector(Header, /*Main=*/"");
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAreArray(
+ {AllOf(QName("Foo"), ForCodeCompletion(true)),
+ AllOf(QName("Foo::Foo"), ForCodeCompletion(false)),
+ AllOf(QName("Foo::Foo"), ForCodeCompletion(false)),
+ AllOf(QName("Foo::f"), ForCodeCompletion(false)),
+ AllOf(QName("Foo::~Foo"), ForCodeCompletion(false)),
+ AllOf(QName("Foo::operator="), ForCodeCompletion(false)),
+ AllOf(QName("Foo::Nested"), ForCodeCompletion(false)),
+ AllOf(QName("Foo::Nested::f"), ForCodeCompletion(false)),
+
+ AllOf(QName("Friend"), ForCodeCompletion(true)),
+ AllOf(QName("f1"), ForCodeCompletion(true)),
+ AllOf(QName("f2"), ForCodeCompletion(true)),
+ AllOf(QName("KInt"), ForCodeCompletion(true)),
+ AllOf(QName("kStr"), ForCodeCompletion(true)),
+ AllOf(QName("foo"), ForCodeCompletion(true)),
+ AllOf(QName("foo::bar"), ForCodeCompletion(true)),
+ AllOf(QName("foo::int32"), ForCodeCompletion(true)),
+ AllOf(QName("foo::int32_t"), ForCodeCompletion(true)),
+ AllOf(QName("foo::v1"), ForCodeCompletion(true)),
+ AllOf(QName("foo::bar::v2"), ForCodeCompletion(true)),
+ AllOf(QName("foo::baz"), ForCodeCompletion(true))}));
+}
+
+TEST_F(SymbolCollectorTest, Template) {
+ Annotations Header(R"(
+ // Template is indexed, specialization and instantiation is not.
+ template <class T> struct [[Tmpl]] {T $xdecl[[x]] = 0;};
+ template <> struct Tmpl<int> {};
+ extern template struct Tmpl<float>;
+ template struct Tmpl<double>;
+ )");
+ runSymbolCollector(Header.code(), /*Main=*/"");
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAreArray(
+ {AllOf(QName("Tmpl"), DeclRange(Header.range())),
+ AllOf(QName("Tmpl::x"), DeclRange(Header.range("xdecl")))}));
+}
+
+TEST_F(SymbolCollectorTest, ObjCSymbols) {
+ const std::string Header = R"(
+ @interface Person
+ - (void)someMethodName:(void*)name1 lastName:(void*)lName;
+ @end
+
+ @implementation Person
+ - (void)someMethodName:(void*)name1 lastName:(void*)lName{
+ int foo;
+ ^(int param){ int bar; };
+ }
+ @end
+
+ @interface Person (MyCategory)
+ - (void)someMethodName2:(void*)name2;
+ @end
+
+ @implementation Person (MyCategory)
+ - (void)someMethodName2:(void*)name2 {
+ int foo2;
+ }
+ @end
+
+ @protocol MyProtocol
+ - (void)someMethodName3:(void*)name3;
+ @end
+ )";
+ TestFileName = "test.m";
+ runSymbolCollector(Header, /*Main=*/"", {"-fblocks", "-xobjective-c++"});
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(
+ QName("Person"), QName("Person::someMethodName:lastName:"),
+ QName("MyCategory"), QName("Person::someMethodName2:"),
+ QName("MyProtocol"), QName("MyProtocol::someMethodName3:")));
+}
+
+TEST_F(SymbolCollectorTest, Locations) {
+ Annotations Header(R"cpp(
+ // Declared in header, defined in main.
+ extern int $xdecl[[X]];
+ class $clsdecl[[Cls]];
+ void $printdecl[[print]]();
+
+ // Declared in header, defined nowhere.
+ extern int $zdecl[[Z]];
+
+ void $foodecl[[fo\
+o]]();
+ )cpp");
+ Annotations Main(R"cpp(
+ int $xdef[[X]] = 42;
+ class $clsdef[[Cls]] {};
+ void $printdef[[print]]() {}
+
+ // Declared/defined in main only.
+ int Y;
+ )cpp");
+ runSymbolCollector(Header.code(), Main.code());
+ EXPECT_THAT(
+ Symbols,
+ UnorderedElementsAre(
+ AllOf(QName("X"), DeclRange(Header.range("xdecl")),
+ DefRange(Main.range("xdef"))),
+ AllOf(QName("Cls"), DeclRange(Header.range("clsdecl")),
+ DefRange(Main.range("clsdef"))),
+ AllOf(QName("print"), DeclRange(Header.range("printdecl")),
+ DefRange(Main.range("printdef"))),
+ AllOf(QName("Z"), DeclRange(Header.range("zdecl"))),
+ AllOf(QName("foo"), DeclRange(Header.range("foodecl")))
+ ));
+}
+
+TEST_F(SymbolCollectorTest, References) {
+ const std::string Header = R"(
+ class W;
+ class X {};
+ class Y;
+ class Z {}; // not used anywhere
+ Y* y = nullptr; // used in header doesn't count
+ #define GLOBAL_Z(name) Z name;
+ )";
+ const std::string Main = R"(
+ W* w = nullptr;
+ W* w2 = nullptr; // only one usage counts
+ X x();
+ class V;
+ V* v = nullptr; // Used, but not eligible for indexing.
+ class Y{}; // definition doesn't count as a reference
+ GLOBAL_Z(z); // Not a reference to Z, we don't spell the type.
+ )";
+ CollectorOpts.CountReferences = true;
+ runSymbolCollector(Header, Main);
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(AllOf(QName("W"), Refs(1)),
+ AllOf(QName("X"), Refs(1)),
+ AllOf(QName("Y"), Refs(0)),
+ AllOf(QName("Z"), Refs(0)), QName("y")));
+}
+
+TEST_F(SymbolCollectorTest, SymbolRelativeNoFallback) {
+ runSymbolCollector("class Foo {};", /*Main=*/"");
+ EXPECT_THAT(Symbols, UnorderedElementsAre(
+ AllOf(QName("Foo"), DeclURI(TestHeaderURI))));
+}
+
+TEST_F(SymbolCollectorTest, SymbolRelativeWithFallback) {
+ TestHeaderName = "x.h";
+ TestFileName = "x.cpp";
+ TestHeaderURI = URI::createFile(testPath(TestHeaderName)).toString();
+ CollectorOpts.FallbackDir = testRoot();
+ runSymbolCollector("class Foo {};", /*Main=*/"");
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(AllOf(QName("Foo"), DeclURI(TestHeaderURI))));
+}
+
+TEST_F(SymbolCollectorTest, CustomURIScheme) {
+ // Use test URI scheme from URITests.cpp
+ CollectorOpts.URISchemes.insert(CollectorOpts.URISchemes.begin(), "unittest");
+ TestHeaderName = testPath("x.h");
+ TestFileName = testPath("x.cpp");
+ runSymbolCollector("class Foo {};", /*Main=*/"");
+ EXPECT_THAT(Symbols, UnorderedElementsAre(
+ AllOf(QName("Foo"), DeclURI("unittest:///x.h"))));
+}
+
+TEST_F(SymbolCollectorTest, InvalidURIScheme) {
+ // Use test URI scheme from URITests.cpp
+ CollectorOpts.URISchemes = {"invalid"};
+ runSymbolCollector("class Foo {};", /*Main=*/"");
+ EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("Foo"), DeclURI(""))));
+}
+
+TEST_F(SymbolCollectorTest, FallbackToFileURI) {
+ // Use test URI scheme from URITests.cpp
+ CollectorOpts.URISchemes = {"invalid", "file"};
+ runSymbolCollector("class Foo {};", /*Main=*/"");
+ EXPECT_THAT(Symbols, UnorderedElementsAre(
+ AllOf(QName("Foo"), DeclURI(TestHeaderURI))));
+}
+
+TEST_F(SymbolCollectorTest, IncludeEnums) {
+ const std::string Header = R"(
+ enum {
+ Red
+ };
+ enum Color {
+ Green
+ };
+ enum class Color2 {
+ Yellow
+ };
+ namespace ns {
+ enum {
+ Black
+ };
+ }
+ )";
+ runSymbolCollector(Header, /*Main=*/"");
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(
+ AllOf(QName("Red"), ForCodeCompletion(true)),
+ AllOf(QName("Color"), ForCodeCompletion(true)),
+ AllOf(QName("Green"), ForCodeCompletion(true)),
+ AllOf(QName("Color2"), ForCodeCompletion(true)),
+ AllOf(QName("Color2::Yellow"), ForCodeCompletion(false)),
+ AllOf(QName("ns"), ForCodeCompletion(true)),
+ AllOf(QName("ns::Black"), ForCodeCompletion(true))));
+}
+
+TEST_F(SymbolCollectorTest, NamelessSymbols) {
+ const std::string Header = R"(
+ struct {
+ int a;
+ } Foo;
+ )";
+ runSymbolCollector(Header, /*Main=*/"");
+ EXPECT_THAT(Symbols, UnorderedElementsAre(QName("Foo"),
+ QName("(anonymous struct)::a")));
+}
+
+TEST_F(SymbolCollectorTest, SymbolFormedFromMacro) {
+
+ Annotations Header(R"(
+ #define FF(name) \
+ class name##_Test {};
+
+ $expansion[[FF]](abc);
+
+ #define FF2() \
+ class $spelling[[Test]] {};
+
+ FF2();
+ )");
+
+ runSymbolCollector(Header.code(), /*Main=*/"");
+ EXPECT_THAT(
+ Symbols,
+ UnorderedElementsAre(
+ AllOf(QName("abc_Test"), DeclRange(Header.range("expansion")),
+ DeclURI(TestHeaderURI)),
+ AllOf(QName("Test"), DeclRange(Header.range("spelling")),
+ DeclURI(TestHeaderURI))));
+}
+
+TEST_F(SymbolCollectorTest, SymbolFormedByCLI) {
+ Annotations Header(R"(
+ #ifdef NAME
+ class $expansion[[NAME]] {};
+ #endif
+ )");
+
+ runSymbolCollector(Header.code(), /*Main=*/"",
+ /*ExtraArgs=*/{"-DNAME=name"});
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(AllOf(
+ QName("name"),
+ DeclRange(Header.range("expansion")),
+ DeclURI(TestHeaderURI))));
+}
+
+TEST_F(SymbolCollectorTest, IgnoreSymbolsInMainFile) {
+ const std::string Header = R"(
+ class Foo {};
+ void f1();
+ inline void f2() {}
+ )";
+ const std::string Main = R"(
+ namespace {
+ void ff() {} // ignore
+ }
+ void main_f() {} // ignore
+ void f1() {}
+ )";
+ runSymbolCollector(Header, Main);
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(QName("Foo"), QName("f1"), QName("f2")));
+}
+
+TEST_F(SymbolCollectorTest, ClassMembers) {
+ const std::string Header = R"(
+ class Foo {
+ void f() {}
+ void g();
+ static void sf() {}
+ static void ssf();
+ static int x;
+ };
+ )";
+ const std::string Main = R"(
+ void Foo::g() {}
+ void Foo::ssf() {}
+ )";
+ runSymbolCollector(Header, Main);
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(QName("Foo"), QName("Foo::f"),
+ QName("Foo::g"), QName("Foo::sf"),
+ QName("Foo::ssf"), QName("Foo::x")));
+}
+
+TEST_F(SymbolCollectorTest, Scopes) {
+ const std::string Header = R"(
+ namespace na {
+ class Foo {};
+ namespace nb {
+ class Bar {};
+ }
+ }
+ )";
+ runSymbolCollector(Header, /*Main=*/"");
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(QName("na"), QName("na::nb"),
+ QName("na::Foo"), QName("na::nb::Bar")));
+}
+
+TEST_F(SymbolCollectorTest, ExternC) {
+ const std::string Header = R"(
+ extern "C" { class Foo {}; }
+ namespace na {
+ extern "C" { class Bar {}; }
+ }
+ )";
+ runSymbolCollector(Header, /*Main=*/"");
+ EXPECT_THAT(Symbols, UnorderedElementsAre(QName("na"), QName("Foo"),
+ QName("na::Bar")));
+}
+
+TEST_F(SymbolCollectorTest, SkipInlineNamespace) {
+ const std::string Header = R"(
+ namespace na {
+ inline namespace nb {
+ class Foo {};
+ }
+ }
+ namespace na {
+ // This is still inlined.
+ namespace nb {
+ class Bar {};
+ }
+ }
+ )";
+ runSymbolCollector(Header, /*Main=*/"");
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(QName("na"), QName("na::nb"),
+ QName("na::Foo"), QName("na::Bar")));
+}
+
+TEST_F(SymbolCollectorTest, SymbolWithDocumentation) {
+ const std::string Header = R"(
+ namespace nx {
+ /// Foo comment.
+ int ff(int x, double y) { return 0; }
+ }
+ )";
+ runSymbolCollector(Header, /*Main=*/"");
+ EXPECT_THAT(
+ Symbols,
+ UnorderedElementsAre(
+ QName("nx"), AllOf(QName("nx::ff"), Labeled("ff(int x, double y)"),
+ ReturnType("int"), Doc("Foo comment."))));
+}
+
+TEST_F(SymbolCollectorTest, Snippet) {
+ const std::string Header = R"(
+ namespace nx {
+ void f() {}
+ int ff(int x, double y) { return 0; }
+ }
+ )";
+ runSymbolCollector(Header, /*Main=*/"");
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(
+ QName("nx"),
+ AllOf(QName("nx::f"), Labeled("f()"), Snippet("f()")),
+ AllOf(QName("nx::ff"), Labeled("ff(int x, double y)"),
+ Snippet("ff(${1:int x}, ${2:double y})"))));
+}
+
+TEST_F(SymbolCollectorTest, YAMLConversions) {
+ const std::string YAML1 = R"(
+---
+ID: 057557CEBF6E6B2DD437FBF60CC58F352D1DF856
+Name: 'Foo1'
+Scope: 'clang::'
+SymInfo:
+ Kind: Function
+ Lang: Cpp
+CanonicalDeclaration:
+ FileURI: file:///path/foo.h
+ Start:
+ Line: 1
+ Column: 0
+ End:
+ Line: 1
+ Column: 1
+IsIndexedForCodeCompletion: true
+Detail:
+ Documentation: 'Foo doc'
+ ReturnType: 'int'
+...
+)";
+ const std::string YAML2 = R"(
+---
+ID: 057557CEBF6E6B2DD437FBF60CC58F352D1DF858
+Name: 'Foo2'
+Scope: 'clang::'
+SymInfo:
+ Kind: Function
+ Lang: Cpp
+CanonicalDeclaration:
+ FileURI: file:///path/bar.h
+ Start:
+ Line: 1
+ Column: 0
+ End:
+ Line: 1
+ Column: 1
+IsIndexedForCodeCompletion: false
+Signature: '-sig'
+CompletionSnippetSuffix: '-snippet'
+...
+)";
+
+ auto Symbols1 = symbolsFromYAML(YAML1);
+
+ EXPECT_THAT(Symbols1,
+ UnorderedElementsAre(AllOf(QName("clang::Foo1"), Labeled("Foo1"),
+ Doc("Foo doc"), ReturnType("int"),
+ DeclURI("file:///path/foo.h"),
+ ForCodeCompletion(true))));
+ auto Symbols2 = symbolsFromYAML(YAML2);
+ EXPECT_THAT(Symbols2, UnorderedElementsAre(AllOf(
+ QName("clang::Foo2"), Labeled("Foo2-sig"),
+ Not(HasReturnType()), DeclURI("file:///path/bar.h"),
+ ForCodeCompletion(false))));
+
+ std::string ConcatenatedYAML;
+ {
+ llvm::raw_string_ostream OS(ConcatenatedYAML);
+ SymbolsToYAML(Symbols1, OS);
+ SymbolsToYAML(Symbols2, OS);
+ }
+ auto ConcatenatedSymbols = symbolsFromYAML(ConcatenatedYAML);
+ EXPECT_THAT(ConcatenatedSymbols,
+ UnorderedElementsAre(QName("clang::Foo1"),
+ QName("clang::Foo2")));
+}
+
+TEST_F(SymbolCollectorTest, IncludeHeaderSameAsFileURI) {
+ CollectorOpts.CollectIncludePath = true;
+ runSymbolCollector("class Foo {};", /*Main=*/"");
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(AllOf(QName("Foo"), DeclURI(TestHeaderURI),
+ IncludeHeader(TestHeaderURI))));
+}
+
+#ifndef _WIN32
+TEST_F(SymbolCollectorTest, CanonicalSTLHeader) {
+ CollectorOpts.CollectIncludePath = true;
+ CanonicalIncludes Includes;
+ addSystemHeadersMapping(&Includes);
+ CollectorOpts.Includes = &Includes;
+ // bits/basic_string.h$ should be mapped to <string>
+ TestHeaderName = "/nasty/bits/basic_string.h";
+ TestFileName = "/nasty/bits/basic_string.cpp";
+ TestHeaderURI = URI::createFile(TestHeaderName).toString();
+ runSymbolCollector("class string {};", /*Main=*/"");
+ EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("string"),
+ DeclURI(TestHeaderURI),
+ IncludeHeader("<string>"))));
+}
+#endif
+
+TEST_F(SymbolCollectorTest, STLiosfwd) {
+ CollectorOpts.CollectIncludePath = true;
+ CanonicalIncludes Includes;
+ addSystemHeadersMapping(&Includes);
+ CollectorOpts.Includes = &Includes;
+ // Symbols from <iosfwd> should be mapped individually.
+ TestHeaderName = testPath("iosfwd");
+ TestFileName = testPath("iosfwd.cpp");
+ std::string Header = R"(
+ namespace std {
+ class no_map {};
+ class ios {};
+ class ostream {};
+ class filebuf {};
+ } // namespace std
+ )";
+ runSymbolCollector(Header, /*Main=*/"");
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(
+ QName("std"),
+ AllOf(QName("std::no_map"), IncludeHeader("<iosfwd>")),
+ AllOf(QName("std::ios"), IncludeHeader("<ios>")),
+ AllOf(QName("std::ostream"), IncludeHeader("<ostream>")),
+ AllOf(QName("std::filebuf"), IncludeHeader("<fstream>"))));
+}
+
+TEST_F(SymbolCollectorTest, IWYUPragma) {
+ CollectorOpts.CollectIncludePath = true;
+ CanonicalIncludes Includes;
+ PragmaHandler = collectIWYUHeaderMaps(&Includes);
+ CollectorOpts.Includes = &Includes;
+ const std::string Header = R"(
+ // IWYU pragma: private, include the/good/header.h
+ class Foo {};
+ )";
+ runSymbolCollector(Header, /*Main=*/"");
+ EXPECT_THAT(Symbols, UnorderedElementsAre(
+ AllOf(QName("Foo"), DeclURI(TestHeaderURI),
+ IncludeHeader("\"the/good/header.h\""))));
+}
+
+TEST_F(SymbolCollectorTest, IWYUPragmaWithDoubleQuotes) {
+ CollectorOpts.CollectIncludePath = true;
+ CanonicalIncludes Includes;
+ PragmaHandler = collectIWYUHeaderMaps(&Includes);
+ CollectorOpts.Includes = &Includes;
+ const std::string Header = R"(
+ // IWYU pragma: private, include "the/good/header.h"
+ class Foo {};
+ )";
+ runSymbolCollector(Header, /*Main=*/"");
+ EXPECT_THAT(Symbols, UnorderedElementsAre(
+ AllOf(QName("Foo"), DeclURI(TestHeaderURI),
+ IncludeHeader("\"the/good/header.h\""))));
+}
+
+TEST_F(SymbolCollectorTest, SkipIncFileWhenCanonicalizeHeaders) {
+ CollectorOpts.CollectIncludePath = true;
+ CanonicalIncludes Includes;
+ Includes.addMapping(TestHeaderName, "<canonical>");
+ CollectorOpts.Includes = &Includes;
+ auto IncFile = testPath("test.inc");
+ auto IncURI = URI::createFile(IncFile).toString();
+ InMemoryFileSystem->addFile(IncFile, 0,
+ llvm::MemoryBuffer::getMemBuffer("class X {};"));
+ runSymbolCollector("#include \"test.inc\"\nclass Y {};", /*Main=*/"",
+ /*ExtraArgs=*/{"-I", testRoot()});
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(AllOf(QName("X"), DeclURI(IncURI),
+ IncludeHeader("<canonical>")),
+ AllOf(QName("Y"), DeclURI(TestHeaderURI),
+ IncludeHeader("<canonical>"))));
+}
+
+TEST_F(SymbolCollectorTest, MainFileIsHeaderWhenSkipIncFile) {
+ CollectorOpts.CollectIncludePath = true;
+ CanonicalIncludes Includes;
+ CollectorOpts.Includes = &Includes;
+ TestFileName = testPath("main.h");
+ TestFileURI = URI::createFile(TestFileName).toString();
+ auto IncFile = testPath("test.inc");
+ auto IncURI = URI::createFile(IncFile).toString();
+ InMemoryFileSystem->addFile(IncFile, 0,
+ llvm::MemoryBuffer::getMemBuffer("class X {};"));
+ runSymbolCollector("", /*Main=*/"#include \"test.inc\"",
+ /*ExtraArgs=*/{"-I", testRoot()});
+ EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("X"), DeclURI(IncURI),
+ IncludeHeader(TestFileURI))));
+}
+
+TEST_F(SymbolCollectorTest, MainFileIsHeaderWithoutExtensionWhenSkipIncFile) {
+ CollectorOpts.CollectIncludePath = true;
+ CanonicalIncludes Includes;
+ CollectorOpts.Includes = &Includes;
+ TestFileName = testPath("no_ext_main");
+ TestFileURI = URI::createFile(TestFileName).toString();
+ auto IncFile = testPath("test.inc");
+ auto IncURI = URI::createFile(IncFile).toString();
+ InMemoryFileSystem->addFile(IncFile, 0,
+ llvm::MemoryBuffer::getMemBuffer("class X {};"));
+ runSymbolCollector("", /*Main=*/"#include \"test.inc\"",
+ /*ExtraArgs=*/{"-I", testRoot()});
+ EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("X"), DeclURI(IncURI),
+ IncludeHeader(TestFileURI))));
+}
+
+TEST_F(SymbolCollectorTest, FallbackToIncFileWhenIncludingFileIsCC) {
+ CollectorOpts.CollectIncludePath = true;
+ CanonicalIncludes Includes;
+ CollectorOpts.Includes = &Includes;
+ auto IncFile = testPath("test.inc");
+ auto IncURI = URI::createFile(IncFile).toString();
+ InMemoryFileSystem->addFile(IncFile, 0,
+ llvm::MemoryBuffer::getMemBuffer("class X {};"));
+ runSymbolCollector("", /*Main=*/"#include \"test.inc\"",
+ /*ExtraArgs=*/{"-I", testRoot()});
+ EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("X"), DeclURI(IncURI),
+ IncludeHeader(IncURI))));
+}
+
+TEST_F(SymbolCollectorTest, AvoidUsingFwdDeclsAsCanonicalDecls) {
+ CollectorOpts.CollectIncludePath = true;
+ Annotations Header(R"(
+ // Forward declarations of TagDecls.
+ class C;
+ struct S;
+ union U;
+
+ // Canonical declarations.
+ class $cdecl[[C]] {};
+ struct $sdecl[[S]] {};
+ union $udecl[[U]] {int $xdecl[[x]]; bool $ydecl[[y]];};
+ )");
+ runSymbolCollector(Header.code(), /*Main=*/"");
+ EXPECT_THAT(
+ Symbols,
+ UnorderedElementsAre(
+ AllOf(QName("C"), DeclURI(TestHeaderURI),
+ DeclRange(Header.range("cdecl")), IncludeHeader(TestHeaderURI),
+ DefURI(TestHeaderURI), DefRange(Header.range("cdecl"))),
+ AllOf(QName("S"), DeclURI(TestHeaderURI),
+ DeclRange(Header.range("sdecl")), IncludeHeader(TestHeaderURI),
+ DefURI(TestHeaderURI), DefRange(Header.range("sdecl"))),
+ AllOf(QName("U"), DeclURI(TestHeaderURI),
+ DeclRange(Header.range("udecl")), IncludeHeader(TestHeaderURI),
+ DefURI(TestHeaderURI), DefRange(Header.range("udecl"))),
+ AllOf(QName("U::x"), DeclURI(TestHeaderURI),
+ DeclRange(Header.range("xdecl")), DefURI(TestHeaderURI),
+ DefRange(Header.range("xdecl"))),
+ AllOf(QName("U::y"), DeclURI(TestHeaderURI),
+ DeclRange(Header.range("ydecl")), DefURI(TestHeaderURI),
+ DefRange(Header.range("ydecl")))));
+}
+
+TEST_F(SymbolCollectorTest, ClassForwardDeclarationIsCanonical) {
+ CollectorOpts.CollectIncludePath = true;
+ runSymbolCollector(/*Header=*/"class X;", /*Main=*/"class X {};");
+ EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(
+ QName("X"), DeclURI(TestHeaderURI),
+ IncludeHeader(TestHeaderURI), DefURI(TestFileURI))));
+}
+
+TEST_F(SymbolCollectorTest, UTF16Character) {
+ // ö is 2-bytes.
+ Annotations Header(/*Header=*/"class [[pörk]] {};");
+ runSymbolCollector(Header.code(), /*Main=*/"");
+ EXPECT_THAT(Symbols, UnorderedElementsAre(
+ AllOf(QName("pörk"), DeclRange(Header.range()))));
+}
+
+TEST_F(SymbolCollectorTest, DoNotIndexSymbolsInFriendDecl) {
+ Annotations Header(R"(
+ namespace nx {
+ class $z[[Z]] {};
+ class X {
+ friend class Y;
+ friend class Z;
+ friend void foo();
+ friend void $bar[[bar]]() {}
+ };
+ class $y[[Y]] {};
+ void $foo[[foo]]();
+ }
+ )");
+ runSymbolCollector(Header.code(), /*Main=*/"");
+
+ EXPECT_THAT(Symbols,
+ UnorderedElementsAre(
+ QName("nx"), QName("nx::X"),
+ AllOf(QName("nx::Y"), DeclRange(Header.range("y"))),
+ AllOf(QName("nx::Z"), DeclRange(Header.range("z"))),
+ AllOf(QName("nx::foo"), DeclRange(Header.range("foo"))),
+ AllOf(QName("nx::bar"), DeclRange(Header.range("bar")))));
+}
+
+TEST_F(SymbolCollectorTest, ReferencesInFriendDecl) {
+ const std::string Header = R"(
+ class X;
+ class Y;
+ )";
+ const std::string Main = R"(
+ class C {
+ friend ::X;
+ friend class Y;
+ };
+ )";
+ CollectorOpts.CountReferences = true;
+ runSymbolCollector(Header, Main);
+ EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(QName("X"), Refs(1)),
+ AllOf(QName("Y"), Refs(1))));
+}
+
+TEST_F(SymbolCollectorTest, Origin) {
+ CollectorOpts.Origin = SymbolOrigin::Static;
+ runSymbolCollector("class Foo {};", /*Main=*/"");
+ EXPECT_THAT(Symbols, UnorderedElementsAre(
+ Field(&Symbol::Origin, SymbolOrigin::Static)));
+}
+
+TEST_F(SymbolCollectorTest, CollectMacros) {
+ CollectorOpts.CollectIncludePath = true;
+ Annotations Header(R"(
+ #define X 1
+ #define $mac[[MAC]](x) int x
+ #define $used[[USED]](y) float y;
+
+ MAC(p);
+ )");
+ const std::string Main = R"(
+ #define MAIN 1 // not indexed
+ USED(t);
+ )";
+ CollectorOpts.CountReferences = true;
+ CollectorOpts.CollectMacro = true;
+ runSymbolCollector(Header.code(), Main);
+ EXPECT_THAT(
+ Symbols,
+ UnorderedElementsAre(
+ QName("p"),
+ AllOf(QName("X"), DeclURI(TestHeaderURI),
+ IncludeHeader(TestHeaderURI)),
+ AllOf(Labeled("MAC(x)"), Refs(0), DeclRange(Header.range("mac"))),
+ AllOf(Labeled("USED(y)"), Refs(1), DeclRange(Header.range("used")))));
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/SyncAPI.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/SyncAPI.cpp
new file mode 100644
index 0000000..ae9ece5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/SyncAPI.cpp
@@ -0,0 +1,128 @@
+//===--- SyncAPI.cpp - Sync version of ClangdServer's API --------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#include "SyncAPI.h"
+
+namespace clang {
+namespace clangd {
+
+void runAddDocument(ClangdServer &Server, PathRef File, StringRef Contents,
+ WantDiagnostics WantDiags) {
+ Server.addDocument(File, Contents, WantDiags);
+ if (!Server.blockUntilIdleForTest())
+ llvm_unreachable("not idle after addDocument");
+}
+
+namespace {
+/// A helper that waits for async callbacks to fire and exposes their result in
+/// the output variable. Intended to be used in the following way:
+/// T Result;
+/// someAsyncFunc(Param1, Param2, /*Callback=*/capture(Result));
+template <typename T> struct CaptureProxy {
+ CaptureProxy(llvm::Optional<T> &Target) : Target(&Target) {
+ assert(!Target.hasValue());
+ }
+
+ CaptureProxy(const CaptureProxy &) = delete;
+ CaptureProxy &operator=(const CaptureProxy &) = delete;
+ // We need move ctor to return a value from the 'capture' helper.
+ CaptureProxy(CaptureProxy &&Other) : Target(Other.Target) {
+ Other.Target = nullptr;
+ }
+ CaptureProxy &operator=(CaptureProxy &&) = delete;
+
+ operator llvm::unique_function<void(T)>() && {
+ assert(!Future.valid() && "conversion to callback called multiple times");
+ Future = Promise.get_future();
+ return Bind(
+ [](std::promise<std::shared_ptr<T>> Promise, T Value) {
+ Promise.set_value(std::make_shared<T>(std::move(Value)));
+ },
+ std::move(Promise));
+ }
+
+ ~CaptureProxy() {
+ if (!Target)
+ return;
+ assert(Future.valid() && "conversion to callback was not called");
+ assert(!Target->hasValue());
+ Target->emplace(std::move(*Future.get()));
+ }
+
+private:
+ llvm::Optional<T> *Target;
+ // Using shared_ptr to workaround compilation errors with MSVC.
+ // MSVC only allows default-construcitble and copyable objects as future<>
+ // arguments.
+ std::promise<std::shared_ptr<T>> Promise;
+ std::future<std::shared_ptr<T>> Future;
+};
+
+template <typename T> CaptureProxy<T> capture(llvm::Optional<T> &Target) {
+ return CaptureProxy<T>(Target);
+}
+} // namespace
+
+llvm::Expected<CodeCompleteResult>
+runCodeComplete(ClangdServer &Server, PathRef File, Position Pos,
+ clangd::CodeCompleteOptions Opts) {
+ llvm::Optional<llvm::Expected<CodeCompleteResult>> Result;
+ Server.codeComplete(File, Pos, Opts, capture(Result));
+ return std::move(*Result);
+}
+
+llvm::Expected<SignatureHelp> runSignatureHelp(ClangdServer &Server,
+ PathRef File, Position Pos) {
+ llvm::Optional<llvm::Expected<SignatureHelp>> Result;
+ Server.signatureHelp(File, Pos, capture(Result));
+ return std::move(*Result);
+}
+
+llvm::Expected<std::vector<Location>>
+runFindDefinitions(ClangdServer &Server, PathRef File, Position Pos) {
+ llvm::Optional<llvm::Expected<std::vector<Location>>> Result;
+ Server.findDefinitions(File, Pos, capture(Result));
+ return std::move(*Result);
+}
+
+llvm::Expected<std::vector<DocumentHighlight>>
+runFindDocumentHighlights(ClangdServer &Server, PathRef File, Position Pos) {
+ llvm::Optional<llvm::Expected<std::vector<DocumentHighlight>>> Result;
+ Server.findDocumentHighlights(File, Pos, capture(Result));
+ return std::move(*Result);
+}
+
+llvm::Expected<std::vector<tooling::Replacement>>
+runRename(ClangdServer &Server, PathRef File, Position Pos, StringRef NewName) {
+ llvm::Optional<llvm::Expected<std::vector<tooling::Replacement>>> Result;
+ Server.rename(File, Pos, NewName, capture(Result));
+ return std::move(*Result);
+}
+
+std::string runDumpAST(ClangdServer &Server, PathRef File) {
+ llvm::Optional<std::string> Result;
+ Server.dumpAST(File, capture(Result));
+ return std::move(*Result);
+}
+
+llvm::Expected<std::vector<SymbolInformation>>
+runWorkspaceSymbols(ClangdServer &Server, StringRef Query, int Limit) {
+ llvm::Optional<llvm::Expected<std::vector<SymbolInformation>>> Result;
+ Server.workspaceSymbols(Query, Limit, capture(Result));
+ return std::move(*Result);
+}
+
+llvm::Expected<std::vector<SymbolInformation>>
+runDocumentSymbols(ClangdServer &Server, PathRef File) {
+ llvm::Optional<llvm::Expected<std::vector<SymbolInformation>>> Result;
+ Server.documentSymbols(File, capture(Result));
+ return std::move(*Result);
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/SyncAPI.h b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/SyncAPI.h
new file mode 100644
index 0000000..ddf90d8
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/SyncAPI.h
@@ -0,0 +1,52 @@
+//===--- SyncAPI.h - Sync version of ClangdServer's API ----------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+// This file contains synchronous versions of ClangdServer's async API. We
+// deliberately don't expose the sync API outside tests to encourage using the
+// async versions in clangd code.
+#ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_SYNCAPI_H
+#define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_SYNCAPI_H
+
+#include "ClangdServer.h"
+#include <future>
+
+namespace clang {
+namespace clangd {
+
+// Calls addDocument and then blockUntilIdleForTest.
+void runAddDocument(ClangdServer &Server, PathRef File, StringRef Contents,
+ WantDiagnostics WantDiags = WantDiagnostics::Auto);
+
+llvm::Expected<CodeCompleteResult>
+runCodeComplete(ClangdServer &Server, PathRef File, Position Pos,
+ clangd::CodeCompleteOptions Opts);
+
+llvm::Expected<SignatureHelp> runSignatureHelp(ClangdServer &Server,
+ PathRef File, Position Pos);
+
+llvm::Expected<std::vector<Location>>
+runFindDefinitions(ClangdServer &Server, PathRef File, Position Pos);
+
+llvm::Expected<std::vector<DocumentHighlight>>
+runFindDocumentHighlights(ClangdServer &Server, PathRef File, Position Pos);
+
+llvm::Expected<std::vector<tooling::Replacement>>
+runRename(ClangdServer &Server, PathRef File, Position Pos, StringRef NewName);
+
+std::string runDumpAST(ClangdServer &Server, PathRef File);
+
+llvm::Expected<std::vector<SymbolInformation>>
+runWorkspaceSymbols(ClangdServer &Server, StringRef Query, int Limit);
+
+llvm::Expected<std::vector<SymbolInformation>>
+runDocumentSymbols(ClangdServer &Server, PathRef File);
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TUSchedulerTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TUSchedulerTests.cpp
new file mode 100644
index 0000000..138a4e2
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TUSchedulerTests.cpp
@@ -0,0 +1,428 @@
+//===-- TUSchedulerTests.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Context.h"
+#include "TUScheduler.h"
+#include "TestFS.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <algorithm>
+#include <utility>
+
+namespace clang {
+namespace clangd {
+
+using ::testing::_;
+using ::testing::Each;
+using ::testing::AnyOf;
+using ::testing::Pair;
+using ::testing::Pointee;
+using ::testing::UnorderedElementsAre;
+
+void ignoreUpdate(llvm::Optional<std::vector<Diag>>) {}
+void ignoreError(llvm::Error Err) {
+ handleAllErrors(std::move(Err), [](const llvm::ErrorInfoBase &) {});
+}
+
+class TUSchedulerTests : public ::testing::Test {
+protected:
+ ParseInputs getInputs(PathRef File, std::string Contents) {
+ return ParseInputs{*CDB.getCompileCommand(File),
+ buildTestFS(Files, Timestamps), std::move(Contents)};
+ }
+
+ llvm::StringMap<std::string> Files;
+ llvm::StringMap<time_t> Timestamps;
+ MockCompilationDatabase CDB;
+};
+
+TEST_F(TUSchedulerTests, MissingFiles) {
+ TUScheduler S(getDefaultAsyncThreadsCount(),
+ /*StorePreamblesInMemory=*/true,
+ /*PreambleParsedCallback=*/nullptr,
+ /*UpdateDebounce=*/std::chrono::steady_clock::duration::zero(),
+ ASTRetentionPolicy());
+
+ auto Added = testPath("added.cpp");
+ Files[Added] = "";
+
+ auto Missing = testPath("missing.cpp");
+ Files[Missing] = "";
+
+ S.update(Added, getInputs(Added, ""), WantDiagnostics::No, ignoreUpdate);
+
+ // Assert each operation for missing file is an error (even if it's available
+ // in VFS).
+ S.runWithAST("", Missing, [&](llvm::Expected<InputsAndAST> AST) {
+ ASSERT_FALSE(bool(AST));
+ ignoreError(AST.takeError());
+ });
+ S.runWithPreamble("", Missing,
+ [&](llvm::Expected<InputsAndPreamble> Preamble) {
+ ASSERT_FALSE(bool(Preamble));
+ ignoreError(Preamble.takeError());
+ });
+ // remove() shouldn't crash on missing files.
+ S.remove(Missing);
+
+ // Assert there aren't any errors for added file.
+ S.runWithAST("", Added, [&](llvm::Expected<InputsAndAST> AST) {
+ EXPECT_TRUE(bool(AST));
+ });
+ S.runWithPreamble("", Added, [&](llvm::Expected<InputsAndPreamble> Preamble) {
+ EXPECT_TRUE(bool(Preamble));
+ });
+ S.remove(Added);
+
+ // Assert that all operations fail after removing the file.
+ S.runWithAST("", Added, [&](llvm::Expected<InputsAndAST> AST) {
+ ASSERT_FALSE(bool(AST));
+ ignoreError(AST.takeError());
+ });
+ S.runWithPreamble("", Added, [&](llvm::Expected<InputsAndPreamble> Preamble) {
+ ASSERT_FALSE(bool(Preamble));
+ ignoreError(Preamble.takeError());
+ });
+ // remove() shouldn't crash on missing files.
+ S.remove(Added);
+}
+
+TEST_F(TUSchedulerTests, WantDiagnostics) {
+ std::atomic<int> CallbackCount(0);
+ {
+ // To avoid a racy test, don't allow tasks to actualy run on the worker
+ // thread until we've scheduled them all.
+ Notification Ready;
+ TUScheduler S(
+ getDefaultAsyncThreadsCount(),
+ /*StorePreamblesInMemory=*/true,
+ /*PreambleParsedCallback=*/nullptr,
+ /*UpdateDebounce=*/std::chrono::steady_clock::duration::zero(),
+ ASTRetentionPolicy());
+ auto Path = testPath("foo.cpp");
+ S.update(Path, getInputs(Path, ""), WantDiagnostics::Yes,
+ [&](std::vector<Diag>) { Ready.wait(); });
+
+ S.update(Path, getInputs(Path, "request diags"), WantDiagnostics::Yes,
+ [&](std::vector<Diag> Diags) { ++CallbackCount; });
+ S.update(Path, getInputs(Path, "auto (clobbered)"), WantDiagnostics::Auto,
+ [&](std::vector<Diag> Diags) {
+ ADD_FAILURE() << "auto should have been cancelled by auto";
+ });
+ S.update(Path, getInputs(Path, "request no diags"), WantDiagnostics::No,
+ [&](std::vector<Diag> Diags) {
+ ADD_FAILURE() << "no diags should not be called back";
+ });
+ S.update(Path, getInputs(Path, "auto (produces)"), WantDiagnostics::Auto,
+ [&](std::vector<Diag> Diags) { ++CallbackCount; });
+ Ready.notify();
+ }
+ EXPECT_EQ(2, CallbackCount);
+}
+
+TEST_F(TUSchedulerTests, Debounce) {
+ std::atomic<int> CallbackCount(0);
+ {
+ TUScheduler S(getDefaultAsyncThreadsCount(),
+ /*StorePreamblesInMemory=*/true,
+ /*PreambleParsedCallback=*/nullptr,
+ /*UpdateDebounce=*/std::chrono::seconds(1),
+ ASTRetentionPolicy());
+ // FIXME: we could probably use timeouts lower than 1 second here.
+ auto Path = testPath("foo.cpp");
+ S.update(Path, getInputs(Path, "auto (debounced)"), WantDiagnostics::Auto,
+ [&](std::vector<Diag> Diags) {
+ ADD_FAILURE() << "auto should have been debounced and canceled";
+ });
+ std::this_thread::sleep_for(std::chrono::milliseconds(200));
+ S.update(Path, getInputs(Path, "auto (timed out)"), WantDiagnostics::Auto,
+ [&](std::vector<Diag> Diags) { ++CallbackCount; });
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ S.update(Path, getInputs(Path, "auto (shut down)"), WantDiagnostics::Auto,
+ [&](std::vector<Diag> Diags) { ++CallbackCount; });
+ }
+ EXPECT_EQ(2, CallbackCount);
+}
+
+TEST_F(TUSchedulerTests, ManyUpdates) {
+ const int FilesCount = 3;
+ const int UpdatesPerFile = 10;
+
+ std::mutex Mut;
+ int TotalASTReads = 0;
+ int TotalPreambleReads = 0;
+ int TotalUpdates = 0;
+
+ // Run TUScheduler and collect some stats.
+ {
+ TUScheduler S(getDefaultAsyncThreadsCount(),
+ /*StorePreamblesInMemory=*/true,
+ /*PreambleParsedCallback=*/nullptr,
+ /*UpdateDebounce=*/std::chrono::milliseconds(50),
+ ASTRetentionPolicy());
+
+ std::vector<std::string> Files;
+ for (int I = 0; I < FilesCount; ++I) {
+ std::string Name = "foo" + std::to_string(I) + ".cpp";
+ Files.push_back(testPath(Name));
+ this->Files[Files.back()] = "";
+ }
+
+ llvm::StringRef Contents1 = R"cpp(int a;)cpp";
+ llvm::StringRef Contents2 = R"cpp(int main() { return 1; })cpp";
+ llvm::StringRef Contents3 =
+ R"cpp(int a; int b; int sum() { return a + b; })cpp";
+
+ llvm::StringRef AllContents[] = {Contents1, Contents2, Contents3};
+ const int AllContentsSize = 3;
+
+ // Scheduler may run tasks asynchronously, but should propagate the context.
+ // We stash a nonce in the context, and verify it in the task.
+ static Key<int> NonceKey;
+ int Nonce = 0;
+
+ for (int FileI = 0; FileI < FilesCount; ++FileI) {
+ for (int UpdateI = 0; UpdateI < UpdatesPerFile; ++UpdateI) {
+ auto Contents = AllContents[(FileI + UpdateI) % AllContentsSize];
+
+ auto File = Files[FileI];
+ auto Inputs = getInputs(File, Contents.str());
+
+ {
+ WithContextValue WithNonce(NonceKey, ++Nonce);
+ S.update(File, Inputs, WantDiagnostics::Auto,
+ [Nonce, &Mut,
+ &TotalUpdates](llvm::Optional<std::vector<Diag>> Diags) {
+ EXPECT_THAT(Context::current().get(NonceKey),
+ Pointee(Nonce));
+
+ std::lock_guard<std::mutex> Lock(Mut);
+ ++TotalUpdates;
+ });
+ }
+
+ {
+ WithContextValue WithNonce(NonceKey, ++Nonce);
+ S.runWithAST("CheckAST", File,
+ [Inputs, Nonce, &Mut,
+ &TotalASTReads](llvm::Expected<InputsAndAST> AST) {
+ EXPECT_THAT(Context::current().get(NonceKey),
+ Pointee(Nonce));
+
+ ASSERT_TRUE((bool)AST);
+ EXPECT_EQ(AST->Inputs.FS, Inputs.FS);
+ EXPECT_EQ(AST->Inputs.Contents, Inputs.Contents);
+
+ std::lock_guard<std::mutex> Lock(Mut);
+ ++TotalASTReads;
+ });
+ }
+
+ {
+ WithContextValue WithNonce(NonceKey, ++Nonce);
+ S.runWithPreamble("CheckPreamble", File,
+ [Inputs, Nonce, &Mut, &TotalPreambleReads](
+ llvm::Expected<InputsAndPreamble> Preamble) {
+ EXPECT_THAT(Context::current().get(NonceKey),
+ Pointee(Nonce));
+
+ ASSERT_TRUE((bool)Preamble);
+ EXPECT_EQ(Preamble->Contents, Inputs.Contents);
+
+ std::lock_guard<std::mutex> Lock(Mut);
+ ++TotalPreambleReads;
+ });
+ }
+ }
+ }
+ } // TUScheduler destructor waits for all operations to finish.
+
+ std::lock_guard<std::mutex> Lock(Mut);
+ EXPECT_EQ(TotalUpdates, FilesCount * UpdatesPerFile);
+ EXPECT_EQ(TotalASTReads, FilesCount * UpdatesPerFile);
+ EXPECT_EQ(TotalPreambleReads, FilesCount * UpdatesPerFile);
+}
+
+TEST_F(TUSchedulerTests, EvictedAST) {
+ std::atomic<int> BuiltASTCounter(0);
+ ASTRetentionPolicy Policy;
+ Policy.MaxRetainedASTs = 2;
+ TUScheduler S(
+ /*AsyncThreadsCount=*/1, /*StorePreambleInMemory=*/true,
+ PreambleParsedCallback(),
+ /*UpdateDebounce=*/std::chrono::steady_clock::duration::zero(), Policy);
+
+ llvm::StringLiteral SourceContents = R"cpp(
+ int* a;
+ double* b = a;
+ )cpp";
+ llvm::StringLiteral OtherSourceContents = R"cpp(
+ int* a;
+ double* b = a + 0;
+ )cpp";
+
+ auto Foo = testPath("foo.cpp");
+ auto Bar = testPath("bar.cpp");
+ auto Baz = testPath("baz.cpp");
+
+ // Build one file in advance. We will not access it later, so it will be the
+ // one that the cache will evict.
+ S.update(Foo, getInputs(Foo, SourceContents), WantDiagnostics::Yes,
+ [&BuiltASTCounter](std::vector<Diag> Diags) { ++BuiltASTCounter; });
+ ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(1)));
+ ASSERT_EQ(BuiltASTCounter.load(), 1);
+
+ // Build two more files. Since we can retain only 2 ASTs, these should be the
+ // ones we see in the cache later.
+ S.update(Bar, getInputs(Bar, SourceContents), WantDiagnostics::Yes,
+ [&BuiltASTCounter](std::vector<Diag> Diags) { ++BuiltASTCounter; });
+ S.update(Baz, getInputs(Baz, SourceContents), WantDiagnostics::Yes,
+ [&BuiltASTCounter](std::vector<Diag> Diags) { ++BuiltASTCounter; });
+ ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(1)));
+ ASSERT_EQ(BuiltASTCounter.load(), 3);
+
+ // Check only the last two ASTs are retained.
+ ASSERT_THAT(S.getFilesWithCachedAST(), UnorderedElementsAre(Bar, Baz));
+
+ // Access the old file again.
+ S.update(Foo, getInputs(Foo, OtherSourceContents), WantDiagnostics::Yes,
+ [&BuiltASTCounter](std::vector<Diag> Diags) { ++BuiltASTCounter; });
+ ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(1)));
+ ASSERT_EQ(BuiltASTCounter.load(), 4);
+
+ // Check the AST for foo.cpp is retained now and one of the others got
+ // evicted.
+ EXPECT_THAT(S.getFilesWithCachedAST(),
+ UnorderedElementsAre(Foo, AnyOf(Bar, Baz)));
+}
+
+TEST_F(TUSchedulerTests, RunWaitsForPreamble) {
+ // Testing strategy: we update the file and schedule a few preamble reads at
+ // the same time. All reads should get the same non-null preamble.
+ TUScheduler S(
+ /*AsyncThreadsCount=*/4, /*StorePreambleInMemory=*/true,
+ PreambleParsedCallback(),
+ /*UpdateDebounce=*/std::chrono::steady_clock::duration::zero(),
+ ASTRetentionPolicy());
+ auto Foo = testPath("foo.cpp");
+ auto NonEmptyPreamble = R"cpp(
+ #define FOO 1
+ #define BAR 2
+
+ int main() {}
+ )cpp";
+ constexpr int ReadsToSchedule = 10;
+ std::mutex PreamblesMut;
+ std::vector<const void *> Preambles(ReadsToSchedule, nullptr);
+ S.update(Foo, getInputs(Foo, NonEmptyPreamble), WantDiagnostics::Auto,
+ [](std::vector<Diag>) {});
+ for (int I = 0; I < ReadsToSchedule; ++I) {
+ S.runWithPreamble(
+ "test", Foo,
+ [I, &PreamblesMut, &Preambles](llvm::Expected<InputsAndPreamble> IP) {
+ std::lock_guard<std::mutex> Lock(PreamblesMut);
+ Preambles[I] = cantFail(std::move(IP)).Preamble;
+ });
+ }
+ ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(10)));
+ // Check all actions got the same non-null preamble.
+ std::lock_guard<std::mutex> Lock(PreamblesMut);
+ ASSERT_NE(Preambles[0], nullptr);
+ ASSERT_THAT(Preambles, Each(Preambles[0]));
+}
+
+TEST_F(TUSchedulerTests, NoopOnEmptyChanges) {
+ TUScheduler S(
+ /*AsyncThreadsCount=*/getDefaultAsyncThreadsCount(),
+ /*StorePreambleInMemory=*/true, PreambleParsedCallback(),
+ /*UpdateDebounce=*/std::chrono::steady_clock::duration::zero(),
+ ASTRetentionPolicy());
+
+ auto Source = testPath("foo.cpp");
+ auto Header = testPath("foo.h");
+
+ Files[Header] = "int a;";
+ Timestamps[Header] = time_t(0);
+
+ auto SourceContents = R"cpp(
+ #include "foo.h"
+ int b = a;
+ )cpp";
+
+ // Return value indicates if the updated callback was received.
+ auto DoUpdate = [&](ParseInputs Inputs) -> bool {
+ std::atomic<bool> Updated(false);
+ Updated = false;
+ S.update(Source, std::move(Inputs), WantDiagnostics::Yes,
+ [&Updated](std::vector<Diag>) { Updated = true; });
+ bool UpdateFinished = S.blockUntilIdle(timeoutSeconds(1));
+ if (!UpdateFinished)
+ ADD_FAILURE() << "Updated has not finished in one second. Threading bug?";
+ return Updated;
+ };
+
+ // Test that subsequent updates with the same inputs do not cause rebuilds.
+ ASSERT_TRUE(DoUpdate(getInputs(Source, SourceContents)));
+ ASSERT_FALSE(DoUpdate(getInputs(Source, SourceContents)));
+
+ // Update to a header should cause a rebuild, though.
+ Files[Header] = time_t(1);
+ ASSERT_TRUE(DoUpdate(getInputs(Source, SourceContents)));
+ ASSERT_FALSE(DoUpdate(getInputs(Source, SourceContents)));
+
+ // Update to the contents should cause a rebuild.
+ auto OtherSourceContents = R"cpp(
+ #include "foo.h"
+ int c = d;
+ )cpp";
+ ASSERT_TRUE(DoUpdate(getInputs(Source, OtherSourceContents)));
+ ASSERT_FALSE(DoUpdate(getInputs(Source, OtherSourceContents)));
+
+ // Update to the compile commands should also cause a rebuild.
+ CDB.ExtraClangFlags.push_back("-DSOMETHING");
+ ASSERT_TRUE(DoUpdate(getInputs(Source, OtherSourceContents)));
+ ASSERT_FALSE(DoUpdate(getInputs(Source, OtherSourceContents)));
+}
+
+TEST_F(TUSchedulerTests, NoChangeDiags) {
+ TUScheduler S(
+ /*AsyncThreadsCount=*/getDefaultAsyncThreadsCount(),
+ /*StorePreambleInMemory=*/true, PreambleParsedCallback(),
+ /*UpdateDebounce=*/std::chrono::steady_clock::duration::zero(),
+ ASTRetentionPolicy());
+
+ auto FooCpp = testPath("foo.cpp");
+ auto Contents = "int a; int b;";
+
+ S.update(FooCpp, getInputs(FooCpp, Contents), WantDiagnostics::No,
+ [](std::vector<Diag>) { ADD_FAILURE() << "Should not be called."; });
+ S.runWithAST("touchAST", FooCpp, [](llvm::Expected<InputsAndAST> IA) {
+ // Make sure the AST was actually built.
+ cantFail(std::move(IA));
+ });
+ ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(1)));
+
+ // Even though the inputs didn't change and AST can be reused, we need to
+ // report the diagnostics, as they were not reported previously.
+ std::atomic<bool> SeenDiags(false);
+ S.update(FooCpp, getInputs(FooCpp, Contents), WantDiagnostics::Auto,
+ [&](std::vector<Diag>) { SeenDiags = true; });
+ ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(1)));
+ ASSERT_TRUE(SeenDiags);
+
+ // Subsequent request does not get any diagnostics callback because the same
+ // diags have previously been reported and the inputs didn't change.
+ S.update(
+ FooCpp, getInputs(FooCpp, Contents), WantDiagnostics::Auto,
+ [&](std::vector<Diag>) { ADD_FAILURE() << "Should not be called."; });
+ ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(1)));
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestFS.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestFS.cpp
new file mode 100644
index 0000000..b3081d6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestFS.cpp
@@ -0,0 +1,111 @@
+//===-- TestFS.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "TestFS.h"
+#include "URI.h"
+#include "clang/AST/DeclCXX.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Path.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+IntrusiveRefCntPtr<vfs::FileSystem>
+buildTestFS(llvm::StringMap<std::string> const &Files,
+ llvm::StringMap<time_t> const &Timestamps) {
+ IntrusiveRefCntPtr<vfs::InMemoryFileSystem> MemFS(
+ new vfs::InMemoryFileSystem);
+ for (auto &FileAndContents : Files) {
+ StringRef File = FileAndContents.first();
+ MemFS->addFile(
+ File, Timestamps.lookup(File),
+ MemoryBuffer::getMemBufferCopy(FileAndContents.second, File));
+ }
+ return MemFS;
+}
+
+MockCompilationDatabase::MockCompilationDatabase(bool UseRelPaths)
+ : ExtraClangFlags({"-ffreestanding"}), UseRelPaths(UseRelPaths) {
+ // -ffreestanding avoids implicit stdc-predef.h.
+}
+
+Optional<tooling::CompileCommand>
+MockCompilationDatabase::getCompileCommand(PathRef File) const {
+ if (ExtraClangFlags.empty())
+ return None;
+
+ auto CommandLine = ExtraClangFlags;
+ auto FileName = sys::path::filename(File);
+ CommandLine.insert(CommandLine.begin(), "clang");
+ CommandLine.insert(CommandLine.end(), UseRelPaths ? FileName : File);
+ return {tooling::CompileCommand(sys::path::parent_path(File), FileName,
+ std::move(CommandLine), "")};
+}
+
+const char *testRoot() {
+#ifdef _WIN32
+ return "C:\\clangd-test";
+#else
+ return "/clangd-test";
+#endif
+}
+
+std::string testPath(PathRef File) {
+ assert(sys::path::is_relative(File) && "FileName should be relative");
+
+ SmallString<32> NativeFile = File;
+ sys::path::native(NativeFile);
+ SmallString<32> Path;
+ sys::path::append(Path, testRoot(), NativeFile);
+ return Path.str();
+}
+
+/// unittest: is a scheme that refers to files relative to testRoot().
+/// URI body is a path relative to testRoot() e.g. unittest:///x.h for
+/// /clangd-test/x.h.
+class TestScheme : public URIScheme {
+public:
+ static const char *Scheme;
+
+ llvm::Expected<std::string>
+ getAbsolutePath(llvm::StringRef /*Authority*/, llvm::StringRef Body,
+ llvm::StringRef HintPath) const override {
+ assert(HintPath.startswith(testRoot()));
+ if (!Body.consume_front("/"))
+ return llvm::make_error<llvm::StringError>(
+ "Body of an unittest: URI must start with '/'",
+ llvm::inconvertibleErrorCode());
+ llvm::SmallString<16> Path(Body.begin(), Body.end());
+ llvm::sys::path::native(Path);
+ return testPath(Path);
+ }
+
+ llvm::Expected<URI>
+ uriFromAbsolutePath(llvm::StringRef AbsolutePath) const override {
+ llvm::StringRef Body = AbsolutePath;
+ if (!Body.consume_front(testRoot()))
+ return llvm::make_error<llvm::StringError>(
+ AbsolutePath + "does not start with " + testRoot(),
+ llvm::inconvertibleErrorCode());
+
+ return URI(Scheme, /*Authority=*/"",
+ llvm::sys::path::convert_to_slash(Body));
+ }
+};
+
+const char *TestScheme::Scheme = "unittest";
+
+static URISchemeRegistry::Add<TestScheme> X(TestScheme::Scheme, "Test schema");
+
+volatile int UnittestSchemeAnchorSource = 0;
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestFS.h b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestFS.h
new file mode 100644
index 0000000..9c2a15e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestFS.h
@@ -0,0 +1,67 @@
+//===-- TestFS.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Allows setting up fake filesystem environments for tests.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_TESTFS_H
+#define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_TESTFS_H
+#include "ClangdServer.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/Support/Path.h"
+
+namespace clang {
+namespace clangd {
+
+// Builds a VFS that provides access to the provided files, plus temporary
+// directories.
+llvm::IntrusiveRefCntPtr<vfs::FileSystem>
+buildTestFS(llvm::StringMap<std::string> const &Files,
+ llvm::StringMap<time_t> const &Timestamps = {});
+
+// A VFS provider that returns TestFSes containing a provided set of files.
+class MockFSProvider : public FileSystemProvider {
+public:
+ IntrusiveRefCntPtr<vfs::FileSystem> getFileSystem() override {
+ return buildTestFS(Files);
+ }
+
+ // If relative paths are used, they are resolved with testPath().
+ llvm::StringMap<std::string> Files;
+};
+
+// A Compilation database that returns a fixed set of compile flags.
+class MockCompilationDatabase : public GlobalCompilationDatabase {
+public:
+ /// When \p UseRelPaths is true, uses relative paths in compile commands.
+ /// When \p UseRelPaths is false, uses absoulte paths.
+ MockCompilationDatabase(bool UseRelPaths = false);
+
+ llvm::Optional<tooling::CompileCommand>
+ getCompileCommand(PathRef File) const override;
+
+ std::vector<std::string> ExtraClangFlags;
+ const bool UseRelPaths;
+};
+
+// Returns an absolute (fake) test directory for this OS.
+const char *testRoot();
+
+// Returns a suitable absolute path for this OS.
+std::string testPath(PathRef File);
+
+// unittest: is a scheme that refers to files relative to testRoot()
+// This anchor is used to force the linker to link in the generated object file
+// and thus register unittest: URI scheme plugin.
+extern volatile int UnittestSchemeAnchorSource;
+
+} // namespace clangd
+} // namespace clang
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestScheme.h b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestScheme.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestScheme.h
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestTU.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestTU.cpp
new file mode 100644
index 0000000..b47d944
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestTU.cpp
@@ -0,0 +1,127 @@
+//===--- TestTU.cpp - Scratch source files for testing --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#include "TestTU.h"
+#include "TestFS.h"
+#include "index/FileIndex.h"
+#include "index/MemIndex.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/PCHContainerOperations.h"
+#include "clang/Frontend/Utils.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+ParsedAST TestTU::build() const {
+ std::string FullFilename = testPath(Filename),
+ FullHeaderName = testPath(HeaderFilename);
+ std::vector<const char *> Cmd = {"clang", FullFilename.c_str()};
+ // FIXME: this shouldn't need to be conditional, but it breaks a
+ // GoToDefinition test for some reason (getMacroArgExpandedLocation fails).
+ if (!HeaderCode.empty()) {
+ Cmd.push_back("-include");
+ Cmd.push_back(FullHeaderName.c_str());
+ }
+ Cmd.insert(Cmd.end(), ExtraArgs.begin(), ExtraArgs.end());
+ auto AST = ParsedAST::build(
+ createInvocationFromCommandLine(Cmd), nullptr,
+ MemoryBuffer::getMemBufferCopy(Code),
+ std::make_shared<PCHContainerOperations>(),
+ buildTestFS({{FullFilename, Code}, {FullHeaderName, HeaderCode}}));
+ if (!AST.hasValue()) {
+ ADD_FAILURE() << "Failed to build code:\n" << Code;
+ llvm_unreachable("Failed to build TestTU!");
+ }
+ return std::move(*AST);
+}
+
+SymbolSlab TestTU::headerSymbols() const {
+ auto AST = build();
+ return indexAST(AST.getASTContext(), AST.getPreprocessorPtr());
+}
+
+std::unique_ptr<SymbolIndex> TestTU::index() const {
+ return MemIndex::build(headerSymbols());
+}
+
+const Symbol &findSymbol(const SymbolSlab &Slab, llvm::StringRef QName) {
+ const Symbol *Result = nullptr;
+ for (const Symbol &S : Slab) {
+ if (QName != (S.Scope + S.Name).str())
+ continue;
+ if (Result) {
+ ADD_FAILURE() << "Multiple symbols named " << QName << ":\n"
+ << *Result << "\n---\n"
+ << S;
+ assert(false && "QName is not unique");
+ }
+ Result = &S;
+ }
+ if (!Result) {
+ ADD_FAILURE() << "No symbol named " << QName << " in "
+ << ::testing::PrintToString(Slab);
+ assert(false && "No symbol with QName");
+ }
+ return *Result;
+}
+
+const NamedDecl &findDecl(ParsedAST &AST, llvm::StringRef QName) {
+ llvm::SmallVector<llvm::StringRef, 4> Components;
+ QName.split(Components, "::");
+
+ auto &Ctx = AST.getASTContext();
+ auto LookupDecl = [&Ctx](const DeclContext &Scope,
+ llvm::StringRef Name) -> const NamedDecl & {
+ auto LookupRes = Scope.lookup(DeclarationName(&Ctx.Idents.get(Name)));
+ assert(!LookupRes.empty() && "Lookup failed");
+ assert(LookupRes.size() == 1 && "Lookup returned multiple results");
+ return *LookupRes.front();
+ };
+
+ const DeclContext *Scope = Ctx.getTranslationUnitDecl();
+ for (auto NameIt = Components.begin(), End = Components.end() - 1;
+ NameIt != End; ++NameIt) {
+ Scope = &cast<DeclContext>(LookupDecl(*Scope, *NameIt));
+ }
+ return LookupDecl(*Scope, Components.back());
+}
+
+const NamedDecl &findAnyDecl(ParsedAST &AST,
+ std::function<bool(const NamedDecl &)> Callback) {
+ struct Visitor : RecursiveASTVisitor<Visitor> {
+ decltype(Callback) CB;
+ llvm::SmallVector<const NamedDecl *, 1> Decls;
+ bool VisitNamedDecl(const NamedDecl *ND) {
+ if (CB(*ND))
+ Decls.push_back(ND);
+ return true;
+ }
+ } Visitor;
+ Visitor.CB = Callback;
+ for (Decl *D : AST.getLocalTopLevelDecls())
+ Visitor.TraverseDecl(D);
+ if (Visitor.Decls.size() != 1) {
+ ADD_FAILURE() << Visitor.Decls.size() << " symbols matched.";
+ assert(Visitor.Decls.size() == 1);
+ }
+ return *Visitor.Decls.front();
+}
+
+const NamedDecl &findAnyDecl(ParsedAST &AST, llvm::StringRef Name) {
+ return findAnyDecl(AST, [Name](const NamedDecl &ND) {
+ if (auto *ID = ND.getIdentifier())
+ if (ID->getName() == Name)
+ return true;
+ return false;
+ });
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestTU.h b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestTU.h
new file mode 100644
index 0000000..b66159e
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TestTU.h
@@ -0,0 +1,67 @@
+//===--- TestTU.h - Scratch source files for testing ------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// Many tests for indexing, code completion etc are most naturally expressed
+// using code examples.
+// TestTU lets test define these examples in a common way without dealing with
+// the mechanics of VFS and compiler interactions, and then easily grab the
+// AST, particular symbols, etc.
+//
+//===---------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_TESTTU_H
+#define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_TESTTU_H
+#include "ClangdUnit.h"
+#include "index/Index.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+
+struct TestTU {
+ static TestTU withCode(llvm::StringRef Code) {
+ TestTU TU;
+ TU.Code = Code;
+ return TU;
+ }
+
+ static TestTU withHeaderCode(llvm::StringRef HeaderCode) {
+ TestTU TU;
+ TU.HeaderCode = HeaderCode;
+ return TU;
+ }
+
+ // The code to be compiled.
+ std::string Code;
+ std::string Filename = "TestTU.cpp";
+
+ // Define contents of a header which will be implicitly included by Code.
+ std::string HeaderCode;
+ std::string HeaderFilename = "TestTU.h";
+
+ // Extra arguments for the compiler invocation.
+ std::vector<const char *> ExtraArgs;
+
+ ParsedAST build() const;
+ SymbolSlab headerSymbols() const;
+ std::unique_ptr<SymbolIndex> index() const;
+};
+
+// Look up an index symbol by qualified name, which must be unique.
+const Symbol &findSymbol(const SymbolSlab &, llvm::StringRef QName);
+// Look up an AST symbol by qualified name, which must be unique and top-level.
+const NamedDecl &findDecl(ParsedAST &AST, llvm::StringRef QName);
+// Look up a main-file AST symbol that satisfies \p Filter.
+const NamedDecl &findAnyDecl(ParsedAST &AST,
+ std::function<bool(const NamedDecl &)> Filter);
+// Look up a main-file AST symbol by unqualified name, which must be unique.
+const NamedDecl &findAnyDecl(ParsedAST &AST, llvm::StringRef Name);
+
+} // namespace clangd
+} // namespace clang
+#endif
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/ThreadingTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/ThreadingTests.cpp
new file mode 100644
index 0000000..dd27dcc
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/ThreadingTests.cpp
@@ -0,0 +1,65 @@
+//===-- ThreadingTests.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Threading.h"
+#include "gtest/gtest.h"
+#include <mutex>
+
+namespace clang {
+namespace clangd {
+class ThreadingTest : public ::testing::Test {};
+
+TEST_F(ThreadingTest, TaskRunner) {
+ const int TasksCnt = 100;
+ // This should be const, but MSVC does not allow to use const vars in lambdas
+ // without capture. On the other hand, clang gives a warning that capture of
+ // const var is not required.
+ // Making it non-const makes both compilers happy.
+ int IncrementsPerTask = 1000;
+
+ std::mutex Mutex;
+ int Counter(0); /* GUARDED_BY(Mutex) */
+ {
+ AsyncTaskRunner Tasks;
+ auto scheduleIncrements = [&]() {
+ for (int TaskI = 0; TaskI < TasksCnt; ++TaskI) {
+ Tasks.runAsync("task", [&Counter, &Mutex, IncrementsPerTask]() {
+ for (int Increment = 0; Increment < IncrementsPerTask; ++Increment) {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ ++Counter;
+ }
+ });
+ }
+ };
+
+ {
+ // Make sure runAsync is not running tasks synchronously on the same
+ // thread by locking the Mutex used for increments.
+ std::lock_guard<std::mutex> Lock(Mutex);
+ scheduleIncrements();
+ }
+
+ Tasks.wait();
+ {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ ASSERT_EQ(Counter, TasksCnt * IncrementsPerTask);
+ }
+
+ {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ Counter = 0;
+ scheduleIncrements();
+ }
+ }
+ // Check that destructor has waited for tasks to finish.
+ std::lock_guard<std::mutex> Lock(Mutex);
+ ASSERT_EQ(Counter, TasksCnt * IncrementsPerTask);
+}
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TraceTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TraceTests.cpp
new file mode 100644
index 0000000..02fe7da
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/TraceTests.cpp
@@ -0,0 +1,127 @@
+//===-- TraceTests.cpp - Tracing unit tests ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Trace.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/YAMLParser.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+using namespace llvm;
+
+MATCHER_P(StringNode, Val, "") {
+ if (arg->getType() != yaml::Node::NK_Scalar) {
+ *result_listener << "is a " << arg->getVerbatimTag();
+ return false;
+ }
+ SmallString<32> S;
+ return Val == static_cast<yaml::ScalarNode *>(arg)->getValue(S);
+}
+
+// Checks that N is a Mapping (JS object) with the expected scalar properties.
+// The object must have all the Expected properties, but may have others.
+bool VerifyObject(yaml::Node &N, std::map<std::string, std::string> Expected) {
+ auto *M = dyn_cast<yaml::MappingNode>(&N);
+ if (!M) {
+ ADD_FAILURE() << "Not an object";
+ return false;
+ }
+ bool Match = true;
+ SmallString<32> Tmp;
+ for (auto &Prop : *M) {
+ auto *K = dyn_cast_or_null<yaml::ScalarNode>(Prop.getKey());
+ if (!K)
+ continue;
+ std::string KS = K->getValue(Tmp).str();
+ auto I = Expected.find(KS);
+ if (I == Expected.end())
+ continue; // Ignore properties with no assertion.
+
+ auto *V = dyn_cast_or_null<yaml::ScalarNode>(Prop.getValue());
+ if (!V) {
+ ADD_FAILURE() << KS << " is not a string";
+ Match = false;
+ }
+ std::string VS = V->getValue(Tmp).str();
+ if (VS != I->second) {
+ ADD_FAILURE() << KS << " expected " << I->second << " but actual " << VS;
+ Match = false;
+ }
+ Expected.erase(I);
+ }
+ for (const auto &P : Expected) {
+ ADD_FAILURE() << P.first << " missing, expected " << P.second;
+ Match = false;
+ }
+ return Match;
+}
+
+TEST(TraceTest, SmokeTest) {
+ // Capture some events.
+ std::string JSON;
+ {
+ raw_string_ostream OS(JSON);
+ auto JSONTracer = trace::createJSONTracer(OS);
+ trace::Session Session(*JSONTracer);
+ {
+ trace::Span Tracer("A");
+ trace::log("B");
+ }
+ }
+
+ // Get the root JSON object using the YAML parser.
+ SourceMgr SM;
+ yaml::Stream Stream(JSON, SM);
+ auto Doc = Stream.begin();
+ ASSERT_NE(Doc, Stream.end());
+ auto *Root = dyn_cast_or_null<yaml::MappingNode>(Doc->getRoot());
+ ASSERT_NE(Root, nullptr) << "Root should be an object";
+
+ // Check whether we expect thread name events on this platform.
+ SmallString<32> ThreadName;
+ llvm::get_thread_name(ThreadName);
+ bool ThreadsHaveNames = !ThreadName.empty();
+
+ // We expect in order:
+ // displayTimeUnit: "ns"
+ // traceEvents: [process name, thread name, start span, log, end span]
+ // (The order doesn't matter, but the YAML parser is awkward to use otherwise)
+ auto Prop = Root->begin();
+ ASSERT_NE(Prop, Root->end()) << "Expected displayTimeUnit property";
+ ASSERT_THAT(Prop->getKey(), StringNode("displayTimeUnit"));
+ EXPECT_THAT(Prop->getValue(), StringNode("ns"));
+ ASSERT_NE(++Prop, Root->end()) << "Expected traceEvents property";
+ EXPECT_THAT(Prop->getKey(), StringNode("traceEvents"));
+ auto *Events = dyn_cast_or_null<yaml::SequenceNode>(Prop->getValue());
+ ASSERT_NE(Events, nullptr) << "traceEvents should be an array";
+ auto Event = Events->begin();
+ ASSERT_NE(Event, Events->end()) << "Expected process name";
+ EXPECT_TRUE(VerifyObject(*Event, {{"ph", "M"}, {"name", "process_name"}}));
+ if (ThreadsHaveNames) {
+ ASSERT_NE(++Event, Events->end()) << "Expected thread name";
+ EXPECT_TRUE(VerifyObject(*Event, {{"ph", "M"}, {"name", "thread_name"}}));
+ }
+ ASSERT_NE(++Event, Events->end()) << "Expected log message";
+ EXPECT_TRUE(VerifyObject(*Event, {{"ph", "i"}, {"name", "Log"}}));
+ ASSERT_NE(++Event, Events->end()) << "Expected span end";
+ EXPECT_TRUE(VerifyObject(*Event, {{"ph", "X"}, {"name", "A"}}));
+ ASSERT_EQ(++Event, Events->end());
+ ASSERT_EQ(++Prop, Root->end());
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/URITests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/URITests.cpp
new file mode 100644
index 0000000..84d5ca1
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/URITests.cpp
@@ -0,0 +1,176 @@
+//===-- URITests.cpp ---------------------------------*- C++ -*-----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestFS.h"
+#include "URI.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+
+// Force the unittest URI scheme to be linked,
+static int LLVM_ATTRIBUTE_UNUSED UnittestSchemeAnchorDest =
+ UnittestSchemeAnchorSource;
+
+namespace {
+
+using ::testing::AllOf;
+
+MATCHER_P(Scheme, S, "") { return arg.scheme() == S; }
+MATCHER_P(Authority, A, "") { return arg.authority() == A; }
+MATCHER_P(Body, B, "") { return arg.body() == B; }
+
+std::string createOrDie(llvm::StringRef AbsolutePath,
+ llvm::StringRef Scheme = "file") {
+ auto Uri = URI::create(AbsolutePath, Scheme);
+ if (!Uri)
+ llvm_unreachable(llvm::toString(Uri.takeError()).c_str());
+ return Uri->toString();
+}
+
+URI parseOrDie(llvm::StringRef Uri) {
+ auto U = URI::parse(Uri);
+ if (!U)
+ llvm_unreachable(llvm::toString(U.takeError()).c_str());
+ return *U;
+}
+
+TEST(PercentEncodingTest, Encode) {
+ EXPECT_EQ(URI("x", /*Authority=*/"", "a/b/c").toString(), "x:a/b/c");
+ EXPECT_EQ(URI("x", /*Authority=*/"", "a!b;c~").toString(), "x:a%21b%3bc~");
+ EXPECT_EQ(URI("x", /*Authority=*/"", "a123b").toString(), "x:a123b");
+}
+
+TEST(PercentEncodingTest, Decode) {
+ EXPECT_EQ(parseOrDie("x:a/b/c").body(), "a/b/c");
+
+ EXPECT_EQ(parseOrDie("%3a://%3a/%3").scheme(), ":");
+ EXPECT_EQ(parseOrDie("%3a://%3a/%3").authority(), ":");
+ EXPECT_EQ(parseOrDie("%3a://%3a/%3").body(), "/%3");
+
+ EXPECT_EQ(parseOrDie("x:a%21b%3ac~").body(), "a!b:c~");
+}
+
+std::string resolveOrDie(const URI &U, llvm::StringRef HintPath = "") {
+ auto Path = URI::resolve(U, HintPath);
+ if (!Path)
+ llvm_unreachable(llvm::toString(Path.takeError()).c_str());
+ return *Path;
+}
+
+TEST(URITest, Create) {
+#ifdef _WIN32
+ EXPECT_THAT(createOrDie("c:\\x\\y\\z"), "file:///c%3a/x/y/z");
+#else
+ EXPECT_THAT(createOrDie("/x/y/z"), "file:///x/y/z");
+ EXPECT_THAT(createOrDie("/(x)/y/\\ z"), "file:///%28x%29/y/%5c%20z");
+#endif
+}
+
+TEST(URITest, FailedCreate) {
+ auto Fail = [](llvm::Expected<URI> U) {
+ if (!U) {
+ llvm::consumeError(U.takeError());
+ return true;
+ }
+ return false;
+ };
+ EXPECT_TRUE(Fail(URI::create("/x/y/z", "no")));
+ // Path has to be absolute.
+ EXPECT_TRUE(Fail(URI::create("x/y/z", "file")));
+}
+
+TEST(URITest, Parse) {
+ EXPECT_THAT(parseOrDie("file://auth/x/y/z"),
+ AllOf(Scheme("file"), Authority("auth"), Body("/x/y/z")));
+
+ EXPECT_THAT(parseOrDie("file://au%3dth/%28x%29/y/%5c%20z"),
+ AllOf(Scheme("file"), Authority("au=th"), Body("/(x)/y/\\ z")));
+
+ EXPECT_THAT(parseOrDie("file:///%28x%29/y/%5c%20z"),
+ AllOf(Scheme("file"), Authority(""), Body("/(x)/y/\\ z")));
+ EXPECT_THAT(parseOrDie("file:///x/y/z"),
+ AllOf(Scheme("file"), Authority(""), Body("/x/y/z")));
+ EXPECT_THAT(parseOrDie("file:"),
+ AllOf(Scheme("file"), Authority(""), Body("")));
+ EXPECT_THAT(parseOrDie("file:///x/y/z%2"),
+ AllOf(Scheme("file"), Authority(""), Body("/x/y/z%2")));
+ EXPECT_THAT(parseOrDie("http://llvm.org"),
+ AllOf(Scheme("http"), Authority("llvm.org"), Body("")));
+ EXPECT_THAT(parseOrDie("http://llvm.org/"),
+ AllOf(Scheme("http"), Authority("llvm.org"), Body("/")));
+ EXPECT_THAT(parseOrDie("http://llvm.org/D"),
+ AllOf(Scheme("http"), Authority("llvm.org"), Body("/D")));
+ EXPECT_THAT(parseOrDie("http:/"),
+ AllOf(Scheme("http"), Authority(""), Body("/")));
+ EXPECT_THAT(parseOrDie("urn:isbn:0451450523"),
+ AllOf(Scheme("urn"), Authority(""), Body("isbn:0451450523")));
+ EXPECT_THAT(
+ parseOrDie("file:///c:/windows/system32/"),
+ AllOf(Scheme("file"), Authority(""), Body("/c:/windows/system32/")));
+}
+
+TEST(URITest, ParseFailed) {
+ auto FailedParse = [](llvm::StringRef U) {
+ auto URI = URI::parse(U);
+ if (!URI) {
+ llvm::consumeError(URI.takeError());
+ return true;
+ }
+ return false;
+ };
+
+ // Expect ':' in URI.
+ EXPECT_TRUE(FailedParse("file//x/y/z"));
+ // Empty.
+ EXPECT_TRUE(FailedParse(""));
+ EXPECT_TRUE(FailedParse(":/a/b/c"));
+}
+
+TEST(URITest, Resolve) {
+#ifdef _WIN32
+ EXPECT_THAT(resolveOrDie(parseOrDie("file:///c%3a/x/y/z")), "c:\\x\\y\\z");
+#else
+ EXPECT_EQ(resolveOrDie(parseOrDie("file:/a/b/c")), "/a/b/c");
+ EXPECT_EQ(resolveOrDie(parseOrDie("file://auth/a/b/c")), "/a/b/c");
+ EXPECT_THAT(resolveOrDie(parseOrDie("file://au%3dth/%28x%29/y/%20z")),
+ "/(x)/y/ z");
+ EXPECT_THAT(resolveOrDie(parseOrDie("file:///c:/x/y/z")), "c:/x/y/z");
+#endif
+ EXPECT_EQ(resolveOrDie(parseOrDie("unittest:///a"), testPath("x")),
+ testPath("a"));
+}
+
+TEST(URITest, Platform) {
+ auto Path = testPath("x");
+ auto U = URI::create(Path, "file");
+ EXPECT_TRUE(static_cast<bool>(U));
+ EXPECT_THAT(resolveOrDie(*U), Path);
+}
+
+TEST(URITest, ResolveFailed) {
+ auto FailedResolve = [](llvm::StringRef Uri) {
+ auto Path = URI::resolve(parseOrDie(Uri));
+ if (!Path) {
+ llvm::consumeError(Path.takeError());
+ return true;
+ }
+ return false;
+ };
+
+ // Invalid scheme.
+ EXPECT_TRUE(FailedResolve("no:/a/b/c"));
+ // File path needs to be absolute.
+ EXPECT_TRUE(FailedResolve("file:a/b/c"));
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/XRefsTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/XRefsTests.cpp
new file mode 100644
index 0000000..3383dd5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/clangd/XRefsTests.cpp
@@ -0,0 +1,988 @@
+//===-- XRefsTests.cpp ---------------------------*- C++ -*--------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "Annotations.h"
+#include "ClangdUnit.h"
+#include "Compiler.h"
+#include "Matchers.h"
+#include "SyncAPI.h"
+#include "TestFS.h"
+#include "TestTU.h"
+#include "XRefs.h"
+#include "index/FileIndex.h"
+#include "index/SymbolCollector.h"
+#include "clang/Index/IndexingAction.h"
+#include "llvm/Support/Path.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+namespace {
+using testing::ElementsAre;
+using testing::Field;
+using testing::IsEmpty;
+using testing::Matcher;
+using testing::UnorderedElementsAreArray;
+
+class IgnoreDiagnostics : public DiagnosticsConsumer {
+ void onDiagnosticsReady(PathRef File,
+ std::vector<Diag> Diagnostics) override {}
+};
+
+// Extracts ranges from an annotated example, and constructs a matcher for a
+// highlight set. Ranges should be named $read/$write as appropriate.
+Matcher<const std::vector<DocumentHighlight> &>
+HighlightsFrom(const Annotations &Test) {
+ std::vector<DocumentHighlight> Expected;
+ auto Add = [&](const Range &R, DocumentHighlightKind K) {
+ Expected.emplace_back();
+ Expected.back().range = R;
+ Expected.back().kind = K;
+ };
+ for (const auto &Range : Test.ranges())
+ Add(Range, DocumentHighlightKind::Text);
+ for (const auto &Range : Test.ranges("read"))
+ Add(Range, DocumentHighlightKind::Read);
+ for (const auto &Range : Test.ranges("write"))
+ Add(Range, DocumentHighlightKind::Write);
+ return UnorderedElementsAreArray(Expected);
+}
+
+TEST(HighlightsTest, All) {
+ const char *Tests[] = {
+ R"cpp(// Local variable
+ int main() {
+ int [[bonjour]];
+ $write[[^bonjour]] = 2;
+ int test1 = $read[[bonjour]];
+ }
+ )cpp",
+
+ R"cpp(// Struct
+ namespace ns1 {
+ struct [[MyClass]] {
+ static void foo([[MyClass]]*) {}
+ };
+ } // namespace ns1
+ int main() {
+ ns1::[[My^Class]]* Params;
+ }
+ )cpp",
+
+ R"cpp(// Function
+ int [[^foo]](int) {}
+ int main() {
+ [[foo]]([[foo]](42));
+ auto *X = &[[foo]];
+ }
+ )cpp",
+ };
+ for (const char *Test : Tests) {
+ Annotations T(Test);
+ auto AST = TestTU::withCode(T.code()).build();
+ EXPECT_THAT(findDocumentHighlights(AST, T.point()), HighlightsFrom(T))
+ << Test;
+ }
+}
+
+MATCHER_P(RangeIs, R, "") { return arg.range == R; }
+
+TEST(GoToDefinition, WithIndex) {
+ Annotations SymbolHeader(R"cpp(
+ class $forward[[Forward]];
+ class $foo[[Foo]] {};
+
+ void $f1[[f1]]();
+
+ inline void $f2[[f2]]() {}
+ )cpp");
+ Annotations SymbolCpp(R"cpp(
+ class $forward[[forward]] {};
+ void $f1[[f1]]() {}
+ )cpp");
+
+ TestTU TU;
+ TU.Code = SymbolCpp.code();
+ TU.HeaderCode = SymbolHeader.code();
+ auto Index = TU.index();
+ auto runFindDefinitionsWithIndex = [&Index](const Annotations &Main) {
+ auto AST = TestTU::withCode(Main.code()).build();
+ return clangd::findDefinitions(AST, Main.point(), Index.get());
+ };
+
+ Annotations Test(R"cpp(// only declaration in AST.
+ void [[f1]]();
+ int main() {
+ ^f1();
+ }
+ )cpp");
+ EXPECT_THAT(runFindDefinitionsWithIndex(Test),
+ testing::ElementsAreArray(
+ {RangeIs(SymbolCpp.range("f1")), RangeIs(Test.range())}));
+
+ Test = Annotations(R"cpp(// definition in AST.
+ void [[f1]]() {}
+ int main() {
+ ^f1();
+ }
+ )cpp");
+ EXPECT_THAT(runFindDefinitionsWithIndex(Test),
+ testing::ElementsAreArray(
+ {RangeIs(Test.range()), RangeIs(SymbolHeader.range("f1"))}));
+
+ Test = Annotations(R"cpp(// forward declaration in AST.
+ class [[Foo]];
+ F^oo* create();
+ )cpp");
+ EXPECT_THAT(runFindDefinitionsWithIndex(Test),
+ testing::ElementsAreArray(
+ {RangeIs(SymbolHeader.range("foo")), RangeIs(Test.range())}));
+
+ Test = Annotations(R"cpp(// defintion in AST.
+ class [[Forward]] {};
+ F^orward create();
+ )cpp");
+ EXPECT_THAT(runFindDefinitionsWithIndex(Test),
+ testing::ElementsAreArray({
+ RangeIs(Test.range()), RangeIs(SymbolHeader.range("forward")),
+ }));
+}
+
+TEST(GoToDefinition, All) {
+ const char *Tests[] = {
+ R"cpp(// Local variable
+ int main() {
+ int [[bonjour]];
+ ^bonjour = 2;
+ int test1 = bonjour;
+ }
+ )cpp",
+
+ R"cpp(// Struct
+ namespace ns1 {
+ struct [[MyClass]] {};
+ } // namespace ns1
+ int main() {
+ ns1::My^Class* Params;
+ }
+ )cpp",
+
+ R"cpp(// Function definition via pointer
+ int [[foo]](int) {}
+ int main() {
+ auto *X = &^foo;
+ }
+ )cpp",
+
+ R"cpp(// Function declaration via call
+ int [[foo]](int);
+ int main() {
+ return ^foo(42);
+ }
+ )cpp",
+
+ R"cpp(// Field
+ struct Foo { int [[x]]; };
+ int main() {
+ Foo bar;
+ bar.^x;
+ }
+ )cpp",
+
+ R"cpp(// Field, member initializer
+ struct Foo {
+ int [[x]];
+ Foo() : ^x(0) {}
+ };
+ )cpp",
+
+ R"cpp(// Field, GNU old-style field designator
+ struct Foo { int [[x]]; };
+ int main() {
+ Foo bar = { ^x : 1 };
+ }
+ )cpp",
+
+ R"cpp(// Field, field designator
+ struct Foo { int [[x]]; };
+ int main() {
+ Foo bar = { .^x = 2 };
+ }
+ )cpp",
+
+ R"cpp(// Method call
+ struct Foo { int [[x]](); };
+ int main() {
+ Foo bar;
+ bar.^x();
+ }
+ )cpp",
+
+ R"cpp(// Typedef
+ typedef int [[Foo]];
+ int main() {
+ ^Foo bar;
+ }
+ )cpp",
+
+ /* FIXME: clangIndex doesn't handle template type parameters
+ R"cpp(// Template type parameter
+ template <[[typename T]]>
+ void foo() { ^T t; }
+ )cpp", */
+
+ R"cpp(// Namespace
+ namespace [[ns]] {
+ struct Foo { static void bar(); }
+ } // namespace ns
+ int main() { ^ns::Foo::bar(); }
+ )cpp",
+
+ R"cpp(// Macro
+ #define MACRO 0
+ #define [[MACRO]] 1
+ int main() { return ^MACRO; }
+ #define MACRO 2
+ #undef macro
+ )cpp",
+
+ R"cpp(// Macro
+ class TTT { public: int a; };
+ #define [[FF]](S) if (int b = S.a) {}
+ void f() {
+ TTT t;
+ F^F(t);
+ }
+ )cpp",
+
+ R"cpp(// Macro argument
+ int [[i]];
+ #define ADDRESSOF(X) &X;
+ int *j = ADDRESSOF(^i);
+ )cpp",
+
+ R"cpp(// Symbol concatenated inside macro (not supported)
+ int *pi;
+ #define POINTER(X) p # X;
+ int i = *POINTER(^i);
+ )cpp",
+
+ R"cpp(// Forward class declaration
+ class Foo;
+ class [[Foo]] {};
+ F^oo* foo();
+ )cpp",
+
+ R"cpp(// Function declaration
+ void foo();
+ void g() { f^oo(); }
+ void [[foo]]() {}
+ )cpp",
+
+ R"cpp(
+ #define FF(name) class name##_Test {};
+ [[FF]](my);
+ void f() { my^_Test a; }
+ )cpp",
+
+ R"cpp(
+ #define FF() class [[Test]] {};
+ FF();
+ void f() { T^est a; }
+ )cpp",
+ };
+ for (const char *Test : Tests) {
+ Annotations T(Test);
+ auto AST = TestTU::withCode(T.code()).build();
+ std::vector<Matcher<Location>> ExpectedLocations;
+ for (const auto &R : T.ranges())
+ ExpectedLocations.push_back(RangeIs(R));
+ EXPECT_THAT(findDefinitions(AST, T.point()),
+ ElementsAreArray(ExpectedLocations))
+ << Test;
+ }
+}
+
+TEST(GoToDefinition, RelPathsInCompileCommand) {
+ Annotations SourceAnnotations(R"cpp(
+int [[foo]];
+int baz = f^oo;
+)cpp");
+
+ IgnoreDiagnostics DiagConsumer;
+ MockCompilationDatabase CDB(/*UseRelPaths=*/true);
+ MockFSProvider FS;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ auto FooCpp = testPath("foo.cpp");
+ FS.Files[FooCpp] = "";
+
+ Server.addDocument(FooCpp, SourceAnnotations.code());
+ runAddDocument(Server, FooCpp, SourceAnnotations.code());
+ auto Locations =
+ runFindDefinitions(Server, FooCpp, SourceAnnotations.point());
+ EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
+
+ EXPECT_THAT(*Locations, ElementsAre(Location{URIForFile{FooCpp},
+ SourceAnnotations.range()}));
+}
+
+TEST(Hover, All) {
+ struct OneTest {
+ StringRef Input;
+ StringRef ExpectedHover;
+ };
+
+ OneTest Tests[] = {
+ {
+ R"cpp(// No hover
+ ^int main() {
+ }
+ )cpp",
+ "",
+ },
+ {
+ R"cpp(// Local variable
+ int main() {
+ int bonjour;
+ ^bonjour = 2;
+ int test1 = bonjour;
+ }
+ )cpp",
+ "Declared in function main\n\nint bonjour",
+ },
+ {
+ R"cpp(// Local variable in method
+ struct s {
+ void method() {
+ int bonjour;
+ ^bonjour = 2;
+ }
+ };
+ )cpp",
+ "Declared in function s::method\n\nint bonjour",
+ },
+ {
+ R"cpp(// Struct
+ namespace ns1 {
+ struct MyClass {};
+ } // namespace ns1
+ int main() {
+ ns1::My^Class* Params;
+ }
+ )cpp",
+ "Declared in namespace ns1\n\nstruct MyClass {}",
+ },
+ {
+ R"cpp(// Class
+ namespace ns1 {
+ class MyClass {};
+ } // namespace ns1
+ int main() {
+ ns1::My^Class* Params;
+ }
+ )cpp",
+ "Declared in namespace ns1\n\nclass MyClass {}",
+ },
+ {
+ R"cpp(// Union
+ namespace ns1 {
+ union MyUnion { int x; int y; };
+ } // namespace ns1
+ int main() {
+ ns1::My^Union Params;
+ }
+ )cpp",
+ "Declared in namespace ns1\n\nunion MyUnion {}",
+ },
+ {
+ R"cpp(// Function definition via pointer
+ int foo(int) {}
+ int main() {
+ auto *X = &^foo;
+ }
+ )cpp",
+ "Declared in global namespace\n\nint foo(int)",
+ },
+ {
+ R"cpp(// Function declaration via call
+ int foo(int);
+ int main() {
+ return ^foo(42);
+ }
+ )cpp",
+ "Declared in global namespace\n\nint foo(int)",
+ },
+ {
+ R"cpp(// Field
+ struct Foo { int x; };
+ int main() {
+ Foo bar;
+ bar.^x;
+ }
+ )cpp",
+ "Declared in struct Foo\n\nint x",
+ },
+ {
+ R"cpp(// Field with initialization
+ struct Foo { int x = 5; };
+ int main() {
+ Foo bar;
+ bar.^x;
+ }
+ )cpp",
+ "Declared in struct Foo\n\nint x = 5",
+ },
+ {
+ R"cpp(// Static field
+ struct Foo { static int x; };
+ int main() {
+ Foo::^x;
+ }
+ )cpp",
+ "Declared in struct Foo\n\nstatic int x",
+ },
+ {
+ R"cpp(// Field, member initializer
+ struct Foo {
+ int x;
+ Foo() : ^x(0) {}
+ };
+ )cpp",
+ "Declared in struct Foo\n\nint x",
+ },
+ {
+ R"cpp(// Field, GNU old-style field designator
+ struct Foo { int x; };
+ int main() {
+ Foo bar = { ^x : 1 };
+ }
+ )cpp",
+ "Declared in struct Foo\n\nint x",
+ },
+ {
+ R"cpp(// Field, field designator
+ struct Foo { int x; };
+ int main() {
+ Foo bar = { .^x = 2 };
+ }
+ )cpp",
+ "Declared in struct Foo\n\nint x",
+ },
+ {
+ R"cpp(// Method call
+ struct Foo { int x(); };
+ int main() {
+ Foo bar;
+ bar.^x();
+ }
+ )cpp",
+ "Declared in struct Foo\n\nint x()",
+ },
+ {
+ R"cpp(// Static method call
+ struct Foo { static int x(); };
+ int main() {
+ Foo::^x();
+ }
+ )cpp",
+ "Declared in struct Foo\n\nstatic int x()",
+ },
+ {
+ R"cpp(// Typedef
+ typedef int Foo;
+ int main() {
+ ^Foo bar;
+ }
+ )cpp",
+ "Declared in global namespace\n\ntypedef int Foo",
+ },
+ {
+ R"cpp(// Namespace
+ namespace ns {
+ struct Foo { static void bar(); }
+ } // namespace ns
+ int main() { ^ns::Foo::bar(); }
+ )cpp",
+ "Declared in global namespace\n\nnamespace ns {\n}",
+ },
+ {
+ R"cpp(// Anonymous namespace
+ namespace ns {
+ namespace {
+ int foo;
+ } // anonymous namespace
+ } // namespace ns
+ int main() { ns::f^oo++; }
+ )cpp",
+ "Declared in namespace ns::(anonymous)\n\nint foo",
+ },
+ {
+ R"cpp(// Macro
+ #define MACRO 0
+ #define MACRO 1
+ int main() { return ^MACRO; }
+ #define MACRO 2
+ #undef macro
+ )cpp",
+ "#define MACRO",
+ },
+ {
+ R"cpp(// Forward class declaration
+ class Foo;
+ class Foo {};
+ F^oo* foo();
+ )cpp",
+ "Declared in global namespace\n\nclass Foo {}",
+ },
+ {
+ R"cpp(// Function declaration
+ void foo();
+ void g() { f^oo(); }
+ void foo() {}
+ )cpp",
+ "Declared in global namespace\n\nvoid foo()",
+ },
+ {
+ R"cpp(// Enum declaration
+ enum Hello {
+ ONE, TWO, THREE,
+ };
+ void foo() {
+ Hel^lo hello = ONE;
+ }
+ )cpp",
+ "Declared in global namespace\n\nenum Hello {\n}",
+ },
+ {
+ R"cpp(// Enumerator
+ enum Hello {
+ ONE, TWO, THREE,
+ };
+ void foo() {
+ Hello hello = O^NE;
+ }
+ )cpp",
+ "Declared in enum Hello\n\nONE",
+ },
+ {
+ R"cpp(// Enumerator in anonymous enum
+ enum {
+ ONE, TWO, THREE,
+ };
+ void foo() {
+ int hello = O^NE;
+ }
+ )cpp",
+ "Declared in enum (anonymous)\n\nONE",
+ },
+ {
+ R"cpp(// Global variable
+ static int hey = 10;
+ void foo() {
+ he^y++;
+ }
+ )cpp",
+ "Declared in global namespace\n\nstatic int hey = 10",
+ },
+ {
+ R"cpp(// Global variable in namespace
+ namespace ns1 {
+ static int hey = 10;
+ }
+ void foo() {
+ ns1::he^y++;
+ }
+ )cpp",
+ "Declared in namespace ns1\n\nstatic int hey = 10",
+ },
+ {
+ R"cpp(// Field in anonymous struct
+ static struct {
+ int hello;
+ } s;
+ void foo() {
+ s.he^llo++;
+ }
+ )cpp",
+ "Declared in struct (anonymous)\n\nint hello",
+ },
+ {
+ R"cpp(// Templated function
+ template <typename T>
+ T foo() {
+ return 17;
+ }
+ void g() { auto x = f^oo<int>(); }
+ )cpp",
+ "Declared in global namespace\n\ntemplate <typename T> T foo()",
+ },
+ {
+ R"cpp(// Anonymous union
+ struct outer {
+ union {
+ int abc, def;
+ } v;
+ };
+ void g() { struct outer o; o.v.d^ef++; }
+ )cpp",
+ "Declared in union outer::(anonymous)\n\nint def",
+ },
+ {
+ R"cpp(// Nothing
+ void foo() {
+ ^
+ }
+ )cpp",
+ "",
+ },
+ {
+ R"cpp(// Simple initialization with auto
+ void foo() {
+ ^auto i = 1;
+ }
+ )cpp",
+ "int",
+ },
+ {
+ R"cpp(// Simple initialization with const auto
+ void foo() {
+ const ^auto i = 1;
+ }
+ )cpp",
+ "int",
+ },
+ {
+ R"cpp(// Simple initialization with const auto&
+ void foo() {
+ const ^auto& i = 1;
+ }
+ )cpp",
+ "int",
+ },
+ {
+ R"cpp(// Simple initialization with auto&
+ void foo() {
+ ^auto& i = 1;
+ }
+ )cpp",
+ "int",
+ },
+ {
+ R"cpp(// Auto with initializer list.
+ namespace std
+ {
+ template<class _E>
+ class initializer_list {};
+ }
+ void foo() {
+ ^auto i = {1,2};
+ }
+ )cpp",
+ "class std::initializer_list<int>",
+ },
+ {
+ R"cpp(// User defined conversion to auto
+ struct Bar {
+ operator ^auto() const { return 10; }
+ };
+ )cpp",
+ "int",
+ },
+ {
+ R"cpp(// Simple initialization with decltype(auto)
+ void foo() {
+ ^decltype(auto) i = 1;
+ }
+ )cpp",
+ "int",
+ },
+ {
+ R"cpp(// Simple initialization with const decltype(auto)
+ void foo() {
+ const int j = 0;
+ ^decltype(auto) i = j;
+ }
+ )cpp",
+ "const int",
+ },
+ {
+ R"cpp(// Simple initialization with const& decltype(auto)
+ void foo() {
+ int k = 0;
+ const int& j = k;
+ ^decltype(auto) i = j;
+ }
+ )cpp",
+ "const int &",
+ },
+ {
+ R"cpp(// Simple initialization with & decltype(auto)
+ void foo() {
+ int k = 0;
+ int& j = k;
+ ^decltype(auto) i = j;
+ }
+ )cpp",
+ "int &",
+ },
+ {
+ R"cpp(// decltype with initializer list: nothing
+ namespace std
+ {
+ template<class _E>
+ class initializer_list {};
+ }
+ void foo() {
+ ^decltype(auto) i = {1,2};
+ }
+ )cpp",
+ "",
+ },
+ {
+ R"cpp(// auto function return with trailing type
+ struct Bar {};
+ ^auto test() -> decltype(Bar()) {
+ return Bar();
+ }
+ )cpp",
+ "struct Bar",
+ },
+ {
+ R"cpp(// trailing return type
+ struct Bar {};
+ auto test() -> ^decltype(Bar()) {
+ return Bar();
+ }
+ )cpp",
+ "struct Bar",
+ },
+ {
+ R"cpp(// auto in function return
+ struct Bar {};
+ ^auto test() {
+ return Bar();
+ }
+ )cpp",
+ "struct Bar",
+ },
+ {
+ R"cpp(// auto& in function return
+ struct Bar {};
+ ^auto& test() {
+ return Bar();
+ }
+ )cpp",
+ "struct Bar",
+ },
+ {
+ R"cpp(// const auto& in function return
+ struct Bar {};
+ const ^auto& test() {
+ return Bar();
+ }
+ )cpp",
+ "struct Bar",
+ },
+ {
+ R"cpp(// decltype(auto) in function return
+ struct Bar {};
+ ^decltype(auto) test() {
+ return Bar();
+ }
+ )cpp",
+ "struct Bar",
+ },
+ {
+ R"cpp(// decltype(auto) reference in function return
+ struct Bar {};
+ ^decltype(auto) test() {
+ int a;
+ return (a);
+ }
+ )cpp",
+ "int &",
+ },
+ {
+ R"cpp(// decltype lvalue reference
+ void foo() {
+ int I = 0;
+ ^decltype(I) J = I;
+ }
+ )cpp",
+ "int",
+ },
+ {
+ R"cpp(// decltype lvalue reference
+ void foo() {
+ int I= 0;
+ int &K = I;
+ ^decltype(K) J = I;
+ }
+ )cpp",
+ "int &",
+ },
+ {
+ R"cpp(// decltype lvalue reference parenthesis
+ void foo() {
+ int I = 0;
+ ^decltype((I)) J = I;
+ }
+ )cpp",
+ "int &",
+ },
+ {
+ R"cpp(// decltype rvalue reference
+ void foo() {
+ int I = 0;
+ ^decltype(static_cast<int&&>(I)) J = static_cast<int&&>(I);
+ }
+ )cpp",
+ "int &&",
+ },
+ {
+ R"cpp(// decltype rvalue reference function call
+ int && bar();
+ void foo() {
+ int I = 0;
+ ^decltype(bar()) J = bar();
+ }
+ )cpp",
+ "int &&",
+ },
+ {
+ R"cpp(// decltype of function with trailing return type.
+ struct Bar {};
+ auto test() -> decltype(Bar()) {
+ return Bar();
+ }
+ void foo() {
+ ^decltype(test()) i = test();
+ }
+ )cpp",
+ "struct Bar",
+ },
+ {
+ R"cpp(// decltype of var with decltype.
+ void foo() {
+ int I = 0;
+ decltype(I) J = I;
+ ^decltype(J) K = J;
+ }
+ )cpp",
+ "int",
+ },
+ {
+ R"cpp(// structured binding. Not supported yet
+ struct Bar {};
+ void foo() {
+ Bar a[2];
+ ^auto [x,y] = a;
+ }
+ )cpp",
+ "",
+ },
+ {
+ R"cpp(// Template auto parameter. Nothing (Not useful).
+ template<^auto T>
+ void func() {
+ }
+ void foo() {
+ func<1>();
+ }
+ )cpp",
+ "",
+ },
+ };
+
+ for (const OneTest &Test : Tests) {
+ Annotations T(Test.Input);
+ TestTU TU = TestTU::withCode(T.code());
+ TU.ExtraArgs.push_back("-std=c++17");
+ auto AST = TU.build();
+ if (auto H = getHover(AST, T.point())) {
+ EXPECT_NE("", Test.ExpectedHover) << Test.Input;
+ EXPECT_EQ(H->contents.value, Test.ExpectedHover.str()) << Test.Input;
+ } else
+ EXPECT_EQ("", Test.ExpectedHover.str()) << Test.Input;
+ }
+}
+
+TEST(GoToInclude, All) {
+ MockFSProvider FS;
+ IgnoreDiagnostics DiagConsumer;
+ MockCompilationDatabase CDB;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ auto FooCpp = testPath("foo.cpp");
+ const char *SourceContents = R"cpp(
+ #include ^"$2^foo.h$3^"
+ #include "$4^invalid.h"
+ int b = a;
+ // test
+ int foo;
+ #in$5^clude "$6^foo.h"$7^
+ )cpp";
+ Annotations SourceAnnotations(SourceContents);
+ FS.Files[FooCpp] = SourceAnnotations.code();
+ auto FooH = testPath("foo.h");
+ auto FooHUri = URIForFile{FooH};
+
+ const char *HeaderContents = R"cpp([[]]#pragma once
+ int a;
+ )cpp";
+ Annotations HeaderAnnotations(HeaderContents);
+ FS.Files[FooH] = HeaderAnnotations.code();
+
+ Server.addDocument(FooH, HeaderAnnotations.code());
+ Server.addDocument(FooCpp, SourceAnnotations.code());
+
+ // Test include in preamble.
+ auto Locations =
+ runFindDefinitions(Server, FooCpp, SourceAnnotations.point());
+ ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
+ EXPECT_THAT(*Locations,
+ ElementsAre(Location{FooHUri, HeaderAnnotations.range()}));
+
+ // Test include in preamble, last char.
+ Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("2"));
+ ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
+ EXPECT_THAT(*Locations,
+ ElementsAre(Location{FooHUri, HeaderAnnotations.range()}));
+
+ Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("3"));
+ ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
+ EXPECT_THAT(*Locations,
+ ElementsAre(Location{FooHUri, HeaderAnnotations.range()}));
+
+ // Test include outside of preamble.
+ Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("6"));
+ ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
+ EXPECT_THAT(*Locations,
+ ElementsAre(Location{FooHUri, HeaderAnnotations.range()}));
+
+ // Test a few positions that do not result in Locations.
+ Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("4"));
+ ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
+ EXPECT_THAT(*Locations, IsEmpty());
+
+ Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("5"));
+ ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
+ EXPECT_THAT(*Locations, IsEmpty());
+
+ Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("7"));
+ ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
+ EXPECT_THAT(*Locations, IsEmpty());
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/CMakeLists.txt
new file mode 100644
index 0000000..80284a6
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/CMakeLists.txt
@@ -0,0 +1,31 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+get_filename_component(INCLUDE_FIXER_SOURCE_DIR
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../include-fixer REALPATH)
+include_directories(
+ ${INCLUDE_FIXER_SOURCE_DIR}
+ )
+
+# We'd like to clang/unittests/Tooling/RewriterTestContext.h in the test.
+include_directories(${CLANG_SOURCE_DIR})
+
+add_extra_unittest(IncludeFixerTests
+ IncludeFixerTest.cpp
+ FuzzySymbolIndexTests.cpp
+ )
+
+target_link_libraries(IncludeFixerTests
+ PRIVATE
+ clangBasic
+ clangFormat
+ clangFrontend
+ clangIncludeFixer
+ clangRewrite
+ clangTooling
+ clangToolingCore
+ findAllSymbols
+ )
+
+add_subdirectory(find-all-symbols)
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/FuzzySymbolIndexTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/FuzzySymbolIndexTests.cpp
new file mode 100644
index 0000000..17679c5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/FuzzySymbolIndexTests.cpp
@@ -0,0 +1,61 @@
+//===-- FuzzySymbolIndexTests.cpp - Fuzzy symbol index unit tests ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FuzzySymbolIndex.h"
+#include "gmock/gmock.h"
+#include "llvm/Support/Regex.h"
+#include "gtest/gtest.h"
+
+using testing::ElementsAre;
+using testing::Not;
+
+namespace clang {
+namespace include_fixer {
+namespace {
+
+TEST(FuzzySymbolIndexTest, Tokenize) {
+ EXPECT_THAT(FuzzySymbolIndex::tokenize("URLHandlerCallback"),
+ ElementsAre("url", "handler", "callback"));
+ EXPECT_THAT(FuzzySymbolIndex::tokenize("snake_case11"),
+ ElementsAre("snake", "case", "11"));
+ EXPECT_THAT(FuzzySymbolIndex::tokenize("__$42!!BOB\nbob"),
+ ElementsAre("42", "bob", "bob"));
+}
+
+MATCHER_P(MatchesSymbol, Identifier, "") {
+ llvm::Regex Pattern("^" + arg);
+ std::string err;
+ if (!Pattern.isValid(err)) {
+ *result_listener << "invalid regex: " << err;
+ return false;
+ }
+ auto Tokens = FuzzySymbolIndex::tokenize(Identifier);
+ std::string Target = llvm::join(Tokens.begin(), Tokens.end(), " ");
+ *result_listener << "matching against '" << Target << "'";
+ return llvm::Regex("^" + arg).match(Target);
+}
+
+TEST(FuzzySymbolIndexTest, QueryRegexp) {
+ auto QueryRegexp = [](const std::string &query) {
+ return FuzzySymbolIndex::queryRegexp(FuzzySymbolIndex::tokenize(query));
+ };
+ EXPECT_THAT(QueryRegexp("uhc"), MatchesSymbol("URLHandlerCallback"));
+ EXPECT_THAT(QueryRegexp("urhaca"), MatchesSymbol("URLHandlerCallback"));
+ EXPECT_THAT(QueryRegexp("uhcb"), Not(MatchesSymbol("URLHandlerCallback")))
+ << "Non-prefix";
+ EXPECT_THAT(QueryRegexp("uc"), Not(MatchesSymbol("URLHandlerCallback")))
+ << "Skip token";
+
+ EXPECT_THAT(QueryRegexp("uptr"), MatchesSymbol("unique_ptr"));
+ EXPECT_THAT(QueryRegexp("UniP"), MatchesSymbol("unique_ptr"));
+}
+
+} // namespace
+} // namespace include_fixer
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/IncludeFixerTest.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/IncludeFixerTest.cpp
new file mode 100644
index 0000000..4da14f5
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/IncludeFixerTest.cpp
@@ -0,0 +1,372 @@
+//===-- IncludeFixerTest.cpp - Include fixer unit tests -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InMemorySymbolIndex.h"
+#include "IncludeFixer.h"
+#include "SymbolIndexManager.h"
+#include "unittests/Tooling/RewriterTestContext.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace include_fixer {
+namespace {
+
+using find_all_symbols::SymbolInfo;
+using find_all_symbols::SymbolAndSignals;
+
+static bool runOnCode(tooling::ToolAction *ToolAction, StringRef Code,
+ StringRef FileName,
+ const std::vector<std::string> &ExtraArgs) {
+ llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
+ new vfs::InMemoryFileSystem);
+ llvm::IntrusiveRefCntPtr<FileManager> Files(
+ new FileManager(FileSystemOptions(), InMemoryFileSystem));
+ // FIXME: Investigate why -fms-compatibility breaks tests.
+ std::vector<std::string> Args = {"include_fixer", "-fsyntax-only",
+ "-fno-ms-compatibility", FileName};
+ Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
+ tooling::ToolInvocation Invocation(
+ Args, ToolAction, Files.get(),
+ std::make_shared<PCHContainerOperations>());
+
+ InMemoryFileSystem->addFile(FileName, 0,
+ llvm::MemoryBuffer::getMemBuffer(Code));
+
+ InMemoryFileSystem->addFile("foo.h", 0,
+ llvm::MemoryBuffer::getMemBuffer("\n"));
+ InMemoryFileSystem->addFile("dir/bar.h", 0,
+ llvm::MemoryBuffer::getMemBuffer("\n"));
+ InMemoryFileSystem->addFile("dir/otherdir/qux.h", 0,
+ llvm::MemoryBuffer::getMemBuffer("\n"));
+ InMemoryFileSystem->addFile("header.h", 0,
+ llvm::MemoryBuffer::getMemBuffer("bar b;"));
+ return Invocation.run();
+}
+
+static std::string runIncludeFixer(
+ StringRef Code,
+ const std::vector<std::string> &ExtraArgs = std::vector<std::string>()) {
+ std::vector<SymbolAndSignals> Symbols = {
+ {SymbolInfo("string", SymbolInfo::SymbolKind::Class, "<string>",
+ {{SymbolInfo::ContextType::Namespace, "std"}}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("sting", SymbolInfo::SymbolKind::Class, "\"sting\"",
+ {{SymbolInfo::ContextType::Namespace, "std"}}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("foo", SymbolInfo::SymbolKind::Class,
+ "\"dir/otherdir/qux.h\"",
+ {{SymbolInfo::ContextType::Namespace, "b"},
+ {SymbolInfo::ContextType::Namespace, "a"}}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("bar", SymbolInfo::SymbolKind::Class, "\"bar.h\"",
+ {{SymbolInfo::ContextType::Namespace, "b"},
+ {SymbolInfo::ContextType::Namespace, "a"}}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("bar", SymbolInfo::SymbolKind::Class, "\"bar2.h\"",
+ {{SymbolInfo::ContextType::Namespace, "c"},
+ {SymbolInfo::ContextType::Namespace, "a"}}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("Green", SymbolInfo::SymbolKind::Class, "\"color.h\"",
+ {{SymbolInfo::ContextType::EnumDecl, "Color"},
+ {SymbolInfo::ContextType::Namespace, "b"},
+ {SymbolInfo::ContextType::Namespace, "a"}}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("Vector", SymbolInfo::SymbolKind::Class, "\"Vector.h\"",
+ {{SymbolInfo::ContextType::Namespace, "__a"},
+ {SymbolInfo::ContextType::Namespace, "a"}}),
+ SymbolInfo::Signals{/*Seen=*/2, 0}},
+ {SymbolInfo("Vector", SymbolInfo::SymbolKind::Class, "\"Vector.h\"",
+ {{SymbolInfo::ContextType::Namespace, "a"}}),
+ SymbolInfo::Signals{/*Seen=*/2, 0}},
+ {SymbolInfo("StrCat", SymbolInfo::SymbolKind::Class, "\"strcat.h\"",
+ {{SymbolInfo::ContextType::Namespace, "str"}}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("str", SymbolInfo::SymbolKind::Class, "\"str.h\"", {}),
+ SymbolInfo::Signals{}},
+ {SymbolInfo("foo2", SymbolInfo::SymbolKind::Class, "\"foo2.h\"", {}),
+ SymbolInfo::Signals{}},
+ };
+ auto SymbolIndexMgr = llvm::make_unique<SymbolIndexManager>();
+ SymbolIndexMgr->addSymbolIndex(
+ [=]() { return llvm::make_unique<InMemorySymbolIndex>(Symbols); });
+
+ std::vector<IncludeFixerContext> FixerContexts;
+ IncludeFixerActionFactory Factory(*SymbolIndexMgr, FixerContexts, "llvm");
+ std::string FakeFileName = "input.cc";
+ runOnCode(&Factory, Code, FakeFileName, ExtraArgs);
+ assert(FixerContexts.size() == 1);
+ if (FixerContexts.front().getHeaderInfos().empty())
+ return Code;
+ auto Replaces = createIncludeFixerReplacements(Code, FixerContexts.front());
+ EXPECT_TRUE(static_cast<bool>(Replaces))
+ << llvm::toString(Replaces.takeError()) << "\n";
+ if (!Replaces)
+ return "";
+ RewriterTestContext Context;
+ FileID ID = Context.createInMemoryFile(FakeFileName, Code);
+ tooling::applyAllReplacements(*Replaces, Context.Rewrite);
+ return Context.getRewrittenText(ID);
+}
+
+TEST(IncludeFixer, Typo) {
+ EXPECT_EQ("#include <string>\nstd::string foo;\n",
+ runIncludeFixer("std::string foo;\n"));
+
+ EXPECT_EQ("// comment\n#include \"foo.h\"\n#include <string>\n"
+ "std::string foo;\n#include \"dir/bar.h\"\n",
+ runIncludeFixer("// comment\n#include \"foo.h\"\nstd::string foo;\n"
+ "#include \"dir/bar.h\"\n"));
+
+ EXPECT_EQ("#include \"foo.h\"\n#include <string>\nstd::string foo;\n",
+ runIncludeFixer("#include \"foo.h\"\nstd::string foo;\n"));
+
+ EXPECT_EQ(
+ "#include \"foo.h\"\n#include <string>\nstd::string::size_type foo;\n",
+ runIncludeFixer("#include \"foo.h\"\nstd::string::size_type foo;\n"));
+
+ EXPECT_EQ("#include <string>\nstd::string foo;\n",
+ runIncludeFixer("string foo;\n"));
+
+ // Should not match std::string.
+ EXPECT_EQ("::string foo;\n", runIncludeFixer("::string foo;\n"));
+}
+
+TEST(IncludeFixer, IncompleteType) {
+ EXPECT_EQ(
+ "#include \"foo.h\"\n#include <string>\n"
+ "namespace std {\nclass string;\n}\nstd::string foo;\n",
+ runIncludeFixer("#include \"foo.h\"\n"
+ "namespace std {\nclass string;\n}\nstring foo;\n"));
+
+ EXPECT_EQ("#include <string>\n"
+ "class string;\ntypedef string foo;\nfoo f;\n",
+ runIncludeFixer("class string;\ntypedef string foo;\nfoo f;\n"));
+}
+
+TEST(IncludeFixer, MinimizeInclude) {
+ std::vector<std::string> IncludePath = {"-Idir/"};
+ EXPECT_EQ("#include \"otherdir/qux.h\"\na::b::foo bar;\n",
+ runIncludeFixer("a::b::foo bar;\n", IncludePath));
+
+ IncludePath = {"-isystemdir"};
+ EXPECT_EQ("#include <otherdir/qux.h>\na::b::foo bar;\n",
+ runIncludeFixer("a::b::foo bar;\n", IncludePath));
+
+ IncludePath = {"-iquotedir"};
+ EXPECT_EQ("#include \"otherdir/qux.h\"\na::b::foo bar;\n",
+ runIncludeFixer("a::b::foo bar;\n", IncludePath));
+
+ IncludePath = {"-Idir", "-Idir/otherdir"};
+ EXPECT_EQ("#include \"qux.h\"\na::b::foo bar;\n",
+ runIncludeFixer("a::b::foo bar;\n", IncludePath));
+}
+
+TEST(IncludeFixer, NestedName) {
+ EXPECT_EQ("#include \"dir/otherdir/qux.h\"\n"
+ "int x = a::b::foo(0);\n",
+ runIncludeFixer("int x = a::b::foo(0);\n"));
+
+ // FIXME: Handle simple macros.
+ EXPECT_EQ("#define FOO a::b::foo\nint x = FOO;\n",
+ runIncludeFixer("#define FOO a::b::foo\nint x = FOO;\n"));
+ EXPECT_EQ("#define FOO(x) a::##x\nint x = FOO(b::foo);\n",
+ runIncludeFixer("#define FOO(x) a::##x\nint x = FOO(b::foo);\n"));
+
+ // The empty namespace is cleaned up by clang-format after include-fixer
+ // finishes.
+ EXPECT_EQ("#include \"dir/otherdir/qux.h\"\n"
+ "\nint a = a::b::foo(0);\n",
+ runIncludeFixer("namespace a {}\nint a = a::b::foo(0);\n"));
+}
+
+TEST(IncludeFixer, MultipleMissingSymbols) {
+ EXPECT_EQ("#include <string>\nstd::string bar;\nstd::sting foo;\n",
+ runIncludeFixer("std::string bar;\nstd::sting foo;\n"));
+}
+
+TEST(IncludeFixer, ScopedNamespaceSymbols) {
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\nb::bar b;\n}",
+ runIncludeFixer("namespace a {\nb::bar b;\n}"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace A {\na::b::bar b;\n}",
+ runIncludeFixer("namespace A {\na::b::bar b;\n}"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\nvoid func() { b::bar b; }\n} "
+ "// namespace a",
+ runIncludeFixer("namespace a {\nvoid func() { b::bar b; }\n}"));
+ EXPECT_EQ("namespace A { c::b::bar b; }\n",
+ runIncludeFixer("namespace A { c::b::bar b; }\n"));
+ // FIXME: The header should not be added here. Remove this after we support
+ // full match.
+ EXPECT_EQ("#include \"bar.h\"\nnamespace A {\na::b::bar b;\n}",
+ runIncludeFixer("namespace A {\nb::bar b;\n}"));
+
+ // Finds candidates for "str::StrCat".
+ EXPECT_EQ("#include \"strcat.h\"\nnamespace foo2 {\nstr::StrCat b;\n}",
+ runIncludeFixer("namespace foo2 {\nstr::StrCat b;\n}"));
+ // str::StrCat2 doesn't exist.
+ // In these two cases, StrCat2 is a nested class of class str.
+ EXPECT_EQ("#include \"str.h\"\nnamespace foo2 {\nstr::StrCat2 b;\n}",
+ runIncludeFixer("namespace foo2 {\nstr::StrCat2 b;\n}"));
+ EXPECT_EQ("#include \"str.h\"\nnamespace ns {\nstr::StrCat2 b;\n}",
+ runIncludeFixer("namespace ns {\nstr::StrCat2 b;\n}"));
+}
+
+TEST(IncludeFixer, EnumConstantSymbols) {
+ EXPECT_EQ("#include \"color.h\"\nint test = a::b::Green;\n",
+ runIncludeFixer("int test = a::b::Green;\n"));
+}
+
+TEST(IncludeFixer, IgnoreSymbolFromHeader) {
+ std::string Code = "#include \"header.h\"";
+ EXPECT_EQ(Code, runIncludeFixer(Code));
+}
+
+// FIXME: add test cases for inserting and sorting multiple headers when
+// include-fixer supports multiple headers insertion.
+TEST(IncludeFixer, InsertAndSortSingleHeader) {
+ // Insert one header.
+ std::string Code = "#include \"a.h\"\n"
+ "#include \"foo.h\"\n"
+ "\n"
+ "namespace a {\nb::bar b;\n}\n";
+ std::string Expected = "#include \"a.h\"\n"
+ "#include \"bar.h\"\n"
+ "#include \"foo.h\"\n"
+ "\n"
+ "namespace a {\nb::bar b;\n}\n";
+ EXPECT_EQ(Expected, runIncludeFixer(Code));
+}
+
+TEST(IncludeFixer, DoNotDeleteMatchedSymbol) {
+ EXPECT_EQ("#include \"Vector.h\"\na::Vector v;",
+ runIncludeFixer("a::Vector v;"));
+}
+
+TEST(IncludeFixer, FixNamespaceQualifiers) {
+ EXPECT_EQ("#include \"bar.h\"\na::b::bar b;\n",
+ runIncludeFixer("b::bar b;\n"));
+ EXPECT_EQ("#include \"bar.h\"\na::b::bar b;\n",
+ runIncludeFixer("a::b::bar b;\n"));
+ EXPECT_EQ("#include \"bar.h\"\na::b::bar b;\n",
+ runIncludeFixer("bar b;\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\nb::bar b;\n}\n",
+ runIncludeFixer("namespace a {\nb::bar b;\n}\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\nb::bar b;\n}\n",
+ runIncludeFixer("namespace a {\nbar b;\n}\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\nnamespace b{\nbar b;\n}\n} "
+ "// namespace a\n",
+ runIncludeFixer("namespace a {\nnamespace b{\nbar b;\n}\n}\n"));
+ EXPECT_EQ("c::b::bar b;\n",
+ runIncludeFixer("c::b::bar b;\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace d {\na::b::bar b;\n}\n",
+ runIncludeFixer("namespace d {\nbar b;\n}\n"));
+ EXPECT_EQ("#include \"bar2.h\"\nnamespace c {\na::c::bar b;\n}\n",
+ runIncludeFixer("namespace c {\nbar b;\n}\n"));
+
+ // Test common qualifers reduction.
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\nnamespace d {\nb::bar b;\n}\n} "
+ "// namespace a\n",
+ runIncludeFixer("namespace a {\nnamespace d {\nbar b;\n}\n}\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace d {\nnamespace a {\na::b::bar "
+ "b;\n}\n} // namespace d\n",
+ runIncludeFixer("namespace d {\nnamespace a {\nbar b;\n}\n}\n"));
+
+ // Test nested classes.
+ EXPECT_EQ("#include \"bar.h\"\nnamespace d {\na::b::bar::t b;\n}\n",
+ runIncludeFixer("namespace d {\nbar::t b;\n}\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace c {\na::b::bar::t b;\n}\n",
+ runIncludeFixer("namespace c {\nbar::t b;\n}\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\nb::bar::t b;\n}\n",
+ runIncludeFixer("namespace a {\nbar::t b;\n}\n"));
+
+ EXPECT_EQ("#include \"color.h\"\nint test = a::b::Green;\n",
+ runIncludeFixer("int test = Green;\n"));
+ EXPECT_EQ("#include \"color.h\"\nnamespace d {\nint test = a::b::Green;\n}\n",
+ runIncludeFixer("namespace d {\nint test = Green;\n}\n"));
+ EXPECT_EQ("#include \"color.h\"\nnamespace a {\nint test = b::Green;\n}\n",
+ runIncludeFixer("namespace a {\nint test = Green;\n}\n"));
+
+ // Test global scope operator.
+ EXPECT_EQ("#include \"bar.h\"\n::a::b::bar b;\n",
+ runIncludeFixer("::a::b::bar b;\n"));
+ EXPECT_EQ("#include \"bar.h\"\nnamespace a {\n::a::b::bar b;\n}\n",
+ runIncludeFixer("namespace a {\n::a::b::bar b;\n}\n"));
+}
+
+TEST(IncludeFixer, FixNamespaceQualifiersForAllInstances) {
+ const char TestCode[] = R"(
+namespace a {
+bar b;
+int func1() {
+ bar a;
+ bar *p = new bar();
+ return 0;
+}
+} // namespace a
+
+namespace a {
+bar func2() {
+ bar f;
+ return f;
+}
+} // namespace a
+
+// Non-fixed cases:
+void f() {
+ bar b;
+}
+
+namespace a {
+namespace c {
+ bar b;
+} // namespace c
+} // namespace a
+)";
+
+ const char ExpectedCode[] = R"(
+#include "bar.h"
+namespace a {
+b::bar b;
+int func1() {
+ b::bar a;
+ b::bar *p = new b::bar();
+ return 0;
+}
+} // namespace a
+
+namespace a {
+b::bar func2() {
+ b::bar f;
+ return f;
+}
+} // namespace a
+
+// Non-fixed cases:
+void f() {
+ bar b;
+}
+
+namespace a {
+namespace c {
+ bar b;
+} // namespace c
+} // namespace a
+)";
+
+ EXPECT_EQ(ExpectedCode, runIncludeFixer(TestCode));
+}
+
+TEST(IncludeFixer, DontAddQualifiersForMissingCompleteType) {
+ EXPECT_EQ("#include \"bar.h\"\nclass bar;\nvoid f() {\nbar* b;\nb->f();\n}",
+ runIncludeFixer("class bar;\nvoid f() {\nbar* b;\nb->f();\n}"));
+}
+
+} // namespace
+} // namespace include_fixer
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/find-all-symbols/CMakeLists.txt b/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/find-all-symbols/CMakeLists.txt
new file mode 100644
index 0000000..5689285
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/find-all-symbols/CMakeLists.txt
@@ -0,0 +1,24 @@
+set(LLVM_LINK_COMPONENTS
+ support
+ )
+
+get_filename_component(INCLUDE_FIXER_SOURCE_DIR
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../include-fixer/find-all-symbols REALPATH)
+include_directories(
+ ${INCLUDE_FIXER_SOURCE_DIR}
+ )
+
+add_extra_unittest(FindAllSymbolsTests
+ FindAllSymbolsTests.cpp
+ )
+
+target_link_libraries(FindAllSymbolsTests
+ PRIVATE
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangFrontend
+ clangLex
+ clangTooling
+ findAllSymbols
+ )
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/find-all-symbols/FindAllSymbolsTests.cpp b/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/find-all-symbols/FindAllSymbolsTests.cpp
new file mode 100644
index 0000000..760a253
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/include-fixer/find-all-symbols/FindAllSymbolsTests.cpp
@@ -0,0 +1,578 @@
+//===-- FindAllSymbolsTests.cpp - find all symbols unit tests ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FindAllSymbolsAction.h"
+#include "HeaderMapCollector.h"
+#include "SymbolInfo.h"
+#include "SymbolReporter.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/PCHContainerOperations.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace find_all_symbols {
+
+static const char HeaderName[] = "symbols.h";
+
+class TestSymbolReporter : public SymbolReporter {
+public:
+ ~TestSymbolReporter() override {}
+
+ void reportSymbols(llvm::StringRef FileName,
+ const SymbolInfo::SignalMap &NewSymbols) override {
+ for (const auto &Entry : NewSymbols)
+ Symbols[Entry.first] += Entry.second;
+ }
+
+ int seen(const SymbolInfo &Symbol) const {
+ auto it = Symbols.find(Symbol);
+ return it == Symbols.end() ? 0 : it->second.Seen;
+ }
+
+ int used(const SymbolInfo &Symbol) const {
+ auto it = Symbols.find(Symbol);
+ return it == Symbols.end() ? 0 : it->second.Used;
+ }
+
+private:
+ SymbolInfo::SignalMap Symbols;
+};
+
+class FindAllSymbolsTest : public ::testing::Test {
+public:
+ int seen(const SymbolInfo &Symbol) { return Reporter.seen(Symbol); }
+
+ int used(const SymbolInfo &Symbol) { return Reporter.used(Symbol); }
+
+ bool runFindAllSymbols(StringRef HeaderCode, StringRef MainCode) {
+ llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
+ new vfs::InMemoryFileSystem);
+ llvm::IntrusiveRefCntPtr<FileManager> Files(
+ new FileManager(FileSystemOptions(), InMemoryFileSystem));
+
+ std::string FileName = "symbol.cc";
+
+ const std::string InternalHeader = "internal/internal_header.h";
+ const std::string TopHeader = "<top>";
+ // Test .inc header path. The header for `IncHeaderClass` should be
+ // internal.h, which will eventually be mapped to <top>.
+ std::string IncHeader = "internal/private.inc";
+ std::string IncHeaderCode = "class IncHeaderClass {};";
+
+ HeaderMapCollector::RegexHeaderMap RegexMap = {
+ {R"(internal_.*\.h$)", TopHeader.c_str()},
+ };
+
+ std::string InternalCode =
+ "#include \"private.inc\"\nclass Internal {};";
+ SymbolInfo InternalSymbol("Internal", SymbolInfo::SymbolKind::Class,
+ TopHeader, {});
+ SymbolInfo IncSymbol("IncHeaderClass", SymbolInfo::SymbolKind::Class,
+ TopHeader, {});
+ InMemoryFileSystem->addFile(
+ IncHeader, 0, llvm::MemoryBuffer::getMemBuffer(IncHeaderCode));
+ InMemoryFileSystem->addFile(InternalHeader, 0,
+ llvm::MemoryBuffer::getMemBuffer(InternalCode));
+
+ std::unique_ptr<tooling::FrontendActionFactory> Factory(
+ new FindAllSymbolsActionFactory(&Reporter, &RegexMap));
+
+ tooling::ToolInvocation Invocation(
+ {std::string("find_all_symbols"), std::string("-fsyntax-only"),
+ std::string("-std=c++11"), FileName},
+ Factory->create(), Files.get(),
+ std::make_shared<PCHContainerOperations>());
+
+ InMemoryFileSystem->addFile(HeaderName, 0,
+ llvm::MemoryBuffer::getMemBuffer(HeaderCode));
+
+ std::string Content = "#include\"" + std::string(HeaderName) +
+ "\"\n"
+ "#include \"" +
+ InternalHeader + "\"";
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+ // Test path cleaning for both decls and macros.
+ const std::string DirtyHeader = "./internal/./a/b.h";
+ Content += "\n#include \"" + DirtyHeader + "\"";
+ const std::string CleanHeader = "internal/a/b.h";
+ const std::string DirtyHeaderContent =
+ "#define INTERNAL 1\nclass ExtraInternal {};";
+ InMemoryFileSystem->addFile(
+ DirtyHeader, 0, llvm::MemoryBuffer::getMemBuffer(DirtyHeaderContent));
+ SymbolInfo DirtyMacro("INTERNAL", SymbolInfo::SymbolKind::Macro,
+ CleanHeader, {});
+ SymbolInfo DirtySymbol("ExtraInternal", SymbolInfo::SymbolKind::Class,
+ CleanHeader, {});
+#endif // _MSC_VER && __MINGW32__
+ Content += "\n" + MainCode.str();
+ InMemoryFileSystem->addFile(FileName, 0,
+ llvm::MemoryBuffer::getMemBuffer(Content));
+ Invocation.run();
+ EXPECT_EQ(1, seen(InternalSymbol));
+ EXPECT_EQ(1, seen(IncSymbol));
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+ EXPECT_EQ(1, seen(DirtySymbol));
+ EXPECT_EQ(1, seen(DirtyMacro));
+#endif // _MSC_VER && __MINGW32__
+ return true;
+ }
+
+protected:
+ TestSymbolReporter Reporter;
+};
+
+TEST_F(FindAllSymbolsTest, VariableSymbols) {
+ static const char Header[] = R"(
+ extern int xargc;
+ namespace na {
+ static bool SSSS = false;
+ namespace nb { const long long *XXXX; }
+ })";
+ static const char Main[] = R"(
+ auto y = &na::nb::XXXX;
+ int main() { if (na::SSSS) return xargc; }
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("xargc", SymbolInfo::SymbolKind::Variable, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("SSSS", SymbolInfo::SymbolKind::Variable, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("XXXX", SymbolInfo::SymbolKind::Variable, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "nb"},
+ {SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, ExternCSymbols) {
+ static const char Header[] = R"(
+ extern "C" {
+ int C_Func() { return 0; }
+ struct C_struct {
+ int Member;
+ };
+ })";
+ static const char Main[] = R"(
+ C_struct q() {
+ int(*ptr)() = C_Func;
+ return {0};
+ }
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("C_Func", SymbolInfo::SymbolKind::Function, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol =
+ SymbolInfo("C_struct", SymbolInfo::SymbolKind::Class, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, CXXRecordSymbols) {
+ static const char Header[] = R"(
+ struct Glob {};
+ struct A; // Not a defintion, ignored.
+ class NOP; // Not a defintion, ignored
+ namespace na {
+ struct A {
+ struct AAAA {};
+ int x;
+ int y;
+ void f() {}
+ };
+ }; //
+ )";
+ static const char Main[] = R"(
+ static Glob glob;
+ static na::A::AAAA* a;
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("Glob", SymbolInfo::SymbolKind::Class, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("A", SymbolInfo::SymbolKind::Class, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("AAA", SymbolInfo::SymbolKind::Class, HeaderName,
+ {{SymbolInfo::ContextType::Record, "A"},
+ {SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(0, seen(Symbol));
+ EXPECT_EQ(0, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, CXXRecordSymbolsTemplate) {
+ static const char Header[] = R"(
+ template <typename T>
+ struct T_TEMP {
+ template <typename _Tp1>
+ struct rebind { typedef T_TEMP<_Tp1> other; };
+ };
+ // Ignore specialization.
+ template class T_TEMP<char>;
+
+ template <typename T>
+ class Observer {
+ };
+ // Ignore specialization.
+ template <> class Observer<int> {};
+ )";
+ static const char Main[] = R"(
+ extern T_TEMP<int>::rebind<char> weirdo;
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("T_TEMP", SymbolInfo::SymbolKind::Class, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, DontIgnoreTemplatePartialSpecialization) {
+ static const char Code[] = R"(
+ template<class> class Class; // undefined
+ template<class R, class... ArgTypes>
+ class Class<R(ArgTypes...)> {
+ };
+
+ template<class T> void f() {};
+ template<> void f<int>() {};
+ )";
+ runFindAllSymbols(Code, "");
+ SymbolInfo Symbol =
+ SymbolInfo("Class", SymbolInfo::SymbolKind::Class, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ Symbol = SymbolInfo("f", SymbolInfo::SymbolKind::Function, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, FunctionSymbols) {
+ static const char Header[] = R"(
+ namespace na {
+ int gg(int);
+ int f(const int &a) { int Local; static int StaticLocal; return 0; }
+ static void SSSFFF() {}
+ } // namespace na
+ namespace na {
+ namespace nb {
+ template<typename T>
+ void fun(T t) {};
+ } // namespace nb
+ } // namespace na";
+ )";
+ static const char Main[] = R"(
+ int(*gg)(int) = &na::gg;
+ int main() {
+ (void)na::SSSFFF;
+ na::nb::fun(0);
+ return na::f(gg(0));
+ }
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("gg", SymbolInfo::SymbolKind::Function, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("f", SymbolInfo::SymbolKind::Function, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("SSSFFF", SymbolInfo::SymbolKind::Function, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("fun", SymbolInfo::SymbolKind::Function, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "nb"},
+ {SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, NamespaceTest) {
+ static const char Header[] = R"(
+ int X1;
+ namespace { int X2; }
+ namespace { namespace { int X3; } }
+ namespace { namespace nb { int X4; } }
+ namespace na { inline namespace __1 { int X5; } }
+ )";
+ static const char Main[] = R"(
+ using namespace nb;
+ int main() {
+ X1 = X2;
+ X3 = X4;
+ (void)na::X5;
+ }
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("X1", SymbolInfo::SymbolKind::Variable, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("X2", SymbolInfo::SymbolKind::Variable, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, ""}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("X3", SymbolInfo::SymbolKind::Variable, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, ""},
+ {SymbolInfo::ContextType::Namespace, ""}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("X4", SymbolInfo::SymbolKind::Variable, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "nb"},
+ {SymbolInfo::ContextType::Namespace, ""}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("X5", SymbolInfo::SymbolKind::Variable, HeaderName,
+ {{SymbolInfo::ContextType::Namespace, "na"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, DecayedTypeTest) {
+ static const char Header[] = "void DecayedFunc(int x[], int y[10]) {}";
+ static const char Main[] = R"(int main() { DecayedFunc(nullptr, nullptr); })";
+ runFindAllSymbols(Header, Main);
+ SymbolInfo Symbol = SymbolInfo(
+ "DecayedFunc", SymbolInfo::SymbolKind::Function, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, CTypedefTest) {
+ static const char Header[] = R"(
+ typedef unsigned size_t_;
+ typedef struct { int x; } X;
+ using XX = X;
+ )";
+ static const char Main[] = R"(
+ size_t_ f;
+ template<typename T> struct vector{};
+ vector<X> list;
+ void foo(const XX&){}
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol = SymbolInfo("size_t_", SymbolInfo::SymbolKind::TypedefName,
+ HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("X", SymbolInfo::SymbolKind::TypedefName, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol =
+ SymbolInfo("XX", SymbolInfo::SymbolKind::TypedefName, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, EnumTest) {
+ static const char Header[] = R"(
+ enum Glob_E { G1, G2 };
+ enum class Altitude { high='h', low='l'};
+ enum { A1, A2 };
+ class A {
+ public:
+ enum A_ENUM { X1, X2 };
+ };
+ enum DECL : int;
+ )";
+ static const char Main[] = R"(
+ static auto flags = G1 | G2;
+ static auto alt = Altitude::high;
+ static auto nested = A::X1;
+ extern DECL whatever;
+ static auto flags2 = A1 | A2;
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("Glob_E", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(0, used(Symbol));
+
+ Symbol =
+ SymbolInfo("G1", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName,
+ {{SymbolInfo::ContextType::EnumDecl, "Glob_E"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol =
+ SymbolInfo("G2", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName,
+ {{SymbolInfo::ContextType::EnumDecl, "Glob_E"}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol =
+ SymbolInfo("Altitude", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+ Symbol =
+ SymbolInfo("high", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName,
+ {{SymbolInfo::ContextType::EnumDecl, "Altitude"}});
+ EXPECT_EQ(0, seen(Symbol));
+ EXPECT_EQ(0, used(Symbol));
+
+ Symbol = SymbolInfo("A1", SymbolInfo::SymbolKind::EnumConstantDecl,
+ HeaderName, {{SymbolInfo::ContextType::EnumDecl, ""}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+ Symbol = SymbolInfo("A2", SymbolInfo::SymbolKind::EnumConstantDecl,
+ HeaderName, {{SymbolInfo::ContextType::EnumDecl, ""}});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+ Symbol = SymbolInfo("", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});
+ EXPECT_EQ(0, seen(Symbol));
+ EXPECT_EQ(0, used(Symbol));
+
+ Symbol = SymbolInfo("A_ENUM", SymbolInfo::SymbolKind::EnumDecl, HeaderName,
+ {{SymbolInfo::ContextType::Record, "A"}});
+ EXPECT_EQ(0, seen(Symbol));
+ EXPECT_EQ(0, used(Symbol));
+
+ Symbol = SymbolInfo("X1", SymbolInfo::SymbolKind::EnumDecl, HeaderName,
+ {{SymbolInfo::ContextType::EnumDecl, "A_ENUM"},
+ {SymbolInfo::ContextType::Record, "A"}});
+ EXPECT_EQ(0, seen(Symbol));
+
+ Symbol = SymbolInfo("DECL", SymbolInfo::SymbolKind::EnumDecl, HeaderName, {});
+ EXPECT_EQ(0, seen(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, IWYUPrivatePragmaTest) {
+ static const char Header[] = R"(
+ // IWYU pragma: private, include "bar.h"
+ struct Bar {
+ };
+ )";
+ static const char Main[] = R"(
+ Bar bar;
+ )";
+ runFindAllSymbols(Header, Main);
+
+ SymbolInfo Symbol =
+ SymbolInfo("Bar", SymbolInfo::SymbolKind::Class, "bar.h", {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, MacroTest) {
+ static const char Header[] = R"(
+ #define X
+ #define Y 1
+ #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+ )";
+ static const char Main[] = R"(
+ #ifdef X
+ int main() { return MAX(0,Y); }
+ #endif
+ )";
+ runFindAllSymbols(Header, Main);
+ SymbolInfo Symbol =
+ SymbolInfo("X", SymbolInfo::SymbolKind::Macro, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("Y", SymbolInfo::SymbolKind::Macro, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("MAX", SymbolInfo::SymbolKind::Macro, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, MacroTestWithIWYU) {
+ static const char Header[] = R"(
+ // IWYU pragma: private, include "bar.h"
+ #define X 1
+ #define Y 1
+ #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+ )";
+ static const char Main[] = R"(
+ #ifdef X
+ int main() { return MAX(0,Y); }
+ #endif
+ )";
+ runFindAllSymbols(Header, Main);
+ SymbolInfo Symbol =
+ SymbolInfo("X", SymbolInfo::SymbolKind::Macro, "bar.h", {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("Y", SymbolInfo::SymbolKind::Macro, "bar.h", {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+
+ Symbol = SymbolInfo("MAX", SymbolInfo::SymbolKind::Macro, "bar.h", {});
+ EXPECT_EQ(1, seen(Symbol));
+ EXPECT_EQ(1, used(Symbol));
+}
+
+TEST_F(FindAllSymbolsTest, NoFriendTest) {
+ static const char Header[] = R"(
+ class WorstFriend {
+ friend void Friend();
+ friend class BestFriend;
+ };
+ )";
+ runFindAllSymbols(Header, "");
+ SymbolInfo Symbol =
+ SymbolInfo("WorstFriend", SymbolInfo::SymbolKind::Class, HeaderName, {});
+ EXPECT_EQ(1, seen(Symbol));
+
+ Symbol =
+ SymbolInfo("Friend", SymbolInfo::SymbolKind::Function, HeaderName, {});
+ EXPECT_EQ(0, seen(Symbol));
+
+ Symbol =
+ SymbolInfo("BestFriend", SymbolInfo::SymbolKind::Class, HeaderName, {});
+ EXPECT_EQ(0, seen(Symbol));
+}
+
+} // namespace find_all_symbols
+} // namespace clang
diff --git a/src/third_party/llvm-project/clang-tools-extra/unittests/include/common/VirtualFileHelper.h b/src/third_party/llvm-project/clang-tools-extra/unittests/include/common/VirtualFileHelper.h
new file mode 100644
index 0000000..5fa4d53
--- /dev/null
+++ b/src/third_party/llvm-project/clang-tools-extra/unittests/include/common/VirtualFileHelper.h
@@ -0,0 +1,82 @@
+//===--- VirtualFileHelper.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \brief This file defines an utility class for tests that needs a source
+/// manager for a virtual file with customizable content.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_MODERNIZE_VIRTUAL_FILE_HELPER_H
+#define CLANG_MODERNIZE_VIRTUAL_FILE_HELPER_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+
+namespace clang {
+
+/// \brief Class that provides easy access to a SourceManager and that allows to
+/// map virtual files conveniently.
+class VirtualFileHelper {
+ struct VirtualFile {
+ std::string FileName;
+ std::string Code;
+ };
+
+public:
+ VirtualFileHelper()
+ : DiagOpts(new DiagnosticOptions()),
+ Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ &*DiagOpts),
+ DiagnosticPrinter(llvm::outs(), &*DiagOpts),
+ Files((FileSystemOptions())) {}
+
+ /// \brief Create a virtual file \p FileName, with content \p Code.
+ void mapFile(llvm::StringRef FileName, llvm::StringRef Code) {
+ VirtualFile VF = { FileName, Code };
+ VirtualFiles.push_back(VF);
+ }
+
+ /// \brief Create a new \c SourceManager with the virtual files and contents
+ /// mapped to it.
+ SourceManager &getNewSourceManager() {
+ Sources.reset(new SourceManager(Diagnostics, Files));
+ mapVirtualFiles(*Sources);
+ return *Sources;
+ }
+
+ /// \brief Map the virtual file contents in the given \c SourceManager.
+ void mapVirtualFiles(SourceManager &SM) const {
+ for (llvm::SmallVectorImpl<VirtualFile>::const_iterator
+ I = VirtualFiles.begin(),
+ E = VirtualFiles.end();
+ I != E; ++I) {
+ std::unique_ptr<llvm::MemoryBuffer> Buf =
+ llvm::MemoryBuffer::getMemBuffer(I->Code);
+ const FileEntry *Entry = SM.getFileManager().getVirtualFile(
+ I->FileName, Buf->getBufferSize(), /*ModificationTime=*/0);
+ SM.overrideFileContents(Entry, std::move(Buf));
+ }
+ }
+
+private:
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+ DiagnosticsEngine Diagnostics;
+ TextDiagnosticPrinter DiagnosticPrinter;
+ FileManager Files;
+ // most tests don't need more than one file
+ llvm::SmallVector<VirtualFile, 1> VirtualFiles;
+ std::unique_ptr<SourceManager> Sources;
+};
+
+} // end namespace clang
+
+#endif // CLANG_MODERNIZE_VIRTUAL_FILE_HELPER_H