Importing rustc-1.38.0
diff --git a/src/llvm-project/clang/unittests/AST/ASTContextParentMapTest.cpp b/src/llvm-project/clang/unittests/AST/ASTContextParentMapTest.cpp
index fb9d517..14da737 100644
--- a/src/llvm-project/clang/unittests/AST/ASTContextParentMapTest.cpp
+++ b/src/llvm-project/clang/unittests/AST/ASTContextParentMapTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/AST/ASTContextParentMapTest.cpp - AST parent map test -----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/AST/ASTImporterFixtures.cpp b/src/llvm-project/clang/unittests/AST/ASTImporterFixtures.cpp
new file mode 100644
index 0000000..0be4e78
--- /dev/null
+++ b/src/llvm-project/clang/unittests/AST/ASTImporterFixtures.cpp
@@ -0,0 +1,215 @@
+//===- unittest/AST/ASTImporterFixtures.cpp - AST unit test support -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Implementation of fixture classes for testing the ASTImporter.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTImporterFixtures.h"
+
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/ASTImporterSharedState.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Tooling/Tooling.h"
+
+namespace clang {
+namespace ast_matchers {
+
+void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
+ std::unique_ptr<llvm::MemoryBuffer> &&Buffer) {
+ assert(ToAST);
+ ASTContext &ToCtx = ToAST->getASTContext();
+ auto *OFS = static_cast<llvm::vfs::OverlayFileSystem *>(
+ &ToCtx.getSourceManager().getFileManager().getVirtualFileSystem());
+ auto *MFS = static_cast<llvm::vfs::InMemoryFileSystem *>(
+ OFS->overlays_begin()->get());
+ MFS->addFile(FileName, 0, std::move(Buffer));
+}
+
+void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
+ StringRef Code) {
+ return createVirtualFileIfNeeded(ToAST, FileName,
+ llvm::MemoryBuffer::getMemBuffer(Code));
+}
+
+ASTImporterTestBase::TU::TU(StringRef Code, StringRef FileName, ArgVector Args,
+ ImporterConstructor C)
+ : Code(Code), FileName(FileName),
+ Unit(tooling::buildASTFromCodeWithArgs(this->Code, Args, this->FileName)),
+ TUDecl(Unit->getASTContext().getTranslationUnitDecl()), Creator(C) {
+ Unit->enableSourceFileDiagnostics();
+
+ // If the test doesn't need a specific ASTImporter, we just create a
+ // normal ASTImporter with it.
+ if (!Creator)
+ Creator = [](ASTContext &ToContext, FileManager &ToFileManager,
+ ASTContext &FromContext, FileManager &FromFileManager,
+ bool MinimalImport,
+ const std::shared_ptr<ASTImporterSharedState> &SharedState) {
+ return new ASTImporter(ToContext, ToFileManager, FromContext,
+ FromFileManager, MinimalImport, SharedState);
+ };
+}
+
+ASTImporterTestBase::TU::~TU() {}
+
+void ASTImporterTestBase::TU::lazyInitImporter(
+ const std::shared_ptr<ASTImporterSharedState> &SharedState,
+ ASTUnit *ToAST) {
+ assert(ToAST);
+ if (!Importer)
+ Importer.reset(Creator(ToAST->getASTContext(), ToAST->getFileManager(),
+ Unit->getASTContext(), Unit->getFileManager(), false,
+ SharedState));
+ assert(&ToAST->getASTContext() == &Importer->getToContext());
+ createVirtualFileIfNeeded(ToAST, FileName, Code);
+}
+
+Decl *ASTImporterTestBase::TU::import(
+ const std::shared_ptr<ASTImporterSharedState> &SharedState, ASTUnit *ToAST,
+ Decl *FromDecl) {
+ lazyInitImporter(SharedState, ToAST);
+ if (auto ImportedOrErr = Importer->Import(FromDecl))
+ return *ImportedOrErr;
+ else {
+ llvm::consumeError(ImportedOrErr.takeError());
+ return nullptr;
+ }
+}
+
+QualType ASTImporterTestBase::TU::import(
+ const std::shared_ptr<ASTImporterSharedState> &SharedState, ASTUnit *ToAST,
+ QualType FromType) {
+ lazyInitImporter(SharedState, ToAST);
+ if (auto ImportedOrErr = Importer->Import(FromType))
+ return *ImportedOrErr;
+ else {
+ llvm::consumeError(ImportedOrErr.takeError());
+ return QualType{};
+ }
+}
+
+void ASTImporterTestBase::lazyInitSharedState(TranslationUnitDecl *ToTU) {
+ assert(ToTU);
+ if (!SharedStatePtr)
+ SharedStatePtr = std::make_shared<ASTImporterSharedState>(*ToTU);
+}
+
+void ASTImporterTestBase::lazyInitToAST(Language ToLang, StringRef ToSrcCode,
+ StringRef FileName) {
+ if (ToAST)
+ return;
+ ArgVector ToArgs = getArgVectorForLanguage(ToLang);
+ // Source code must be a valid live buffer through the tests lifetime.
+ ToCode = ToSrcCode;
+ // Build the AST from an empty file.
+ ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, FileName);
+ ToAST->enableSourceFileDiagnostics();
+ lazyInitSharedState(ToAST->getASTContext().getTranslationUnitDecl());
+}
+
+ASTImporterTestBase::TU *ASTImporterTestBase::findFromTU(Decl *From) {
+ // Create a virtual file in the To Ctx which corresponds to the file from
+ // which we want to import the `From` Decl. Without this source locations
+ // will be invalid in the ToCtx.
+ auto It = llvm::find_if(FromTUs, [From](const TU &E) {
+ return E.TUDecl == From->getTranslationUnitDecl();
+ });
+ assert(It != FromTUs.end());
+ return &*It;
+}
+
+std::tuple<Decl *, Decl *>
+ASTImporterTestBase::getImportedDecl(StringRef FromSrcCode, Language FromLang,
+ StringRef ToSrcCode, Language ToLang,
+ StringRef Identifier) {
+ ArgVector FromArgs = getArgVectorForLanguage(FromLang),
+ ToArgs = getArgVectorForLanguage(ToLang);
+
+ FromTUs.emplace_back(FromSrcCode, InputFileName, FromArgs, Creator);
+ TU &FromTU = FromTUs.back();
+
+ assert(!ToAST);
+ lazyInitToAST(ToLang, ToSrcCode, OutputFileName);
+
+ ASTContext &FromCtx = FromTU.Unit->getASTContext();
+
+ IdentifierInfo *ImportedII = &FromCtx.Idents.get(Identifier);
+ assert(ImportedII && "Declaration with the given identifier "
+ "should be specified in test!");
+ DeclarationName ImportDeclName(ImportedII);
+ SmallVector<NamedDecl *, 1> FoundDecls;
+ FromCtx.getTranslationUnitDecl()->localUncachedLookup(ImportDeclName,
+ FoundDecls);
+
+ assert(FoundDecls.size() == 1);
+
+ Decl *Imported =
+ FromTU.import(SharedStatePtr, ToAST.get(), FoundDecls.front());
+
+ assert(Imported);
+ return std::make_tuple(*FoundDecls.begin(), Imported);
+}
+
+TranslationUnitDecl *ASTImporterTestBase::getTuDecl(StringRef SrcCode,
+ Language Lang,
+ StringRef FileName) {
+ assert(llvm::find_if(FromTUs, [FileName](const TU &E) {
+ return E.FileName == FileName;
+ }) == FromTUs.end());
+
+ ArgVector Args = getArgVectorForLanguage(Lang);
+ FromTUs.emplace_back(SrcCode, FileName, Args, Creator);
+ TU &Tu = FromTUs.back();
+
+ return Tu.TUDecl;
+}
+
+TranslationUnitDecl *ASTImporterTestBase::getToTuDecl(StringRef ToSrcCode,
+ Language ToLang) {
+ ArgVector ToArgs = getArgVectorForLanguage(ToLang);
+ assert(!ToAST);
+ lazyInitToAST(ToLang, ToSrcCode, OutputFileName);
+ return ToAST->getASTContext().getTranslationUnitDecl();
+}
+
+Decl *ASTImporterTestBase::Import(Decl *From, Language ToLang) {
+ lazyInitToAST(ToLang, "", OutputFileName);
+ TU *FromTU = findFromTU(From);
+ assert(SharedStatePtr);
+ Decl *To = FromTU->import(SharedStatePtr, ToAST.get(), From);
+ return To;
+}
+
+QualType ASTImporterTestBase::ImportType(QualType FromType, Decl *TUDecl,
+ Language ToLang) {
+ lazyInitToAST(ToLang, "", OutputFileName);
+ TU *FromTU = findFromTU(TUDecl);
+ assert(SharedStatePtr);
+ return FromTU->import(SharedStatePtr, ToAST.get(), FromType);
+}
+
+ASTImporterTestBase::~ASTImporterTestBase() {
+ if (!::testing::Test::HasFailure())
+ return;
+
+ for (auto &Tu : FromTUs) {
+ assert(Tu.Unit);
+ llvm::errs() << "FromAST:\n";
+ Tu.Unit->getASTContext().getTranslationUnitDecl()->dump();
+ llvm::errs() << "\n";
+ }
+ if (ToAST) {
+ llvm::errs() << "ToAST:\n";
+ ToAST->getASTContext().getTranslationUnitDecl()->dump();
+ }
+}
+
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/src/llvm-project/clang/unittests/AST/ASTImporterFixtures.h b/src/llvm-project/clang/unittests/AST/ASTImporterFixtures.h
new file mode 100644
index 0000000..4b67a94
--- /dev/null
+++ b/src/llvm-project/clang/unittests/AST/ASTImporterFixtures.h
@@ -0,0 +1,180 @@
+//===- unittest/AST/ASTImporterFixtures.h - AST unit test support ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Fixture classes for testing the ASTImporter.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_UNITTESTS_AST_IMPORTER_FIXTURES_H
+#define LLVM_CLANG_UNITTESTS_AST_IMPORTER_FIXTURES_H
+
+#include "gmock/gmock.h"
+
+#include "clang/AST/ASTImporter.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/AST/ASTImporterSharedState.h"
+
+#include "DeclMatcher.h"
+#include "Language.h"
+
+namespace clang {
+
+class ASTImporter;
+class ASTImporterSharedState;
+class ASTUnit;
+
+namespace ast_matchers {
+
+const StringRef DeclToImportID = "declToImport";
+const StringRef DeclToVerifyID = "declToVerify";
+
+// Creates a virtual file and assigns that to the context of given AST. If the
+// file already exists then the file will not be created again as a duplicate.
+void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
+ std::unique_ptr<llvm::MemoryBuffer> &&Buffer);
+
+void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
+ StringRef Code);
+
+// Common base for the different families of ASTImporter tests that are
+// parameterized on the compiler options which may result a different AST. E.g.
+// -fms-compatibility or -fdelayed-template-parsing.
+class CompilerOptionSpecificTest : public ::testing::Test {
+protected:
+ // Return the extra arguments appended to runtime options at compilation.
+ virtual ArgVector getExtraArgs() const { return ArgVector(); }
+
+ // Returns the argument vector used for a specific language option, this set
+ // can be tweaked by the test parameters.
+ ArgVector getArgVectorForLanguage(Language Lang) const {
+ ArgVector Args = getBasicRunOptionsForLanguage(Lang);
+ ArgVector ExtraArgs = getExtraArgs();
+ for (const auto &Arg : ExtraArgs) {
+ Args.push_back(Arg);
+ }
+ return Args;
+ }
+};
+
+const auto DefaultTestValuesForRunOptions = ::testing::Values(
+ ArgVector(), ArgVector{"-fdelayed-template-parsing"},
+ ArgVector{"-fms-compatibility"},
+ ArgVector{"-fdelayed-template-parsing", "-fms-compatibility"});
+
+// This class provides generic methods to write tests which can check internal
+// attributes of AST nodes like getPreviousDecl(), isVirtual(), etc. Also,
+// this fixture makes it possible to import from several "From" contexts.
+class ASTImporterTestBase : public CompilerOptionSpecificTest {
+
+ const char *const InputFileName = "input.cc";
+ const char *const OutputFileName = "output.cc";
+
+public:
+ /// Allocates an ASTImporter (or one of its subclasses).
+ typedef std::function<ASTImporter *(
+ ASTContext &, FileManager &, ASTContext &, FileManager &, bool,
+ const std::shared_ptr<ASTImporterSharedState> &SharedState)>
+ ImporterConstructor;
+
+ // The lambda that constructs the ASTImporter we use in this test.
+ ImporterConstructor Creator;
+
+private:
+ // Buffer for the To context, must live in the test scope.
+ std::string ToCode;
+
+ // Represents a "From" translation unit and holds an importer object which we
+ // use to import from this translation unit.
+ struct TU {
+ // Buffer for the context, must live in the test scope.
+ std::string Code;
+ std::string FileName;
+ std::unique_ptr<ASTUnit> Unit;
+ TranslationUnitDecl *TUDecl = nullptr;
+ std::unique_ptr<ASTImporter> Importer;
+ ImporterConstructor Creator;
+
+ TU(StringRef Code, StringRef FileName, ArgVector Args,
+ ImporterConstructor C = ImporterConstructor());
+ ~TU();
+
+ void
+ lazyInitImporter(const std::shared_ptr<ASTImporterSharedState> &SharedState,
+ ASTUnit *ToAST);
+ Decl *import(const std::shared_ptr<ASTImporterSharedState> &SharedState,
+ ASTUnit *ToAST, Decl *FromDecl);
+ QualType import(const std::shared_ptr<ASTImporterSharedState> &SharedState,
+ ASTUnit *ToAST, QualType FromType);
+ };
+
+ // We may have several From contexts and related translation units. In each
+ // AST, the buffers for the source are handled via references and are set
+ // during the creation of the AST. These references must point to a valid
+ // buffer until the AST is alive. Thus, we must use a list in order to avoid
+ // moving of the stored objects because that would mean breaking the
+ // references in the AST. By using a vector a move could happen when the
+ // vector is expanding, with the list we won't have these issues.
+ std::list<TU> FromTUs;
+
+ // Initialize the shared state if not initialized already.
+ void lazyInitSharedState(TranslationUnitDecl *ToTU);
+
+ void lazyInitToAST(Language ToLang, StringRef ToSrcCode, StringRef FileName);
+
+protected:
+ std::shared_ptr<ASTImporterSharedState> SharedStatePtr;
+
+public:
+ // We may have several From context but only one To context.
+ std::unique_ptr<ASTUnit> ToAST;
+
+ // Returns with the TU associated with the given Decl.
+ TU *findFromTU(Decl *From);
+
+ // Creates an AST both for the From and To source code and imports the Decl
+ // of the identifier into the To context.
+ // Must not be called more than once within the same test.
+ std::tuple<Decl *, Decl *>
+ getImportedDecl(StringRef FromSrcCode, Language FromLang, StringRef ToSrcCode,
+ Language ToLang, StringRef Identifier = DeclToImportID);
+
+ // Creates a TU decl for the given source code which can be used as a From
+ // context. May be called several times in a given test (with different file
+ // name).
+ TranslationUnitDecl *getTuDecl(StringRef SrcCode, Language Lang,
+ StringRef FileName = "input.cc");
+
+ // Creates the To context with the given source code and returns the TU decl.
+ TranslationUnitDecl *getToTuDecl(StringRef ToSrcCode, Language ToLang);
+
+ // Import the given Decl into the ToCtx.
+ // May be called several times in a given test.
+ // The different instances of the param From may have different ASTContext.
+ Decl *Import(Decl *From, Language ToLang);
+
+ template <class DeclT> DeclT *Import(DeclT *From, Language Lang) {
+ return cast_or_null<DeclT>(Import(cast<Decl>(From), Lang));
+ }
+
+ QualType ImportType(QualType FromType, Decl *TUDecl, Language ToLang);
+
+ ~ASTImporterTestBase();
+};
+
+class ASTImporterOptionSpecificTestBase
+ : public ASTImporterTestBase,
+ public ::testing::WithParamInterface<ArgVector> {
+protected:
+ ArgVector getExtraArgs() const override { return GetParam(); }
+};
+
+} // end namespace ast_matchers
+} // end namespace clang
+
+#endif
diff --git a/src/llvm-project/clang/unittests/AST/ASTImporterGenericRedeclTest.cpp b/src/llvm-project/clang/unittests/AST/ASTImporterGenericRedeclTest.cpp
new file mode 100644
index 0000000..0f994c1
--- /dev/null
+++ b/src/llvm-project/clang/unittests/AST/ASTImporterGenericRedeclTest.cpp
@@ -0,0 +1,577 @@
+//===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Type-parameterized tests for the correct import of redecl chains.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTImporterFixtures.h"
+
+namespace clang {
+namespace ast_matchers {
+
+using internal::BindableMatcher;
+
+struct Function {
+ using DeclTy = FunctionDecl;
+ static constexpr auto *Prototype = "void X();";
+ static constexpr auto *Definition = "void X() {}";
+ BindableMatcher<Decl> getPattern() {
+ return functionDecl(hasName("X"), unless(isImplicit()));
+ }
+};
+
+struct Class {
+ using DeclTy = CXXRecordDecl;
+ static constexpr auto *Prototype = "class X;";
+ static constexpr auto *Definition = "class X {};";
+ BindableMatcher<Decl> getPattern() {
+ return cxxRecordDecl(hasName("X"), unless(isImplicit()));
+ }
+};
+
+struct Variable {
+ using DeclTy = VarDecl;
+ static constexpr auto *Prototype = "extern int X;";
+ static constexpr auto *Definition = "int X;";
+ BindableMatcher<Decl> getPattern() { return varDecl(hasName("X")); }
+};
+
+struct FunctionTemplate {
+ using DeclTy = FunctionTemplateDecl;
+ static constexpr auto *Prototype = "template <class T> void X();";
+ static constexpr auto *Definition =
+ R"(
+ template <class T> void X() {};
+ // Explicit instantiation is a must because of -fdelayed-template-parsing:
+ template void X<int>();
+ )";
+ BindableMatcher<Decl> getPattern() {
+ return functionTemplateDecl(hasName("X"), unless(isImplicit()));
+ }
+};
+
+struct ClassTemplate {
+ using DeclTy = ClassTemplateDecl;
+ static constexpr auto *Prototype = "template <class T> class X;";
+ static constexpr auto *Definition = "template <class T> class X {};";
+ BindableMatcher<Decl> getPattern() {
+ return classTemplateDecl(hasName("X"), unless(isImplicit()));
+ }
+};
+
+struct FunctionTemplateSpec {
+ using DeclTy = FunctionDecl;
+ static constexpr auto *Prototype =
+ R"(
+ // Proto of the primary template.
+ template <class T>
+ void X();
+ // Proto of the specialization.
+ template <>
+ void X<int>();
+ )";
+ static constexpr auto *Definition =
+ R"(
+ // Proto of the primary template.
+ template <class T>
+ void X();
+ // Specialization and definition.
+ template <>
+ void X<int>() {}
+ )";
+ BindableMatcher<Decl> getPattern() {
+ return functionDecl(hasName("X"), isExplicitTemplateSpecialization());
+ }
+};
+
+struct ClassTemplateSpec {
+ using DeclTy = ClassTemplateSpecializationDecl;
+ static constexpr auto *Prototype =
+ R"(
+ template <class T> class X;
+ template <> class X<int>;
+ )";
+ static constexpr auto *Definition =
+ R"(
+ template <class T> class X;
+ template <> class X<int> {};
+ )";
+ BindableMatcher<Decl> getPattern() {
+ return classTemplateSpecializationDecl(hasName("X"), unless(isImplicit()));
+ }
+};
+
+template <typename TypeParam>
+struct RedeclChain : ASTImporterOptionSpecificTestBase {
+
+ using DeclTy = typename TypeParam::DeclTy;
+ std::string getPrototype() { return TypeParam::Prototype; }
+ std::string getDefinition() { return TypeParam::Definition; }
+ BindableMatcher<Decl> getPattern() const { return TypeParam().getPattern(); }
+
+ void CheckPreviousDecl(Decl *Prev, Decl *Current) {
+ ASSERT_NE(Prev, Current);
+ ASSERT_EQ(&Prev->getASTContext(), &Current->getASTContext());
+ EXPECT_EQ(Prev->getCanonicalDecl(), Current->getCanonicalDecl());
+
+ // Templates.
+ if (auto *PrevT = dyn_cast<TemplateDecl>(Prev)) {
+ EXPECT_EQ(Current->getPreviousDecl(), Prev);
+ auto *CurrentT = cast<TemplateDecl>(Current);
+ ASSERT_TRUE(PrevT->getTemplatedDecl());
+ ASSERT_TRUE(CurrentT->getTemplatedDecl());
+ EXPECT_EQ(CurrentT->getTemplatedDecl()->getPreviousDecl(),
+ PrevT->getTemplatedDecl());
+ return;
+ }
+
+ // Specializations.
+ if (auto *PrevF = dyn_cast<FunctionDecl>(Prev)) {
+ if (PrevF->getTemplatedKind() ==
+ FunctionDecl::TK_FunctionTemplateSpecialization) {
+ // There may be a hidden fwd spec decl before a spec decl.
+ // In that case the previous visible decl can be reached through that
+ // invisible one.
+ EXPECT_THAT(Prev, testing::AnyOf(
+ Current->getPreviousDecl(),
+ Current->getPreviousDecl()->getPreviousDecl()));
+ auto *ToTU = Prev->getTranslationUnitDecl();
+ auto *TemplateD = FirstDeclMatcher<FunctionTemplateDecl>().match(
+ ToTU, functionTemplateDecl());
+ auto *FirstSpecD = *(TemplateD->spec_begin());
+ EXPECT_EQ(FirstSpecD->getCanonicalDecl(), PrevF->getCanonicalDecl());
+ return;
+ }
+ }
+
+ // The rest: Classes, Functions, etc.
+ EXPECT_EQ(Current->getPreviousDecl(), Prev);
+ }
+
+ void
+ TypedTest_PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition() {
+ Decl *FromTU = getTuDecl(getPrototype(), Lang_CXX);
+ auto *FromD = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
+ ASSERT_FALSE(FromD->isThisDeclarationADefinition());
+
+ Decl *ImportedD = Import(FromD, Lang_CXX);
+ Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+ EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 1u);
+ auto *ToD = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ EXPECT_TRUE(ImportedD == ToD);
+ EXPECT_FALSE(ToD->isThisDeclarationADefinition());
+ if (auto *ToT = dyn_cast<TemplateDecl>(ToD)) {
+ EXPECT_TRUE(ToT->getTemplatedDecl());
+ }
+ }
+
+ void TypedTest_DefinitionShouldBeImportedAsADefinition() {
+ Decl *FromTU = getTuDecl(getDefinition(), Lang_CXX);
+ auto *FromD = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
+ ASSERT_TRUE(FromD->isThisDeclarationADefinition());
+
+ Decl *ImportedD = Import(FromD, Lang_CXX);
+ Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+ EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 1u);
+ auto *ToD = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ EXPECT_TRUE(ToD->isThisDeclarationADefinition());
+ if (auto *ToT = dyn_cast<TemplateDecl>(ToD)) {
+ EXPECT_TRUE(ToT->getTemplatedDecl());
+ }
+ }
+
+ void TypedTest_ImportPrototypeAfterImportedPrototype() {
+ Decl *FromTU = getTuDecl(getPrototype() + getPrototype(), Lang_CXX);
+ auto *From0 = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
+ auto *From1 = LastDeclMatcher<DeclTy>().match(FromTU, getPattern());
+ ASSERT_FALSE(From0->isThisDeclarationADefinition());
+ ASSERT_FALSE(From1->isThisDeclarationADefinition());
+
+ Decl *Imported0 = Import(From0, Lang_CXX);
+ Decl *Imported1 = Import(From1, Lang_CXX);
+ Decl *ToTU = Imported0->getTranslationUnitDecl();
+
+ EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
+ auto *To0 = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ auto *To1 = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ EXPECT_TRUE(Imported0 == To0);
+ EXPECT_TRUE(Imported1 == To1);
+ EXPECT_FALSE(To0->isThisDeclarationADefinition());
+ EXPECT_FALSE(To1->isThisDeclarationADefinition());
+
+ CheckPreviousDecl(To0, To1);
+ }
+
+ void TypedTest_ImportDefinitionAfterImportedPrototype() {
+ Decl *FromTU = getTuDecl(getPrototype() + getDefinition(), Lang_CXX);
+ auto *FromProto = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
+ auto *FromDef = LastDeclMatcher<DeclTy>().match(FromTU, getPattern());
+ ASSERT_FALSE(FromProto->isThisDeclarationADefinition());
+ ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
+
+ Decl *ImportedProto = Import(FromProto, Lang_CXX);
+ Decl *ImportedDef = Import(FromDef, Lang_CXX);
+ Decl *ToTU = ImportedProto->getTranslationUnitDecl();
+
+ EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
+ auto *ToProto = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ auto *ToDef = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ EXPECT_TRUE(ImportedProto == ToProto);
+ EXPECT_TRUE(ImportedDef == ToDef);
+ EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
+ EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
+
+ CheckPreviousDecl(ToProto, ToDef);
+ }
+
+ void TypedTest_ImportPrototypeAfterImportedDefinition() {
+ Decl *FromTU = getTuDecl(getDefinition() + getPrototype(), Lang_CXX);
+ auto *FromDef = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
+ auto *FromProto = LastDeclMatcher<DeclTy>().match(FromTU, getPattern());
+ ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
+ ASSERT_FALSE(FromProto->isThisDeclarationADefinition());
+
+ Decl *ImportedDef = Import(FromDef, Lang_CXX);
+ Decl *ImportedProto = Import(FromProto, Lang_CXX);
+ Decl *ToTU = ImportedDef->getTranslationUnitDecl();
+
+ EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
+ auto *ToDef = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ auto *ToProto = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ EXPECT_TRUE(ImportedDef == ToDef);
+ EXPECT_TRUE(ImportedProto == ToProto);
+ EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
+ EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
+
+ CheckPreviousDecl(ToDef, ToProto);
+ }
+
+ void TypedTest_ImportPrototypes() {
+ Decl *FromTU0 = getTuDecl(getPrototype(), Lang_CXX, "input0.cc");
+ Decl *FromTU1 = getTuDecl(getPrototype(), Lang_CXX, "input1.cc");
+ auto *From0 = FirstDeclMatcher<DeclTy>().match(FromTU0, getPattern());
+ auto *From1 = FirstDeclMatcher<DeclTy>().match(FromTU1, getPattern());
+ ASSERT_FALSE(From0->isThisDeclarationADefinition());
+ ASSERT_FALSE(From1->isThisDeclarationADefinition());
+
+ Decl *Imported0 = Import(From0, Lang_CXX);
+ Decl *Imported1 = Import(From1, Lang_CXX);
+ Decl *ToTU = Imported0->getTranslationUnitDecl();
+
+ EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
+ auto *To0 = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ auto *To1 = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ EXPECT_TRUE(Imported0 == To0);
+ EXPECT_TRUE(Imported1 == To1);
+ EXPECT_FALSE(To0->isThisDeclarationADefinition());
+ EXPECT_FALSE(To1->isThisDeclarationADefinition());
+
+ CheckPreviousDecl(To0, To1);
+ }
+
+ void TypedTest_ImportDefinitions() {
+ Decl *FromTU0 = getTuDecl(getDefinition(), Lang_CXX, "input0.cc");
+ Decl *FromTU1 = getTuDecl(getDefinition(), Lang_CXX, "input1.cc");
+ auto *From0 = FirstDeclMatcher<DeclTy>().match(FromTU0, getPattern());
+ auto *From1 = FirstDeclMatcher<DeclTy>().match(FromTU1, getPattern());
+ ASSERT_TRUE(From0->isThisDeclarationADefinition());
+ ASSERT_TRUE(From1->isThisDeclarationADefinition());
+
+ Decl *Imported0 = Import(From0, Lang_CXX);
+ Decl *Imported1 = Import(From1, Lang_CXX);
+ Decl *ToTU = Imported0->getTranslationUnitDecl();
+
+ EXPECT_EQ(Imported0, Imported1);
+ EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 1u);
+ auto *To0 = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ EXPECT_TRUE(Imported0 == To0);
+ EXPECT_TRUE(To0->isThisDeclarationADefinition());
+ if (auto *ToT0 = dyn_cast<TemplateDecl>(To0)) {
+ EXPECT_TRUE(ToT0->getTemplatedDecl());
+ }
+ }
+
+ void TypedTest_ImportDefinitionThenPrototype() {
+ Decl *FromTUDef = getTuDecl(getDefinition(), Lang_CXX, "input0.cc");
+ Decl *FromTUProto = getTuDecl(getPrototype(), Lang_CXX, "input1.cc");
+ auto *FromDef = FirstDeclMatcher<DeclTy>().match(FromTUDef, getPattern());
+ auto *FromProto =
+ FirstDeclMatcher<DeclTy>().match(FromTUProto, getPattern());
+ ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
+ ASSERT_FALSE(FromProto->isThisDeclarationADefinition());
+
+ Decl *ImportedDef = Import(FromDef, Lang_CXX);
+ Decl *ImportedProto = Import(FromProto, Lang_CXX);
+ Decl *ToTU = ImportedDef->getTranslationUnitDecl();
+
+ EXPECT_NE(ImportedDef, ImportedProto);
+ EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
+ auto *ToDef = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ auto *ToProto = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ EXPECT_TRUE(ImportedDef == ToDef);
+ EXPECT_TRUE(ImportedProto == ToProto);
+ EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
+ EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
+
+ CheckPreviousDecl(ToDef, ToProto);
+ }
+
+ void TypedTest_ImportPrototypeThenDefinition() {
+ Decl *FromTUProto = getTuDecl(getPrototype(), Lang_CXX, "input0.cc");
+ Decl *FromTUDef = getTuDecl(getDefinition(), Lang_CXX, "input1.cc");
+ auto *FromProto =
+ FirstDeclMatcher<DeclTy>().match(FromTUProto, getPattern());
+ auto *FromDef = FirstDeclMatcher<DeclTy>().match(FromTUDef, getPattern());
+ ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
+ ASSERT_FALSE(FromProto->isThisDeclarationADefinition());
+
+ Decl *ImportedProto = Import(FromProto, Lang_CXX);
+ Decl *ImportedDef = Import(FromDef, Lang_CXX);
+ Decl *ToTU = ImportedDef->getTranslationUnitDecl();
+
+ EXPECT_NE(ImportedDef, ImportedProto);
+ EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
+ auto *ToProto = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ auto *ToDef = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ EXPECT_TRUE(ImportedDef == ToDef);
+ EXPECT_TRUE(ImportedProto == ToProto);
+ EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
+ EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
+
+ CheckPreviousDecl(ToProto, ToDef);
+ }
+
+ void TypedTest_WholeRedeclChainIsImportedAtOnce() {
+ Decl *FromTU = getTuDecl(getPrototype() + getDefinition(), Lang_CXX);
+ auto *FromD = // Definition
+ LastDeclMatcher<DeclTy>().match(FromTU, getPattern());
+ ASSERT_TRUE(FromD->isThisDeclarationADefinition());
+
+ Decl *ImportedD = Import(FromD, Lang_CXX);
+ Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+ // The whole redecl chain is imported at once.
+ EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
+ EXPECT_TRUE(cast<DeclTy>(ImportedD)->isThisDeclarationADefinition());
+ }
+
+ void TypedTest_ImportPrototypeThenProtoAndDefinition() {
+ {
+ Decl *FromTU = getTuDecl(getPrototype(), Lang_CXX, "input0.cc");
+ auto *FromD = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
+ Import(FromD, Lang_CXX);
+ }
+ {
+ Decl *FromTU =
+ getTuDecl(getPrototype() + getDefinition(), Lang_CXX, "input1.cc");
+ auto *FromD = FirstDeclMatcher<DeclTy>().match(FromTU, getPattern());
+ Import(FromD, Lang_CXX);
+ }
+
+ Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+
+ ASSERT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 3u);
+ DeclTy *ProtoD = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ EXPECT_FALSE(ProtoD->isThisDeclarationADefinition());
+
+ DeclTy *DefinitionD = LastDeclMatcher<DeclTy>().match(ToTU, getPattern());
+ EXPECT_TRUE(DefinitionD->isThisDeclarationADefinition());
+
+ EXPECT_TRUE(DefinitionD->getPreviousDecl());
+ EXPECT_FALSE(
+ DefinitionD->getPreviousDecl()->isThisDeclarationADefinition());
+
+ CheckPreviousDecl(ProtoD, DefinitionD->getPreviousDecl());
+ }
+};
+
+#define ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(BaseTemplate, TypeParam, \
+ NamePrefix, TestCase) \
+ using BaseTemplate##TypeParam = BaseTemplate<TypeParam>; \
+ TEST_P(BaseTemplate##TypeParam, NamePrefix##TestCase) { \
+ TypedTest_##TestCase(); \
+ }
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+ RedeclChain, Function, ,
+ PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+ RedeclChain, Class, ,
+ PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+ RedeclChain, Variable, ,
+ PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+ RedeclChain, FunctionTemplate, ,
+ PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+ RedeclChain, ClassTemplate, ,
+ PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+ RedeclChain, FunctionTemplateSpec, ,
+ PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+ RedeclChain, ClassTemplateSpec, ,
+ PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+ DefinitionShouldBeImportedAsADefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
+ DefinitionShouldBeImportedAsADefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+ DefinitionShouldBeImportedAsADefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+ DefinitionShouldBeImportedAsADefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+ DefinitionShouldBeImportedAsADefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+ DefinitionShouldBeImportedAsADefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+ DefinitionShouldBeImportedAsADefinition)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+ ImportPrototypeAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
+ ImportPrototypeAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+ ImportPrototypeAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+ ImportPrototypeAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+ ImportPrototypeAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+ ImportPrototypeAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+ ImportPrototypeAfterImportedPrototype)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+ ImportDefinitionAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
+ ImportDefinitionAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+ ImportDefinitionAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+ ImportDefinitionAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+ ImportDefinitionAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+ ImportDefinitionAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+ ImportDefinitionAfterImportedPrototype)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+ ImportPrototypeAfterImportedDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
+ ImportPrototypeAfterImportedDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+ ImportPrototypeAfterImportedDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+ ImportPrototypeAfterImportedDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+ ImportPrototypeAfterImportedDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+ ImportPrototypeAfterImportedDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+ ImportPrototypeAfterImportedDefinition)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+ ImportPrototypes)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, , ImportPrototypes)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+ ImportPrototypes)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+ ImportPrototypes)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+ ImportPrototypes)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+ ImportPrototypes)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+ ImportPrototypes)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+ ImportDefinitions)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, , ImportDefinitions)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+ ImportDefinitions)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+ ImportDefinitions)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+ ImportDefinitions)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+ ImportDefinitions)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+ ImportDefinitions)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+ ImportDefinitionThenPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
+ ImportDefinitionThenPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+ ImportDefinitionThenPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+ ImportDefinitionThenPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+ ImportDefinitionThenPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+ ImportDefinitionThenPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+ ImportDefinitionThenPrototype)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+ ImportPrototypeThenDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
+ ImportPrototypeThenDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+ ImportPrototypeThenDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+ ImportPrototypeThenDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplate, ,
+ ImportPrototypeThenDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+ ImportPrototypeThenDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
+ ImportPrototypeThenDefinition)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+ WholeRedeclChainIsImportedAtOnce)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+ WholeRedeclChainIsImportedAtOnce)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+ WholeRedeclChainIsImportedAtOnce)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+ WholeRedeclChainIsImportedAtOnce)
+
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
+ ImportPrototypeThenProtoAndDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
+ ImportPrototypeThenProtoAndDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
+ ImportPrototypeThenProtoAndDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
+ ImportPrototypeThenProtoAndDefinition)
+
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunction,
+ DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainClass,
+ DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainVariable,
+ DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunctionTemplate,
+ DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainClassTemplate,
+ DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunctionTemplateSpec,
+ DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainClassTemplateSpec,
+ DefaultTestValuesForRunOptions, );
+
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/src/llvm-project/clang/unittests/AST/ASTImporterTest.cpp b/src/llvm-project/clang/unittests/AST/ASTImporterTest.cpp
index c6acf57..6ea350c 100644
--- a/src/llvm-project/clang/unittests/AST/ASTImporterTest.cpp
+++ b/src/llvm-project/clang/unittests/AST/ASTImporterTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -11,21 +10,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/ASTImporter.h"
-#include "MatchVerifier.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclContextInternals.h"
-#include "clang/AST/ASTImporter.h"
-#include "clang/AST/ASTImporterLookupTable.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/ASTMatchers/ASTMatchers.h"
-#include "clang/Tooling/Tooling.h"
-
-#include "DeclMatcher.h"
-#include "Language.h"
-#include "gmock/gmock.h"
#include "llvm/ADT/StringMap.h"
+#include "clang/AST/DeclContextInternals.h"
+
+#include "ASTImporterFixtures.h"
+#include "MatchVerifier.h"
+
namespace clang {
namespace ast_matchers {
@@ -33,53 +24,13 @@
using internal::BindableMatcher;
using llvm::StringMap;
-// Creates a virtual file and assigns that to the context of given AST. If the
-// file already exists then the file will not be created again as a duplicate.
-static void
-createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
- std::unique_ptr<llvm::MemoryBuffer> &&Buffer) {
- assert(ToAST);
- ASTContext &ToCtx = ToAST->getASTContext();
- auto *OFS = static_cast<llvm::vfs::OverlayFileSystem *>(
- ToCtx.getSourceManager().getFileManager().getVirtualFileSystem().get());
- auto *MFS = static_cast<llvm::vfs::InMemoryFileSystem *>(
- OFS->overlays_begin()->get());
- MFS->addFile(FileName, 0, std::move(Buffer));
-}
-
-static void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
- StringRef Code) {
- return createVirtualFileIfNeeded(ToAST, FileName,
- llvm::MemoryBuffer::getMemBuffer(Code));
-}
-
-const StringRef DeclToImportID = "declToImport";
-const StringRef DeclToVerifyID = "declToVerify";
-
-// Common base for the different families of ASTImporter tests that are
-// parameterized on the compiler options which may result a different AST. E.g.
-// -fms-compatibility or -fdelayed-template-parsing.
-struct ParameterizedTestsFixture : ::testing::TestWithParam<ArgVector> {
-
- // Returns the argument vector used for a specific language option, this set
- // can be tweaked by the test parameters.
- ArgVector getArgVectorForLanguage(Language Lang) const {
- ArgVector Args = getBasicRunOptionsForLanguage(Lang);
- ArgVector ExtraArgs = GetParam();
- for (const auto &Arg : ExtraArgs) {
- Args.push_back(Arg);
- }
- return Args;
- }
-
-};
-
// Base class for those tests which use the family of `testImport` functions.
-class TestImportBase : public ParameterizedTestsFixture {
+class TestImportBase : public CompilerOptionSpecificTest,
+ public ::testing::WithParamInterface<ArgVector> {
template <typename NodeType>
- NodeType importNode(ASTUnit *From, ASTUnit *To, ASTImporter &Importer,
- NodeType Node) {
+ llvm::Expected<NodeType> importNode(ASTUnit *From, ASTUnit *To,
+ ASTImporter &Importer, NodeType Node) {
ASTContext &ToCtx = To->getASTContext();
// Add 'From' file to virtual file system so importer can 'find' it
@@ -91,15 +42,17 @@
auto Imported = Importer.Import(Node);
- // This should dump source locations and assert if some source locations
- // were not imported.
- SmallString<1024> ImportChecker;
- llvm::raw_svector_ostream ToNothing(ImportChecker);
- ToCtx.getTranslationUnitDecl()->print(ToNothing);
+ if (Imported) {
+ // This should dump source locations and assert if some source locations
+ // were not imported.
+ SmallString<1024> ImportChecker;
+ llvm::raw_svector_ostream ToNothing(ImportChecker);
+ ToCtx.getTranslationUnitDecl()->print(ToNothing);
- // This traverses the AST to catch certain bugs like poorly or not
- // implemented subtrees.
- Imported->dump(ToNothing);
+ // This traverses the AST to catch certain bugs like poorly or not
+ // implemented subtrees.
+ (*Imported)->dump(ToNothing);
+ }
return Imported;
}
@@ -140,11 +93,16 @@
EXPECT_TRUE(Verifier.match(ToImport, WrapperMatcher));
auto Imported = importNode(FromAST.get(), ToAST.get(), Importer, ToImport);
- if (!Imported)
- return testing::AssertionFailure() << "Import failed, nullptr returned!";
+ if (!Imported) {
+ std::string ErrorText;
+ handleAllErrors(
+ Imported.takeError(),
+ [&ErrorText](const ImportError &Err) { ErrorText = Err.message(); });
+ return testing::AssertionFailure()
+ << "Import failed, error: \"" << ErrorText << "\"!";
+ }
-
- return Verifier.match(Imported, WrapperMatcher);
+ return Verifier.match(*Imported, WrapperMatcher);
}
template <typename NodeType>
@@ -160,6 +118,9 @@
VerificationMatcher);
}
+protected:
+ ArgVector getExtraArgs() const override { return GetParam(); }
+
public:
/// Test how AST node named "declToImport" located in the translation unit
@@ -263,7 +224,9 @@
EXPECT_TRUE(FoundDecl.size() == 1);
const Decl *ToImport = selectFirst<Decl>(DeclToImportID, FoundDecl);
auto Imported = importNode(From, To, *ImporterRef, ToImport);
- EXPECT_TRUE(Imported);
+ EXPECT_TRUE(static_cast<bool>(Imported));
+ if (!Imported)
+ llvm::consumeError(Imported.takeError());
}
// Find the declaration and import it.
@@ -282,203 +245,11 @@
return cast<RecordType>(ET->getNamedType().getTypePtr())->getDecl();
}
-// This class provides generic methods to write tests which can check internal
-// attributes of AST nodes like getPreviousDecl(), isVirtual(), etc. Also,
-// this fixture makes it possible to import from several "From" contexts.
-class ASTImporterTestBase : public ParameterizedTestsFixture {
-
- const char *const InputFileName = "input.cc";
- const char *const OutputFileName = "output.cc";
-
- // Buffer for the To context, must live in the test scope.
- std::string ToCode;
-
- // Represents a "From" translation unit and holds an importer object which we
- // use to import from this translation unit.
- struct TU {
- // Buffer for the context, must live in the test scope.
- std::string Code;
- std::string FileName;
- std::unique_ptr<ASTUnit> Unit;
- TranslationUnitDecl *TUDecl = nullptr;
- std::unique_ptr<ASTImporter> Importer;
- TU(StringRef Code, StringRef FileName, ArgVector Args)
- : Code(Code), FileName(FileName),
- Unit(tooling::buildASTFromCodeWithArgs(this->Code, Args,
- this->FileName)),
- TUDecl(Unit->getASTContext().getTranslationUnitDecl()) {
- Unit->enableSourceFileDiagnostics();
- }
-
- void lazyInitImporter(ASTImporterLookupTable &LookupTable, ASTUnit *ToAST) {
- assert(ToAST);
- if (!Importer) {
- Importer.reset(
- new ASTImporter(ToAST->getASTContext(), ToAST->getFileManager(),
- Unit->getASTContext(), Unit->getFileManager(),
- false, &LookupTable));
- }
- assert(&ToAST->getASTContext() == &Importer->getToContext());
- createVirtualFileIfNeeded(ToAST, FileName, Code);
- }
-
- Decl *import(ASTImporterLookupTable &LookupTable, ASTUnit *ToAST,
- Decl *FromDecl) {
- lazyInitImporter(LookupTable, ToAST);
- return Importer->Import(FromDecl);
- }
-
- QualType import(ASTImporterLookupTable &LookupTable, ASTUnit *ToAST,
- QualType FromType) {
- lazyInitImporter(LookupTable, ToAST);
- return Importer->Import(FromType);
- }
- };
-
- // We may have several From contexts and related translation units. In each
- // AST, the buffers for the source are handled via references and are set
- // during the creation of the AST. These references must point to a valid
- // buffer until the AST is alive. Thus, we must use a list in order to avoid
- // moving of the stored objects because that would mean breaking the
- // references in the AST. By using a vector a move could happen when the
- // vector is expanding, with the list we won't have these issues.
- std::list<TU> FromTUs;
-
- // Initialize the lookup table if not initialized already.
- void lazyInitLookupTable(TranslationUnitDecl *ToTU) {
- assert(ToTU);
- if (!LookupTablePtr)
- LookupTablePtr = llvm::make_unique<ASTImporterLookupTable>(*ToTU);
- }
-
- void lazyInitToAST(Language ToLang, StringRef ToSrcCode, StringRef FileName) {
- if (ToAST)
- return;
- ArgVector ToArgs = getArgVectorForLanguage(ToLang);
- // Source code must be a valid live buffer through the tests lifetime.
- ToCode = ToSrcCode;
- // Build the AST from an empty file.
- ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, FileName);
- ToAST->enableSourceFileDiagnostics();
- lazyInitLookupTable(ToAST->getASTContext().getTranslationUnitDecl());
- }
-
- TU *findFromTU(Decl *From) {
- // Create a virtual file in the To Ctx which corresponds to the file from
- // which we want to import the `From` Decl. Without this source locations
- // will be invalid in the ToCtx.
- auto It = std::find_if(FromTUs.begin(), FromTUs.end(), [From](const TU &E) {
- return E.TUDecl == From->getTranslationUnitDecl();
- });
- assert(It != FromTUs.end());
- return &*It;
- }
-
-protected:
-
- std::unique_ptr<ASTImporterLookupTable> LookupTablePtr;
-
-public:
- // We may have several From context but only one To context.
- std::unique_ptr<ASTUnit> ToAST;
-
- // Creates an AST both for the From and To source code and imports the Decl
- // of the identifier into the To context.
- // Must not be called more than once within the same test.
- std::tuple<Decl *, Decl *>
- getImportedDecl(StringRef FromSrcCode, Language FromLang, StringRef ToSrcCode,
- Language ToLang, StringRef Identifier = DeclToImportID) {
- ArgVector FromArgs = getArgVectorForLanguage(FromLang),
- ToArgs = getArgVectorForLanguage(ToLang);
-
- FromTUs.emplace_back(FromSrcCode, InputFileName, FromArgs);
- TU &FromTU = FromTUs.back();
-
- assert(!ToAST);
- lazyInitToAST(ToLang, ToSrcCode, OutputFileName);
-
- ASTContext &FromCtx = FromTU.Unit->getASTContext();
-
- IdentifierInfo *ImportedII = &FromCtx.Idents.get(Identifier);
- assert(ImportedII && "Declaration with the given identifier "
- "should be specified in test!");
- DeclarationName ImportDeclName(ImportedII);
- SmallVector<NamedDecl *, 1> FoundDecls;
- FromCtx.getTranslationUnitDecl()->localUncachedLookup(ImportDeclName,
- FoundDecls);
-
- assert(FoundDecls.size() == 1);
-
- Decl *Imported =
- FromTU.import(*LookupTablePtr, ToAST.get(), FoundDecls.front());
-
- assert(Imported);
- return std::make_tuple(*FoundDecls.begin(), Imported);
- }
-
- // Creates a TU decl for the given source code which can be used as a From
- // context. May be called several times in a given test (with different file
- // name).
- TranslationUnitDecl *getTuDecl(StringRef SrcCode, Language Lang,
- StringRef FileName = "input.cc") {
- assert(
- std::find_if(FromTUs.begin(), FromTUs.end(), [FileName](const TU &E) {
- return E.FileName == FileName;
- }) == FromTUs.end());
-
- ArgVector Args = getArgVectorForLanguage(Lang);
- FromTUs.emplace_back(SrcCode, FileName, Args);
- TU &Tu = FromTUs.back();
-
- return Tu.TUDecl;
- }
-
- // Creates the To context with the given source code and returns the TU decl.
- TranslationUnitDecl *getToTuDecl(StringRef ToSrcCode, Language ToLang) {
- ArgVector ToArgs = getArgVectorForLanguage(ToLang);
- assert(!ToAST);
- lazyInitToAST(ToLang, ToSrcCode, OutputFileName);
- return ToAST->getASTContext().getTranslationUnitDecl();
- }
-
- // Import the given Decl into the ToCtx.
- // May be called several times in a given test.
- // The different instances of the param From may have different ASTContext.
- Decl *Import(Decl *From, Language ToLang) {
- lazyInitToAST(ToLang, "", OutputFileName);
- TU *FromTU = findFromTU(From);
- assert(LookupTablePtr);
- return FromTU->import(*LookupTablePtr, ToAST.get(), From);
- }
-
- QualType ImportType(QualType FromType, Decl *TUDecl, Language ToLang) {
- lazyInitToAST(ToLang, "", OutputFileName);
- TU *FromTU = findFromTU(TUDecl);
- assert(LookupTablePtr);
- return FromTU->import(*LookupTablePtr, ToAST.get(), FromType);
- }
-
- ~ASTImporterTestBase() {
- if (!::testing::Test::HasFailure()) return;
-
- for (auto &Tu : FromTUs) {
- assert(Tu.Unit);
- llvm::errs() << "FromAST:\n";
- Tu.Unit->getASTContext().getTranslationUnitDecl()->dump();
- llvm::errs() << "\n";
- }
- if (ToAST) {
- llvm::errs() << "ToAST:\n";
- ToAST->getASTContext().getTranslationUnitDecl()->dump();
- }
- }
-};
-
struct ImportExpr : TestImportBase {};
struct ImportType : TestImportBase {};
struct ImportDecl : TestImportBase {};
-struct CanonicalRedeclChain : ASTImporterTestBase {};
+struct CanonicalRedeclChain : ASTImporterOptionSpecificTestBase {};
TEST_P(CanonicalRedeclChain, ShouldBeConsequentWithMatchers) {
Decl *FromTU = getTuDecl("void f();", Lang_CXX);
@@ -519,6 +290,175 @@
EXPECT_THAT(RedeclsD1, ::testing::ContainerEq(RedeclsD2));
}
+namespace {
+struct RedirectingImporter : public ASTImporter {
+ using ASTImporter::ASTImporter;
+
+protected:
+ llvm::Expected<Decl *> ImportImpl(Decl *FromD) override {
+ auto *ND = dyn_cast<NamedDecl>(FromD);
+ if (!ND || ND->getName() != "shouldNotBeImported")
+ return ASTImporter::ImportImpl(FromD);
+ for (Decl *D : getToContext().getTranslationUnitDecl()->decls()) {
+ if (auto *ND = dyn_cast<NamedDecl>(D))
+ if (ND->getName() == "realDecl") {
+ RegisterImportedDecl(FromD, ND);
+ return ND;
+ }
+ }
+ return ASTImporter::ImportImpl(FromD);
+ }
+};
+
+} // namespace
+
+struct RedirectingImporterTest : ASTImporterOptionSpecificTestBase {
+ RedirectingImporterTest() {
+ Creator = [](ASTContext &ToContext, FileManager &ToFileManager,
+ ASTContext &FromContext, FileManager &FromFileManager,
+ bool MinimalImport,
+ const std::shared_ptr<ASTImporterSharedState> &SharedState) {
+ return new RedirectingImporter(ToContext, ToFileManager, FromContext,
+ FromFileManager, MinimalImport,
+ SharedState);
+ };
+ }
+};
+
+// Test that an ASTImporter subclass can intercept an import call.
+TEST_P(RedirectingImporterTest, InterceptImport) {
+ Decl *From, *To;
+ std::tie(From, To) =
+ getImportedDecl("class shouldNotBeImported {};", Lang_CXX,
+ "class realDecl {};", Lang_CXX, "shouldNotBeImported");
+ auto *Imported = cast<CXXRecordDecl>(To);
+ EXPECT_EQ(Imported->getQualifiedNameAsString(), "realDecl");
+
+ // Make sure our importer prevented the importing of the decl.
+ auto *ToTU = Imported->getTranslationUnitDecl();
+ auto Pattern = functionDecl(hasName("shouldNotBeImported"));
+ unsigned count =
+ DeclCounterWithPredicate<CXXRecordDecl>().match(ToTU, Pattern);
+ EXPECT_EQ(0U, count);
+}
+
+// Test that when we indirectly import a declaration the custom ASTImporter
+// is still intercepting the import.
+TEST_P(RedirectingImporterTest, InterceptIndirectImport) {
+ Decl *From, *To;
+ std::tie(From, To) =
+ getImportedDecl("class shouldNotBeImported {};"
+ "class F { shouldNotBeImported f; };",
+ Lang_CXX, "class realDecl {};", Lang_CXX, "F");
+
+ // Make sure our ASTImporter prevented the importing of the decl.
+ auto *ToTU = To->getTranslationUnitDecl();
+ auto Pattern = functionDecl(hasName("shouldNotBeImported"));
+ unsigned count =
+ DeclCounterWithPredicate<CXXRecordDecl>().match(ToTU, Pattern);
+ EXPECT_EQ(0U, count);
+}
+
+struct ImportPath : ASTImporterOptionSpecificTestBase {
+ Decl *FromTU;
+ FunctionDecl *D0, *D1, *D2;
+ ImportPath() {
+ FromTU = getTuDecl("void f(); void f(); void f();", Lang_CXX);
+ auto Pattern = functionDecl(hasName("f"));
+ D0 = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+ D2 = LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+ D1 = D2->getPreviousDecl();
+ }
+};
+
+TEST_P(ImportPath, Push) {
+ ASTImporter::ImportPathTy path;
+ path.push(D0);
+ EXPECT_FALSE(path.hasCycleAtBack());
+}
+
+TEST_P(ImportPath, SmallCycle) {
+ ASTImporter::ImportPathTy path;
+ path.push(D0);
+ path.push(D0);
+ EXPECT_TRUE(path.hasCycleAtBack());
+ path.pop();
+ EXPECT_FALSE(path.hasCycleAtBack());
+ path.push(D0);
+ EXPECT_TRUE(path.hasCycleAtBack());
+}
+
+TEST_P(ImportPath, GetSmallCycle) {
+ ASTImporter::ImportPathTy path;
+ path.push(D0);
+ path.push(D0);
+ EXPECT_TRUE(path.hasCycleAtBack());
+ std::array<Decl* ,2> Res;
+ int i = 0;
+ for (Decl *Di : path.getCycleAtBack()) {
+ Res[i++] = Di;
+ }
+ ASSERT_EQ(i, 2);
+ EXPECT_EQ(Res[0], D0);
+ EXPECT_EQ(Res[1], D0);
+}
+
+TEST_P(ImportPath, GetCycle) {
+ ASTImporter::ImportPathTy path;
+ path.push(D0);
+ path.push(D1);
+ path.push(D2);
+ path.push(D0);
+ EXPECT_TRUE(path.hasCycleAtBack());
+ std::array<Decl* ,4> Res;
+ int i = 0;
+ for (Decl *Di : path.getCycleAtBack()) {
+ Res[i++] = Di;
+ }
+ ASSERT_EQ(i, 4);
+ EXPECT_EQ(Res[0], D0);
+ EXPECT_EQ(Res[1], D2);
+ EXPECT_EQ(Res[2], D1);
+ EXPECT_EQ(Res[3], D0);
+}
+
+TEST_P(ImportPath, CycleAfterCycle) {
+ ASTImporter::ImportPathTy path;
+ path.push(D0);
+ path.push(D1);
+ path.push(D0);
+ path.push(D1);
+ path.push(D2);
+ path.push(D0);
+ EXPECT_TRUE(path.hasCycleAtBack());
+ std::array<Decl* ,4> Res;
+ int i = 0;
+ for (Decl *Di : path.getCycleAtBack()) {
+ Res[i++] = Di;
+ }
+ ASSERT_EQ(i, 4);
+ EXPECT_EQ(Res[0], D0);
+ EXPECT_EQ(Res[1], D2);
+ EXPECT_EQ(Res[2], D1);
+ EXPECT_EQ(Res[3], D0);
+
+ path.pop();
+ path.pop();
+ path.pop();
+ EXPECT_TRUE(path.hasCycleAtBack());
+ i = 0;
+ for (Decl *Di : path.getCycleAtBack()) {
+ Res[i++] = Di;
+ }
+ ASSERT_EQ(i, 3);
+ EXPECT_EQ(Res[0], D0);
+ EXPECT_EQ(Res[1], D1);
+ EXPECT_EQ(Res[2], D0);
+
+ path.pop();
+ EXPECT_FALSE(path.hasCycleAtBack());
+}
+
TEST_P(ImportExpr, ImportStringLiteral) {
MatchVerifier<Decl> Verifier;
testImport(
@@ -538,6 +478,17 @@
stringLiteral(hasType(asString("const char [7]"))))));
}
+TEST_P(ImportExpr, ImportChooseExpr) {
+ MatchVerifier<Decl> Verifier;
+
+ // This case tests C code that is not condition-dependent and has a true
+ // condition.
+ testImport(
+ "void declToImport() { (void)__builtin_choose_expr(1, 2, 3); }",
+ Lang_C, "", Lang_C, Verifier,
+ functionDecl(hasDescendant(chooseExpr())));
+}
+
TEST_P(ImportExpr, ImportGNUNullExpr) {
MatchVerifier<Decl> Verifier;
testImport(
@@ -1001,7 +952,7 @@
has(declStmt(hasSingleDecl(varDecl(hasName("d")))))))));
}
-TEST_P(ASTImporterTestBase, ImportRecordTypeInFunc) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportRecordTypeInFunc) {
Decl *FromTU = getTuDecl("int declToImport() { "
" struct data_t {int a;int b;};"
" struct data_t d;"
@@ -1016,7 +967,7 @@
EXPECT_FALSE(ToType.isNull());
}
-TEST_P(ASTImporterTestBase, ImportRecordDeclInFuncParams) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportRecordDeclInFuncParams) {
// This construct is not supported by ASTImporter.
Decl *FromTU = getTuDecl(
"int declToImport(struct data_t{int a;int b;} ***d){ return 0; }",
@@ -1028,7 +979,7 @@
EXPECT_EQ(To, nullptr);
}
-TEST_P(ASTImporterTestBase, ImportRecordDeclInFuncFromMacro) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportRecordDeclInFuncFromMacro) {
Decl *FromTU = getTuDecl(
"#define NONAME_SIZEOF(type) sizeof(struct{type *dummy;}) \n"
"int declToImport(){ return NONAME_SIZEOF(int); }",
@@ -1043,7 +994,8 @@
hasDescendant(unaryExprOrTypeTraitExpr()))));
}
-TEST_P(ASTImporterTestBase, ImportRecordDeclInFuncParamsFromMacro) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportRecordDeclInFuncParamsFromMacro) {
// This construct is not supported by ASTImporter.
Decl *FromTU = getTuDecl(
"#define PAIR_STRUCT(type) struct data_t{type a;type b;} \n"
@@ -1195,7 +1147,28 @@
has(fieldDecl(hasType(dependentSizedArrayType())))))));
}
-TEST_P(ASTImporterTestBase, ImportOfTemplatedDeclOfClassTemplateDecl) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportBeginLocOfDeclRefExpr) {
+ Decl *FromTU = getTuDecl(
+ "class A { public: static int X; }; void f() { (void)A::X; }", Lang_CXX);
+ auto From = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("f")));
+ ASSERT_TRUE(From);
+ ASSERT_TRUE(
+ cast<CStyleCastExpr>(cast<CompoundStmt>(From->getBody())->body_front())
+ ->getSubExpr()
+ ->getBeginLoc()
+ .isValid());
+ FunctionDecl *To = Import(From, Lang_CXX);
+ ASSERT_TRUE(To);
+ ASSERT_TRUE(
+ cast<CStyleCastExpr>(cast<CompoundStmt>(To->getBody())->body_front())
+ ->getSubExpr()
+ ->getBeginLoc()
+ .isValid());
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportOfTemplatedDeclOfClassTemplateDecl) {
Decl *FromTU = getTuDecl("template<class X> struct S{};", Lang_CXX);
auto From =
FirstDeclMatcher<ClassTemplateDecl>().match(FromTU, classTemplateDecl());
@@ -1208,7 +1181,8 @@
EXPECT_EQ(ToTemplated1, ToTemplated);
}
-TEST_P(ASTImporterTestBase, ImportOfTemplatedDeclOfFunctionTemplateDecl) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportOfTemplatedDeclOfFunctionTemplateDecl) {
Decl *FromTU = getTuDecl("template<class X> void f(){}", Lang_CXX);
auto From = FirstDeclMatcher<FunctionTemplateDecl>().match(
FromTU, functionTemplateDecl());
@@ -1221,7 +1195,7 @@
EXPECT_EQ(ToTemplated1, ToTemplated);
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ImportOfTemplatedDeclShouldImportTheClassTemplateDecl) {
Decl *FromTU = getTuDecl("template<class X> struct S{};", Lang_CXX);
auto FromFT =
@@ -1237,7 +1211,7 @@
EXPECT_TRUE(ToFT);
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ImportOfTemplatedDeclShouldImportTheFunctionTemplateDecl) {
Decl *FromTU = getTuDecl("template<class X> void f(){}", Lang_CXX);
auto FromFT = FirstDeclMatcher<FunctionTemplateDecl>().match(
@@ -1253,7 +1227,7 @@
EXPECT_TRUE(ToFT);
}
-TEST_P(ASTImporterTestBase, ImportCorrectTemplatedDecl) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplatedDecl) {
auto Code =
R"(
namespace x {
@@ -1284,7 +1258,31 @@
ASSERT_EQ(ToTemplated1, ToTemplated);
}
-TEST_P(ASTImporterTestBase, ImportFunctionWithBackReferringParameter) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportChooseExpr) {
+ // This tests the import of isConditionTrue directly to make sure the importer
+ // gets it right.
+ Decl *From, *To;
+ std::tie(From, To) = getImportedDecl(
+ "void declToImport() { (void)__builtin_choose_expr(1, 0, 1); }",
+ Lang_C, "", Lang_C);
+
+ auto ToResults = match(chooseExpr().bind("choose"), To->getASTContext());
+ auto FromResults = match(chooseExpr().bind("choose"), From->getASTContext());
+
+ const ChooseExpr *FromChooseExpr =
+ selectFirst<ChooseExpr>("choose", FromResults);
+ ASSERT_TRUE(FromChooseExpr);
+
+ const ChooseExpr *ToChooseExpr = selectFirst<ChooseExpr>("choose", ToResults);
+ ASSERT_TRUE(ToChooseExpr);
+
+ EXPECT_EQ(FromChooseExpr->isConditionTrue(), ToChooseExpr->isConditionTrue());
+ EXPECT_EQ(FromChooseExpr->isConditionDependent(),
+ ToChooseExpr->isConditionDependent());
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportFunctionWithBackReferringParameter) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
R"(
@@ -1311,7 +1309,7 @@
EXPECT_TRUE(Verifier.match(To, Matcher));
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
TUshouldNotContainTemplatedDeclOfFunctionTemplates) {
Decl *From, *To;
std::tie(From, To) =
@@ -1337,7 +1335,8 @@
EXPECT_TRUE(Check(To));
}
-TEST_P(ASTImporterTestBase, TUshouldNotContainTemplatedDeclOfClassTemplates) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ TUshouldNotContainTemplatedDeclOfClassTemplates) {
Decl *From, *To;
std::tie(From, To) =
getImportedDecl("template <typename T> struct declToImport { T t; };"
@@ -1362,7 +1361,8 @@
EXPECT_TRUE(Check(To));
}
-TEST_P(ASTImporterTestBase, TUshouldNotContainTemplatedDeclOfTypeAlias) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ TUshouldNotContainTemplatedDeclOfTypeAlias) {
Decl *From, *To;
std::tie(From, To) =
getImportedDecl(
@@ -1389,9 +1389,8 @@
EXPECT_TRUE(Check(To));
}
-TEST_P(
- ASTImporterTestBase,
- TUshouldNotContainClassTemplateSpecializationOfImplicitInstantiation) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ TUshouldNotContainClassTemplateSpecializationOfImplicitInstantiation) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
@@ -1432,7 +1431,7 @@
return Index == Order.size();
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
TUshouldContainClassTemplateSpecializationOfExplicitInstantiation) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
@@ -1459,7 +1458,8 @@
EXPECT_TRUE(MatchVerifier<Decl>{}.match(To, Pattern));
}
-TEST_P(ASTImporterTestBase, CXXRecordDeclFieldsShouldBeInCorrectOrder) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ CXXRecordDeclFieldsShouldBeInCorrectOrder) {
Decl *From, *To;
std::tie(From, To) =
getImportedDecl(
@@ -1471,7 +1471,7 @@
EXPECT_TRUE(Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b"}))));
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
DISABLED_CXXRecordDeclFieldOrderShouldNotDependOnImportOrder) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
@@ -1493,7 +1493,7 @@
Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b", "c"}))));
}
-TEST_P(ASTImporterTestBase, ShouldImportImplicitCXXRecordDecl) {
+TEST_P(ASTImporterOptionSpecificTestBase, ShouldImportImplicitCXXRecordDecl) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
R"(
@@ -1509,7 +1509,8 @@
EXPECT_TRUE(Verifier.match(To, Matcher));
}
-TEST_P(ASTImporterTestBase, ShouldImportImplicitCXXRecordDeclOfClassTemplate) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ShouldImportImplicitCXXRecordDeclOfClassTemplate) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
R"(
@@ -1526,9 +1527,8 @@
EXPECT_TRUE(Verifier.match(To, Matcher));
}
-TEST_P(
- ASTImporterTestBase,
- ShouldImportImplicitCXXRecordDeclOfClassTemplateSpecializationDecl) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ShouldImportImplicitCXXRecordDeclOfClassTemplateSpecializationDecl) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
R"(
@@ -1548,7 +1548,7 @@
MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
}
-TEST_P(ASTImporterTestBase, IDNSOrdinary) {
+TEST_P(ASTImporterOptionSpecificTestBase, IDNSOrdinary) {
Decl *From, *To;
std::tie(From, To) =
getImportedDecl("void declToImport() {}", Lang_CXX, "", Lang_CXX);
@@ -1560,7 +1560,7 @@
EXPECT_EQ(From->getIdentifierNamespace(), To->getIdentifierNamespace());
}
-TEST_P(ASTImporterTestBase, IDNSOfNonmemberOperator) {
+TEST_P(ASTImporterOptionSpecificTestBase, IDNSOfNonmemberOperator) {
Decl *FromTU = getTuDecl(
R"(
struct X {};
@@ -1572,7 +1572,7 @@
EXPECT_EQ(From->getIdentifierNamespace(), To->getIdentifierNamespace());
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ShouldImportMembersOfClassTemplateSpecializationDecl) {
Decl *From, *To;
std::tie(From, To) = getImportedDecl(
@@ -1592,7 +1592,8 @@
MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
}
-TEST_P(ASTImporterTestBase, ImportDefinitionOfClassTemplateAfterFwdDecl) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportDefinitionOfClassTemplateAfterFwdDecl) {
{
Decl *FromTU = getTuDecl(
R"(
@@ -1625,7 +1626,7 @@
}
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ImportDefinitionOfClassTemplateIfThereIsAnExistingFwdDeclAndDefinition) {
Decl *ToTU = getToTuDecl(
R"(
@@ -1665,7 +1666,7 @@
.match(ToTU, classTemplateDecl()));
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ImportDefinitionOfClassIfThereIsAnExistingFwdDeclAndDefinition) {
Decl *ToTU = getToTuDecl(
R"(
@@ -1708,7 +1709,7 @@
CompareSourceLocs(FullSourceLoc{ Range1.getEnd(), SM1 },
FullSourceLoc{ Range2.getEnd(), SM2 });
}
-TEST_P(ASTImporterTestBase, ImportSourceLocs) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportSourceLocs) {
Decl *FromTU = getTuDecl(
R"(
#define MFOO(arg) arg = arg + 1
@@ -1738,7 +1739,7 @@
FromSM);
}
-TEST_P(ASTImporterTestBase, ImportNestedMacro) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportNestedMacro) {
Decl *FromTU = getTuDecl(
R"(
#define FUNC_INT void declToImport
@@ -1756,9 +1757,8 @@
}
TEST_P(
- ASTImporterTestBase,
- ImportDefinitionOfClassTemplateSpecIfThereIsAnExistingFwdDeclAndDefinition)
-{
+ ASTImporterOptionSpecificTestBase,
+ ImportDefinitionOfClassTemplateSpecIfThereIsAnExistingFwdDeclAndDefinition) {
Decl *ToTU = getToTuDecl(
R"(
template <typename T>
@@ -1800,7 +1800,7 @@
.match(ToTU, classTemplateSpecializationDecl()));
}
-TEST_P(ASTImporterTestBase, ObjectsWithUnnamedStructType) {
+TEST_P(ASTImporterOptionSpecificTestBase, ObjectsWithUnnamedStructType) {
Decl *FromTU = getTuDecl(
R"(
struct { int a; int b; } object0 = { 2, 3 };
@@ -1824,7 +1824,7 @@
EXPECT_NE(To0->getCanonicalDecl(), To1->getCanonicalDecl());
}
-TEST_P(ASTImporterTestBase, AnonymousRecords) {
+TEST_P(ASTImporterOptionSpecificTestBase, AnonymousRecords) {
auto *Code =
R"(
struct X {
@@ -1850,7 +1850,7 @@
DeclCounter<RecordDecl>().match(ToTU, recordDecl(hasName("X"))));
}
-TEST_P(ASTImporterTestBase, AnonymousRecordsReversed) {
+TEST_P(ASTImporterOptionSpecificTestBase, AnonymousRecordsReversed) {
Decl *FromTU0 = getTuDecl(
R"(
struct X {
@@ -1883,7 +1883,7 @@
DeclCounter<RecordDecl>().match(ToTU, recordDecl(hasName("X"))));
}
-TEST_P(ASTImporterTestBase, ImportDoesUpdateUsedFlag) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportDoesUpdateUsedFlag) {
auto Pattern = varDecl(hasName("x"));
VarDecl *Imported1;
{
@@ -1909,7 +1909,7 @@
EXPECT_TRUE(Imported2->isUsed(false));
}
-TEST_P(ASTImporterTestBase, ImportDoesUpdateUsedFlag2) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportDoesUpdateUsedFlag2) {
auto Pattern = varDecl(hasName("x"));
VarDecl *ExistingD;
{
@@ -1927,7 +1927,7 @@
EXPECT_TRUE(ExistingD->isUsed(false));
}
-TEST_P(ASTImporterTestBase, ImportDoesUpdateUsedFlag3) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportDoesUpdateUsedFlag3) {
auto Pattern = varDecl(hasName("a"));
VarDecl *ExistingD;
{
@@ -1958,7 +1958,7 @@
EXPECT_TRUE(ExistingD->isUsed(false));
}
-TEST_P(ASTImporterTestBase, ReimportWithUsedFlag) {
+TEST_P(ASTImporterOptionSpecificTestBase, ReimportWithUsedFlag) {
auto Pattern = varDecl(hasName("x"));
Decl *FromTU = getTuDecl("int x;", Lang_CXX, "input0.cc");
@@ -1975,34 +1975,7 @@
EXPECT_TRUE(Imported2->isUsed(false));
}
-struct ImportFunctions : ASTImporterTestBase {};
-
-TEST_P(ImportFunctions,
- DefinitionShouldBeImportedAsDefintionWhenThereIsAPrototype) {
- Decl *FromTU = getTuDecl("void f(); void f() {}", Lang_CXX);
- auto Pattern = functionDecl(hasName("f"));
- FunctionDecl *FromD = // Definition
- LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-
- Decl *ImportedD = Import(FromD, Lang_CXX);
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
-}
-
-TEST_P(ImportFunctions, DefinitionShouldBeImportedAsADefinition) {
- Decl *FromTU = getTuDecl("void f() {}", Lang_CXX);
- auto Pattern = functionDecl(hasName("f"));
- FunctionDecl *FromD =
- FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-
- Decl *ImportedD = Import(FromD, Lang_CXX);
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
- EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
-}
+struct ImportFunctions : ASTImporterOptionSpecificTestBase {};
TEST_P(ImportFunctions, ImportPrototypeOfRecursiveFunction) {
Decl *FromTU = getTuDecl("void f(); void f() { f(); }", Lang_CXX);
@@ -2040,138 +2013,6 @@
EXPECT_EQ(To1->getPreviousDecl(), To0);
}
-TEST_P(ImportFunctions, ImportPrototypes) {
- auto Pattern = functionDecl(hasName("f"));
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-
- ImportedD = Import(FromD, Lang_CXX);
- }
- {
- Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input1.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- auto *To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_FALSE(To0->doesThisDeclarationHaveABody());
- EXPECT_FALSE(To1->doesThisDeclarationHaveABody());
- EXPECT_EQ(To1->getPreviousDecl(), To0);
-}
-
-TEST_P(ImportFunctions, ImportDefinitions) {
- auto Pattern = functionDecl(hasName("f"));
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl("void f(){}", Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- ImportedD = Import(FromD, Lang_CXX);
- }
- {
- Decl *FromTU = getTuDecl("void f(){};", Lang_CXX, "input1.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_TRUE(To0->doesThisDeclarationHaveABody());
-}
-
-TEST_P(ImportFunctions, ImportDefinitionThenPrototype) {
- auto Pattern = functionDecl(hasName("f"));
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl("void f(){}", Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- ImportedD = Import(FromD, Lang_CXX);
- }
- {
- Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input1.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- auto *To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_TRUE(To0->doesThisDeclarationHaveABody());
- EXPECT_FALSE(To1->doesThisDeclarationHaveABody());
- EXPECT_EQ(To1->getPreviousDecl(), To0);
-}
-
-TEST_P(ImportFunctions, ImportPrototypeThenDefinition) {
- auto Pattern = functionDecl(hasName("f"));
-
- {
- Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input0.cc");
- FunctionDecl *FromD =
- FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-
- Import(FromD, Lang_CXX);
- }
- {
- Decl *FromTU = getTuDecl("void f(){}", Lang_CXX, "input1.cc");
- FunctionDecl *FromD =
- FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
- ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- FunctionDecl *ProtoD = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_FALSE(ProtoD->doesThisDeclarationHaveABody());
- FunctionDecl *DefinitionD =
- LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(DefinitionD->doesThisDeclarationHaveABody());
- EXPECT_EQ(DefinitionD->getPreviousDecl(), ProtoD);
-}
-
-TEST_P(ImportFunctions, ImportPrototypeThenProtoAndDefinition) {
- auto Pattern = functionDecl(hasName("f"));
-
- {
- Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
- {
- Decl *FromTU = getTuDecl("void f(); void f(){}", Lang_CXX, "input1.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
-
- ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 3u);
- FunctionDecl *ProtoD = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_FALSE(ProtoD->doesThisDeclarationHaveABody());
-
- FunctionDecl *DefinitionD =
- LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(DefinitionD->doesThisDeclarationHaveABody());
-
- EXPECT_TRUE(DefinitionD->getPreviousDecl());
- EXPECT_FALSE(DefinitionD->getPreviousDecl()->doesThisDeclarationHaveABody());
- EXPECT_EQ(DefinitionD->getPreviousDecl()->getPreviousDecl(), ProtoD);
-}
-
TEST_P(ImportFunctions, OverriddenMethodsShouldBeImported) {
auto Code =
R"(
@@ -2233,6 +2074,321 @@
}).match(ToTU, functionDecl()));
}
+TEST_P(ImportFunctions, ImportOverriddenMethodTwice) {
+ auto Code =
+ R"(
+ struct B { virtual void f(); };
+ struct D:B { void f(); };
+ )";
+ auto BFP =
+ cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B"))));
+ auto DFP =
+ cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D"))));
+
+ Decl *FromTU0 = getTuDecl(Code, Lang_CXX);
+ auto *DF = FirstDeclMatcher<CXXMethodDecl>().match(FromTU0, DFP);
+ Import(DF, Lang_CXX);
+
+ Decl *FromTU1 = getTuDecl(Code, Lang_CXX, "input1.cc");
+ auto *BF = FirstDeclMatcher<CXXMethodDecl>().match(FromTU1, BFP);
+ Import(BF, Lang_CXX);
+
+ auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFP), 1u);
+}
+
+TEST_P(ImportFunctions, ImportOverriddenMethodTwiceDefinitionFirst) {
+ auto CodeWithoutDef =
+ R"(
+ struct B { virtual void f(); };
+ struct D:B { void f(); };
+ )";
+ auto CodeWithDef =
+ R"(
+ struct B { virtual void f(){}; };
+ struct D:B { void f(){}; };
+ )";
+ auto BFP =
+ cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B"))));
+ auto DFP =
+ cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D"))));
+ auto BFDefP = cxxMethodDecl(
+ hasName("f"), hasParent(cxxRecordDecl(hasName("B"))), isDefinition());
+ auto DFDefP = cxxMethodDecl(
+ hasName("f"), hasParent(cxxRecordDecl(hasName("D"))), isDefinition());
+ auto FDefAllP = cxxMethodDecl(hasName("f"), isDefinition());
+
+ {
+ Decl *FromTU = getTuDecl(CodeWithDef, Lang_CXX, "input0.cc");
+ auto *FromD = FirstDeclMatcher<CXXMethodDecl>().match(FromTU, DFP);
+ Import(FromD, Lang_CXX);
+ }
+ {
+ Decl *FromTU = getTuDecl(CodeWithoutDef, Lang_CXX, "input1.cc");
+ auto *FromB = FirstDeclMatcher<CXXMethodDecl>().match(FromTU, BFP);
+ Import(FromB, Lang_CXX);
+ }
+
+ auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFDefP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFDefP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, FDefAllP), 2u);
+}
+
+TEST_P(ImportFunctions, ImportOverriddenMethodTwiceOutOfClassDef) {
+ auto Code =
+ R"(
+ struct B { virtual void f(); };
+ struct D:B { void f(); };
+ void B::f(){};
+ )";
+
+ auto BFP =
+ cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B"))));
+ auto BFDefP = cxxMethodDecl(
+ hasName("f"), hasParent(cxxRecordDecl(hasName("B"))), isDefinition());
+ auto DFP = cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D"))),
+ unless(isDefinition()));
+
+ Decl *FromTU0 = getTuDecl(Code, Lang_CXX);
+ auto *D = FirstDeclMatcher<CXXMethodDecl>().match(FromTU0, DFP);
+ Import(D, Lang_CXX);
+
+ Decl *FromTU1 = getTuDecl(Code, Lang_CXX, "input1.cc");
+ auto *B = FirstDeclMatcher<CXXMethodDecl>().match(FromTU1, BFP);
+ Import(B, Lang_CXX);
+
+ auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFDefP), 0u);
+
+ auto *ToB = FirstDeclMatcher<CXXRecordDecl>().match(
+ ToTU, cxxRecordDecl(hasName("B")));
+ auto *ToBFInClass = FirstDeclMatcher<CXXMethodDecl>().match(ToTU, BFP);
+ auto *ToBFOutOfClass = FirstDeclMatcher<CXXMethodDecl>().match(
+ ToTU, cxxMethodDecl(hasName("f"), isDefinition()));
+
+ // The definition should be out-of-class.
+ EXPECT_NE(ToBFInClass, ToBFOutOfClass);
+ EXPECT_NE(ToBFInClass->getLexicalDeclContext(),
+ ToBFOutOfClass->getLexicalDeclContext());
+ EXPECT_EQ(ToBFOutOfClass->getDeclContext(), ToB);
+ EXPECT_EQ(ToBFOutOfClass->getLexicalDeclContext(), ToTU);
+
+ // Check that the redecl chain is intact.
+ EXPECT_EQ(ToBFOutOfClass->getPreviousDecl(), ToBFInClass);
+}
+
+TEST_P(ImportFunctions,
+ ImportOverriddenMethodTwiceOutOfClassDefInSeparateCode) {
+ auto CodeTU0 =
+ R"(
+ struct B { virtual void f(); };
+ struct D:B { void f(); };
+ )";
+ auto CodeTU1 =
+ R"(
+ struct B { virtual void f(); };
+ struct D:B { void f(); };
+ void B::f(){}
+ void D::f(){}
+ void foo(B &b, D &d) { b.f(); d.f(); }
+ )";
+
+ auto BFP =
+ cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B"))));
+ auto BFDefP = cxxMethodDecl(
+ hasName("f"), hasParent(cxxRecordDecl(hasName("B"))), isDefinition());
+ auto DFP =
+ cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D"))));
+ auto DFDefP = cxxMethodDecl(
+ hasName("f"), hasParent(cxxRecordDecl(hasName("D"))), isDefinition());
+ auto FooDef = functionDecl(hasName("foo"));
+
+ {
+ Decl *FromTU0 = getTuDecl(CodeTU0, Lang_CXX, "input0.cc");
+ auto *D = FirstDeclMatcher<CXXMethodDecl>().match(FromTU0, DFP);
+ Import(D, Lang_CXX);
+ }
+
+ {
+ Decl *FromTU1 = getTuDecl(CodeTU1, Lang_CXX, "input1.cc");
+ auto *Foo = FirstDeclMatcher<FunctionDecl>().match(FromTU1, FooDef);
+ Import(Foo, Lang_CXX);
+ }
+
+ auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFP), 1u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFDefP), 0u);
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFDefP), 0u);
+
+ auto *ToB = FirstDeclMatcher<CXXRecordDecl>().match(
+ ToTU, cxxRecordDecl(hasName("B")));
+ auto *ToD = FirstDeclMatcher<CXXRecordDecl>().match(
+ ToTU, cxxRecordDecl(hasName("D")));
+ auto *ToBFInClass = FirstDeclMatcher<CXXMethodDecl>().match(ToTU, BFP);
+ auto *ToBFOutOfClass = FirstDeclMatcher<CXXMethodDecl>().match(
+ ToTU, cxxMethodDecl(hasName("f"), isDefinition()));
+ auto *ToDFInClass = FirstDeclMatcher<CXXMethodDecl>().match(ToTU, DFP);
+ auto *ToDFOutOfClass = LastDeclMatcher<CXXMethodDecl>().match(
+ ToTU, cxxMethodDecl(hasName("f"), isDefinition()));
+
+ // The definition should be out-of-class.
+ EXPECT_NE(ToBFInClass, ToBFOutOfClass);
+ EXPECT_NE(ToBFInClass->getLexicalDeclContext(),
+ ToBFOutOfClass->getLexicalDeclContext());
+ EXPECT_EQ(ToBFOutOfClass->getDeclContext(), ToB);
+ EXPECT_EQ(ToBFOutOfClass->getLexicalDeclContext(), ToTU);
+
+ EXPECT_NE(ToDFInClass, ToDFOutOfClass);
+ EXPECT_NE(ToDFInClass->getLexicalDeclContext(),
+ ToDFOutOfClass->getLexicalDeclContext());
+ EXPECT_EQ(ToDFOutOfClass->getDeclContext(), ToD);
+ EXPECT_EQ(ToDFOutOfClass->getLexicalDeclContext(), ToTU);
+
+ // Check that the redecl chain is intact.
+ EXPECT_EQ(ToBFOutOfClass->getPreviousDecl(), ToBFInClass);
+ EXPECT_EQ(ToDFOutOfClass->getPreviousDecl(), ToDFInClass);
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase, ImportVariableChainInC) {
+ std::string Code = "static int v; static int v = 0;";
+ auto Pattern = varDecl(hasName("v"));
+
+ TranslationUnitDecl *FromTu = getTuDecl(Code, Lang_C, "input0.c");
+
+ auto *From0 = FirstDeclMatcher<VarDecl>().match(FromTu, Pattern);
+ auto *From1 = LastDeclMatcher<VarDecl>().match(FromTu, Pattern);
+
+ auto *To0 = Import(From0, Lang_C);
+ auto *To1 = Import(From1, Lang_C);
+
+ EXPECT_TRUE(To0);
+ ASSERT_TRUE(To1);
+ EXPECT_NE(To0, To1);
+ EXPECT_EQ(To1->getPreviousDecl(), To0);
+}
+
+TEST_P(ImportFunctions, ImportFromDifferentScopedAnonNamespace) {
+ TranslationUnitDecl *FromTu = getTuDecl(
+ "namespace NS0 { namespace { void f(); } }"
+ "namespace NS1 { namespace { void f(); } }",
+ Lang_CXX, "input0.cc");
+ auto Pattern = functionDecl(hasName("f"));
+
+ auto *FromF0 = FirstDeclMatcher<FunctionDecl>().match(FromTu, Pattern);
+ auto *FromF1 = LastDeclMatcher<FunctionDecl>().match(FromTu, Pattern);
+
+ auto *ToF0 = Import(FromF0, Lang_CXX);
+ auto *ToF1 = Import(FromF1, Lang_CXX);
+
+ EXPECT_TRUE(ToF0);
+ ASSERT_TRUE(ToF1);
+ EXPECT_NE(ToF0, ToF1);
+ EXPECT_FALSE(ToF1->getPreviousDecl());
+}
+
+TEST_P(ImportFunctions, ImportFunctionFromUnnamedNamespace) {
+ {
+ Decl *FromTU = getTuDecl("namespace { void f() {} } void g0() { f(); }",
+ Lang_CXX, "input0.cc");
+ auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("g0")));
+
+ Import(FromD, Lang_CXX);
+ }
+ {
+ Decl *FromTU =
+ getTuDecl("namespace { void f() { int a; } } void g1() { f(); }",
+ Lang_CXX, "input1.cc");
+ auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("g1")));
+ Import(FromD, Lang_CXX);
+ }
+
+ Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+ ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, functionDecl(hasName("f"))),
+ 2u);
+}
+
+TEST_P(ImportFunctions, ImportImplicitFunctionsInLambda) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ void foo() {
+ (void)[]() { ; };
+ }
+ )",
+ Lang_CXX11);
+ auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("foo")));
+ auto *ToD = Import(FromD, Lang_CXX);
+ EXPECT_TRUE(ToD);
+ CXXRecordDecl *LambdaRec =
+ cast<LambdaExpr>(cast<CStyleCastExpr>(
+ *cast<CompoundStmt>(ToD->getBody())->body_begin())
+ ->getSubExpr())
+ ->getLambdaClass();
+ EXPECT_TRUE(LambdaRec->getDestructor());
+}
+
+TEST_P(ImportFunctions,
+ CallExprOfMemberFunctionTemplateWithExplicitTemplateArgs) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ struct X {
+ template <typename T>
+ void foo(){}
+ };
+ void f() {
+ X x;
+ x.foo<int>();
+ }
+ )",
+ Lang_CXX);
+ auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("f")));
+ auto *ToD = Import(FromD, Lang_CXX);
+ EXPECT_TRUE(ToD);
+ EXPECT_TRUE(MatchVerifier<FunctionDecl>().match(
+ ToD, functionDecl(hasName("f"), hasDescendant(declRefExpr()))));
+}
+
+TEST_P(ImportFunctions,
+ DependentCallExprOfMemberFunctionTemplateWithExplicitTemplateArgs) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ struct X {
+ template <typename T>
+ void foo(){}
+ };
+ template <typename T>
+ void f() {
+ X x;
+ x.foo<T>();
+ }
+ void g() {
+ f<int>();
+ }
+ )",
+ Lang_CXX);
+ auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("g")));
+ auto *ToD = Import(FromD, Lang_CXX);
+ EXPECT_TRUE(ToD);
+ Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+ EXPECT_TRUE(MatchVerifier<TranslationUnitDecl>().match(
+ ToTU, translationUnitDecl(hasDescendant(
+ functionDecl(hasName("f"), hasDescendant(declRefExpr()))))));
+}
+
struct ImportFriendFunctions : ImportFunctions {};
TEST_P(ImportFriendFunctions, ImportFriendFunctionRedeclChainProto) {
@@ -2307,12 +2463,7 @@
EXPECT_EQ(ToFD->getPreviousDecl(), ImportedD);
}
-// Disabled temporarily, because the new structural equivalence check
-// (https://reviews.llvm.org/D48628) breaks it.
-// PreviousDecl is not set because there is no structural match.
-// FIXME Enable!
-TEST_P(ImportFriendFunctions,
- DISABLED_ImportFriendFunctionRedeclChainDefWithClass) {
+TEST_P(ImportFriendFunctions, ImportFriendFunctionRedeclChainDefWithClass) {
auto Pattern = functionDecl(hasName("f"));
Decl *FromTU = getTuDecl(
@@ -2340,12 +2491,8 @@
(*ImportedD->param_begin())->getOriginalType());
}
-// Disabled temporarily, because the new structural equivalence check
-// (https://reviews.llvm.org/D48628) breaks it.
-// PreviousDecl is not set because there is no structural match.
-// FIXME Enable!
TEST_P(ImportFriendFunctions,
- DISABLED_ImportFriendFunctionRedeclChainDefWithClass_ImportTheProto) {
+ ImportFriendFunctionRedeclChainDefWithClass_ImportTheProto) {
auto Pattern = functionDecl(hasName("f"));
Decl *FromTU = getTuDecl(
@@ -2701,7 +2848,7 @@
compoundStmt(has(callExpr(has(unresolvedMemberExpr())))))))));
}
-class ImportImplicitMethods : public ASTImporterTestBase {
+class ImportImplicitMethods : public ASTImporterOptionSpecificTestBase {
public:
static constexpr auto DefaultCode = R"(
struct A { int x; };
@@ -2742,7 +2889,7 @@
CXXMethodDecl *Method =
FirstDeclMatcher<CXXMethodDecl>().match(ToClass, MethodMatcher);
ToClass->removeDecl(Method);
- LookupTablePtr->remove(Method);
+ SharedStatePtr->getLookupTable()->remove(Method);
}
ASSERT_EQ(DeclCounter<CXXMethodDecl>().match(ToClass, MethodMatcher), 0u);
@@ -2813,7 +2960,7 @@
testNoImportOf(cxxMethodDecl(hasName("f")), Code);
}
-TEST_P(ASTImporterTestBase, ImportOfEquivalentRecord) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportOfEquivalentRecord) {
Decl *ToR1;
{
Decl *FromTU = getTuDecl(
@@ -2837,7 +2984,7 @@
EXPECT_EQ(ToR1, ToR2);
}
-TEST_P(ASTImporterTestBase, ImportOfNonEquivalentRecord) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportOfNonEquivalentRecord) {
Decl *ToR1;
{
Decl *FromTU = getTuDecl(
@@ -2857,7 +3004,7 @@
EXPECT_NE(ToR1, ToR2);
}
-TEST_P(ASTImporterTestBase, ImportOfEquivalentField) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportOfEquivalentField) {
Decl *ToF1;
{
Decl *FromTU = getTuDecl(
@@ -2877,7 +3024,7 @@
EXPECT_EQ(ToF1, ToF2);
}
-TEST_P(ASTImporterTestBase, ImportOfNonEquivalentField) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportOfNonEquivalentField) {
Decl *ToF1;
{
Decl *FromTU = getTuDecl(
@@ -2897,7 +3044,7 @@
EXPECT_NE(ToF1, ToF2);
}
-TEST_P(ASTImporterTestBase, ImportOfEquivalentMethod) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportOfEquivalentMethod) {
Decl *ToM1;
{
Decl *FromTU = getTuDecl(
@@ -2917,7 +3064,7 @@
EXPECT_EQ(ToM1, ToM2);
}
-TEST_P(ASTImporterTestBase, ImportOfNonEquivalentMethod) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportOfNonEquivalentMethod) {
Decl *ToM1;
{
Decl *FromTU = getTuDecl(
@@ -2939,7 +3086,8 @@
EXPECT_NE(ToM1, ToM2);
}
-TEST_P(ASTImporterTestBase, ImportUnnamedStructsWithRecursingField) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportUnnamedStructsWithRecursingField) {
Decl *FromTU = getTuDecl(
R"(
struct A {
@@ -2971,7 +3119,7 @@
R1, recordDecl(has(fieldDecl(hasName("next"))))));
}
-TEST_P(ASTImporterTestBase, ImportUnnamedFieldsInCorrectOrder) {
+TEST_P(ASTImporterOptionSpecificTestBase, ImportUnnamedFieldsInCorrectOrder) {
Decl *FromTU = getTuDecl(
R"(
void f(int X, int Y, bool Z) {
@@ -3006,7 +3154,8 @@
EXPECT_EQ(FromIndex, 3u);
}
-TEST_P(ASTImporterTestBase, MergeFieldDeclsOfClassTemplateSpecialization) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ MergeFieldDeclsOfClassTemplateSpecialization) {
std::string ClassTemplate =
R"(
template <typename T>
@@ -3051,7 +3200,8 @@
EXPECT_TRUE(ToField->getInClassInitializer());
}
-TEST_P(ASTImporterTestBase, MergeFunctionOfClassTemplateSpecialization) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ MergeFunctionOfClassTemplateSpecialization) {
std::string ClassTemplate =
R"(
template <typename T>
@@ -3092,7 +3242,7 @@
EXPECT_TRUE(ToFun->hasBody());
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ODRViolationOfClassTemplateSpecializationsShouldBeReported) {
std::string ClassTemplate =
R"(
@@ -3131,15 +3281,14 @@
// The second specialization is different from the first, thus it violates
// ODR, consequently we expect to keep the first specialization only, which is
// already in the "To" context.
- EXPECT_TRUE(ImportedSpec);
- auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
- ToTU, classTemplateSpecializationDecl(hasName("X")));
- EXPECT_EQ(ImportedSpec, ToSpec);
- EXPECT_EQ(1u, DeclCounter<ClassTemplateSpecializationDecl>().match(
- ToTU, classTemplateSpecializationDecl()));
+ EXPECT_FALSE(ImportedSpec);
+ EXPECT_EQ(1u,
+ DeclCounter<ClassTemplateSpecializationDecl>().match(
+ ToTU, classTemplateSpecializationDecl(hasName("X"))));
}
-TEST_P(ASTImporterTestBase, MergeCtorOfClassTemplateSpecialization) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ MergeCtorOfClassTemplateSpecialization) {
std::string ClassTemplate =
R"(
template <typename T>
@@ -3180,7 +3329,7 @@
EXPECT_TRUE(ToCtor->hasBody());
}
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ClassTemplatePartialSpecializationsShouldNotBeDuplicated) {
auto Code =
R"(
@@ -3207,7 +3356,8 @@
ToTU, classTemplatePartialSpecializationDecl()));
}
-TEST_P(ASTImporterTestBase, ClassTemplateSpecializationsShouldNotBeDuplicated) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ClassTemplateSpecializationsShouldNotBeDuplicated) {
auto Code =
R"(
// primary template
@@ -3231,7 +3381,8 @@
ToTU, classTemplateSpecializationDecl()));
}
-TEST_P(ASTImporterTestBase, ClassTemplateFullAndPartialSpecsShouldNotBeMixed) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ClassTemplateFullAndPartialSpecsShouldNotBeMixed) {
std::string PrimaryTemplate =
R"(
template<class T1, class T2, int I>
@@ -3263,7 +3414,8 @@
unless(classTemplatePartialSpecializationDecl()))));
}
-TEST_P(ASTImporterTestBase, InitListExprValueKindShouldBeImported) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ InitListExprValueKindShouldBeImported) {
Decl *TU = getTuDecl(
R"(
const int &init();
@@ -3282,7 +3434,7 @@
EXPECT_TRUE(ToInitExpr->isGLValue());
}
-struct ImportVariables : ASTImporterTestBase {};
+struct ImportVariables : ASTImporterOptionSpecificTestBase {};
TEST_P(ImportVariables, ImportOfOneDeclBringsInTheWholeChain) {
Decl *FromTU = getTuDecl(
@@ -3370,155 +3522,7 @@
EXPECT_TRUE(ImportedD->getDefinition());
}
-struct ImportClasses : ASTImporterTestBase {};
-
-TEST_P(ImportClasses,
- PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition) {
- Decl *FromTU = getTuDecl("class X;", Lang_CXX);
- auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit()));
- auto FromD = FirstDeclMatcher<CXXRecordDecl>().match(FromTU, Pattern);
-
- Decl *ImportedD = Import(FromD, Lang_CXX);
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, Pattern), 1u);
- auto ToD = LastDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == ToD);
- EXPECT_FALSE(ToD->isThisDeclarationADefinition());
-}
-
-TEST_P(ImportClasses, ImportPrototypeAfterImportedPrototype) {
- Decl *FromTU = getTuDecl("class X; class X;", Lang_CXX);
- auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit()));
- auto From0 = FirstDeclMatcher<CXXRecordDecl>().match(FromTU, Pattern);
- auto From1 = LastDeclMatcher<CXXRecordDecl>().match(FromTU, Pattern);
-
- Decl *Imported0 = Import(From0, Lang_CXX);
- Decl *Imported1 = Import(From1, Lang_CXX);
- Decl *ToTU = Imported0->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, Pattern), 2u);
- auto To0 = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
- auto To1 = LastDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(Imported0 == To0);
- EXPECT_TRUE(Imported1 == To1);
- EXPECT_FALSE(To0->isThisDeclarationADefinition());
- EXPECT_FALSE(To1->isThisDeclarationADefinition());
- EXPECT_EQ(To1->getPreviousDecl(), To0);
-}
-
-TEST_P(ImportClasses, DefinitionShouldBeImportedAsADefinition) {
- Decl *FromTU = getTuDecl("class X {};", Lang_CXX);
- auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit()));
- auto *FromD = FirstDeclMatcher<CXXRecordDecl>().match(FromTU, Pattern);
-
- Decl *ImportedD = Import(FromD, Lang_CXX);
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, Pattern), 1u);
- EXPECT_TRUE(cast<CXXRecordDecl>(ImportedD)->isThisDeclarationADefinition());
-}
-
-TEST_P(ImportClasses, ImportPrototypeFromDifferentTUAfterImportedPrototype) {
- Decl *FromTU0 = getTuDecl("class X;", Lang_CXX, "input0.cc");
- Decl *FromTU1 = getTuDecl("class X;", Lang_CXX, "input1.cc");
- auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit()));
- auto From0 = FirstDeclMatcher<CXXRecordDecl>().match(FromTU0, Pattern);
- auto From1 = FirstDeclMatcher<CXXRecordDecl>().match(FromTU1, Pattern);
-
- Decl *Imported0 = Import(From0, Lang_CXX);
- Decl *Imported1 = Import(From1, Lang_CXX);
- Decl *ToTU = Imported0->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, Pattern), 2u);
- auto To0 = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
- auto To1 = LastDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(Imported0 == To0);
- EXPECT_TRUE(Imported1 == To1);
- EXPECT_FALSE(To0->isThisDeclarationADefinition());
- EXPECT_FALSE(To1->isThisDeclarationADefinition());
- EXPECT_EQ(To1->getPreviousDecl(), To0);
-}
-
-TEST_P(ImportClasses, ImportDefinitions) {
- Decl *FromTU0 = getTuDecl("class X {};", Lang_CXX, "input0.cc");
- Decl *FromTU1 = getTuDecl("class X {};", Lang_CXX, "input1.cc");
- auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit()));
- auto From0 = FirstDeclMatcher<CXXRecordDecl>().match(FromTU0, Pattern);
- auto From1 = FirstDeclMatcher<CXXRecordDecl>().match(FromTU1, Pattern);
-
- Decl *Imported0 = Import(From0, Lang_CXX);
- Decl *Imported1 = Import(From1, Lang_CXX);
- Decl *ToTU = Imported0->getTranslationUnitDecl();
-
- EXPECT_EQ(Imported0, Imported1);
- EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, Pattern), 1u);
- auto To0 = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(Imported0 == To0);
- EXPECT_TRUE(To0->isThisDeclarationADefinition());
-}
-
-TEST_P(ImportClasses, ImportDefinitionThenPrototype) {
- Decl *FromTU0 = getTuDecl("class X {};", Lang_CXX, "input0.cc");
- Decl *FromTU1 = getTuDecl("class X;", Lang_CXX, "input1.cc");
- auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit()));
- auto FromDef = FirstDeclMatcher<CXXRecordDecl>().match(FromTU0, Pattern);
- auto FromProto = FirstDeclMatcher<CXXRecordDecl>().match(FromTU1, Pattern);
-
- Decl *ImportedDef = Import(FromDef, Lang_CXX);
- Decl *ImportedProto = Import(FromProto, Lang_CXX);
- Decl *ToTU = ImportedDef->getTranslationUnitDecl();
-
- EXPECT_NE(ImportedDef, ImportedProto);
- EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, Pattern), 2u);
- auto ToDef = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
- auto ToProto = LastDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedDef == ToDef);
- EXPECT_TRUE(ImportedProto == ToProto);
- EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
- EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
- EXPECT_EQ(ToProto->getPreviousDecl(), ToDef);
-}
-
-TEST_P(ImportClasses, ImportPrototypeThenDefinition) {
- Decl *FromTU0 = getTuDecl("class X;", Lang_CXX, "input0.cc");
- Decl *FromTU1 = getTuDecl("class X {};", Lang_CXX, "input1.cc");
- auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit()));
- auto FromProto = FirstDeclMatcher<CXXRecordDecl>().match(FromTU0, Pattern);
- auto FromDef = FirstDeclMatcher<CXXRecordDecl>().match(FromTU1, Pattern);
-
- Decl *ImportedProto = Import(FromProto, Lang_CXX);
- Decl *ImportedDef = Import(FromDef, Lang_CXX);
- Decl *ToTU = ImportedDef->getTranslationUnitDecl();
-
- EXPECT_NE(ImportedDef, ImportedProto);
- EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, Pattern), 2u);
- auto ToProto = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
- auto ToDef = LastDeclMatcher<CXXRecordDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedDef == ToDef);
- EXPECT_TRUE(ImportedProto == ToProto);
- EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
- EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
- EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
-}
-
-TEST_P(ImportClasses, ImportDefinitionWhenProtoIsInToContext) {
- Decl *ToTU = getToTuDecl("struct X;", Lang_C);
- Decl *FromTU1 = getTuDecl("struct X {};", Lang_C, "input1.cc");
- auto Pattern = recordDecl(hasName("X"), unless(isImplicit()));
- auto ToProto = FirstDeclMatcher<RecordDecl>().match(ToTU, Pattern);
- auto FromDef = FirstDeclMatcher<RecordDecl>().match(FromTU1, Pattern);
-
- Decl *ImportedDef = Import(FromDef, Lang_C);
-
- EXPECT_NE(ImportedDef, ToProto);
- EXPECT_EQ(DeclCounter<RecordDecl>().match(ToTU, Pattern), 2u);
- auto ToDef = LastDeclMatcher<RecordDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedDef == ToDef);
- EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
- EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
- EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
-}
+struct ImportClasses : ASTImporterOptionSpecificTestBase {};
TEST_P(ImportClasses, ImportDefinitionWhenProtoIsInNestedToContext) {
Decl *ToTU = getToTuDecl("struct A { struct X *Xp; };", Lang_C);
@@ -3578,171 +3582,8 @@
EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
}
-struct ImportClassTemplates : ASTImporterTestBase {};
-TEST_P(ImportClassTemplates,
- PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition) {
- Decl *FromTU = getTuDecl("template <class T> class X;", Lang_CXX);
- auto Pattern = classTemplateDecl(hasName("X"), unless(isImplicit()));
- auto FromD = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU, Pattern);
-
- Decl *ImportedD = Import(FromD, Lang_CXX);
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<ClassTemplateDecl>().match(ToTU, Pattern), 1u);
- auto ToD = LastDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == ToD);
- ASSERT_TRUE(ToD->getTemplatedDecl());
- EXPECT_FALSE(ToD->isThisDeclarationADefinition());
-}
-
-TEST_P(ImportClassTemplates, ImportPrototypeAfterImportedPrototype) {
- Decl *FromTU = getTuDecl(
- "template <class T> class X; template <class T> class X;", Lang_CXX);
- auto Pattern = classTemplateDecl(hasName("X"), unless(isImplicit()));
- auto From0 = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU, Pattern);
- auto From1 = LastDeclMatcher<ClassTemplateDecl>().match(FromTU, Pattern);
-
- Decl *Imported0 = Import(From0, Lang_CXX);
- Decl *Imported1 = Import(From1, Lang_CXX);
- Decl *ToTU = Imported0->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<ClassTemplateDecl>().match(ToTU, Pattern), 2u);
- auto To0 = FirstDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
- auto To1 = LastDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(Imported0 == To0);
- EXPECT_TRUE(Imported1 == To1);
- ASSERT_TRUE(To0->getTemplatedDecl());
- ASSERT_TRUE(To1->getTemplatedDecl());
- EXPECT_FALSE(To0->isThisDeclarationADefinition());
- EXPECT_FALSE(To1->isThisDeclarationADefinition());
- EXPECT_EQ(To1->getPreviousDecl(), To0);
- EXPECT_EQ(To1->getTemplatedDecl()->getPreviousDecl(),
- To0->getTemplatedDecl());
-}
-
-TEST_P(ImportClassTemplates, DefinitionShouldBeImportedAsADefinition) {
- Decl *FromTU = getTuDecl("template <class T> class X {};", Lang_CXX);
- auto Pattern = classTemplateDecl(hasName("X"), unless(isImplicit()));
- auto *FromD = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU, Pattern);
-
- Decl *ImportedD = Import(FromD, Lang_CXX);
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<ClassTemplateDecl>().match(ToTU, Pattern), 1u);
- auto ToD = LastDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
- ASSERT_TRUE(ToD->getTemplatedDecl());
- EXPECT_TRUE(ToD->isThisDeclarationADefinition());
-}
-
-TEST_P(ImportClassTemplates,
- ImportPrototypeFromDifferentTUAfterImportedPrototype) {
- Decl *FromTU0 =
- getTuDecl("template <class T> class X;", Lang_CXX, "input0.cc");
- Decl *FromTU1 =
- getTuDecl("template <class T> class X;", Lang_CXX, "input1.cc");
- auto Pattern = classTemplateDecl(hasName("X"), unless(isImplicit()));
- auto From0 = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU0, Pattern);
- auto From1 = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU1, Pattern);
-
- Decl *Imported0 = Import(From0, Lang_CXX);
- Decl *Imported1 = Import(From1, Lang_CXX);
- Decl *ToTU = Imported0->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<ClassTemplateDecl>().match(ToTU, Pattern), 2u);
- auto To0 = FirstDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
- auto To1 = LastDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(Imported0 == To0);
- EXPECT_TRUE(Imported1 == To1);
- ASSERT_TRUE(To0->getTemplatedDecl());
- ASSERT_TRUE(To1->getTemplatedDecl());
- EXPECT_FALSE(To0->isThisDeclarationADefinition());
- EXPECT_FALSE(To1->isThisDeclarationADefinition());
- EXPECT_EQ(To1->getPreviousDecl(), To0);
- EXPECT_EQ(To1->getTemplatedDecl()->getPreviousDecl(),
- To0->getTemplatedDecl());
-}
-
-TEST_P(ImportClassTemplates, ImportDefinitions) {
- Decl *FromTU0 =
- getTuDecl("template <class T> class X {};", Lang_CXX, "input0.cc");
- Decl *FromTU1 =
- getTuDecl("template <class T> class X {};", Lang_CXX, "input1.cc");
- auto Pattern = classTemplateDecl(hasName("X"), unless(isImplicit()));
- auto From0 = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU0, Pattern);
- auto From1 = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU1, Pattern);
-
- Decl *Imported0 = Import(From0, Lang_CXX);
- Decl *Imported1 = Import(From1, Lang_CXX);
- Decl *ToTU = Imported0->getTranslationUnitDecl();
-
- EXPECT_EQ(Imported0, Imported1);
- EXPECT_EQ(DeclCounter<ClassTemplateDecl>().match(ToTU, Pattern), 1u);
- auto To0 = FirstDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(Imported0 == To0);
- ASSERT_TRUE(To0->getTemplatedDecl());
- EXPECT_TRUE(To0->isThisDeclarationADefinition());
-}
-
-TEST_P(ImportClassTemplates, ImportDefinitionThenPrototype) {
- Decl *FromTU0 =
- getTuDecl("template <class T> class X {};", Lang_CXX, "input0.cc");
- Decl *FromTU1 =
- getTuDecl("template <class T> class X;", Lang_CXX, "input1.cc");
- auto Pattern = classTemplateDecl(hasName("X"), unless(isImplicit()));
- auto FromDef = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU0, Pattern);
- auto FromProto =
- FirstDeclMatcher<ClassTemplateDecl>().match(FromTU1, Pattern);
-
- Decl *ImportedDef = Import(FromDef, Lang_CXX);
- Decl *ImportedProto = Import(FromProto, Lang_CXX);
- Decl *ToTU = ImportedDef->getTranslationUnitDecl();
-
- EXPECT_NE(ImportedDef, ImportedProto);
- EXPECT_EQ(DeclCounter<ClassTemplateDecl>().match(ToTU, Pattern), 2u);
- auto ToDef = FirstDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
- auto ToProto = LastDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedDef == ToDef);
- EXPECT_TRUE(ImportedProto == ToProto);
- ASSERT_TRUE(ToDef->getTemplatedDecl());
- ASSERT_TRUE(ToProto->getTemplatedDecl());
- EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
- EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
- EXPECT_EQ(ToProto->getPreviousDecl(), ToDef);
- EXPECT_EQ(ToProto->getTemplatedDecl()->getPreviousDecl(),
- ToDef->getTemplatedDecl());
-}
-
-TEST_P(ImportClassTemplates, ImportPrototypeThenDefinition) {
- Decl *FromTU0 =
- getTuDecl("template <class T> class X;", Lang_CXX, "input0.cc");
- Decl *FromTU1 =
- getTuDecl("template <class T> class X {};", Lang_CXX, "input1.cc");
- auto Pattern = classTemplateDecl(hasName("X"), unless(isImplicit()));
- auto FromProto =
- FirstDeclMatcher<ClassTemplateDecl>().match(FromTU0, Pattern);
- auto FromDef = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU1, Pattern);
-
- Decl *ImportedProto = Import(FromProto, Lang_CXX);
- Decl *ImportedDef = Import(FromDef, Lang_CXX);
- Decl *ToTU = ImportedDef->getTranslationUnitDecl();
-
- EXPECT_NE(ImportedDef, ImportedProto);
- EXPECT_EQ(DeclCounter<ClassTemplateDecl>().match(ToTU, Pattern), 2u);
- auto ToProto = FirstDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
- auto ToDef = LastDeclMatcher<ClassTemplateDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedDef == ToDef);
- EXPECT_TRUE(ImportedProto == ToProto);
- ASSERT_TRUE(ToProto->getTemplatedDecl());
- ASSERT_TRUE(ToDef->getTemplatedDecl());
- EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
- EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
- EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
- EXPECT_EQ(ToDef->getTemplatedDecl()->getPreviousDecl(),
- ToProto->getTemplatedDecl());
-}
-
-struct ImportFriendClasses : ASTImporterTestBase {};
+struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {};
TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
Decl *FromTU = getTuDecl(
@@ -3982,7 +3823,7 @@
EXPECT_EQ(ImportedFwd, ImportedDef->getPreviousDecl());
}
-TEST_P(ASTImporterTestBase, FriendFunInClassTemplate) {
+TEST_P(ASTImporterOptionSpecificTestBase, FriendFunInClassTemplate) {
auto *Code = R"(
template <class T>
struct X {
@@ -4000,7 +3841,7 @@
EXPECT_EQ(ImportedFoo, ToFoo);
}
-struct DeclContextTest : ASTImporterTestBase {};
+struct DeclContextTest : ASTImporterOptionSpecificTestBase {};
TEST_P(DeclContextTest, removeDeclOfClassTemplateSpecialization) {
Decl *TU = getTuDecl(
@@ -4063,7 +3904,8 @@
EXPECT_FALSE(DC->containsDecl(A0));
}
-struct ImportFunctionTemplateSpecializations : ASTImporterTestBase {};
+struct ImportFunctionTemplateSpecializations
+ : ASTImporterOptionSpecificTestBase {};
TEST_P(ImportFunctionTemplateSpecializations,
TUshouldNotContainFunctionTemplateImplicitInstantiation) {
@@ -4200,185 +4042,7 @@
DeclCounter<FunctionDecl>().match(ToTU, functionDecl(hasName("f"))));
}
-TEST_P(ImportFunctionTemplateSpecializations,
- ImportPrototypes) {
- auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
- auto Code =
- R"(
- // Proto of the primary template.
- template <class T>
- void f();
- // Proto of the specialization.
- template <>
- void f<int>();
- )";
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
- auto *FromD = LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-
- ImportedD = Import(FromD, Lang_CXX);
- }
- {
- Decl *FromTU = getTuDecl(Code, Lang_CXX, "input1.cc");
- auto *FromD = LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- auto *To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_TRUE(ImportedD != To1);
- EXPECT_FALSE(To0->doesThisDeclarationHaveABody());
- EXPECT_FALSE(To1->doesThisDeclarationHaveABody());
- // Check that they are part of the same redecl chain.
- EXPECT_EQ(To1->getCanonicalDecl(), To0->getCanonicalDecl());
-}
-
-TEST_P(ImportFunctionTemplateSpecializations, ImportDefinitions) {
- auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
- auto Code =
- R"(
- // Proto of the primary template.
- template <class T>
- void f();
- // Specialization and definition.
- template <>
- void f<int>() {}
- )";
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- ImportedD = Import(FromD, Lang_CXX);
- }
- {
- Decl *FromTU = getTuDecl(Code, Lang_CXX, "input1.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_TRUE(To0->doesThisDeclarationHaveABody());
-
- auto *TemplateD = FirstDeclMatcher<FunctionTemplateDecl>().match(
- ToTU, functionTemplateDecl());
- auto *FirstSpecD = *(TemplateD->spec_begin());
- EXPECT_EQ(FirstSpecD->getCanonicalDecl(), To0->getCanonicalDecl());
-}
-
-TEST_P(ImportFunctionTemplateSpecializations, PrototypeThenPrototype) {
- auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
- auto Code =
- R"(
- // Proto of the primary template.
- template <class T>
- void f();
- // Specialization proto.
- template <>
- void f<int>();
- // Specialization proto.
- template <>
- void f<int>();
- )";
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- ImportedD = Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- auto *To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_TRUE(ImportedD != To1);
- EXPECT_FALSE(To0->doesThisDeclarationHaveABody());
- EXPECT_FALSE(To1->doesThisDeclarationHaveABody());
- EXPECT_EQ(To1->getPreviousDecl(), To0);
-}
-
-TEST_P(ImportFunctionTemplateSpecializations, PrototypeThenDefinition) {
- auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
- auto Code =
- R"(
- // Proto of the primary template.
- template <class T>
- void f();
- // Specialization proto.
- template <>
- void f<int>();
- // Specialization definition.
- template <>
- void f<int>() {}
- )";
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- ImportedD = Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- auto *To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_TRUE(ImportedD != To1);
- EXPECT_FALSE(To0->doesThisDeclarationHaveABody());
- EXPECT_TRUE(To1->doesThisDeclarationHaveABody());
- EXPECT_EQ(To1->getPreviousDecl(), To0);
-}
-
-TEST_P(ImportFunctionTemplateSpecializations, DefinitionThenPrototype) {
- auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
- auto Code =
- R"(
- // Proto of the primary template.
- template <class T>
- void f();
- // Specialization definition.
- template <>
- void f<int>() {}
- // Specialization proto.
- template <>
- void f<int>();
- )";
-
- Decl *ImportedD;
- {
- Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
- auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
- ImportedD = Import(FromD, Lang_CXX);
- }
-
- Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
- EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
- auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- auto *To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
- EXPECT_TRUE(ImportedD == To0);
- EXPECT_TRUE(ImportedD != To1);
- EXPECT_TRUE(To0->doesThisDeclarationHaveABody());
- EXPECT_FALSE(To1->doesThisDeclarationHaveABody());
- EXPECT_EQ(To1->getPreviousDecl(), To0);
-}
-
-TEST_P(ASTImporterTestBase,
+TEST_P(ASTImporterOptionSpecificTestBase,
ImportShouldNotReportFalseODRErrorWhenRecordIsBeingDefined) {
{
Decl *FromTU = getTuDecl(
@@ -4417,7 +4081,8 @@
}
}
-TEST_P(ASTImporterTestBase, ImportingTypedefShouldImportTheCompleteType) {
+TEST_P(ASTImporterOptionSpecificTestBase,
+ ImportingTypedefShouldImportTheCompleteType) {
// We already have an incomplete underlying type in the "To" context.
auto Code =
R"(
@@ -4449,7 +4114,25 @@
EXPECT_FALSE(ImportedD->getUnderlyingType()->isIncompleteType());
}
-struct ASTImporterLookupTableTest : ASTImporterTestBase {};
+TEST_P(ASTImporterOptionSpecificTestBase, ImportTemplateParameterLists) {
+ auto Code =
+ R"(
+ template<class T>
+ int f() { return 0; }
+ template <> int f<int>() { return 4; }
+ )";
+
+ Decl *FromTU = getTuDecl(Code, Lang_CXX);
+ auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU,
+ functionDecl(hasName("f"), isExplicitTemplateSpecialization()));
+ ASSERT_EQ(FromD->getNumTemplateParameterLists(), 1u);
+
+ auto *ToD = Import(FromD, Lang_CXX);
+ // The template parameter list should exist.
+ EXPECT_EQ(ToD->getNumTemplateParameterLists(), 1u);
+}
+
+struct ASTImporterLookupTableTest : ASTImporterOptionSpecificTestBase {};
TEST_P(ASTImporterLookupTableTest, OneDecl) {
auto *ToTU = getToTuDecl("int a;", Lang_CXX);
@@ -4595,13 +4278,73 @@
EXPECT_EQ(Res.count(F2), 1u);
}
-static const RecordDecl * getRecordDeclOfFriend(FriendDecl *FD) {
- QualType Ty = FD->getFriendType()->getType();
- QualType NamedTy = cast<ElaboratedType>(Ty)->getNamedType();
- return cast<RecordType>(NamedTy)->getDecl();
+TEST_P(ASTImporterLookupTableTest,
+ DifferentOperatorsShouldHaveDifferentResultSet) {
+ TranslationUnitDecl *ToTU = getToTuDecl(
+ R"(
+ struct X{};
+ void operator+(X, X);
+ void operator-(X, X);
+ )",
+ Lang_CXX);
+
+ ASTImporterLookupTable LT(*ToTU);
+ auto *FPlus = FirstDeclMatcher<FunctionDecl>().match(
+ ToTU, functionDecl(hasOverloadedOperatorName("+")));
+ auto *FMinus = FirstDeclMatcher<FunctionDecl>().match(
+ ToTU, functionDecl(hasOverloadedOperatorName("-")));
+ DeclarationName NamePlus = FPlus->getDeclName();
+ auto ResPlus = LT.lookup(ToTU, NamePlus);
+ EXPECT_EQ(ResPlus.size(), 1u);
+ EXPECT_EQ(ResPlus.count(FPlus), 1u);
+ EXPECT_EQ(ResPlus.count(FMinus), 0u);
+ DeclarationName NameMinus = FMinus->getDeclName();
+ auto ResMinus = LT.lookup(ToTU, NameMinus);
+ EXPECT_EQ(ResMinus.size(), 1u);
+ EXPECT_EQ(ResMinus.count(FMinus), 1u);
+ EXPECT_EQ(ResMinus.count(FPlus), 0u);
+ EXPECT_NE(*ResMinus.begin(), *ResPlus.begin());
}
-TEST_P(ASTImporterLookupTableTest, LookupFindsFwdFriendClassDecl) {
+TEST_P(ASTImporterLookupTableTest, LookupDeclNamesFromDifferentTUs) {
+ TranslationUnitDecl *ToTU = getToTuDecl(
+ R"(
+ struct X {};
+ void operator+(X, X);
+ )",
+ Lang_CXX);
+ auto *ToPlus = FirstDeclMatcher<FunctionDecl>().match(
+ ToTU, functionDecl(hasOverloadedOperatorName("+")));
+
+ Decl *FromTU = getTuDecl(
+ R"(
+ struct X {};
+ void operator+(X, X);
+ )",
+ Lang_CXX);
+ auto *FromPlus = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasOverloadedOperatorName("+")));
+
+ // FromPlus have a different TU, thus its DeclarationName is different too.
+ ASSERT_NE(ToPlus->getDeclName(), FromPlus->getDeclName());
+
+ ASTImporterLookupTable LT(*ToTU);
+ auto Res = LT.lookup(ToTU, ToPlus->getDeclName());
+ ASSERT_EQ(Res.size(), 1u);
+ EXPECT_EQ(*Res.begin(), ToPlus);
+
+ // FromPlus have a different TU, thus its DeclarationName is different too.
+ Res = LT.lookup(ToTU, FromPlus->getDeclName());
+ ASSERT_EQ(Res.size(), 0u);
+}
+
+static const RecordDecl *getRecordDeclOfFriend(FriendDecl *FD) {
+ QualType Ty = FD->getFriendType()->getType().getCanonicalType();
+ return cast<RecordType>(Ty)->getDecl();
+}
+
+TEST_P(ASTImporterLookupTableTest,
+ LookupFindsFwdFriendClassDeclWithElaboratedType) {
TranslationUnitDecl *ToTU = getToTuDecl(
R"(
class Y { friend class F; };
@@ -4625,6 +4368,52 @@
EXPECT_EQ(Res.size(), 0u);
}
+TEST_P(ASTImporterLookupTableTest,
+ LookupFindsFwdFriendClassDeclWithUnelaboratedType) {
+ TranslationUnitDecl *ToTU = getToTuDecl(
+ R"(
+ class F;
+ class Y { friend F; };
+ )",
+ Lang_CXX11);
+
+ // In this case, the CXXRecordDecl is hidden, the FriendDecl is not a parent.
+ // So we must dig up the underlying CXXRecordDecl.
+ ASTImporterLookupTable LT(*ToTU);
+ auto *FriendD = FirstDeclMatcher<FriendDecl>().match(ToTU, friendDecl());
+ const RecordDecl *RD = getRecordDeclOfFriend(FriendD);
+ auto *Y = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, cxxRecordDecl(hasName("Y")));
+
+ DeclarationName Name = RD->getDeclName();
+ auto Res = LT.lookup(ToTU, Name);
+ EXPECT_EQ(Res.size(), 1u);
+ EXPECT_EQ(*Res.begin(), RD);
+
+ Res = LT.lookup(Y, Name);
+ EXPECT_EQ(Res.size(), 0u);
+}
+
+TEST_P(ASTImporterLookupTableTest,
+ LookupFindsFriendClassDeclWithTypeAliasDoesNotAssert) {
+ TranslationUnitDecl *ToTU = getToTuDecl(
+ R"(
+ class F;
+ using alias_of_f = F;
+ class Y { friend alias_of_f; };
+ )",
+ Lang_CXX11);
+
+ // ASTImporterLookupTable constructor handles using declarations correctly,
+ // no assert is expected.
+ ASTImporterLookupTable LT(*ToTU);
+
+ auto *Alias = FirstDeclMatcher<TypeAliasDecl>().match(
+ ToTU, typeAliasDecl(hasName("alias_of_f")));
+ DeclarationName Name = Alias->getDeclName();
+ auto Res = LT.lookup(ToTU, Name);
+ EXPECT_EQ(Res.count(Alias), 1u);
+}
+
TEST_P(ASTImporterLookupTableTest, LookupFindsFwdFriendClassTemplateDecl) {
TranslationUnitDecl *ToTU = getToTuDecl(
R"(
@@ -4859,22 +4648,547 @@
EXPECT_EQ(*Res.begin(), A);
}
+
+// FIXME This test is disabled currently, upcoming patches will make it
+// possible to enable.
+TEST_P(ASTImporterOptionSpecificTestBase,
+ DISABLED_RedeclChainShouldBeCorrectAmongstNamespaces) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ namespace NS {
+ struct X;
+ struct Y {
+ static const int I = 3;
+ };
+ }
+ namespace NS {
+ struct X { // <--- To be imported
+ void method(int i = Y::I) {}
+ int f;
+ };
+ }
+ )",
+ Lang_CXX);
+ auto *FromFwd = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("X"), unless(isImplicit())));
+ auto *FromDef = LastDeclMatcher<CXXRecordDecl>().match(
+ FromTU,
+ cxxRecordDecl(hasName("X"), isDefinition(), unless(isImplicit())));
+ ASSERT_NE(FromFwd, FromDef);
+ ASSERT_FALSE(FromFwd->isThisDeclarationADefinition());
+ ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
+ ASSERT_EQ(FromFwd->getCanonicalDecl(), FromDef->getCanonicalDecl());
+
+ auto *ToDef = cast_or_null<CXXRecordDecl>(Import(FromDef, Lang_CXX));
+ auto *ToFwd = cast_or_null<CXXRecordDecl>(Import(FromFwd, Lang_CXX));
+ EXPECT_NE(ToFwd, ToDef);
+ EXPECT_FALSE(ToFwd->isThisDeclarationADefinition());
+ EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
+ EXPECT_EQ(ToFwd->getCanonicalDecl(), ToDef->getCanonicalDecl());
+ auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+ // We expect no (ODR) warning during the import.
+ EXPECT_EQ(0u, ToTU->getASTContext().getDiagnostics().getNumWarnings());
+}
+
+struct ImportFriendFunctionTemplates : ASTImporterOptionSpecificTestBase {};
+
+TEST_P(ImportFriendFunctionTemplates, LookupShouldFindPreviousFriend) {
+ Decl *ToTU = getToTuDecl(
+ R"(
+ class X {
+ template <typename T> friend void foo();
+ };
+ )",
+ Lang_CXX);
+ auto *Friend = FirstDeclMatcher<FunctionTemplateDecl>().match(
+ ToTU, functionTemplateDecl(hasName("foo")));
+
+ Decl *FromTU = getTuDecl(
+ R"(
+ template <typename T> void foo();
+ )",
+ Lang_CXX);
+ auto *FromFoo = FirstDeclMatcher<FunctionTemplateDecl>().match(
+ FromTU, functionTemplateDecl(hasName("foo")));
+ auto *Imported = Import(FromFoo, Lang_CXX);
+
+ EXPECT_EQ(Imported->getPreviousDecl(), Friend);
+}
+
+struct ASTImporterWithFakeErrors : ASTImporter {
+ using ASTImporter::ASTImporter;
+ bool returnWithErrorInTest() override { return true; }
+};
+
+struct ErrorHandlingTest : ASTImporterOptionSpecificTestBase {
+ ErrorHandlingTest() {
+ Creator = [](ASTContext &ToContext, FileManager &ToFileManager,
+ ASTContext &FromContext, FileManager &FromFileManager,
+ bool MinimalImport,
+ const std::shared_ptr<ASTImporterSharedState> &SharedState) {
+ return new ASTImporterWithFakeErrors(ToContext, ToFileManager,
+ FromContext, FromFileManager,
+ MinimalImport, SharedState);
+ };
+ }
+ // In this test we purposely report an error (UnsupportedConstruct) when
+ // importing the below stmt.
+ static constexpr auto* ErroneousStmt = R"( asm(""); )";
+};
+
+// Check a case when no new AST node is created in the AST before encountering
+// the error.
+TEST_P(ErrorHandlingTest, ErrorHappensBeforeCreatingANewNode) {
+ TranslationUnitDecl *ToTU = getToTuDecl(
+ R"(
+ template <typename T>
+ class X {};
+ template <>
+ class X<int> { int a; };
+ )",
+ Lang_CXX);
+ TranslationUnitDecl *FromTU = getTuDecl(
+ R"(
+ template <typename T>
+ class X {};
+ template <>
+ class X<int> { double b; };
+ )",
+ Lang_CXX);
+ auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
+ FromTU, classTemplateSpecializationDecl(hasName("X")));
+ ClassTemplateSpecializationDecl *ImportedSpec = Import(FromSpec, Lang_CXX);
+ EXPECT_FALSE(ImportedSpec);
+
+ // The original Decl is kept, no new decl is created.
+ EXPECT_EQ(DeclCounter<ClassTemplateSpecializationDecl>().match(
+ ToTU, classTemplateSpecializationDecl(hasName("X"))),
+ 1u);
+
+ // But an error is set to the counterpart in the "from" context.
+ ASTImporter *Importer = findFromTU(FromSpec)->Importer.get();
+ Optional<ImportError> OptErr = Importer->getImportDeclErrorIfAny(FromSpec);
+ ASSERT_TRUE(OptErr);
+ EXPECT_EQ(OptErr->Error, ImportError::NameConflict);
+}
+
+// Check a case when a new AST node is created but not linked to the AST before
+// encountering the error.
+TEST_P(ErrorHandlingTest,
+ ErrorHappensAfterCreatingTheNodeButBeforeLinkingThatToTheAST) {
+ TranslationUnitDecl *FromTU = getTuDecl(
+ std::string("void foo() { ") + ErroneousStmt + " }",
+ Lang_CXX);
+ auto *FromFoo = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("foo")));
+
+ FunctionDecl *ImportedFoo = Import(FromFoo, Lang_CXX);
+ EXPECT_FALSE(ImportedFoo);
+
+ TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+ // Created, but not linked.
+ EXPECT_EQ(
+ DeclCounter<FunctionDecl>().match(ToTU, functionDecl(hasName("foo"))),
+ 0u);
+
+ ASTImporter *Importer = findFromTU(FromFoo)->Importer.get();
+ Optional<ImportError> OptErr = Importer->getImportDeclErrorIfAny(FromFoo);
+ ASSERT_TRUE(OptErr);
+ EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
+}
+
+// Check a case when a new AST node is created and linked to the AST before
+// encountering the error. The error is set for the counterpart of the nodes in
+// the "from" context.
+TEST_P(ErrorHandlingTest, ErrorHappensAfterNodeIsCreatedAndLinked) {
+ TranslationUnitDecl *FromTU = getTuDecl(
+ std::string(R"(
+ void f();
+ void f() { )") + ErroneousStmt + R"( }
+ )",
+ Lang_CXX);
+ auto *FromProto = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("f")));
+ auto *FromDef =
+ LastDeclMatcher<FunctionDecl>().match(FromTU, functionDecl(hasName("f")));
+ FunctionDecl *ImportedProto = Import(FromProto, Lang_CXX);
+ EXPECT_FALSE(ImportedProto); // Could not import.
+ // However, we created two nodes in the AST. 1) the fwd decl 2) the
+ // definition. The definition is not added to its DC, but the fwd decl is
+ // there.
+ TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+ EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, functionDecl(hasName("f"))),
+ 1u);
+ // Match the fwd decl.
+ auto *ToProto =
+ FirstDeclMatcher<FunctionDecl>().match(ToTU, functionDecl(hasName("f")));
+ EXPECT_TRUE(ToProto);
+ // An error is set to the counterpart in the "from" context both for the fwd
+ // decl and the definition.
+ ASTImporter *Importer = findFromTU(FromProto)->Importer.get();
+ Optional<ImportError> OptErr = Importer->getImportDeclErrorIfAny(FromProto);
+ ASSERT_TRUE(OptErr);
+ EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
+ OptErr = Importer->getImportDeclErrorIfAny(FromDef);
+ ASSERT_TRUE(OptErr);
+ EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
+}
+
+// An error should be set for a class if we cannot import one member.
+TEST_P(ErrorHandlingTest, ErrorIsPropagatedFromMemberToClass) {
+ TranslationUnitDecl *FromTU = getTuDecl(
+ std::string(R"(
+ class X {
+ void f() { )") + ErroneousStmt + R"( } // This member has the error
+ // during import.
+ void ok(); // The error should not prevent importing this.
+ }; // An error will be set for X too.
+ )",
+ Lang_CXX);
+ auto *FromX = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("X")));
+ CXXRecordDecl *ImportedX = Import(FromX, Lang_CXX);
+
+ // An error is set for X.
+ EXPECT_FALSE(ImportedX);
+ ASTImporter *Importer = findFromTU(FromX)->Importer.get();
+ Optional<ImportError> OptErr = Importer->getImportDeclErrorIfAny(FromX);
+ ASSERT_TRUE(OptErr);
+ EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
+
+ // An error is set for f().
+ auto *FromF = FirstDeclMatcher<CXXMethodDecl>().match(
+ FromTU, cxxMethodDecl(hasName("f")));
+ OptErr = Importer->getImportDeclErrorIfAny(FromF);
+ ASSERT_TRUE(OptErr);
+ EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
+ // And any subsequent import should fail.
+ CXXMethodDecl *ImportedF = Import(FromF, Lang_CXX);
+ EXPECT_FALSE(ImportedF);
+
+ // There is an error set for the other member too.
+ auto *FromOK = FirstDeclMatcher<CXXMethodDecl>().match(
+ FromTU, cxxMethodDecl(hasName("ok")));
+ OptErr = Importer->getImportDeclErrorIfAny(FromOK);
+ EXPECT_TRUE(OptErr);
+ // Cannot import the other member.
+ CXXMethodDecl *ImportedOK = Import(FromOK, Lang_CXX);
+ EXPECT_FALSE(ImportedOK);
+}
+
+// Check that an error propagates to the dependent AST nodes.
+// In the below code it means that an error in X should propagate to A.
+// And even to F since the containing A is erroneous.
+// And to all AST nodes which we visit during the import process which finally
+// ends up in a failure (in the error() function).
+TEST_P(ErrorHandlingTest, ErrorPropagatesThroughImportCycles) {
+ Decl *FromTU = getTuDecl(
+ std::string(R"(
+ namespace NS {
+ class A {
+ template <int I> class F {};
+ class X {
+ template <int I> friend class F;
+ void error() { )") + ErroneousStmt + R"( }
+ };
+ };
+
+ class B {};
+ } // NS
+ )",
+ Lang_CXX, "input0.cc");
+
+ auto *FromFRD = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("F"), isDefinition()));
+ auto *FromA = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("A"), isDefinition()));
+ auto *FromB = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("B"), isDefinition()));
+ auto *FromNS = FirstDeclMatcher<NamespaceDecl>().match(
+ FromTU, namespaceDecl(hasName("NS")));
+
+ // Start by importing the templated CXXRecordDecl of F.
+ // Import fails for that.
+ EXPECT_FALSE(Import(FromFRD, Lang_CXX));
+ // Import fails for A.
+ EXPECT_FALSE(Import(FromA, Lang_CXX));
+ // But we should be able to import the independent B.
+ EXPECT_TRUE(Import(FromB, Lang_CXX));
+ // And the namespace.
+ EXPECT_TRUE(Import(FromNS, Lang_CXX));
+
+ // An error is set to the templated CXXRecordDecl of F.
+ ASTImporter *Importer = findFromTU(FromFRD)->Importer.get();
+ Optional<ImportError> OptErr = Importer->getImportDeclErrorIfAny(FromFRD);
+ EXPECT_TRUE(OptErr);
+
+ // An error is set to A.
+ OptErr = Importer->getImportDeclErrorIfAny(FromA);
+ EXPECT_TRUE(OptErr);
+
+ // There is no error set to B.
+ OptErr = Importer->getImportDeclErrorIfAny(FromB);
+ EXPECT_FALSE(OptErr);
+
+ // There is no error set to NS.
+ OptErr = Importer->getImportDeclErrorIfAny(FromNS);
+ EXPECT_FALSE(OptErr);
+
+ // Check some of those decls whose ancestor is X, they all should have an
+ // error set if we visited them during an import process which finally failed.
+ // These decls are part of a cycle in an ImportPath.
+ // There would not be any error set for these decls if we hadn't follow the
+ // ImportPaths and the cycles.
+ OptErr = Importer->getImportDeclErrorIfAny(
+ FirstDeclMatcher<ClassTemplateDecl>().match(
+ FromTU, classTemplateDecl(hasName("F"))));
+ // An error is set to the 'F' ClassTemplateDecl.
+ EXPECT_TRUE(OptErr);
+ // An error is set to the FriendDecl.
+ OptErr = Importer->getImportDeclErrorIfAny(
+ FirstDeclMatcher<FriendDecl>().match(
+ FromTU, friendDecl()));
+ EXPECT_TRUE(OptErr);
+ // An error is set to the implicit class of A.
+ OptErr =
+ Importer->getImportDeclErrorIfAny(FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("A"), isImplicit())));
+ EXPECT_TRUE(OptErr);
+ // An error is set to the implicit class of X.
+ OptErr =
+ Importer->getImportDeclErrorIfAny(FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("X"), isImplicit())));
+ EXPECT_TRUE(OptErr);
+}
+
+TEST_P(ErrorHandlingTest, ErrorIsNotPropagatedFromMemberToNamespace) {
+ TranslationUnitDecl *FromTU = getTuDecl(
+ std::string(R"(
+ namespace X {
+ void f() { )") + ErroneousStmt + R"( } // This member has the error
+ // during import.
+ void ok(); // The error should not prevent importing this.
+ }; // An error will be set for X too.
+ )",
+ Lang_CXX);
+ auto *FromX = FirstDeclMatcher<NamespaceDecl>().match(
+ FromTU, namespaceDecl(hasName("X")));
+ NamespaceDecl *ImportedX = Import(FromX, Lang_CXX);
+
+ // There is no error set for X.
+ EXPECT_TRUE(ImportedX);
+ ASTImporter *Importer = findFromTU(FromX)->Importer.get();
+ Optional<ImportError> OptErr = Importer->getImportDeclErrorIfAny(FromX);
+ ASSERT_FALSE(OptErr);
+
+ // An error is set for f().
+ auto *FromF = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("f")));
+ OptErr = Importer->getImportDeclErrorIfAny(FromF);
+ ASSERT_TRUE(OptErr);
+ EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
+ // And any subsequent import should fail.
+ FunctionDecl *ImportedF = Import(FromF, Lang_CXX);
+ EXPECT_FALSE(ImportedF);
+
+ // There is no error set for ok().
+ auto *FromOK = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("ok")));
+ OptErr = Importer->getImportDeclErrorIfAny(FromOK);
+ EXPECT_FALSE(OptErr);
+ // And we should be able to import.
+ FunctionDecl *ImportedOK = Import(FromOK, Lang_CXX);
+ EXPECT_TRUE(ImportedOK);
+}
+
+// An error should be set for a class if it had a previous import with an error
+// from another TU.
+TEST_P(ErrorHandlingTest,
+ ImportedDeclWithErrorShouldFailTheImportOfDeclWhichMapToIt) {
+ // We already have a fwd decl.
+ TranslationUnitDecl *ToTU = getToTuDecl(
+ "class X;", Lang_CXX);
+ // Then we import a definition.
+ {
+ TranslationUnitDecl *FromTU = getTuDecl(std::string(R"(
+ class X {
+ void f() { )") + ErroneousStmt + R"( }
+ void ok();
+ };
+ )",
+ Lang_CXX);
+ auto *FromX = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("X")));
+ CXXRecordDecl *ImportedX = Import(FromX, Lang_CXX);
+
+ // An error is set for X ...
+ EXPECT_FALSE(ImportedX);
+ ASTImporter *Importer = findFromTU(FromX)->Importer.get();
+ Optional<ImportError> OptErr = Importer->getImportDeclErrorIfAny(FromX);
+ ASSERT_TRUE(OptErr);
+ EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
+ }
+ // ... but the node had been created.
+ auto *ToXDef = FirstDeclMatcher<CXXRecordDecl>().match(
+ ToTU, cxxRecordDecl(hasName("X"), isDefinition()));
+ // An error is set for "ToXDef" in the shared state.
+ Optional<ImportError> OptErr =
+ SharedStatePtr->getImportDeclErrorIfAny(ToXDef);
+ ASSERT_TRUE(OptErr);
+ EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
+
+ auto *ToXFwd = FirstDeclMatcher<CXXRecordDecl>().match(
+ ToTU, cxxRecordDecl(hasName("X"), unless(isDefinition())));
+ // An error is NOT set for the fwd Decl of X in the shared state.
+ OptErr = SharedStatePtr->getImportDeclErrorIfAny(ToXFwd);
+ ASSERT_FALSE(OptErr);
+
+ // Try to import X again but from another TU.
+ {
+ TranslationUnitDecl *FromTU = getTuDecl(std::string(R"(
+ class X {
+ void f() { )") + ErroneousStmt + R"( }
+ void ok();
+ };
+ )",
+ Lang_CXX, "input1.cc");
+
+ auto *FromX = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("X")));
+ CXXRecordDecl *ImportedX = Import(FromX, Lang_CXX);
+
+ // If we did not save the errors for the "to" context then the below checks
+ // would fail, because the lookup finds the fwd Decl of the existing
+ // definition in the "to" context. We can reach the existing definition via
+ // the found fwd Decl. That existing definition is structurally equivalent
+ // (we check only the fields) with this one we want to import, so we return
+ // with the existing definition, which is erroneous (one method is missing).
+
+ // The import should fail.
+ EXPECT_FALSE(ImportedX);
+ ASTImporter *Importer = findFromTU(FromX)->Importer.get();
+ Optional<ImportError> OptErr = Importer->getImportDeclErrorIfAny(FromX);
+ // And an error is set for this new X in the "from" ctx.
+ ASSERT_TRUE(OptErr);
+ EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct);
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ErrorHandlingTest,
+ DefaultTestValuesForRunOptions, );
+
INSTANTIATE_TEST_CASE_P(ParameterizedTests, DeclContextTest,
::testing::Values(ArgVector()), );
-INSTANTIATE_TEST_CASE_P(
- ParameterizedTests, CanonicalRedeclChain,
- ::testing::Values(ArgVector()),);
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, CanonicalRedeclChain,
+ ::testing::Values(ArgVector()), );
-auto DefaultTestValuesForRunOptions = ::testing::Values(
- ArgVector(),
- ArgVector{"-fdelayed-template-parsing"},
- ArgVector{"-fms-compatibility"},
- ArgVector{"-fdelayed-template-parsing", "-fms-compatibility"});
+TEST_P(ASTImporterOptionSpecificTestBase, LambdaInFunctionBody) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ void f() {
+ auto L = [](){};
+ }
+ )",
+ Lang_CXX11, "input0.cc");
+ auto Pattern = lambdaExpr();
+ CXXRecordDecl *FromL =
+ FirstDeclMatcher<LambdaExpr>().match(FromTU, Pattern)->getLambdaClass();
+
+ auto ToL = Import(FromL, Lang_CXX11);
+ unsigned ToLSize = std::distance(ToL->decls().begin(), ToL->decls().end());
+ unsigned FromLSize =
+ std::distance(FromL->decls().begin(), FromL->decls().end());
+ EXPECT_NE(ToLSize, 0u);
+ EXPECT_EQ(ToLSize, FromLSize);
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase, LambdaInFunctionParam) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ template <typename F>
+ void f(F L = [](){}) {}
+ )",
+ Lang_CXX11, "input0.cc");
+ auto Pattern = lambdaExpr();
+ CXXRecordDecl *FromL =
+ FirstDeclMatcher<LambdaExpr>().match(FromTU, Pattern)->getLambdaClass();
+
+ auto ToL = Import(FromL, Lang_CXX11);
+ unsigned ToLSize = std::distance(ToL->decls().begin(), ToL->decls().end());
+ unsigned FromLSize =
+ std::distance(FromL->decls().begin(), FromL->decls().end());
+ EXPECT_NE(ToLSize, 0u);
+ EXPECT_EQ(ToLSize, FromLSize);
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase, LambdaInGlobalScope) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ auto l1 = [](unsigned lp) { return 1; };
+ auto l2 = [](int lp) { return 2; };
+ int f(int p) {
+ return l1(p) + l2(p);
+ }
+ )",
+ Lang_CXX11, "input0.cc");
+ FunctionDecl *FromF = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("f")));
+ FunctionDecl *ToF = Import(FromF, Lang_CXX11);
+ EXPECT_TRUE(ToF);
+}
+
+struct LLDBLookupTest : ASTImporterOptionSpecificTestBase {
+ LLDBLookupTest() {
+ Creator = [](ASTContext &ToContext, FileManager &ToFileManager,
+ ASTContext &FromContext, FileManager &FromFileManager,
+ bool MinimalImport,
+ const std::shared_ptr<ASTImporterSharedState> &SharedState) {
+ return new ASTImporter(ToContext, ToFileManager, FromContext,
+ FromFileManager, MinimalImport,
+ // We use the regular lookup.
+ /*SharedState=*/nullptr);
+ };
+ }
+};
+
+TEST_P(LLDBLookupTest, ImporterShouldFindInTransparentContext) {
+ TranslationUnitDecl *ToTU = getToTuDecl(
+ R"(
+ extern "C" {
+ class X{};
+ };
+ )",
+ Lang_CXX);
+ auto *ToX = FirstDeclMatcher<CXXRecordDecl>().match(
+ ToTU, cxxRecordDecl(hasName("X")));
+
+ // Set up a stub external storage.
+ ToTU->setHasExternalLexicalStorage(true);
+ // Set up DeclContextBits.HasLazyExternalLexicalLookups to true.
+ ToTU->setMustBuildLookupTable();
+ struct TestExternalASTSource : ExternalASTSource {};
+ ToTU->getASTContext().setExternalSource(new TestExternalASTSource());
+
+ Decl *FromTU = getTuDecl(
+ R"(
+ class X;
+ )",
+ Lang_CXX);
+ auto *FromX = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("X")));
+ auto *ImportedX = Import(FromX, Lang_CXX);
+ // The lookup must find the existing class definition in the LinkageSpecDecl.
+ // Then the importer renders the existing and the new decl into one chain.
+ EXPECT_EQ(ImportedX->getCanonicalDecl(), ToX->getCanonicalDecl());
+}
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest,
DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportPath,
+ ::testing::Values(ArgVector()), );
+
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportExpr,
DefaultTestValuesForRunOptions, );
@@ -4884,21 +5198,24 @@
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportDecl,
DefaultTestValuesForRunOptions, );
-INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterTestBase,
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterOptionSpecificTestBase,
+ DefaultTestValuesForRunOptions, );
+
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedirectingImporterTest,
DefaultTestValuesForRunOptions, );
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFunctions,
DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFriendFunctionTemplates,
+ DefaultTestValuesForRunOptions, );
+
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportClasses,
DefaultTestValuesForRunOptions, );
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFriendFunctions,
DefaultTestValuesForRunOptions, );
-INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportClassTemplates,
- DefaultTestValuesForRunOptions, );
-
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFriendClasses,
DefaultTestValuesForRunOptions, );
@@ -4912,5 +5229,8 @@
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportVariables,
DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, LLDBLookupTest,
+ DefaultTestValuesForRunOptions, );
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/src/llvm-project/clang/unittests/AST/ASTImporterVisibilityTest.cpp b/src/llvm-project/clang/unittests/AST/ASTImporterVisibilityTest.cpp
new file mode 100644
index 0000000..8854325
--- /dev/null
+++ b/src/llvm-project/clang/unittests/AST/ASTImporterVisibilityTest.cpp
@@ -0,0 +1,323 @@
+//===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Type-parameterized tests for the correct import of Decls with different
+// visibility.
+//
+//===----------------------------------------------------------------------===//
+
+// Define this to have ::testing::Combine available.
+// FIXME: Better solution for this?
+#define GTEST_HAS_COMBINE 1
+
+#include "ASTImporterFixtures.h"
+
+namespace clang {
+namespace ast_matchers {
+
+using internal::BindableMatcher;
+
+// Type parameters for type-parameterized test fixtures.
+struct GetFunPattern {
+ using DeclTy = FunctionDecl;
+ BindableMatcher<Decl> operator()() { return functionDecl(hasName("f")); }
+};
+struct GetVarPattern {
+ using DeclTy = VarDecl;
+ BindableMatcher<Decl> operator()() { return varDecl(hasName("v")); }
+};
+struct GetClassPattern {
+ using DeclTy = CXXRecordDecl;
+ BindableMatcher<Decl> operator()() { return cxxRecordDecl(hasName("X")); }
+};
+struct GetEnumPattern {
+ using DeclTy = EnumDecl;
+ BindableMatcher<Decl> operator()() { return enumDecl(hasName("E")); }
+};
+
+// Values for the value-parameterized test fixtures.
+// FunctionDecl:
+const auto *ExternF = "void f();";
+const auto *StaticF = "static void f();";
+const auto *AnonF = "namespace { void f(); }";
+// VarDecl:
+const auto *ExternV = "extern int v;";
+const auto *StaticV = "static int v;";
+const auto *AnonV = "namespace { extern int v; }";
+// CXXRecordDecl:
+const auto *ExternC = "class X;";
+const auto *AnonC = "namespace { class X; }";
+// EnumDecl:
+const auto *ExternE = "enum E {};";
+const auto *AnonE = "namespace { enum E {}; }";
+
+// First value in tuple: Compile options.
+// Second value in tuple: Source code to be used in the test.
+using ImportVisibilityChainParams =
+ ::testing::WithParamInterface<std::tuple<ArgVector, const char *>>;
+// Fixture to test the redecl chain of Decls with the same visibility. Gtest
+// makes it possible to have either value-parameterized or type-parameterized
+// fixtures. However, we cannot have both value- and type-parameterized test
+// fixtures. This is a value-parameterized test fixture in the gtest sense. We
+// intend to mimic gtest's type-parameters via the PatternFactory template
+// parameter. We manually instantiate the different tests with the each types.
+template <typename PatternFactory>
+class ImportVisibilityChain
+ : public ASTImporterTestBase, public ImportVisibilityChainParams {
+protected:
+ using DeclTy = typename PatternFactory::DeclTy;
+ ArgVector getExtraArgs() const override { return std::get<0>(GetParam()); }
+ std::string getCode() const { return std::get<1>(GetParam()); }
+ BindableMatcher<Decl> getPattern() const { return PatternFactory()(); }
+
+ // Type-parameterized test.
+ void TypedTest_ImportChain() {
+ std::string Code = getCode() + getCode();
+ auto Pattern = getPattern();
+
+ TranslationUnitDecl *FromTu = getTuDecl(Code, Lang_CXX14, "input0.cc");
+
+ auto *FromD0 = FirstDeclMatcher<DeclTy>().match(FromTu, Pattern);
+ auto *FromD1 = LastDeclMatcher<DeclTy>().match(FromTu, Pattern);
+
+ auto *ToD0 = Import(FromD0, Lang_CXX14);
+ auto *ToD1 = Import(FromD1, Lang_CXX14);
+
+ EXPECT_TRUE(ToD0);
+ ASSERT_TRUE(ToD1);
+ EXPECT_NE(ToD0, ToD1);
+ EXPECT_EQ(ToD1->getPreviousDecl(), ToD0);
+ }
+};
+
+// Manual instantiation of the fixture with each type.
+using ImportFunctionsVisibilityChain = ImportVisibilityChain<GetFunPattern>;
+using ImportVariablesVisibilityChain = ImportVisibilityChain<GetVarPattern>;
+using ImportClassesVisibilityChain = ImportVisibilityChain<GetClassPattern>;
+// Value-parameterized test for functions.
+TEST_P(ImportFunctionsVisibilityChain, ImportChain) {
+ TypedTest_ImportChain();
+}
+// Value-parameterized test for variables.
+TEST_P(ImportVariablesVisibilityChain, ImportChain) {
+ TypedTest_ImportChain();
+}
+// Value-parameterized test for classes.
+TEST_P(ImportClassesVisibilityChain, ImportChain) {
+ TypedTest_ImportChain();
+}
+
+// Automatic instantiation of the value-parameterized tests.
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFunctionsVisibilityChain,
+ ::testing::Combine(
+ DefaultTestValuesForRunOptions,
+ ::testing::Values(ExternF, StaticF, AnonF)), );
+INSTANTIATE_TEST_CASE_P(
+ ParameterizedTests, ImportVariablesVisibilityChain,
+ ::testing::Combine(
+ DefaultTestValuesForRunOptions,
+ // There is no point to instantiate with StaticV, because in C++ we can
+ // forward declare a variable only with the 'extern' keyword.
+ // Consequently, each fwd declared variable has external linkage. This
+ // is different in the C language where any declaration without an
+ // initializer is a tentative definition, subsequent definitions may be
+ // provided but they must have the same linkage. See also the test
+ // ImportVariableChainInC which test for this special C Lang case.
+ ::testing::Values(ExternV, AnonV)), );
+INSTANTIATE_TEST_CASE_P(
+ ParameterizedTests, ImportClassesVisibilityChain,
+ ::testing::Combine(
+ DefaultTestValuesForRunOptions,
+ ::testing::Values(ExternC, AnonC)), );
+
+// First value in tuple: Compile options.
+// Second value in tuple: Tuple with informations for the test.
+// Code for first import (or initial code), code to import, whether the `f`
+// functions are expected to be linked in a declaration chain.
+// One value of this tuple is combined with every value of compile options.
+// The test can have a single tuple as parameter only.
+using ImportVisibilityParams = ::testing::WithParamInterface<
+ std::tuple<ArgVector, std::tuple<const char *, const char *, bool>>>;
+
+template <typename PatternFactory>
+class ImportVisibility
+ : public ASTImporterTestBase,
+ public ImportVisibilityParams {
+protected:
+ using DeclTy = typename PatternFactory::DeclTy;
+ ArgVector getExtraArgs() const override { return std::get<0>(GetParam()); }
+ std::string getCode0() const { return std::get<0>(std::get<1>(GetParam())); }
+ std::string getCode1() const { return std::get<1>(std::get<1>(GetParam())); }
+ bool shouldBeLinked() const { return std::get<2>(std::get<1>(GetParam())); }
+ BindableMatcher<Decl> getPattern() const { return PatternFactory()(); }
+
+ void TypedTest_ImportAfter() {
+ TranslationUnitDecl *ToTu = getToTuDecl(getCode0(), Lang_CXX14);
+ TranslationUnitDecl *FromTu =
+ getTuDecl(getCode1(), Lang_CXX14, "input1.cc");
+
+ auto *ToD0 = FirstDeclMatcher<DeclTy>().match(ToTu, getPattern());
+ auto *FromD1 = FirstDeclMatcher<DeclTy>().match(FromTu, getPattern());
+
+ auto *ToD1 = Import(FromD1, Lang_CXX14);
+
+ ASSERT_TRUE(ToD0);
+ ASSERT_TRUE(ToD1);
+ EXPECT_NE(ToD0, ToD1);
+
+ if (shouldBeLinked())
+ EXPECT_EQ(ToD1->getPreviousDecl(), ToD0);
+ else
+ EXPECT_FALSE(ToD1->getPreviousDecl());
+ }
+
+ void TypedTest_ImportAfterImport() {
+ TranslationUnitDecl *FromTu0 =
+ getTuDecl(getCode0(), Lang_CXX14, "input0.cc");
+ TranslationUnitDecl *FromTu1 =
+ getTuDecl(getCode1(), Lang_CXX14, "input1.cc");
+ auto *FromD0 = FirstDeclMatcher<DeclTy>().match(FromTu0, getPattern());
+ auto *FromD1 = FirstDeclMatcher<DeclTy>().match(FromTu1, getPattern());
+ auto *ToD0 = Import(FromD0, Lang_CXX14);
+ auto *ToD1 = Import(FromD1, Lang_CXX14);
+ ASSERT_TRUE(ToD0);
+ ASSERT_TRUE(ToD1);
+ EXPECT_NE(ToD0, ToD1);
+ if (shouldBeLinked())
+ EXPECT_EQ(ToD1->getPreviousDecl(), ToD0);
+ else
+ EXPECT_FALSE(ToD1->getPreviousDecl());
+ }
+
+ void TypedTest_ImportAfterWithMerge() {
+ TranslationUnitDecl *ToTu = getToTuDecl(getCode0(), Lang_CXX14);
+ TranslationUnitDecl *FromTu =
+ getTuDecl(getCode1(), Lang_CXX14, "input1.cc");
+
+ auto *ToF0 = FirstDeclMatcher<DeclTy>().match(ToTu, getPattern());
+ auto *FromF1 = FirstDeclMatcher<DeclTy>().match(FromTu, getPattern());
+
+ auto *ToF1 = Import(FromF1, Lang_CXX14);
+
+ ASSERT_TRUE(ToF0);
+ ASSERT_TRUE(ToF1);
+
+ if (shouldBeLinked())
+ EXPECT_EQ(ToF0, ToF1);
+ else
+ EXPECT_NE(ToF0, ToF1);
+
+ // We expect no (ODR) warning during the import.
+ EXPECT_EQ(0u, ToTu->getASTContext().getDiagnostics().getNumWarnings());
+ }
+
+ void TypedTest_ImportAfterImportWithMerge() {
+ TranslationUnitDecl *FromTu0 =
+ getTuDecl(getCode0(), Lang_CXX14, "input0.cc");
+ TranslationUnitDecl *FromTu1 =
+ getTuDecl(getCode1(), Lang_CXX14, "input1.cc");
+ auto *FromF0 = FirstDeclMatcher<DeclTy>().match(FromTu0, getPattern());
+ auto *FromF1 = FirstDeclMatcher<DeclTy>().match(FromTu1, getPattern());
+ auto *ToF0 = Import(FromF0, Lang_CXX14);
+ auto *ToF1 = Import(FromF1, Lang_CXX14);
+ ASSERT_TRUE(ToF0);
+ ASSERT_TRUE(ToF1);
+ if (shouldBeLinked())
+ EXPECT_EQ(ToF0, ToF1);
+ else
+ EXPECT_NE(ToF0, ToF1);
+
+ // We expect no (ODR) warning during the import.
+ EXPECT_EQ(0u, ToF0->getTranslationUnitDecl()
+ ->getASTContext()
+ .getDiagnostics()
+ .getNumWarnings());
+ }
+};
+using ImportFunctionsVisibility = ImportVisibility<GetFunPattern>;
+using ImportVariablesVisibility = ImportVisibility<GetVarPattern>;
+using ImportClassesVisibility = ImportVisibility<GetClassPattern>;
+using ImportEnumsVisibility = ImportVisibility<GetEnumPattern>;
+
+// FunctionDecl.
+TEST_P(ImportFunctionsVisibility, ImportAfter) {
+ TypedTest_ImportAfter();
+}
+TEST_P(ImportFunctionsVisibility, ImportAfterImport) {
+ TypedTest_ImportAfterImport();
+}
+// VarDecl.
+TEST_P(ImportVariablesVisibility, ImportAfter) {
+ TypedTest_ImportAfter();
+}
+TEST_P(ImportVariablesVisibility, ImportAfterImport) {
+ TypedTest_ImportAfterImport();
+}
+// CXXRecordDecl.
+TEST_P(ImportClassesVisibility, ImportAfter) {
+ TypedTest_ImportAfter();
+}
+TEST_P(ImportClassesVisibility, ImportAfterImport) {
+ TypedTest_ImportAfterImport();
+}
+// EnumDecl.
+TEST_P(ImportEnumsVisibility, ImportAfter) {
+ TypedTest_ImportAfterWithMerge();
+}
+TEST_P(ImportEnumsVisibility, ImportAfterImport) {
+ TypedTest_ImportAfterImportWithMerge();
+}
+
+const bool ExpectLink = true;
+const bool ExpectNotLink = false;
+
+INSTANTIATE_TEST_CASE_P(
+ ParameterizedTests, ImportFunctionsVisibility,
+ ::testing::Combine(
+ DefaultTestValuesForRunOptions,
+ ::testing::Values(std::make_tuple(ExternF, ExternF, ExpectLink),
+ std::make_tuple(ExternF, StaticF, ExpectNotLink),
+ std::make_tuple(ExternF, AnonF, ExpectNotLink),
+ std::make_tuple(StaticF, ExternF, ExpectNotLink),
+ std::make_tuple(StaticF, StaticF, ExpectNotLink),
+ std::make_tuple(StaticF, AnonF, ExpectNotLink),
+ std::make_tuple(AnonF, ExternF, ExpectNotLink),
+ std::make_tuple(AnonF, StaticF, ExpectNotLink),
+ std::make_tuple(AnonF, AnonF, ExpectNotLink))), );
+INSTANTIATE_TEST_CASE_P(
+ ParameterizedTests, ImportVariablesVisibility,
+ ::testing::Combine(
+ DefaultTestValuesForRunOptions,
+ ::testing::Values(std::make_tuple(ExternV, ExternV, ExpectLink),
+ std::make_tuple(ExternV, StaticV, ExpectNotLink),
+ std::make_tuple(ExternV, AnonV, ExpectNotLink),
+ std::make_tuple(StaticV, ExternV, ExpectNotLink),
+ std::make_tuple(StaticV, StaticV, ExpectNotLink),
+ std::make_tuple(StaticV, AnonV, ExpectNotLink),
+ std::make_tuple(AnonV, ExternV, ExpectNotLink),
+ std::make_tuple(AnonV, StaticV, ExpectNotLink),
+ std::make_tuple(AnonV, AnonV, ExpectNotLink))), );
+INSTANTIATE_TEST_CASE_P(
+ ParameterizedTests, ImportClassesVisibility,
+ ::testing::Combine(
+ DefaultTestValuesForRunOptions,
+ ::testing::Values(std::make_tuple(ExternC, ExternC, ExpectLink),
+ std::make_tuple(ExternC, AnonC, ExpectNotLink),
+ std::make_tuple(AnonC, ExternC, ExpectNotLink),
+ std::make_tuple(AnonC, AnonC, ExpectNotLink))), );
+INSTANTIATE_TEST_CASE_P(
+ ParameterizedTests, ImportEnumsVisibility,
+ ::testing::Combine(
+ DefaultTestValuesForRunOptions,
+ ::testing::Values(std::make_tuple(ExternE, ExternE, ExpectLink),
+ std::make_tuple(ExternE, AnonE, ExpectNotLink),
+ std::make_tuple(AnonE, ExternE, ExpectNotLink),
+ std::make_tuple(AnonE, AnonE, ExpectNotLink))), );
+
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/src/llvm-project/clang/unittests/AST/ASTPrint.h b/src/llvm-project/clang/unittests/AST/ASTPrint.h
new file mode 100644
index 0000000..c3b6b84
--- /dev/null
+++ b/src/llvm-project/clang/unittests/AST/ASTPrint.h
@@ -0,0 +1,92 @@
+//===- unittests/AST/ASTPrint.h ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helpers to simplify testing of printing of AST constructs provided in the/
+// form of the source code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallString.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+
+using PolicyAdjusterType =
+ Optional<llvm::function_ref<void(PrintingPolicy &Policy)>>;
+
+static void PrintStmt(raw_ostream &Out, const ASTContext *Context,
+ const Stmt *S, PolicyAdjusterType PolicyAdjuster) {
+ assert(S != nullptr && "Expected non-null Stmt");
+ PrintingPolicy Policy = Context->getPrintingPolicy();
+ if (PolicyAdjuster)
+ (*PolicyAdjuster)(Policy);
+ S->printPretty(Out, /*Helper*/ nullptr, Policy);
+}
+
+class PrintMatch : public ast_matchers::MatchFinder::MatchCallback {
+ SmallString<1024> Printed;
+ unsigned NumFoundStmts;
+ PolicyAdjusterType PolicyAdjuster;
+
+public:
+ PrintMatch(PolicyAdjusterType PolicyAdjuster)
+ : NumFoundStmts(0), PolicyAdjuster(PolicyAdjuster) {}
+
+ void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
+ const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id");
+ if (!S)
+ return;
+ NumFoundStmts++;
+ if (NumFoundStmts > 1)
+ return;
+
+ llvm::raw_svector_ostream Out(Printed);
+ PrintStmt(Out, Result.Context, S, PolicyAdjuster);
+ }
+
+ StringRef getPrinted() const { return Printed; }
+
+ unsigned getNumFoundStmts() const { return NumFoundStmts; }
+};
+
+template <typename T>
+::testing::AssertionResult
+PrintedStmtMatches(StringRef Code, const std::vector<std::string> &Args,
+ const T &NodeMatch, StringRef ExpectedPrinted,
+ PolicyAdjusterType PolicyAdjuster = None) {
+
+ PrintMatch Printer(PolicyAdjuster);
+ ast_matchers::MatchFinder Finder;
+ Finder.addMatcher(NodeMatch, &Printer);
+ std::unique_ptr<tooling::FrontendActionFactory> Factory(
+ tooling::newFrontendActionFactory(&Finder));
+
+ if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args))
+ return testing::AssertionFailure()
+ << "Parsing error in \"" << Code.str() << "\"";
+
+ if (Printer.getNumFoundStmts() == 0)
+ return testing::AssertionFailure() << "Matcher didn't find any statements";
+
+ if (Printer.getNumFoundStmts() > 1)
+ return testing::AssertionFailure()
+ << "Matcher should match only one statement (found "
+ << Printer.getNumFoundStmts() << ")";
+
+ if (Printer.getPrinted() != ExpectedPrinted)
+ return ::testing::AssertionFailure()
+ << "Expected \"" << ExpectedPrinted.str() << "\", got \""
+ << Printer.getPrinted().str() << "\"";
+
+ return ::testing::AssertionSuccess();
+}
+
+} // namespace clang
diff --git a/src/llvm-project/clang/unittests/AST/ASTTraverserTest.cpp b/src/llvm-project/clang/unittests/AST/ASTTraverserTest.cpp
new file mode 100644
index 0000000..cddb219
--- /dev/null
+++ b/src/llvm-project/clang/unittests/AST/ASTTraverserTest.cpp
@@ -0,0 +1,224 @@
+//===- unittests/AST/ASTTraverserTest.h------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTNodeTraverser.h"
+#include "clang/AST/TextNodeDumper.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang::tooling;
+using namespace clang::ast_matchers;
+
+namespace clang {
+
+class NodeTreePrinter : public TextTreeStructure {
+ llvm::raw_ostream &OS;
+
+public:
+ NodeTreePrinter(llvm::raw_ostream &OS)
+ : TextTreeStructure(OS, /* showColors */ false), OS(OS) {}
+
+ void Visit(const Decl *D) { OS << D->getDeclKindName() << "Decl"; }
+
+ void Visit(const Stmt *S) { OS << S->getStmtClassName(); }
+
+ void Visit(QualType QT) {
+ OS << "QualType " << QT.split().Quals.getAsString();
+ }
+
+ void Visit(const Type *T) { OS << T->getTypeClassName() << "Type"; }
+
+ void Visit(const comments::Comment *C, const comments::FullComment *FC) {
+ OS << C->getCommentKindName();
+ }
+
+ void Visit(const CXXCtorInitializer *Init) { OS << "CXXCtorInitializer"; }
+
+ void Visit(const Attr *A) {
+ switch (A->getKind()) {
+#define ATTR(X) \
+ case attr::X: \
+ OS << #X; \
+ break;
+#include "clang/Basic/AttrList.inc"
+ }
+ OS << "Attr";
+ }
+
+ void Visit(const OMPClause *C) { OS << "OMPClause"; }
+ void Visit(const TemplateArgument &A, SourceRange R = {},
+ const Decl *From = nullptr, const char *Label = nullptr) {
+ OS << "TemplateArgument";
+ }
+
+ template <typename... T> void Visit(T...) {}
+};
+
+class TestASTDumper : public ASTNodeTraverser<TestASTDumper, NodeTreePrinter> {
+
+ NodeTreePrinter MyNodeRecorder;
+
+public:
+ TestASTDumper(llvm::raw_ostream &OS) : MyNodeRecorder(OS) {}
+ NodeTreePrinter &doGetNodeDelegate() { return MyNodeRecorder; }
+};
+
+template <typename... NodeType> std::string dumpASTString(NodeType &&... N) {
+ std::string Buffer;
+ llvm::raw_string_ostream OS(Buffer);
+
+ TestASTDumper Dumper(OS);
+
+ OS << "\n";
+
+ Dumper.Visit(std::forward<NodeType &&>(N)...);
+
+ return OS.str();
+}
+
+const FunctionDecl *getFunctionNode(clang::ASTUnit *AST,
+ const std::string &Name) {
+ auto Result = ast_matchers::match(functionDecl(hasName(Name)).bind("fn"),
+ AST->getASTContext());
+ EXPECT_EQ(Result.size(), 1u);
+ return Result[0].getNodeAs<FunctionDecl>("fn");
+}
+
+template <typename T> struct Verifier {
+ static void withDynNode(T Node, const std::string &DumpString) {
+ EXPECT_EQ(dumpASTString(ast_type_traits::DynTypedNode::create(Node)),
+ DumpString);
+ }
+};
+
+template <typename T> struct Verifier<T *> {
+ static void withDynNode(T *Node, const std::string &DumpString) {
+ EXPECT_EQ(dumpASTString(ast_type_traits::DynTypedNode::create(*Node)),
+ DumpString);
+ }
+};
+
+template <typename T>
+void verifyWithDynNode(T Node, const std::string &DumpString) {
+ EXPECT_EQ(dumpASTString(Node), DumpString);
+
+ Verifier<T>::withDynNode(Node, DumpString);
+}
+
+TEST(Traverse, Dump) {
+
+ auto AST = buildASTFromCode(R"cpp(
+struct A {
+ int m_number;
+
+ /// CTor
+ A() : m_number(42) {}
+
+ [[nodiscard]] const int func() {
+ return 42;
+ }
+
+};
+
+template<typename T>
+struct templ
+{
+};
+
+template<>
+struct templ<int>
+{
+};
+
+)cpp");
+
+ const FunctionDecl *Func = getFunctionNode(AST.get(), "func");
+
+ verifyWithDynNode(Func,
+ R"cpp(
+CXXMethodDecl
+|-CompoundStmt
+| `-ReturnStmt
+| `-IntegerLiteral
+`-WarnUnusedResultAttr
+)cpp");
+
+ Stmt *Body = Func->getBody();
+
+ verifyWithDynNode(Body,
+ R"cpp(
+CompoundStmt
+`-ReturnStmt
+ `-IntegerLiteral
+)cpp");
+
+ QualType QT = Func->getType();
+
+ verifyWithDynNode(QT,
+ R"cpp(
+FunctionProtoType
+`-QualType const
+ `-BuiltinType
+)cpp");
+
+ const FunctionDecl *CTorFunc = getFunctionNode(AST.get(), "A");
+
+ verifyWithDynNode(CTorFunc->getType(),
+ R"cpp(
+FunctionProtoType
+`-BuiltinType
+)cpp");
+
+ Attr *A = *Func->attr_begin();
+
+ {
+ std::string expectedString = R"cpp(
+WarnUnusedResultAttr
+)cpp";
+
+ EXPECT_EQ(dumpASTString(A), expectedString);
+ }
+
+ auto *CTor = dyn_cast<CXXConstructorDecl>(CTorFunc);
+ const CXXCtorInitializer *Init = *CTor->init_begin();
+
+ verifyWithDynNode(Init,
+ R"cpp(
+CXXCtorInitializer
+`-IntegerLiteral
+)cpp");
+
+ const comments::FullComment *Comment =
+ AST->getASTContext().getLocalCommentForDeclUncached(CTorFunc);
+ {
+ std::string expectedString = R"cpp(
+FullComment
+`-ParagraphComment
+ `-TextComment
+)cpp";
+ EXPECT_EQ(dumpASTString(Comment, Comment), expectedString);
+ }
+
+ auto Result = ast_matchers::match(
+ classTemplateSpecializationDecl(hasName("templ")).bind("fn"),
+ AST->getASTContext());
+ EXPECT_EQ(Result.size(), 1u);
+ auto Templ = Result[0].getNodeAs<ClassTemplateSpecializationDecl>("fn");
+
+ TemplateArgument TA = Templ->getTemplateArgs()[0];
+
+ verifyWithDynNode(TA,
+ R"cpp(
+TemplateArgument
+)cpp");
+}
+} // namespace clang
diff --git a/src/llvm-project/clang/unittests/AST/ASTTypeTraitsTest.cpp b/src/llvm-project/clang/unittests/AST/ASTTypeTraitsTest.cpp
index 722c468..2313f9f 100644
--- a/src/llvm-project/clang/unittests/AST/ASTTypeTraitsTest.cpp
+++ b/src/llvm-project/clang/unittests/AST/ASTTypeTraitsTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/AST/ASTTypeTraits.cpp - AST type traits unit tests ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===--------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/AST/ASTVectorTest.cpp b/src/llvm-project/clang/unittests/AST/ASTVectorTest.cpp
index 359d2f4..f5b208a 100644
--- a/src/llvm-project/clang/unittests/AST/ASTVectorTest.cpp
+++ b/src/llvm-project/clang/unittests/AST/ASTVectorTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/AST/DeclTest.cpp --- Declaration tests -------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/AST/CMakeLists.txt b/src/llvm-project/clang/unittests/AST/CMakeLists.txt
index c416e5b..333aded 100644
--- a/src/llvm-project/clang/unittests/AST/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/AST/CMakeLists.txt
@@ -8,7 +8,11 @@
add_clang_unittest(ASTTests
ASTContextParentMapTest.cpp
+ ASTImporterFixtures.cpp
ASTImporterTest.cpp
+ ASTImporterGenericRedeclTest.cpp
+ ASTImporterVisibilityTest.cpp
+ ASTTraverserTest.cpp
ASTTypeTraitsTest.cpp
ASTVectorTest.cpp
CommentLexer.cpp
@@ -21,12 +25,13 @@
ExternalASTSourceTest.cpp
Language.cpp
NamedDeclPrinterTest.cpp
+ OMPStructuredBlockTest.cpp
SourceLocationTest.cpp
StmtPrinterTest.cpp
StructuralEquivalenceTest.cpp
)
-target_link_libraries(ASTTests
+clang_target_link_libraries(ASTTests
PRIVATE
clangAST
clangASTMatchers
diff --git a/src/llvm-project/clang/unittests/AST/CommentLexer.cpp b/src/llvm-project/clang/unittests/AST/CommentLexer.cpp
index f96d6cd..1883050 100644
--- a/src/llvm-project/clang/unittests/AST/CommentLexer.cpp
+++ b/src/llvm-project/clang/unittests/AST/CommentLexer.cpp
@@ -1,9 +1,8 @@
//===- unittests/AST/CommentLexer.cpp ------ Comment lexer tests ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/AST/CommentParser.cpp b/src/llvm-project/clang/unittests/AST/CommentParser.cpp
index a185f73..d1f732c 100644
--- a/src/llvm-project/clang/unittests/AST/CommentParser.cpp
+++ b/src/llvm-project/clang/unittests/AST/CommentParser.cpp
@@ -1,9 +1,8 @@
//===- unittests/AST/CommentParser.cpp ------ Comment parser tests --------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/AST/CommentTextTest.cpp b/src/llvm-project/clang/unittests/AST/CommentTextTest.cpp
index 5fb7795..3de6758 100644
--- a/src/llvm-project/clang/unittests/AST/CommentTextTest.cpp
+++ b/src/llvm-project/clang/unittests/AST/CommentTextTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/AST/CommentTextTest.cpp - Comment text extraction test ----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/AST/DataCollectionTest.cpp b/src/llvm-project/clang/unittests/AST/DataCollectionTest.cpp
index e8ebd16..b732a44 100644
--- a/src/llvm-project/clang/unittests/AST/DataCollectionTest.cpp
+++ b/src/llvm-project/clang/unittests/AST/DataCollectionTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/AST/DataCollectionTest.cpp -------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/AST/DeclMatcher.h b/src/llvm-project/clang/unittests/AST/DeclMatcher.h
index 602f8df..a7698aa 100644
--- a/src/llvm-project/clang/unittests/AST/DeclMatcher.h
+++ b/src/llvm-project/clang/unittests/AST/DeclMatcher.h
@@ -1,9 +1,8 @@
//===- unittest/AST/DeclMatcher.h - AST unit test support ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/AST/DeclPrinterTest.cpp b/src/llvm-project/clang/unittests/AST/DeclPrinterTest.cpp
index 4cf8bce..c003e36 100644
--- a/src/llvm-project/clang/unittests/AST/DeclPrinterTest.cpp
+++ b/src/llvm-project/clang/unittests/AST/DeclPrinterTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/AST/DeclPrinterTest.cpp --- Declaration printer tests ----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/AST/DeclTest.cpp b/src/llvm-project/clang/unittests/AST/DeclTest.cpp
index 87aeef4..6691952 100644
--- a/src/llvm-project/clang/unittests/AST/DeclTest.cpp
+++ b/src/llvm-project/clang/unittests/AST/DeclTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/AST/DeclTest.cpp --- Declaration tests -------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/AST/EvaluateAsRValueTest.cpp b/src/llvm-project/clang/unittests/AST/EvaluateAsRValueTest.cpp
index 820edbc..e737507 100644
--- a/src/llvm-project/clang/unittests/AST/EvaluateAsRValueTest.cpp
+++ b/src/llvm-project/clang/unittests/AST/EvaluateAsRValueTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/AST/EvaluateAsRValueTest.cpp -----------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/AST/ExternalASTSourceTest.cpp b/src/llvm-project/clang/unittests/AST/ExternalASTSourceTest.cpp
index 513ff5b..3a0fe01 100644
--- a/src/llvm-project/clang/unittests/AST/ExternalASTSourceTest.cpp
+++ b/src/llvm-project/clang/unittests/AST/ExternalASTSourceTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/AST/ExternalASTSourceTest.cpp -----------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/AST/Language.cpp b/src/llvm-project/clang/unittests/AST/Language.cpp
index 5d16640..68b78a3 100644
--- a/src/llvm-project/clang/unittests/AST/Language.cpp
+++ b/src/llvm-project/clang/unittests/AST/Language.cpp
@@ -1,9 +1,8 @@
//===------ unittest/AST/Language.cpp - AST unit test support -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -35,6 +34,9 @@
case Lang_CXX14:
BasicArgs = {"-std=c++14", "-frtti"};
break;
+ case Lang_CXX2a:
+ BasicArgs = {"-std=c++2a", "-frtti"};
+ break;
case Lang_OpenCL:
case Lang_OBJCXX:
llvm_unreachable("Not implemented yet!");
diff --git a/src/llvm-project/clang/unittests/AST/Language.h b/src/llvm-project/clang/unittests/AST/Language.h
index 0eb2fb2..dd61ef8 100644
--- a/src/llvm-project/clang/unittests/AST/Language.h
+++ b/src/llvm-project/clang/unittests/AST/Language.h
@@ -1,9 +1,8 @@
//===------ unittest/AST/Language.h - AST unit test support ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -29,6 +28,7 @@
Lang_CXX,
Lang_CXX11,
Lang_CXX14,
+ Lang_CXX2a,
Lang_OpenCL,
Lang_OBJCXX
};
diff --git a/src/llvm-project/clang/unittests/AST/MatchVerifier.h b/src/llvm-project/clang/unittests/AST/MatchVerifier.h
index 3e94d53..7aca7f4 100644
--- a/src/llvm-project/clang/unittests/AST/MatchVerifier.h
+++ b/src/llvm-project/clang/unittests/AST/MatchVerifier.h
@@ -1,9 +1,8 @@
//===- unittest/AST/MatchVerifier.h - AST unit test support ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -109,6 +108,10 @@
Args.push_back("-std=c++14");
FileName = "input.cc";
break;
+ case Lang_CXX2a:
+ Args.push_back("-std=c++2a");
+ FileName = "input.cc";
+ break;
case Lang_OpenCL:
FileName = "input.cl";
break;
diff --git a/src/llvm-project/clang/unittests/AST/NamedDeclPrinterTest.cpp b/src/llvm-project/clang/unittests/AST/NamedDeclPrinterTest.cpp
index 5715a34..a506265 100644
--- a/src/llvm-project/clang/unittests/AST/NamedDeclPrinterTest.cpp
+++ b/src/llvm-project/clang/unittests/AST/NamedDeclPrinterTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/AST/NamedDeclPrinterTest.cpp --- NamedDecl printer tests -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -116,6 +115,18 @@
"input.cc");
}
+::testing::AssertionResult
+PrintedWrittenPropertyDeclObjCMatches(StringRef Code, StringRef DeclName,
+ StringRef ExpectedPrinted) {
+ std::vector<std::string> Args{"-std=c++11", "-xobjective-c++"};
+ return PrintedNamedDeclMatches(Code,
+ Args,
+ /*SuppressUnwrittenScope*/ true,
+ objcPropertyDecl(hasName(DeclName)).bind("id"),
+ ExpectedPrinted,
+ "input.m");
+}
+
} // unnamed namespace
TEST(NamedDeclPrinter, TestNamespace1) {
@@ -180,3 +191,35 @@
"A",
"X::A"));
}
+
+TEST(NamedDeclPrinter, TestObjCClassExtension) {
+ const char *Code =
+R"(
+ @interface Obj
+ @end
+
+ @interface Obj ()
+ @property(nonatomic) int property;
+ @end
+)";
+ ASSERT_TRUE(PrintedWrittenPropertyDeclObjCMatches(
+ Code,
+ "property",
+ "Obj::property"));
+}
+
+TEST(NamedDeclPrinter, TestObjCClassExtensionWithGetter) {
+ const char *Code =
+R"(
+ @interface Obj
+ @end
+
+ @interface Obj ()
+ @property(nonatomic, getter=myPropertyGetter) int property;
+ @end
+)";
+ ASSERT_TRUE(PrintedWrittenPropertyDeclObjCMatches(
+ Code,
+ "property",
+ "Obj::property"));
+}
diff --git a/src/llvm-project/clang/unittests/AST/OMPStructuredBlockTest.cpp b/src/llvm-project/clang/unittests/AST/OMPStructuredBlockTest.cpp
new file mode 100644
index 0000000..f4a3fad
--- /dev/null
+++ b/src/llvm-project/clang/unittests/AST/OMPStructuredBlockTest.cpp
@@ -0,0 +1,540 @@
+//===- unittests/AST/OMPStructuredBlockTest.cpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Fine-grained tests for IsOMPStructuredBlock bit of Stmt.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTPrint.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/StmtOpenMP.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallString.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace ast_matchers;
+using namespace tooling;
+
+namespace {
+
+const ast_matchers::internal::VariadicDynCastAllOfMatcher<
+ OMPExecutableDirective, OMPTargetDirective>
+ ompTargetDirective;
+
+StatementMatcher OMPInnermostStructuredBlockMatcher() {
+ return stmt(isOMPStructuredBlock(),
+ unless(hasDescendant(stmt(isOMPStructuredBlock()))))
+ .bind("id");
+}
+
+StatementMatcher OMPStandaloneDirectiveMatcher() {
+ return stmt(ompExecutableDirective(isStandaloneDirective())).bind("id");
+}
+
+template <typename T>
+::testing::AssertionResult
+PrintedOMPStmtMatches(StringRef Code, const T &NodeMatch,
+ StringRef ExpectedPrinted,
+ PolicyAdjusterType PolicyAdjuster = None) {
+ std::vector<std::string> Args = {
+ "-fopenmp=libomp",
+ };
+ return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
+ PolicyAdjuster);
+}
+
+static testing::AssertionResult NoMatches(StringRef Code,
+ const StatementMatcher &StmtMatch) {
+ PrintMatch Printer((PolicyAdjusterType()));
+ MatchFinder Finder;
+ Finder.addMatcher(StmtMatch, &Printer);
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
+ if (!runToolOnCode(Factory->create(), Code))
+ return testing::AssertionFailure()
+ << "Parsing error in \"" << Code.str() << "\"";
+ if (Printer.getNumFoundStmts() == 0)
+ return testing::AssertionSuccess();
+ return testing::AssertionFailure()
+ << "Matcher should match only zero statements (found "
+ << Printer.getNumFoundStmts() << ")";
+}
+
+} // unnamed namespace
+
+TEST(OMPStructuredBlock, TestAtomic) {
+ const char *Source =
+ R"(
+void test(int i) {
+#pragma omp atomic
+++i;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), "++i"));
+}
+
+TEST(OMPStructuredBlock, TestBarrier) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp barrier
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(),
+ "#pragma omp barrier\n"));
+ ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher()));
+}
+
+TEST(OMPStructuredBlock, TestCancel) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp parallel
+{
+ #pragma omp cancel parallel
+}
+})";
+ const char *Expected = R"({
+ #pragma omp cancel parallel
+}
+)";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), Expected));
+ ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(),
+ "#pragma omp cancel parallel\n"));
+}
+
+TEST(OMPStructuredBlock, TestCancellationPoint) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp parallel
+{
+ #pragma omp cancellation point parallel
+}
+})";
+ const char *Expected = R"({
+ #pragma omp cancellation point parallel
+}
+)";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), Expected));
+ ASSERT_TRUE(
+ PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(),
+ "#pragma omp cancellation point parallel\n"));
+}
+
+TEST(OMPStructuredBlock, TestCritical) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp critical
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+//----------------------------------------------------------------------------//
+// Loop tests
+//----------------------------------------------------------------------------//
+
+class OMPStructuredBlockLoop : public ::testing::TestWithParam<const char *> {};
+
+TEST_P(OMPStructuredBlockLoop, TestDirective0) {
+ const std::string Source =
+ R"(
+void test(int x) {
+#pragma omp )" +
+ std::string(GetParam()) + R"(
+for (int i = 0; i < x; i++)
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+TEST_P(OMPStructuredBlockLoop, TestDirective1) {
+ const std::string Source =
+ R"(
+void test(int x, int y) {
+#pragma omp )" +
+ std::string(GetParam()) + R"(
+for (int i = 0; i < x; i++)
+for (int i = 0; i < y; i++)
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(Source,
+ OMPInnermostStructuredBlockMatcher(),
+ "for (int i = 0; i < y; i++)\n ;\n"));
+}
+
+TEST_P(OMPStructuredBlockLoop, TestDirectiveCollapse1) {
+ const std::string Source =
+ R"(
+void test(int x, int y) {
+#pragma omp )" +
+ std::string(GetParam()) + R"( collapse(1)
+for (int i = 0; i < x; i++)
+for (int i = 0; i < y; i++)
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(Source,
+ OMPInnermostStructuredBlockMatcher(),
+ "for (int i = 0; i < y; i++)\n ;\n"));
+}
+
+TEST_P(OMPStructuredBlockLoop, TestDirectiveCollapse2) {
+ const std::string Source =
+ R"(
+void test(int x, int y) {
+#pragma omp )" +
+ std::string(GetParam()) + R"( collapse(2)
+for (int i = 0; i < x; i++)
+for (int i = 0; i < y; i++)
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+TEST_P(OMPStructuredBlockLoop, TestDirectiveCollapse22) {
+ const std::string Source =
+ R"(
+void test(int x, int y, int z) {
+#pragma omp )" +
+ std::string(GetParam()) + R"( collapse(2)
+for (int i = 0; i < x; i++)
+for (int i = 0; i < y; i++)
+for (int i = 0; i < z; i++)
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(Source,
+ OMPInnermostStructuredBlockMatcher(),
+ "for (int i = 0; i < z; i++)\n ;\n"));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ OMPStructuredBlockLoopDirectives, OMPStructuredBlockLoop,
+ ::testing::Values("simd", "for", "for simd", "parallel for",
+ "parallel for simd", "target parallel for", "taskloop",
+ "taskloop simd", "distribute", "distribute parallel for",
+ "distribute parallel for simd", "distribute simd",
+ "target parallel for simd", "target simd",
+ "target\n#pragma omp teams distribute",
+ "target\n#pragma omp teams distribute simd",
+ "target\n#pragma omp teams distribute parallel for simd",
+ "target\n#pragma omp teams distribute parallel for",
+ "target teams distribute",
+ "target teams distribute parallel for",
+ "target teams distribute parallel for simd",
+ "target teams distribute simd"), );
+
+//----------------------------------------------------------------------------//
+// End Loop tests
+//----------------------------------------------------------------------------//
+
+TEST(OMPStructuredBlock, TestFlush) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp flush
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(),
+ "#pragma omp flush\n"));
+ ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher()));
+}
+
+TEST(OMPStructuredBlock, TestMaster) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp master
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+TEST(OMPStructuredBlock, TestOrdered0) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp ordered
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+TEST(OMPStructuredBlock, TestOrdered1) {
+ const char *Source =
+ R"(
+void test(int x) {
+#pragma omp for ordered
+for (int i = 0; i < x; i++)
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+TEST(OMPStructuredBlock, TestOrdered2) {
+ const char *Source =
+ R"(
+void test(int x) {
+#pragma omp for ordered(1)
+for (int i = 0; i < x; i++) {
+#pragma omp ordered depend(source)
+}
+})";
+ ASSERT_TRUE(
+ PrintedOMPStmtMatches(Source, OMPInnermostStructuredBlockMatcher(),
+ "{\n #pragma omp ordered depend(source)\n}\n"));
+ ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(),
+ "#pragma omp ordered depend(source)\n"));
+}
+
+TEST(OMPStructuredBlock, DISABLED_TestParallelMaster0XFAIL) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp parallel master
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+TEST(OMPStructuredBlock, DISABLED_TestParallelMaster1XFAIL) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp parallel master
+{ ; }
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), "{\n ;\n}\n"));
+}
+
+TEST(OMPStructuredBlock, TestParallelSections) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp parallel sections
+{ ; }
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), "{\n ;\n}\n"));
+}
+
+TEST(OMPStructuredBlock, TestParallelDirective) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp parallel
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+const ast_matchers::internal::VariadicDynCastAllOfMatcher<
+ OMPExecutableDirective, OMPSectionsDirective>
+ ompSectionsDirective;
+
+const ast_matchers::internal::VariadicDynCastAllOfMatcher<
+ OMPExecutableDirective, OMPSectionDirective>
+ ompSectionDirective;
+
+StatementMatcher OMPSectionsDirectiveMatcher() {
+ return stmt(
+ isOMPStructuredBlock(),
+ hasAncestor(ompExecutableDirective(ompSectionsDirective())),
+ unless(hasAncestor(ompExecutableDirective(ompSectionDirective()))))
+ .bind("id");
+}
+
+TEST(OMPStructuredBlock, TestSectionDirective) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp sections
+{
+#pragma omp section
+;
+}
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPSectionsDirectiveMatcher(),
+ "{\n"
+ " #pragma omp section\n"
+ " ;\n"
+ "}\n"));
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+TEST(OMPStructuredBlock, TestSections) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp sections
+{ ; }
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), "{\n ;\n}\n"));
+}
+
+TEST(OMPStructuredBlock, TestSingleDirective) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp single
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+TEST(OMPStructuredBlock, TesTargetDataDirective) {
+ const char *Source =
+ R"(
+void test(int x) {
+#pragma omp target data map(x)
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+TEST(OMPStructuredBlock, TesTargetEnterDataDirective) {
+ const char *Source =
+ R"(
+void test(int x) {
+#pragma omp target enter data map(to : x)
+})";
+ ASSERT_TRUE(
+ PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(),
+ "#pragma omp target enter data map(to: x)\n"));
+ ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher()));
+}
+
+TEST(OMPStructuredBlock, TesTargetExitDataDirective) {
+ const char *Source =
+ R"(
+void test(int x) {
+#pragma omp target exit data map(from : x)
+})";
+ ASSERT_TRUE(
+ PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(),
+ "#pragma omp target exit data map(from: x)\n"));
+ ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher()));
+}
+
+TEST(OMPStructuredBlock, TestTargetParallelDirective) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp target parallel
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+TEST(OMPStructuredBlock, TestTargetTeams) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp target teams
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+TEST(OMPStructuredBlock, TestTargetUpdateDirective) {
+ const char *Source =
+ R"(
+void test(int x) {
+#pragma omp target update to(x)
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(),
+ "#pragma omp target update to(x)\n"));
+ ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher()));
+}
+
+TEST(OMPStructuredBlock, TestTarget) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp target
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+TEST(OMPStructuredBlock, TestTask) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp task
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+TEST(OMPStructuredBlock, TestTaskgroup) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp taskgroup
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
+
+TEST(OMPStructuredBlock, TestTaskwaitDirective) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp taskwait
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(),
+ "#pragma omp taskwait\n"));
+ ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher()));
+}
+
+TEST(OMPStructuredBlock, TestTaskyieldDirective) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp taskyield
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(Source, OMPStandaloneDirectiveMatcher(),
+ "#pragma omp taskyield\n"));
+ ASSERT_TRUE(NoMatches(Source, OMPInnermostStructuredBlockMatcher()));
+}
+
+TEST(OMPStructuredBlock, TestTeams) {
+ const char *Source =
+ R"(
+void test() {
+#pragma omp target
+#pragma omp teams
+;
+})";
+ ASSERT_TRUE(PrintedOMPStmtMatches(
+ Source, OMPInnermostStructuredBlockMatcher(), ";\n"));
+}
diff --git a/src/llvm-project/clang/unittests/AST/SourceLocationTest.cpp b/src/llvm-project/clang/unittests/AST/SourceLocationTest.cpp
index 5f69c54..6b4dddc 100644
--- a/src/llvm-project/clang/unittests/AST/SourceLocationTest.cpp
+++ b/src/llvm-project/clang/unittests/AST/SourceLocationTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/AST/SourceLocationTest.cpp - AST source loc unit tests ----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/AST/StmtPrinterTest.cpp b/src/llvm-project/clang/unittests/AST/StmtPrinterTest.cpp
index 40da6ca..080c18b 100644
--- a/src/llvm-project/clang/unittests/AST/StmtPrinterTest.cpp
+++ b/src/llvm-project/clang/unittests/AST/StmtPrinterTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/AST/StmtPrinterTest.cpp --- Statement printer tests ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -19,6 +18,7 @@
//
//===----------------------------------------------------------------------===//
+#include "ASTPrint.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/Tooling.h"
@@ -31,81 +31,6 @@
namespace {
-using PolicyAdjusterType =
- Optional<llvm::function_ref<void(PrintingPolicy &Policy)>>;
-
-void PrintStmt(raw_ostream &Out, const ASTContext *Context, const Stmt *S,
- PolicyAdjusterType PolicyAdjuster) {
- assert(S != nullptr && "Expected non-null Stmt");
- PrintingPolicy Policy = Context->getPrintingPolicy();
- if (PolicyAdjuster)
- (*PolicyAdjuster)(Policy);
- S->printPretty(Out, /*Helper*/ nullptr, Policy);
-}
-
-class PrintMatch : public MatchFinder::MatchCallback {
- SmallString<1024> Printed;
- unsigned NumFoundStmts;
- PolicyAdjusterType PolicyAdjuster;
-
-public:
- PrintMatch(PolicyAdjusterType PolicyAdjuster)
- : NumFoundStmts(0), PolicyAdjuster(PolicyAdjuster) {}
-
- void run(const MatchFinder::MatchResult &Result) override {
- const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id");
- if (!S)
- return;
- NumFoundStmts++;
- if (NumFoundStmts > 1)
- return;
-
- llvm::raw_svector_ostream Out(Printed);
- PrintStmt(Out, Result.Context, S, PolicyAdjuster);
- }
-
- StringRef getPrinted() const {
- return Printed;
- }
-
- unsigned getNumFoundStmts() const {
- return NumFoundStmts;
- }
-};
-
-template <typename T>
-::testing::AssertionResult
-PrintedStmtMatches(StringRef Code, const std::vector<std::string> &Args,
- const T &NodeMatch, StringRef ExpectedPrinted,
- PolicyAdjusterType PolicyAdjuster = None) {
-
- PrintMatch Printer(PolicyAdjuster);
- MatchFinder Finder;
- Finder.addMatcher(NodeMatch, &Printer);
- std::unique_ptr<FrontendActionFactory> Factory(
- newFrontendActionFactory(&Finder));
-
- if (!runToolOnCodeWithArgs(Factory->create(), Code, Args))
- return testing::AssertionFailure()
- << "Parsing error in \"" << Code.str() << "\"";
-
- if (Printer.getNumFoundStmts() == 0)
- return testing::AssertionFailure()
- << "Matcher didn't find any statements";
-
- if (Printer.getNumFoundStmts() > 1)
- return testing::AssertionFailure()
- << "Matcher should match only one statement "
- "(found " << Printer.getNumFoundStmts() << ")";
-
- if (Printer.getPrinted() != ExpectedPrinted)
- return ::testing::AssertionFailure()
- << "Expected \"" << ExpectedPrinted.str() << "\", "
- "got \"" << Printer.getPrinted().str() << "\"";
-
- return ::testing::AssertionSuccess();
-}
-
enum class StdVer { CXX98, CXX11, CXX14, CXX17, CXX2a };
DeclarationMatcher FunctionBodyMatcher(StringRef ContainingFunction) {
@@ -232,6 +157,43 @@
// WRONG; Should be: (a & b).operator void *()
}
+TEST(StmtPrinter, TestCXXLamda) {
+ ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
+ "void A() {"
+ " auto l = [] { };"
+ "}",
+ lambdaExpr(anything()).bind("id"),
+ "[] {\n"
+ "}"));
+
+ ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
+ "void A() {"
+ " int a = 0, b = 1;"
+ " auto l = [a,b](int c, float d) { };"
+ "}",
+ lambdaExpr(anything()).bind("id"),
+ "[a, b](int c, float d) {\n"
+ "}"));
+
+ ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX14,
+ "void A() {"
+ " auto l = [](auto a, int b, auto c, int, auto) { };"
+ "}",
+ lambdaExpr(anything()).bind("id"),
+ "[](auto a, int b, auto c, int, auto) {\n"
+ "}"));
+
+ ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX2a,
+ "void A() {"
+ " auto l = []<typename T1, class T2, int I,"
+ " template<class, typename> class T3>"
+ " (int a, auto, int, auto d) { };"
+ "}",
+ lambdaExpr(anything()).bind("id"),
+ "[]<typename T1, class T2, int I, template <class, typename> class T3>(int a, auto, int, auto d) {\n"
+ "}"));
+}
+
TEST(StmtPrinter, TestNoImplicitBases) {
const char *CPPSource = R"(
class A {
@@ -269,3 +231,17 @@
ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"),
"return self->ivar;\n"));
}
+
+TEST(StmtPrinter, TerseOutputWithLambdas) {
+ const char *CPPSource = "auto lamb = []{ return 0; };";
+
+ // body is printed when TerseOutput is off(default).
+ ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11, CPPSource,
+ lambdaExpr(anything()).bind("id"),
+ "[] {\n return 0;\n}"));
+
+ // body not printed when TerseOutput is on.
+ ASSERT_TRUE(PrintedStmtCXXMatches(
+ StdVer::CXX11, CPPSource, lambdaExpr(anything()).bind("id"), "[] {}",
+ PolicyAdjusterType([](PrintingPolicy &PP) { PP.TerseOutput = true; })));
+}
diff --git a/src/llvm-project/clang/unittests/AST/StructuralEquivalenceTest.cpp b/src/llvm-project/clang/unittests/AST/StructuralEquivalenceTest.cpp
index cd1f01d..cdb55d9 100644
--- a/src/llvm-project/clang/unittests/AST/StructuralEquivalenceTest.cpp
+++ b/src/llvm-project/clang/unittests/AST/StructuralEquivalenceTest.cpp
@@ -230,6 +230,33 @@
EXPECT_FALSE(testStructuralMatch(t));
}
+TEST_F(StructuralEquivalenceFunctionTest, DifferentOperators) {
+ auto t = makeDecls<FunctionDecl>(
+ "struct X{}; bool operator<(X, X);",
+ "struct X{}; bool operator==(X, X);", Lang_CXX,
+ functionDecl(hasOverloadedOperatorName("<")),
+ functionDecl(hasOverloadedOperatorName("==")));
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, SameOperators) {
+ auto t = makeDecls<FunctionDecl>(
+ "struct X{}; bool operator<(X, X);",
+ "struct X{}; bool operator<(X, X);", Lang_CXX,
+ functionDecl(hasOverloadedOperatorName("<")),
+ functionDecl(hasOverloadedOperatorName("<")));
+ EXPECT_TRUE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, CtorVsDtor) {
+ auto t = makeDecls<FunctionDecl>(
+ "struct X{ X(); };",
+ "struct X{ ~X(); };", Lang_CXX,
+ cxxConstructorDecl(),
+ cxxDestructorDecl());
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) {
auto t = makeNamedDecls("void foo(int&);",
"void foo(const int&);", Lang_CXX);
@@ -273,8 +300,7 @@
EXPECT_FALSE(testStructuralMatch(t));
}
-TEST_F(StructuralEquivalenceFunctionTest, DISABLED_NoexceptNonMatch) {
- // The expression is not checked yet.
+TEST_F(StructuralEquivalenceFunctionTest, NoexceptNonMatch) {
auto t = makeNamedDecls("void foo() noexcept(false);",
"void foo() noexcept(true);", Lang_CXX11);
EXPECT_FALSE(testStructuralMatch(t));
@@ -370,6 +396,38 @@
EXPECT_FALSE(testStructuralMatch(t));
}
+TEST_F(StructuralEquivalenceFunctionTest, FunctionsWithDifferentNoreturnAttr) {
+ auto t = makeNamedDecls(
+ "__attribute__((noreturn)) void foo();",
+ " void foo();",
+ Lang_C);
+ EXPECT_TRUE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest,
+ FunctionsWithDifferentCallingConventions) {
+ // These attributes may not be available on certain platforms.
+ if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getArch() !=
+ llvm::Triple::x86_64)
+ return;
+ auto t = makeNamedDecls(
+ "__attribute__((preserve_all)) void foo();",
+ "__attribute__((ms_abi)) void foo();",
+ Lang_C);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceFunctionTest, FunctionsWithDifferentSavedRegsAttr) {
+ if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getArch() !=
+ llvm::Triple::x86_64)
+ return;
+ auto t = makeNamedDecls(
+ "__attribute__((no_caller_saved_registers)) void foo();",
+ " void foo();",
+ Lang_C);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
struct StructuralEquivalenceCXXMethodTest : StructuralEquivalenceTest {
};
@@ -739,6 +797,58 @@
EXPECT_FALSE(testStructuralMatch(t));
}
+struct StructuralEquivalenceLambdaTest : StructuralEquivalenceTest {};
+
+TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithDifferentMethods) {
+ // Get the LambdaExprs, unfortunately we can't match directly the underlying
+ // implicit CXXRecordDecl of the Lambda classes.
+ auto t = makeDecls<LambdaExpr>(
+ "void f() { auto L0 = [](int){}; }",
+ "void f() { auto L1 = [](){}; }",
+ Lang_CXX11,
+ lambdaExpr(),
+ lambdaExpr());
+ CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
+ CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
+ EXPECT_FALSE(testStructuralMatch(L0, L1));
+}
+
+TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithEqMethods) {
+ auto t = makeDecls<LambdaExpr>(
+ "void f() { auto L0 = [](int){}; }",
+ "void f() { auto L1 = [](int){}; }",
+ Lang_CXX11,
+ lambdaExpr(),
+ lambdaExpr());
+ CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
+ CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
+ EXPECT_TRUE(testStructuralMatch(L0, L1));
+}
+
+TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithDifferentFields) {
+ auto t = makeDecls<LambdaExpr>(
+ "void f() { char* X; auto L0 = [X](){}; }",
+ "void f() { float X; auto L1 = [X](){}; }",
+ Lang_CXX11,
+ lambdaExpr(),
+ lambdaExpr());
+ CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
+ CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
+ EXPECT_FALSE(testStructuralMatch(L0, L1));
+}
+
+TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithEqFields) {
+ auto t = makeDecls<LambdaExpr>(
+ "void f() { float X; auto L0 = [X](){}; }",
+ "void f() { float X; auto L1 = [X](){}; }",
+ Lang_CXX11,
+ lambdaExpr(),
+ lambdaExpr());
+ CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
+ CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
+ EXPECT_TRUE(testStructuralMatch(L0, L1));
+}
+
TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
auto t = makeNamedDecls(
"struct A{ }; struct B{ }; void foo(A a, A b);",
@@ -747,6 +857,26 @@
EXPECT_FALSE(testStructuralMatch(t));
}
+TEST_F(StructuralEquivalenceTest, ExplicitBoolDifferent) {
+ auto Decls = makeNamedDecls("struct foo {explicit(false) foo(int);};",
+ "struct foo {explicit(true) foo(int);};", Lang_CXX2a);
+ CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
+ get<0>(Decls), cxxConstructorDecl(hasName("foo")));
+ CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
+ get<1>(Decls), cxxConstructorDecl(hasName("foo")));
+ EXPECT_FALSE(testStructuralMatch(First, Second));
+}
+
+TEST_F(StructuralEquivalenceTest, ExplicitBoolSame) {
+ auto Decls = makeNamedDecls("struct foo {explicit(true) foo(int);};",
+ "struct foo {explicit(true) foo(int);};", Lang_CXX2a);
+ CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
+ get<0>(Decls), cxxConstructorDecl(hasName("foo")));
+ CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
+ get<1>(Decls), cxxConstructorDecl(hasName("foo")));
+ EXPECT_TRUE(testStructuralMatch(First, Second));
+}
+
struct StructuralEquivalenceEnumTest : StructuralEquivalenceTest {};
TEST_F(StructuralEquivalenceEnumTest, FwdDeclEnumShouldBeEqualWithFwdDeclEnum) {
@@ -774,6 +904,183 @@
EXPECT_FALSE(testStructuralMatch(t));
}
+struct StructuralEquivalenceTemplateTest : StructuralEquivalenceTest {};
+
+TEST_F(StructuralEquivalenceTemplateTest, ExactlySameTemplates) {
+ auto t = makeNamedDecls("template <class T> struct foo;",
+ "template <class T> struct foo;", Lang_CXX);
+ EXPECT_TRUE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgName) {
+ auto t = makeNamedDecls("template <class T> struct foo;",
+ "template <class U> struct foo;", Lang_CXX);
+ EXPECT_TRUE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgKind) {
+ auto t = makeNamedDecls("template <class T> struct foo;",
+ "template <int T> struct foo;", Lang_CXX);
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolSame) {
+ auto Decls = makeNamedDecls("template <bool b> struct foo {explicit(b) foo(int);};",
+ "template <bool b> struct foo {explicit(b) foo(int);};", Lang_CXX2a);
+ CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
+ get<0>(Decls), cxxConstructorDecl(hasName("foo<b>")));
+ CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
+ get<1>(Decls), cxxConstructorDecl(hasName("foo<b>")));
+ EXPECT_TRUE(testStructuralMatch(First, Second));
+}
+
+TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolDifference) {
+ auto Decls = makeNamedDecls("template <bool b> struct foo {explicit(b) foo(int);};",
+ "template <bool b> struct foo {explicit(!b) foo(int);};", Lang_CXX2a);
+ CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
+ get<0>(Decls), cxxConstructorDecl(hasName("foo<b>")));
+ CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
+ get<1>(Decls), cxxConstructorDecl(hasName("foo<b>")));
+ EXPECT_FALSE(testStructuralMatch(First, Second));
+}
+
+struct StructuralEquivalenceDependentTemplateArgsTest
+ : StructuralEquivalenceTemplateTest {};
+
+TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
+ SameStructsInDependentArgs) {
+ std::string Code =
+ R"(
+ template <typename>
+ struct S1;
+
+ template <typename>
+ struct enable_if;
+
+ struct S
+ {
+ template <typename T, typename enable_if<S1<T>>::type>
+ void f();
+ };
+ )";
+ auto t = makeDecls<FunctionTemplateDecl>(Code, Code, Lang_CXX11,
+ functionTemplateDecl(hasName("f")));
+ EXPECT_TRUE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
+ DifferentStructsInDependentArgs) {
+ std::string Code =
+ R"(
+ template <typename>
+ struct S1;
+
+ template <typename>
+ struct S2;
+
+ template <typename>
+ struct enable_if;
+ )";
+ auto t = makeDecls<FunctionTemplateDecl>(Code + R"(
+ struct S
+ {
+ template <typename T, typename enable_if<S1<T>>::type>
+ void f();
+ };
+ )",
+ Code + R"(
+ struct S
+ {
+ template <typename T, typename enable_if<S2<T>>::type>
+ void f();
+ };
+ )",
+ Lang_CXX11,
+ functionTemplateDecl(hasName("f")));
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
+ SameStructsInDependentScopeDeclRefExpr) {
+ std::string Code =
+ R"(
+ template <typename>
+ struct S1;
+
+ template <bool>
+ struct enable_if;
+
+ struct S
+ {
+ template <typename T, typename enable_if<S1<T>::value>::type>
+ void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^
+ };
+ )";
+ auto t = makeDecls<FunctionTemplateDecl>(Code, Code, Lang_CXX11,
+ functionTemplateDecl(hasName("f")));
+ EXPECT_TRUE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
+ DifferentStructsInDependentScopeDeclRefExpr) {
+ std::string Code =
+ R"(
+ template <typename>
+ struct S1;
+
+ template <typename>
+ struct S2;
+
+ template <bool>
+ struct enable_if;
+ )";
+ auto t = makeDecls<FunctionTemplateDecl>(Code + R"(
+ struct S
+ {
+ template <typename T, typename enable_if<S1<T>::value>::type>
+ void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^
+ };
+ )",
+ Code + R"(
+ struct S
+ {
+ template <typename T, typename enable_if<S2<T>::value>::type>
+ void f();
+ };
+ )",
+ Lang_CXX,
+ functionTemplateDecl(hasName("f")));
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
+ DifferentValueInDependentScopeDeclRefExpr) {
+ std::string Code =
+ R"(
+ template <typename>
+ struct S1;
+
+ template <bool>
+ struct enable_if;
+ )";
+ auto t = makeDecls<FunctionTemplateDecl>(Code + R"(
+ struct S
+ {
+ template <typename T, typename enable_if<S1<T>::value1>::type>
+ void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^
+ };
+ )",
+ Code + R"(
+ struct S
+ {
+ template <typename T, typename enable_if<S1<T>::value2>::type>
+ void f();
+ };
+ )",
+ Lang_CXX,
+ functionTemplateDecl(hasName("f")));
+ EXPECT_FALSE(testStructuralMatch(t));
+}
} // end namespace ast_matchers
} // end namespace clang
diff --git a/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp b/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp
index 288fce0..6015825 100644
--- a/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp
+++ b/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp
@@ -1,9 +1,8 @@
// unittests/ASTMatchers/ASTMatchersInternalTest.cpp - AST matcher unit tests //
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -77,7 +76,7 @@
internal::Matcher<Decl>, AMatcher) {
return Finder->matchesChildOf(
Node, AMatcher, Builder,
- ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
+ ast_type_traits::TraversalKind::TK_IgnoreImplicitCastsAndParentheses,
ASTMatchFinder::BK_First);
}
diff --git a/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index fb17d10..8ab472e9 100644
--- a/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1,9 +1,8 @@
// unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp - AST matcher unit tests//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -567,6 +566,74 @@
llvm::make_unique<VerifyIdIsBoundTo<CXXMemberCallExpr>>("x")));
}
+TEST(Matcher, IgnoresElidableConstructors) {
+ EXPECT_TRUE(
+ matches("struct H {};"
+ "template<typename T> H B(T A);"
+ "void f() {"
+ " H D1;"
+ " D1 = B(B(1));"
+ "}",
+ cxxOperatorCallExpr(hasArgument(
+ 1, callExpr(hasArgument(
+ 0, ignoringElidableConstructorCall(callExpr()))))),
+ LanguageMode::Cxx11OrLater));
+ EXPECT_TRUE(
+ matches("struct H {};"
+ "template<typename T> H B(T A);"
+ "void f() {"
+ " H D1;"
+ " D1 = B(1);"
+ "}",
+ cxxOperatorCallExpr(hasArgument(
+ 1, callExpr(hasArgument(0, ignoringElidableConstructorCall(
+ integerLiteral()))))),
+ LanguageMode::Cxx11OrLater));
+ EXPECT_TRUE(matches(
+ "struct H {};"
+ "H G();"
+ "void f() {"
+ " H D = G();"
+ "}",
+ varDecl(hasInitializer(anyOf(
+ ignoringElidableConstructorCall(callExpr()),
+ exprWithCleanups(has(ignoringElidableConstructorCall(callExpr())))))),
+ LanguageMode::Cxx11OrLater));
+}
+
+TEST(Matcher, IgnoresElidableInReturn) {
+ auto matcher = expr(ignoringElidableConstructorCall(declRefExpr()));
+ EXPECT_TRUE(matches("struct H {};"
+ "H f() {"
+ " H g;"
+ " return g;"
+ "}",
+ matcher, LanguageMode::Cxx11OrLater));
+ EXPECT_TRUE(notMatches("struct H {};"
+ "H f() {"
+ " return H();"
+ "}",
+ matcher, LanguageMode::Cxx11OrLater));
+}
+
+TEST(Matcher, IgnoreElidableConstructorDoesNotMatchConstructors) {
+ EXPECT_TRUE(matches("struct H {};"
+ "void f() {"
+ " H D;"
+ "}",
+ varDecl(hasInitializer(
+ ignoringElidableConstructorCall(cxxConstructExpr()))),
+ LanguageMode::Cxx11OrLater));
+}
+
+TEST(Matcher, IgnoresElidableDoesNotPreventMatches) {
+ EXPECT_TRUE(matches("void f() {"
+ " int D = 10;"
+ "}",
+ expr(ignoringElidableConstructorCall(integerLiteral())),
+ LanguageMode::Cxx11OrLater));
+}
+
TEST(Matcher, BindTheSameNameInAlternatives) {
StatementMatcher matcher = anyOf(
binaryOperator(hasOperatorName("+"),
@@ -811,6 +878,15 @@
cxxConversionDecl(isExplicit())));
EXPECT_TRUE(notMatches("struct S { operator int(); };",
cxxConversionDecl(isExplicit())));
+ EXPECT_TRUE(matchesConditionally(
+ "template<bool b> struct S { explicit(b) operator int(); };",
+ cxxConversionDecl(isExplicit()), false, "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally(
+ "struct S { explicit(true) operator int(); };",
+ cxxConversionDecl(isExplicit()), true, "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally(
+ "struct S { explicit(false) operator int(); };",
+ cxxConversionDecl(isExplicit()), false, "-std=c++2a"));
}
TEST(Matcher, ArgumentCount) {
@@ -915,10 +991,10 @@
varDecl(hasName("foo"), isConstexpr())));
EXPECT_TRUE(matches("constexpr int bar();",
functionDecl(hasName("bar"), isConstexpr())));
- EXPECT_TRUE(matchesConditionally("void baz() { if constexpr(1 > 0) {} }",
- ifStmt(isConstexpr()), true, "-std=c++17"));
- EXPECT_TRUE(matchesConditionally("void baz() { if (1 > 0) {} }",
- ifStmt(isConstexpr()), false, "-std=c++17"));
+ EXPECT_TRUE(matches("void baz() { if constexpr(1 > 0) {} }",
+ ifStmt(isConstexpr()), LanguageMode::Cxx17OrLater));
+ EXPECT_TRUE(notMatches("void baz() { if (1 > 0) {} }", ifStmt(isConstexpr()),
+ LanguageMode::Cxx17OrLater));
}
TEST(TemplateArgumentCountIs, Matches) {
@@ -1130,6 +1206,38 @@
cxxConstructorDecl(isExplicit())));
EXPECT_TRUE(notMatches("struct S { S(int); };",
cxxConstructorDecl(isExplicit())));
+ EXPECT_TRUE(matchesConditionally(
+ "template<bool b> struct S { explicit(b) S(int);};",
+ cxxConstructorDecl(isExplicit()), false, "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally("struct S { explicit(true) S(int);};",
+ cxxConstructorDecl(isExplicit()), true,
+ "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally("struct S { explicit(false) S(int);};",
+ cxxConstructorDecl(isExplicit()), false,
+ "-std=c++2a"));
+}
+
+TEST(DeductionGuideDeclaration, IsExplicit) {
+ EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int);};"
+ "S(int) -> S<int>;",
+ cxxDeductionGuideDecl(isExplicit()), false,
+ "-std=c++17"));
+ EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int);};"
+ "explicit S(int) -> S<int>;",
+ cxxDeductionGuideDecl(isExplicit()), true,
+ "-std=c++17"));
+ EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int);};"
+ "explicit(true) S(int) -> S<int>;",
+ cxxDeductionGuideDecl(isExplicit()), true,
+ "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int);};"
+ "explicit(false) S(int) -> S<int>;",
+ cxxDeductionGuideDecl(isExplicit()), false,
+ "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally(
+ "template<typename T> struct S { S(int);};"
+ "template<bool b = true> explicit(b) S(int) -> S<int>;",
+ cxxDeductionGuideDecl(isExplicit()), false, "-std=c++2a"));
}
TEST(ConstructorDeclaration, Kinds) {
@@ -2032,6 +2140,57 @@
EXPECT_TRUE(matches("namespace {}", namespaceDecl(isAnonymous())));
}
+TEST(DeclarationMatcher, InStdNamespace) {
+ EXPECT_TRUE(notMatches("class vector {};"
+ "namespace foo {"
+ " class vector {};"
+ "}"
+ "namespace foo {"
+ " namespace std {"
+ " class vector {};"
+ " }"
+ "}",
+ cxxRecordDecl(hasName("vector"), isInStdNamespace())));
+
+ EXPECT_TRUE(matches("namespace std {"
+ " class vector {};"
+ "}",
+ cxxRecordDecl(hasName("vector"), isInStdNamespace())));
+ EXPECT_TRUE(matches("namespace std {"
+ " inline namespace __1 {"
+ " class vector {};"
+ " }"
+ "}",
+ cxxRecordDecl(hasName("vector"), isInStdNamespace())));
+ EXPECT_TRUE(notMatches("namespace std {"
+ " inline namespace __1 {"
+ " inline namespace __fs {"
+ " namespace filesystem {"
+ " inline namespace v1 {"
+ " class path {};"
+ " }"
+ " }"
+ " }"
+ " }"
+ "}",
+ cxxRecordDecl(hasName("path"), isInStdNamespace())));
+ EXPECT_TRUE(
+ matches("namespace std {"
+ " inline namespace __1 {"
+ " inline namespace __fs {"
+ " namespace filesystem {"
+ " inline namespace v1 {"
+ " class path {};"
+ " }"
+ " }"
+ " }"
+ " }"
+ "}",
+ cxxRecordDecl(hasName("path"),
+ hasAncestor(namespaceDecl(hasName("filesystem"),
+ isInStdNamespace())))));
+}
+
TEST(EqualsBoundNodeMatcher, QualType) {
EXPECT_TRUE(matches(
"int i = 1;", varDecl(hasType(qualType().bind("type")),
@@ -2275,5 +2434,238 @@
notMatches("int main2() {}", functionDecl(isMain())));
}
+TEST(OMPExecutableDirective, isStandaloneDirective) {
+ auto Matcher = ompExecutableDirective(isStandaloneDirective());
+
+ const std::string Source0 = R"(
+void x() {
+#pragma omp parallel
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+
+ const std::string Source1 = R"(
+void x() {
+#pragma omp taskyield
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source1, Matcher));
+}
+
+TEST(Stmt, isOMPStructuredBlock) {
+ const std::string Source0 = R"(
+void x() {
+#pragma omp parallel
+;
+})";
+ EXPECT_TRUE(
+ matchesWithOpenMP(Source0, stmt(nullStmt(), isOMPStructuredBlock())));
+
+ const std::string Source1 = R"(
+void x() {
+#pragma omp parallel
+{;}
+})";
+ EXPECT_TRUE(
+ notMatchesWithOpenMP(Source1, stmt(nullStmt(), isOMPStructuredBlock())));
+ EXPECT_TRUE(
+ matchesWithOpenMP(Source1, stmt(compoundStmt(), isOMPStructuredBlock())));
+}
+
+TEST(OMPExecutableDirective, hasStructuredBlock) {
+ const std::string Source0 = R"(
+void x() {
+#pragma omp parallel
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(
+ Source0, ompExecutableDirective(hasStructuredBlock(nullStmt()))));
+
+ const std::string Source1 = R"(
+void x() {
+#pragma omp parallel
+{;}
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(
+ Source1, ompExecutableDirective(hasStructuredBlock(nullStmt()))));
+ EXPECT_TRUE(matchesWithOpenMP(
+ Source1, ompExecutableDirective(hasStructuredBlock(compoundStmt()))));
+
+ const std::string Source2 = R"(
+void x() {
+#pragma omp taskyield
+{;}
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(
+ Source2, ompExecutableDirective(hasStructuredBlock(anything()))));
+}
+
+TEST(OMPExecutableDirective, hasClause) {
+ auto Matcher = ompExecutableDirective(hasAnyClause(anything()));
+
+ const std::string Source0 = R"(
+void x() {
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+
+ const std::string Source1 = R"(
+void x() {
+#pragma omp parallel
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source1, Matcher));
+
+ const std::string Source2 = R"(
+void x() {
+#pragma omp parallel default(none)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source2, Matcher));
+
+ const std::string Source3 = R"(
+void x() {
+#pragma omp parallel default(shared)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source3, Matcher));
+
+ const std::string Source4 = R"(
+void x(int x) {
+#pragma omp parallel num_threads(x)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source4, Matcher));
+}
+
+TEST(OMPDefaultClause, isNoneKind) {
+ auto Matcher =
+ ompExecutableDirective(hasAnyClause(ompDefaultClause(isNoneKind())));
+
+ const std::string Source0 = R"(
+void x() {
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+
+ const std::string Source1 = R"(
+void x() {
+#pragma omp parallel
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source1, Matcher));
+
+ const std::string Source2 = R"(
+void x() {
+#pragma omp parallel default(none)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source2, Matcher));
+
+ const std::string Source3 = R"(
+void x() {
+#pragma omp parallel default(shared)
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source3, Matcher));
+
+ const std::string Source4 = R"(
+void x(int x) {
+#pragma omp parallel num_threads(x)
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source4, Matcher));
+}
+
+TEST(OMPDefaultClause, isSharedKind) {
+ auto Matcher =
+ ompExecutableDirective(hasAnyClause(ompDefaultClause(isSharedKind())));
+
+ const std::string Source0 = R"(
+void x() {
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+
+ const std::string Source1 = R"(
+void x() {
+#pragma omp parallel
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source1, Matcher));
+
+ const std::string Source2 = R"(
+void x() {
+#pragma omp parallel default(shared)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source2, Matcher));
+
+ const std::string Source3 = R"(
+void x() {
+#pragma omp parallel default(none)
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source3, Matcher));
+
+ const std::string Source4 = R"(
+void x(int x) {
+#pragma omp parallel num_threads(x)
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source4, Matcher));
+}
+
+TEST(OMPExecutableDirective, isAllowedToContainClauseKind) {
+ auto Matcher =
+ ompExecutableDirective(isAllowedToContainClauseKind(OMPC_default));
+
+ const std::string Source0 = R"(
+void x() {
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+
+ const std::string Source1 = R"(
+void x() {
+#pragma omp parallel
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source1, Matcher));
+
+ const std::string Source2 = R"(
+void x() {
+#pragma omp parallel default(none)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source2, Matcher));
+
+ const std::string Source3 = R"(
+void x() {
+#pragma omp parallel default(shared)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source3, Matcher));
+
+ const std::string Source4 = R"(
+void x(int x) {
+#pragma omp parallel num_threads(x)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source4, Matcher));
+
+ const std::string Source5 = R"(
+void x() {
+#pragma omp taskyield
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source5, Matcher));
+
+ const std::string Source6 = R"(
+void x() {
+#pragma omp task
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source6, Matcher));
+}
+
} // namespace ast_matchers
} // namespace clang
diff --git a/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index 1bd4e09..16e682a 100644
--- a/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1,9 +1,8 @@
//== unittests/ASTMatchers/ASTMatchersNodeTest.cpp - AST matcher unit tests ==//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -755,6 +754,11 @@
EXPECT_TRUE(matches("int* i = nullptr;", cxxNullPtrLiteralExpr()));
}
+TEST(Matcher, ChooseExpr) {
+ EXPECT_TRUE(matchesC("void f() { (void)__builtin_choose_expr(1, 2, 3); }",
+ chooseExpr()));
+}
+
TEST(Matcher, GNUNullExpr) {
EXPECT_TRUE(matches("int* i = __null;", gnuNullExpr()));
}
@@ -1761,5 +1765,67 @@
EXPECT_FALSE(matchesObjC(ObjCStringNoPool, autoreleasePoolStmt()));
}
+TEST(OMPExecutableDirective, Matches) {
+ auto Matcher = stmt(ompExecutableDirective());
+
+ const std::string Source0 = R"(
+void x() {
+#pragma omp parallel
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source0, Matcher));
+
+ const std::string Source1 = R"(
+void x() {
+#pragma omp taskyield
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source1, Matcher));
+
+ const std::string Source2 = R"(
+void x() {
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source2, Matcher));
+}
+
+TEST(OMPDefaultClause, Matches) {
+ auto Matcher = ompExecutableDirective(hasAnyClause(ompDefaultClause()));
+
+ const std::string Source0 = R"(
+void x() {
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+
+ const std::string Source1 = R"(
+void x() {
+#pragma omp parallel
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source1, Matcher));
+
+ const std::string Source2 = R"(
+void x() {
+#pragma omp parallel default(none)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source2, Matcher));
+
+ const std::string Source3 = R"(
+void x() {
+#pragma omp parallel default(shared)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source3, Matcher));
+
+ const std::string Source4 = R"(
+void x(int x) {
+#pragma omp parallel num_threads(x)
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source4, Matcher));
+}
+
} // namespace ast_matchers
} // namespace clang
diff --git a/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersTest.h b/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersTest.h
index 5046688..745122a 100644
--- a/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersTest.h
@@ -1,9 +1,8 @@
//===- unittest/Tooling/ASTMatchersTest.h - Matcher tests helpers ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -58,6 +57,17 @@
const std::unique_ptr<BoundNodesCallback> FindResultReviewer;
};
+enum class LanguageMode {
+ Cxx11,
+ Cxx14,
+ Cxx17,
+ Cxx2a,
+ Cxx11OrLater,
+ Cxx14OrLater,
+ Cxx17OrLater,
+ Cxx2aOrLater
+};
+
template <typename T>
testing::AssertionResult matchesConditionally(
const std::string &Code, const T &AMatcher, bool ExpectMatch,
@@ -117,14 +127,71 @@
}
template <typename T>
-testing::AssertionResult matches(const std::string &Code, const T &AMatcher) {
- return matchesConditionally(Code, AMatcher, true, "-std=c++11");
+testing::AssertionResult
+matchesConditionally(const std::string &Code, const T &AMatcher,
+ bool ExpectMatch, const LanguageMode &Mode) {
+ std::vector<LanguageMode> LangModes;
+ switch (Mode) {
+ case LanguageMode::Cxx11:
+ case LanguageMode::Cxx14:
+ case LanguageMode::Cxx17:
+ case LanguageMode::Cxx2a:
+ LangModes = {Mode};
+ break;
+ case LanguageMode::Cxx11OrLater:
+ LangModes = {LanguageMode::Cxx11, LanguageMode::Cxx14, LanguageMode::Cxx17,
+ LanguageMode::Cxx2a};
+ break;
+ case LanguageMode::Cxx14OrLater:
+ LangModes = {LanguageMode::Cxx14, LanguageMode::Cxx17, LanguageMode::Cxx2a};
+ break;
+ case LanguageMode::Cxx17OrLater:
+ LangModes = {LanguageMode::Cxx17, LanguageMode::Cxx2a};
+ break;
+ case LanguageMode::Cxx2aOrLater:
+ LangModes = {LanguageMode::Cxx2a};
+ }
+
+ for (auto Mode : LangModes) {
+ std::string LangModeArg;
+ switch (Mode) {
+ case LanguageMode::Cxx11:
+ LangModeArg = "-std=c++11";
+ break;
+ case LanguageMode::Cxx14:
+ LangModeArg = "-std=c++14";
+ break;
+ case LanguageMode::Cxx17:
+ LangModeArg = "-std=c++17";
+ break;
+ case LanguageMode::Cxx2a:
+ LangModeArg = "-std=c++2a";
+ break;
+ default:
+ llvm_unreachable("Invalid language mode");
+ }
+
+ auto Result =
+ matchesConditionally(Code, AMatcher, ExpectMatch, LangModeArg);
+ if (!Result)
+ return Result;
+ }
+
+ return testing::AssertionSuccess();
}
template <typename T>
-testing::AssertionResult notMatches(const std::string &Code,
- const T &AMatcher) {
- return matchesConditionally(Code, AMatcher, false, "-std=c++11");
+testing::AssertionResult
+matches(const std::string &Code, const T &AMatcher,
+ const LanguageMode &Mode = LanguageMode::Cxx11) {
+ return matchesConditionally(Code, AMatcher, true, Mode);
+}
+
+template <typename T>
+testing::AssertionResult
+notMatches(const std::string &Code, const T &AMatcher,
+ const LanguageMode &Mode = LanguageMode::Cxx11) {
+ return matchesConditionally(Code, AMatcher, false, Mode);
}
template <typename T>
@@ -184,7 +251,9 @@
"typedef struct cudaStream *cudaStream_t;"
"int cudaConfigureCall(dim3 gridSize, dim3 blockSize,"
" size_t sharedSize = 0,"
- " cudaStream_t stream = 0);";
+ " cudaStream_t stream = 0);"
+ "extern \"C\" unsigned __cudaPushCallConfiguration("
+ " dim3 gridDim, dim3 blockDim, size_t sharedMem = 0, void *stream = 0);";
bool Found = false, DynamicFound = false;
MatchFinder Finder;
@@ -234,6 +303,18 @@
}
template <typename T>
+testing::AssertionResult matchesWithOpenMP(const std::string &Code,
+ const T &AMatcher) {
+ return matchesConditionally(Code, AMatcher, true, "-fopenmp=libomp");
+}
+
+template <typename T>
+testing::AssertionResult notMatchesWithOpenMP(const std::string &Code,
+ const T &AMatcher) {
+ return matchesConditionally(Code, AMatcher, false, "-fopenmp=libomp");
+}
+
+template <typename T>
testing::AssertionResult
matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
std::unique_ptr<BoundNodesCallback> FindResultVerifier,
diff --git a/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index 5f6ecc0..7c17a9b 100644
--- a/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/src/llvm-project/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1,9 +1,8 @@
//= unittests/ASTMatchers/ASTMatchersTraversalTest.cpp - matchers unit tests =//
//
-// The LLVM Compiler Infrastructure
-//`
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -455,6 +454,20 @@
objcMessageExpr(hasReceiver(declRefExpr(to(varDecl(hasName("x"))))))));
}
+TEST(Matcher, isClassMessage) {
+ EXPECT_TRUE(matchesObjC(
+ "@interface NSString +(NSString *) stringWithFormat; @end "
+ "void f() { [NSString stringWithFormat]; }",
+ objcMessageExpr(isClassMessage())));
+
+ EXPECT_FALSE(matchesObjC(
+ "@interface NSString @end "
+ "void f(NSString *x) {"
+ "[x containsString];"
+ "}",
+ objcMessageExpr(isClassMessage())));
+}
+
TEST(Matcher, isInstanceMessage) {
EXPECT_TRUE(matchesObjC(
"@interface NSString @end "
@@ -470,6 +483,138 @@
}
+TEST(Matcher, isClassMethod) {
+ EXPECT_TRUE(matchesObjC(
+ "@interface Bar + (void)bar; @end",
+ objcMethodDecl(isClassMethod())));
+
+ EXPECT_TRUE(matchesObjC(
+ "@interface Bar @end"
+ "@implementation Bar + (void)bar {} @end",
+ objcMethodDecl(isClassMethod())));
+
+ EXPECT_FALSE(matchesObjC(
+ "@interface Foo - (void)foo; @end",
+ objcMethodDecl(isClassMethod())));
+
+ EXPECT_FALSE(matchesObjC(
+ "@interface Foo @end "
+ "@implementation Foo - (void)foo {} @end",
+ objcMethodDecl(isClassMethod())));
+}
+
+TEST(Matcher, isInstanceMethod) {
+ EXPECT_TRUE(matchesObjC(
+ "@interface Foo - (void)foo; @end",
+ objcMethodDecl(isInstanceMethod())));
+
+ EXPECT_TRUE(matchesObjC(
+ "@interface Foo @end "
+ "@implementation Foo - (void)foo {} @end",
+ objcMethodDecl(isInstanceMethod())));
+
+ EXPECT_FALSE(matchesObjC(
+ "@interface Bar + (void)bar; @end",
+ objcMethodDecl(isInstanceMethod())));
+
+ EXPECT_FALSE(matchesObjC(
+ "@interface Bar @end"
+ "@implementation Bar + (void)bar {} @end",
+ objcMethodDecl(isInstanceMethod())));
+}
+
+TEST(MatcherCXXMemberCallExpr, On) {
+ auto Snippet1 = R"cc(
+ struct Y {
+ void m();
+ };
+ void z(Y y) { y.m(); }
+ )cc";
+ auto Snippet2 = R"cc(
+ struct Y {
+ void m();
+ };
+ struct X : public Y {};
+ void z(X x) { x.m(); }
+ )cc";
+ auto MatchesY = cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y")))));
+ EXPECT_TRUE(matches(Snippet1, MatchesY));
+ EXPECT_TRUE(notMatches(Snippet2, MatchesY));
+
+ auto MatchesX = cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("X")))));
+ EXPECT_TRUE(matches(Snippet2, MatchesX));
+
+ // Parens are ignored.
+ auto Snippet3 = R"cc(
+ struct Y {
+ void m();
+ };
+ Y g();
+ void z(Y y) { (g()).m(); }
+ )cc";
+ auto MatchesCall = cxxMemberCallExpr(on(callExpr()));
+ EXPECT_TRUE(matches(Snippet3, MatchesCall));
+}
+
+TEST(MatcherCXXMemberCallExpr, OnImplicitObjectArgument) {
+ auto Snippet1 = R"cc(
+ struct Y {
+ void m();
+ };
+ void z(Y y) { y.m(); }
+ )cc";
+ auto Snippet2 = R"cc(
+ struct Y {
+ void m();
+ };
+ struct X : public Y {};
+ void z(X x) { x.m(); }
+ )cc";
+ auto MatchesY = cxxMemberCallExpr(
+ onImplicitObjectArgument(hasType(cxxRecordDecl(hasName("Y")))));
+ EXPECT_TRUE(matches(Snippet1, MatchesY));
+ EXPECT_TRUE(matches(Snippet2, MatchesY));
+
+ auto MatchesX = cxxMemberCallExpr(
+ onImplicitObjectArgument(hasType(cxxRecordDecl(hasName("X")))));
+ EXPECT_TRUE(notMatches(Snippet2, MatchesX));
+
+ // Parens are not ignored.
+ auto Snippet3 = R"cc(
+ struct Y {
+ void m();
+ };
+ Y g();
+ void z(Y y) { (g()).m(); }
+ )cc";
+ auto MatchesCall = cxxMemberCallExpr(onImplicitObjectArgument(callExpr()));
+ EXPECT_TRUE(notMatches(Snippet3, MatchesCall));
+}
+
+TEST(Matcher, HasObjectExpr) {
+ auto Snippet1 = R"cc(
+ struct X {
+ int m;
+ int f(X x) { return x.m; }
+ };
+ )cc";
+ auto Snippet2 = R"cc(
+ struct X {
+ int m;
+ int f(X x) { return m; }
+ };
+ )cc";
+ auto MatchesX =
+ memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X")))));
+ EXPECT_TRUE(matches(Snippet1, MatchesX));
+ EXPECT_TRUE(notMatches(Snippet2, MatchesX));
+
+ auto MatchesXPointer = memberExpr(
+ hasObjectExpression(hasType(pointsTo(cxxRecordDecl(hasName("X"))))));
+ EXPECT_TRUE(notMatches(Snippet1, MatchesXPointer));
+ EXPECT_TRUE(matches(Snippet2, MatchesXPointer));
+}
+
TEST(ForEachArgumentWithParam, ReportsNoFalsePositives) {
StatementMatcher ArgumentY =
declRefExpr(to(varDecl(hasName("y")))).bind("arg");
@@ -1590,6 +1735,56 @@
llvm::make_unique<VerifyIdIsBoundTo<CaseStmt>>("x", 3)));
}
+TEST(Declaration, HasExplicitSpecifier) {
+ EXPECT_TRUE(matchesConditionally(
+ "void f();", functionDecl(hasExplicitSpecifier(constantExpr())), false,
+ "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally(
+ "template<bool b> struct S { explicit operator int(); };",
+ cxxConversionDecl(hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))),
+ false, "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally(
+ "template<bool b> struct S { explicit(b) operator int(); };",
+ cxxConversionDecl(hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))),
+ false, "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally(
+ "struct S { explicit(true) operator int(); };",
+ cxxConversionDecl(hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))),
+ true, "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally(
+ "struct S { explicit(false) operator int(); };",
+ cxxConversionDecl(hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))),
+ true, "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally(
+ "template<bool b> struct S { explicit(b) S(int); };",
+ cxxConstructorDecl(hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))),
+ false, "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally(
+ "struct S { explicit(true) S(int); };",
+ cxxConstructorDecl(hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))),
+ true, "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally(
+ "struct S { explicit(false) S(int); };",
+ cxxConstructorDecl(hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))),
+ true, "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally(
+ "template<typename T> struct S { S(int); };"
+ "template<bool b = true> explicit(b) S(int) -> S<int>;",
+ cxxDeductionGuideDecl(
+ hasExplicitSpecifier(constantExpr(has(cxxBoolLiteral())))),
+ false, "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int); };"
+ "explicit(true) S(int) -> S<int>;",
+ cxxDeductionGuideDecl(hasExplicitSpecifier(
+ constantExpr(has(cxxBoolLiteral())))),
+ true, "-std=c++2a"));
+ EXPECT_TRUE(matchesConditionally("template<typename T> struct S { S(int); };"
+ "explicit(false) S(int) -> S<int>;",
+ cxxDeductionGuideDecl(hasExplicitSpecifier(
+ constantExpr(has(cxxBoolLiteral())))),
+ true, "-std=c++2a"));
+}
+
TEST(ForEachConstructorInitializer, MatchesInitializers) {
EXPECT_TRUE(matches(
"struct X { X() : i(42), j(42) {} int i, j; };",
diff --git a/src/llvm-project/clang/unittests/ASTMatchers/CMakeLists.txt b/src/llvm-project/clang/unittests/ASTMatchers/CMakeLists.txt
index 4e44c79..09c4290 100644
--- a/src/llvm-project/clang/unittests/ASTMatchers/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/ASTMatchers/CMakeLists.txt
@@ -18,7 +18,7 @@
ASTMatchersTraversalTest.cpp
)
-target_link_libraries(ASTMatchersTests
+clang_target_link_libraries(ASTMatchersTests
PRIVATE
clangAST
clangASTMatchers
diff --git a/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/CMakeLists.txt b/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/CMakeLists.txt
index 07742ca..c40964d 100644
--- a/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/CMakeLists.txt
@@ -8,7 +8,7 @@
RegistryTest.cpp
)
-target_link_libraries(DynamicASTMatchersTests
+clang_target_link_libraries(DynamicASTMatchersTests
PRIVATE
clangAST
clangASTMatchers
diff --git a/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index 9e891069..aba094c 100644
--- a/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/ASTMatchers/Dynamic/ParserTest.cpp - Parser unit tests -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===-------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index 1ca394d..cf016a1 100644
--- a/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/ASTMatchers/Dynamic/RegistryTest.cpp - Registry unit tests -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===-----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp b/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
index 7d3a070..c08d7fc 100644
--- a/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
+++ b/src/llvm-project/clang/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/ASTMatchers/Dynamic/VariantValueTest.cpp - VariantValue unit tests -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===-----------------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Analysis/CFGBuildResult.h b/src/llvm-project/clang/unittests/Analysis/CFGBuildResult.h
new file mode 100644
index 0000000..17511dc
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Analysis/CFGBuildResult.h
@@ -0,0 +1,69 @@
+//===- unittests/Analysis/CFGBuildResult.h - CFG tests --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/CFG.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+
+namespace clang {
+namespace analysis {
+
+class BuildResult {
+public:
+ enum Status {
+ ToolFailed,
+ ToolRan,
+ SawFunctionBody,
+ BuiltCFG,
+ };
+
+ BuildResult(Status S, std::unique_ptr<CFG> Cfg = nullptr)
+ : S(S), Cfg(std::move(Cfg)) {}
+
+ Status getStatus() const { return S; }
+ CFG *getCFG() const { return Cfg.get(); }
+
+private:
+ Status S;
+ std::unique_ptr<CFG> Cfg;
+};
+
+class CFGCallback : public ast_matchers::MatchFinder::MatchCallback {
+public:
+ BuildResult TheBuildResult = BuildResult::ToolRan;
+
+ void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
+ const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
+ Stmt *Body = Func->getBody();
+ if (!Body)
+ return;
+ TheBuildResult = BuildResult::SawFunctionBody;
+ CFG::BuildOptions Options;
+ Options.AddImplicitDtors = true;
+ if (std::unique_ptr<CFG> Cfg =
+ CFG::buildCFG(nullptr, Body, Result.Context, Options))
+ TheBuildResult = {BuildResult::BuiltCFG, std::move(Cfg)};
+ }
+};
+
+inline BuildResult BuildCFG(const char *Code) {
+ CFGCallback Callback;
+
+ ast_matchers::MatchFinder Finder;
+ Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback);
+ std::unique_ptr<tooling::FrontendActionFactory> Factory(
+ tooling::newFrontendActionFactory(&Finder));
+ std::vector<std::string> Args = {"-std=c++11",
+ "-fno-delayed-template-parsing"};
+ if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args))
+ return BuildResult::ToolFailed;
+ return std::move(Callback.TheBuildResult);
+}
+
+} // namespace analysis
+} // namespace clang
diff --git a/src/llvm-project/clang/unittests/Analysis/CFGDominatorTree.cpp b/src/llvm-project/clang/unittests/Analysis/CFGDominatorTree.cpp
new file mode 100644
index 0000000..8cbd72c
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Analysis/CFGDominatorTree.cpp
@@ -0,0 +1,194 @@
+//===- unittests/Analysis/CFGDominatorTree.cpp - CFG tests ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFGBuildResult.h"
+#include "clang/Analysis/Analyses/Dominators.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace analysis {
+namespace {
+
+TEST(CFGDominatorTree, DomTree) {
+ const char *Code = R"(enum Kind {
+ A
+ };
+
+ void f() {
+ switch(Kind{}) {
+ case A:
+ break;
+ }
+ })";
+ BuildResult Result = BuildCFG(Code);
+ EXPECT_EQ(BuildResult::BuiltCFG, Result.getStatus());
+
+ // [B3 (ENTRY)] -> [B1] -> [B2] -> [B0 (EXIT)]
+ // switch case A
+
+ CFG *cfg = Result.getCFG();
+
+ // Sanity checks.
+ EXPECT_EQ(cfg->size(), 4u);
+
+ CFGBlock *ExitBlock = *cfg->begin();
+ EXPECT_EQ(ExitBlock, &cfg->getExit());
+
+ CFGBlock *SwitchBlock = *(cfg->begin() + 1);
+
+ CFGBlock *CaseABlock = *(cfg->begin() + 2);
+
+ CFGBlock *EntryBlock = *(cfg->begin() + 3);
+ EXPECT_EQ(EntryBlock, &cfg->getEntry());
+
+ // Test the dominator tree.
+ CFGDomTree Dom;
+ Dom.buildDominatorTree(cfg);
+
+ EXPECT_TRUE(Dom.dominates(ExitBlock, ExitBlock));
+ EXPECT_FALSE(Dom.properlyDominates(ExitBlock, ExitBlock));
+ EXPECT_TRUE(Dom.dominates(CaseABlock, ExitBlock));
+ EXPECT_TRUE(Dom.dominates(SwitchBlock, ExitBlock));
+ EXPECT_TRUE(Dom.dominates(EntryBlock, ExitBlock));
+
+ EXPECT_TRUE(Dom.dominates(CaseABlock, CaseABlock));
+ EXPECT_FALSE(Dom.properlyDominates(CaseABlock, CaseABlock));
+ EXPECT_TRUE(Dom.dominates(SwitchBlock, CaseABlock));
+ EXPECT_TRUE(Dom.dominates(EntryBlock, CaseABlock));
+
+ EXPECT_TRUE(Dom.dominates(SwitchBlock, SwitchBlock));
+ EXPECT_FALSE(Dom.properlyDominates(SwitchBlock, SwitchBlock));
+ EXPECT_TRUE(Dom.dominates(EntryBlock, SwitchBlock));
+
+ EXPECT_TRUE(Dom.dominates(EntryBlock, EntryBlock));
+ EXPECT_FALSE(Dom.properlyDominates(EntryBlock, EntryBlock));
+
+ // Test the post dominator tree.
+
+ CFGPostDomTree PostDom;
+ PostDom.buildDominatorTree(cfg);
+
+ EXPECT_TRUE(PostDom.dominates(ExitBlock, EntryBlock));
+ EXPECT_TRUE(PostDom.dominates(CaseABlock, EntryBlock));
+ EXPECT_TRUE(PostDom.dominates(SwitchBlock, EntryBlock));
+ EXPECT_TRUE(PostDom.dominates(EntryBlock, EntryBlock));
+ EXPECT_FALSE(Dom.properlyDominates(EntryBlock, EntryBlock));
+
+ EXPECT_TRUE(PostDom.dominates(ExitBlock, SwitchBlock));
+ EXPECT_TRUE(PostDom.dominates(CaseABlock, SwitchBlock));
+ EXPECT_TRUE(PostDom.dominates(SwitchBlock, SwitchBlock));
+ EXPECT_FALSE(Dom.properlyDominates(SwitchBlock, SwitchBlock));
+
+ EXPECT_TRUE(PostDom.dominates(ExitBlock, CaseABlock));
+ EXPECT_TRUE(PostDom.dominates(CaseABlock, CaseABlock));
+ EXPECT_FALSE(Dom.properlyDominates(CaseABlock, CaseABlock));
+
+ EXPECT_TRUE(PostDom.dominates(ExitBlock, ExitBlock));
+ EXPECT_FALSE(Dom.properlyDominates(ExitBlock, ExitBlock));
+
+ // Tests for the post dominator tree's virtual root.
+ EXPECT_TRUE(PostDom.dominates(nullptr, EntryBlock));
+ EXPECT_TRUE(PostDom.dominates(nullptr, SwitchBlock));
+ EXPECT_TRUE(PostDom.dominates(nullptr, CaseABlock));
+ EXPECT_TRUE(PostDom.dominates(nullptr, ExitBlock));
+}
+
+TEST(CFGDominatorTree, ControlDependency) {
+ const char *Code = R"(bool coin();
+
+ void funcWithBranch() {
+ int x = 0;
+ if (coin()) {
+ if (coin()) {
+ x = 5;
+ }
+ int j = 10 / x;
+ (void)j;
+ }
+ };)";
+ BuildResult Result = BuildCFG(Code);
+ EXPECT_EQ(BuildResult::BuiltCFG, Result.getStatus());
+
+ // 1st if 2nd if
+ // [B5 (ENTRY)] -> [B4] -> [B3] -> [B2] -> [B1] -> [B0 (EXIT)]
+ // \ \ / /
+ // \ -------------> /
+ // ------------------------------>
+
+ CFG *cfg = Result.getCFG();
+
+ // Sanity checks.
+ EXPECT_EQ(cfg->size(), 6u);
+
+ CFGBlock *ExitBlock = *cfg->begin();
+ EXPECT_EQ(ExitBlock, &cfg->getExit());
+
+ CFGBlock *NullDerefBlock = *(cfg->begin() + 1);
+
+ CFGBlock *SecondThenBlock = *(cfg->begin() + 2);
+
+ CFGBlock *SecondIfBlock = *(cfg->begin() + 3);
+
+ CFGBlock *FirstIfBlock = *(cfg->begin() + 4);
+
+ CFGBlock *EntryBlock = *(cfg->begin() + 5);
+ EXPECT_EQ(EntryBlock, &cfg->getEntry());
+
+ ControlDependencyCalculator Control(cfg);
+
+ EXPECT_TRUE(Control.isControlDependent(SecondThenBlock, SecondIfBlock));
+ EXPECT_TRUE(Control.isControlDependent(SecondIfBlock, FirstIfBlock));
+ EXPECT_FALSE(Control.isControlDependent(NullDerefBlock, SecondIfBlock));
+}
+
+TEST(CFGDominatorTree, ControlDependencyWithLoops) {
+ const char *Code = R"(int test3() {
+ int x,y,z;
+
+ x = y = z = 1;
+ if (x > 0) {
+ while (x >= 0){
+ while (y >= x) {
+ x = x-1;
+ y = y/2;
+ }
+ }
+ }
+ z = y;
+
+ return 0;
+ })";
+ BuildResult Result = BuildCFG(Code);
+ EXPECT_EQ(BuildResult::BuiltCFG, Result.getStatus());
+
+ // <- [B2] <-
+ // / \
+ // [B8 (ENTRY)] -> [B7] -> [B6] ---> [B5] -> [B4] -> [B3]
+ // \ | \ /
+ // \ | <-------------
+ // \ \
+ // --------> [B1] -> [B0 (EXIT)]
+
+ CFG *cfg = Result.getCFG();
+
+ ControlDependencyCalculator Control(cfg);
+
+ auto GetBlock = [cfg] (unsigned Index) -> CFGBlock * {
+ assert(Index < cfg->size());
+ return *(cfg->begin() + Index);
+ };
+
+ // While not immediately obvious, the second block in fact post dominates the
+ // fifth, hence B5 is not a control dependency of 2.
+ EXPECT_FALSE(Control.isControlDependent(GetBlock(5), GetBlock(2)));
+}
+
+
+} // namespace
+} // namespace analysis
+} // namespace clang
diff --git a/src/llvm-project/clang/unittests/Analysis/CFGTest.cpp b/src/llvm-project/clang/unittests/Analysis/CFGTest.cpp
index 768705f..7cd3da2 100644
--- a/src/llvm-project/clang/unittests/Analysis/CFGTest.cpp
+++ b/src/llvm-project/clang/unittests/Analysis/CFGTest.cpp
@@ -1,12 +1,12 @@
//===- unittests/Analysis/CFGTest.cpp - CFG tests -------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+#include "CFGBuildResult.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Analysis/CFG.h"
#include "clang/Tooling/Tooling.h"
@@ -18,43 +18,6 @@
namespace analysis {
namespace {
-enum BuildResult {
- ToolFailed,
- ToolRan,
- SawFunctionBody,
- BuiltCFG,
-};
-
-class CFGCallback : public ast_matchers::MatchFinder::MatchCallback {
-public:
- BuildResult TheBuildResult = ToolRan;
-
- void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
- const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
- Stmt *Body = Func->getBody();
- if (!Body)
- return;
- TheBuildResult = SawFunctionBody;
- CFG::BuildOptions Options;
- Options.AddImplicitDtors = true;
- if (CFG::buildCFG(nullptr, Body, Result.Context, Options))
- TheBuildResult = BuiltCFG;
- }
-};
-
-BuildResult BuildCFG(const char *Code) {
- CFGCallback Callback;
-
- ast_matchers::MatchFinder Finder;
- Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback);
- std::unique_ptr<tooling::FrontendActionFactory> Factory(
- tooling::newFrontendActionFactory(&Finder));
- std::vector<std::string> Args = {"-std=c++11", "-fno-delayed-template-parsing"};
- if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args))
- return ToolFailed;
- return Callback.TheBuildResult;
-}
-
// Constructing a CFG for a range-based for over a dependent type fails (but
// should not crash).
TEST(CFG, RangeBasedForOverDependentType) {
@@ -64,7 +27,7 @@
" for (const Foo *TheFoo : Range) {\n"
" }\n"
"}\n";
- EXPECT_EQ(SawFunctionBody, BuildCFG(Code));
+ EXPECT_EQ(BuildResult::SawFunctionBody, BuildCFG(Code).getStatus());
}
// Constructing a CFG containing a delete expression on a dependent type should
@@ -74,7 +37,7 @@
"void f(T t) {\n"
" delete t;\n"
"}\n";
- EXPECT_EQ(BuiltCFG, BuildCFG(Code));
+ EXPECT_EQ(BuildResult::BuiltCFG, BuildCFG(Code).getStatus());
}
// Constructing a CFG on a function template with a variable of incomplete type
@@ -84,7 +47,24 @@
" class Undefined;\n"
" Undefined u;\n"
"}\n";
- EXPECT_EQ(BuiltCFG, BuildCFG(Code));
+ EXPECT_EQ(BuildResult::BuiltCFG, BuildCFG(Code).getStatus());
+}
+
+TEST(CFG, IsLinear) {
+ auto expectLinear = [](bool IsLinear, const char *Code) {
+ BuildResult B = BuildCFG(Code);
+ EXPECT_EQ(BuildResult::BuiltCFG, B.getStatus());
+ EXPECT_EQ(IsLinear, B.getCFG()->isLinear());
+ };
+
+ expectLinear(true, "void foo() {}");
+ expectLinear(true, "void foo() { if (true) return; }");
+ expectLinear(true, "void foo() { if constexpr (false); }");
+ expectLinear(false, "void foo(bool coin) { if (coin) return; }");
+ expectLinear(false, "void foo() { for(;;); }");
+ expectLinear(false, "void foo() { do {} while (true); }");
+ expectLinear(true, "void foo() { do {} while (false); }");
+ expectLinear(true, "void foo() { foo(); }"); // Recursion is not our problem.
}
} // namespace
diff --git a/src/llvm-project/clang/unittests/Analysis/CMakeLists.txt b/src/llvm-project/clang/unittests/Analysis/CMakeLists.txt
index c760ae2..03716e2 100644
--- a/src/llvm-project/clang/unittests/Analysis/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/Analysis/CMakeLists.txt
@@ -3,12 +3,13 @@
)
add_clang_unittest(ClangAnalysisTests
+ CFGDominatorTree.cpp
CFGTest.cpp
CloneDetectionTest.cpp
ExprMutationAnalyzerTest.cpp
)
-target_link_libraries(ClangAnalysisTests
+clang_target_link_libraries(ClangAnalysisTests
PRIVATE
clangAnalysis
clangAST
diff --git a/src/llvm-project/clang/unittests/Analysis/CloneDetectionTest.cpp b/src/llvm-project/clang/unittests/Analysis/CloneDetectionTest.cpp
index 965a4bc..03b63c4 100644
--- a/src/llvm-project/clang/unittests/Analysis/CloneDetectionTest.cpp
+++ b/src/llvm-project/clang/unittests/Analysis/CloneDetectionTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Analysis/CloneDetectionTest.cpp - Clone detection tests --===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp b/src/llvm-project/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
index 68c921e..2c22a5c 100644
--- a/src/llvm-project/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
+++ b/src/llvm-project/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
@@ -1,9 +1,8 @@
//===---------- ExprMutationAnalyzerTest.cpp ------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -882,6 +881,137 @@
EXPECT_FALSE(isMutated(Results, AST.get()));
}
+TEST(ExprMutationAnalyzerTest, CommaExprWithAnAssigment) {
+ const auto AST =
+ buildASTFromCodeWithArgs("void f() { int x; int y; (x, y) = 5; }",
+ {"-Wno-unused-value"});
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
+ EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprWithDecOp) {
+ const auto AST =
+ buildASTFromCodeWithArgs("void f() { int x; int y; (x, y)++; }",
+ {"-Wno-unused-value"});
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
+ EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprWithNonConstMemberCall) {
+ const auto AST =
+ buildASTFromCodeWithArgs("class A { public: int mem; void f() { mem ++; } };"
+ "void fn() { A o1, o2; (o1, o2).f(); }",
+ {"-Wno-unused-value"});
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("o2")), AST->getASTContext());
+ EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprWithConstMemberCall) {
+ const auto AST =
+ buildASTFromCodeWithArgs("class A { public: int mem; void f() const { } };"
+ "void fn() { A o1, o2; (o1, o2).f(); }",
+ {"-Wno-unused-value"});
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("o2")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprWithCallExpr) {
+ const auto AST =
+ buildASTFromCodeWithArgs("class A { public: int mem; void f(A &O1) {} };"
+ "void fn() { A o1, o2; o2.f((o2, o1)); }",
+ {"-Wno-unused-value"});
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext());
+ EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprWithCallUnresolved) {
+ auto AST = buildASTFromCodeWithArgs(
+ "template <class T> struct S;"
+ "template <class T> void f() { S<T> s; int x, y; s.mf((y, x)); }",
+ {"-fno-delayed-template-parsing", "-Wno-unused-value"});
+ auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_TRUE(isMutated(Results, AST.get()));
+
+ AST = buildASTFromCodeWithArgs(
+ "template <class T> void f(T t) { int x, y; g(t, (y, x)); }",
+ {"-fno-delayed-template-parsing", "-Wno-unused-value"});
+ Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprParmRef) {
+ const auto AST =
+ buildASTFromCodeWithArgs("class A { public: int mem;};"
+ "extern void fn(A &o1);"
+ "void fn2 () { A o1, o2; fn((o2, o1)); } ",
+ {"-Wno-unused-value"});
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext());
+ EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprWithAmpersandOp) {
+ const auto AST =
+ buildASTFromCodeWithArgs("class A { public: int mem;};"
+ "void fn () { A o1, o2;"
+ "void *addr = &(o2, o1); } ",
+ {"-Wno-unused-value"});
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext());
+ EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprAsReturnAsValue) {
+ auto AST = buildASTFromCodeWithArgs("int f() { int x, y; return (x, y); }",
+ {"-Wno-unused-value"});
+ auto Results =
+ match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
+ EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaEpxrAsReturnAsNonConstRef) {
+ const auto AST =
+ buildASTFromCodeWithArgs("int& f() { int x, y; return (y, x); }",
+ {"-Wno-unused-value"});
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprAsArrayToPointerDecay) {
+ const auto AST =
+ buildASTFromCodeWithArgs("void g(int*); "
+ "void f() { int x[2], y[2]; g((y, x)); }",
+ {"-Wno-unused-value"});
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprAsUniquePtr) {
+ const std::string UniquePtrDef =
+ "template <class T> struct UniquePtr {"
+ " UniquePtr();"
+ " UniquePtr(const UniquePtr&) = delete;"
+ " T& operator*() const;"
+ " T* operator->() const;"
+ "};";
+ const auto AST = buildASTFromCodeWithArgs(
+ UniquePtrDef + "template <class T> void f() "
+ "{ UniquePtr<T> x; UniquePtr<T> y;"
+ " (y, x)->mf(); }",
+ {"-fno-delayed-template-parsing", "-Wno-unused-value"});
+ const auto Results =
+ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+ EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByValue) {
const auto AST = buildASTFromCode("void f() { int x; [=]() { x; }; }");
const auto Results =
@@ -1109,4 +1239,23 @@
EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x->mf()"));
}
+TEST(ExprMutationAnalyzerTest, ReproduceFailureMinimal) {
+ const std::string Reproducer =
+ "namespace std {"
+ "template <class T> T forward(T & A) { return static_cast<T&&>(A); }"
+ "template <class T> struct __bind {"
+ " T f;"
+ " template <class V> __bind(T v, V &&) : f(forward(v)) {}"
+ "};"
+ "}"
+ "void f() {"
+ " int x = 42;"
+ " auto Lambda = [] {};"
+ " std::__bind<decltype(Lambda)>(Lambda, x);"
+ "}";
+ auto AST11 = buildASTFromCodeWithArgs(Reproducer, {"-std=c++11"});
+ auto Results11 =
+ match(withEnclosingCompound(declRefTo("x")), AST11->getASTContext());
+ EXPECT_FALSE(isMutated(Results11, AST11.get()));
+}
} // namespace clang
diff --git a/src/llvm-project/clang/unittests/Basic/CMakeLists.txt b/src/llvm-project/clang/unittests/Basic/CMakeLists.txt
index 537f3ba..a54e939 100644
--- a/src/llvm-project/clang/unittests/Basic/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/Basic/CMakeLists.txt
@@ -7,11 +7,10 @@
DiagnosticTest.cpp
FileManagerTest.cpp
FixedPointTest.cpp
- MemoryBufferCacheTest.cpp
SourceManagerTest.cpp
)
-target_link_libraries(BasicTests
+clang_target_link_libraries(BasicTests
PRIVATE
clangAST
clangBasic
diff --git a/src/llvm-project/clang/unittests/Basic/CharInfoTest.cpp b/src/llvm-project/clang/unittests/Basic/CharInfoTest.cpp
index 7a9d17f..4f84beb 100644
--- a/src/llvm-project/clang/unittests/Basic/CharInfoTest.cpp
+++ b/src/llvm-project/clang/unittests/Basic/CharInfoTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Basic/CharInfoTest.cpp -- ASCII classification tests -----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Basic/DiagnosticTest.cpp b/src/llvm-project/clang/unittests/Basic/DiagnosticTest.cpp
index 3068e1c..ffb750b 100644
--- a/src/llvm-project/clang/unittests/Basic/DiagnosticTest.cpp
+++ b/src/llvm-project/clang/unittests/Basic/DiagnosticTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Basic/DiagnosticTest.cpp -- Diagnostic engine tests ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -47,13 +46,13 @@
EXPECT_FALSE(Diags.hasUnrecoverableErrorOccurred());
}
-// Check that SuppressAfterFatalError works as intended
-TEST(DiagnosticTest, suppressAfterFatalError) {
- for (unsigned Suppress = 0; Suppress != 2; ++Suppress) {
+// Check that FatalsAsError works as intended
+TEST(DiagnosticTest, fatalsAsError) {
+ for (unsigned FatalsAsError = 0; FatalsAsError != 2; ++FatalsAsError) {
DiagnosticsEngine Diags(new DiagnosticIDs(),
new DiagnosticOptions,
new IgnoringDiagConsumer());
- Diags.setSuppressAfterFatalError(Suppress);
+ Diags.setFatalsAsError(FatalsAsError);
// Diag that would set UnrecoverableErrorOccurred and ErrorOccurred.
Diags.Report(diag::err_cannot_open_file) << "file" << "error";
@@ -63,16 +62,15 @@
Diags.Report(diag::warn_mt_message) << "warning";
EXPECT_TRUE(Diags.hasErrorOccurred());
- EXPECT_TRUE(Diags.hasFatalErrorOccurred());
+ EXPECT_EQ(Diags.hasFatalErrorOccurred(), FatalsAsError ? 0u : 1u);
EXPECT_TRUE(Diags.hasUncompilableErrorOccurred());
EXPECT_TRUE(Diags.hasUnrecoverableErrorOccurred());
// The warning should be emitted and counted only if we're not suppressing
// after fatal errors.
- EXPECT_EQ(Diags.getNumWarnings(), Suppress ? 0u : 1u);
+ EXPECT_EQ(Diags.getNumWarnings(), FatalsAsError);
}
}
-
TEST(DiagnosticTest, diagnosticError) {
DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions,
new IgnoringDiagConsumer());
diff --git a/src/llvm-project/clang/unittests/Basic/FileManagerTest.cpp b/src/llvm-project/clang/unittests/Basic/FileManagerTest.cpp
index 8e98f44..19e2180 100644
--- a/src/llvm-project/clang/unittests/Basic/FileManagerTest.cpp
+++ b/src/llvm-project/clang/unittests/Basic/FileManagerTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Basic/FileMangerTest.cpp ------------ FileManger tests ---===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -27,7 +26,7 @@
private:
// Maps a file/directory path to its desired stat result. Anything
// not in this map is considered to not exist in the file system.
- llvm::StringMap<FileData, llvm::BumpPtrAllocator> StatCalls;
+ llvm::StringMap<llvm::vfs::Status, llvm::BumpPtrAllocator> StatCalls;
void InjectFileOrDirectory(const char *Path, ino_t INode, bool IsFile) {
#ifndef _WIN32
@@ -36,15 +35,14 @@
Path = NormalizedPath.c_str();
#endif
- FileData Data;
- Data.Name = Path;
- Data.Size = 0;
- Data.ModTime = 0;
- Data.UniqueID = llvm::sys::fs::UniqueID(1, INode);
- Data.IsDirectory = !IsFile;
- Data.IsNamedPipe = false;
- Data.InPCH = false;
- StatCalls[Path] = Data;
+ auto fileType = IsFile ?
+ llvm::sys::fs::file_type::regular_file :
+ llvm::sys::fs::file_type::directory_file;
+ llvm::vfs::Status Status(Path, llvm::sys::fs::UniqueID(1, INode),
+ /*MTime*/{}, /*User*/0, /*Group*/0,
+ /*Size*/0, fileType,
+ llvm::sys::fs::perms::all_all);
+ StatCalls[Path] = Status;
}
public:
@@ -59,9 +57,10 @@
}
// Implement FileSystemStatCache::getStat().
- LookupResult getStat(StringRef Path, FileData &Data, bool isFile,
- std::unique_ptr<llvm::vfs::File> *F,
- llvm::vfs::FileSystem &FS) override {
+ std::error_code getStat(StringRef Path, llvm::vfs::Status &Status,
+ bool isFile,
+ std::unique_ptr<llvm::vfs::File> *F,
+ llvm::vfs::FileSystem &FS) override {
#ifndef _WIN32
SmallString<128> NormalizedPath(Path);
llvm::sys::path::native(NormalizedPath);
@@ -69,11 +68,11 @@
#endif
if (StatCalls.count(Path) != 0) {
- Data = StatCalls[Path];
- return CacheExists;
+ Status = StatCalls[Path];
+ return std::error_code();
}
- return CacheMissing; // This means the file/directory doesn't exist.
+ return std::make_error_code(std::errc::no_such_file_or_directory);
}
};
@@ -347,4 +346,37 @@
EXPECT_EQ(file->tryGetRealPathName(), ExpectedResult);
}
+TEST_F(FileManagerTest, getFileDontOpenRealPath) {
+ SmallString<64> CustomWorkingDir;
+#ifdef _WIN32
+ CustomWorkingDir = "C:/";
+#else
+ CustomWorkingDir = "/";
+#endif
+
+ auto FS = IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem>(
+ new llvm::vfs::InMemoryFileSystem);
+ // setCurrentworkingdirectory must finish without error.
+ ASSERT_TRUE(!FS->setCurrentWorkingDirectory(CustomWorkingDir));
+
+ FileSystemOptions Opts;
+ FileManager Manager(Opts, FS);
+
+ // Inject fake files into the file system.
+ auto statCache = llvm::make_unique<FakeStatCache>();
+ statCache->InjectDirectory("/tmp", 42);
+ statCache->InjectFile("/tmp/test", 43);
+
+ Manager.setStatCache(std::move(statCache));
+
+ // Check for real path.
+ const FileEntry *file = Manager.getFile("/tmp/test", /*OpenFile=*/false);
+ ASSERT_TRUE(file != nullptr);
+ ASSERT_TRUE(file->isValid());
+ SmallString<64> ExpectedResult = CustomWorkingDir;
+
+ llvm::sys::path::append(ExpectedResult, "tmp", "test");
+ EXPECT_EQ(file->tryGetRealPathName(), ExpectedResult);
+}
+
} // anonymous namespace
diff --git a/src/llvm-project/clang/unittests/Basic/FixedPointTest.cpp b/src/llvm-project/clang/unittests/Basic/FixedPointTest.cpp
index 8e184a7..5d991c0 100644
--- a/src/llvm-project/clang/unittests/Basic/FixedPointTest.cpp
+++ b/src/llvm-project/clang/unittests/Basic/FixedPointTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Basic/FixedPointTest.cpp -- fixed point number tests -----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Basic/MemoryBufferCacheTest.cpp b/src/llvm-project/clang/unittests/Basic/MemoryBufferCacheTest.cpp
deleted file mode 100644
index 99178f8..0000000
--- a/src/llvm-project/clang/unittests/Basic/MemoryBufferCacheTest.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-//===- MemoryBufferCacheTest.cpp - MemoryBufferCache tests ----------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Basic/MemoryBufferCache.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "gtest/gtest.h"
-
-using namespace llvm;
-using namespace clang;
-
-namespace {
-
-std::unique_ptr<MemoryBuffer> getBuffer(int I) {
- SmallVector<char, 8> Bytes;
- raw_svector_ostream(Bytes) << "data:" << I;
- return MemoryBuffer::getMemBuffer(StringRef(Bytes.data(), Bytes.size()), "",
- /* RequiresNullTerminator = */ false);
-}
-
-TEST(MemoryBufferCacheTest, addBuffer) {
- auto B1 = getBuffer(1);
- auto B2 = getBuffer(2);
- auto B3 = getBuffer(3);
- auto *RawB1 = B1.get();
- auto *RawB2 = B2.get();
- auto *RawB3 = B3.get();
-
- // Add a few buffers.
- MemoryBufferCache Cache;
- EXPECT_EQ(RawB1, &Cache.addBuffer("1", std::move(B1)));
- EXPECT_EQ(RawB2, &Cache.addBuffer("2", std::move(B2)));
- EXPECT_EQ(RawB3, &Cache.addBuffer("3", std::move(B3)));
- EXPECT_EQ(RawB1, Cache.lookupBuffer("1"));
- EXPECT_EQ(RawB2, Cache.lookupBuffer("2"));
- EXPECT_EQ(RawB3, Cache.lookupBuffer("3"));
- EXPECT_FALSE(Cache.isBufferFinal("1"));
- EXPECT_FALSE(Cache.isBufferFinal("2"));
- EXPECT_FALSE(Cache.isBufferFinal("3"));
-
- // Remove the middle buffer.
- EXPECT_FALSE(Cache.tryToRemoveBuffer("2"));
- EXPECT_EQ(nullptr, Cache.lookupBuffer("2"));
- EXPECT_FALSE(Cache.isBufferFinal("2"));
-
- // Replace the middle buffer.
- B2 = getBuffer(2);
- RawB2 = B2.get();
- EXPECT_EQ(RawB2, &Cache.addBuffer("2", std::move(B2)));
-
- // Check that nothing is final.
- EXPECT_FALSE(Cache.isBufferFinal("1"));
- EXPECT_FALSE(Cache.isBufferFinal("2"));
- EXPECT_FALSE(Cache.isBufferFinal("3"));
-}
-
-TEST(MemoryBufferCacheTest, finalizeCurrentBuffers) {
- // Add a buffer.
- MemoryBufferCache Cache;
- auto B1 = getBuffer(1);
- auto *RawB1 = B1.get();
- Cache.addBuffer("1", std::move(B1));
- ASSERT_FALSE(Cache.isBufferFinal("1"));
-
- // Finalize it.
- Cache.finalizeCurrentBuffers();
- EXPECT_TRUE(Cache.isBufferFinal("1"));
- EXPECT_TRUE(Cache.tryToRemoveBuffer("1"));
- EXPECT_EQ(RawB1, Cache.lookupBuffer("1"));
- EXPECT_TRUE(Cache.isBufferFinal("1"));
-
- // Repeat.
- auto B2 = getBuffer(2);
- auto *RawB2 = B2.get();
- Cache.addBuffer("2", std::move(B2));
- EXPECT_FALSE(Cache.isBufferFinal("2"));
-
- Cache.finalizeCurrentBuffers();
- EXPECT_TRUE(Cache.isBufferFinal("1"));
- EXPECT_TRUE(Cache.isBufferFinal("2"));
- EXPECT_TRUE(Cache.tryToRemoveBuffer("1"));
- EXPECT_TRUE(Cache.tryToRemoveBuffer("2"));
- EXPECT_EQ(RawB1, Cache.lookupBuffer("1"));
- EXPECT_EQ(RawB2, Cache.lookupBuffer("2"));
- EXPECT_TRUE(Cache.isBufferFinal("1"));
- EXPECT_TRUE(Cache.isBufferFinal("2"));
-}
-
-} // namespace
diff --git a/src/llvm-project/clang/unittests/Basic/SourceManagerTest.cpp b/src/llvm-project/clang/unittests/Basic/SourceManagerTest.cpp
index b548bf5..ff8a364 100644
--- a/src/llvm-project/clang/unittests/Basic/SourceManagerTest.cpp
+++ b/src/llvm-project/clang/unittests/Basic/SourceManagerTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Basic/SourceManagerTest.cpp ------ SourceManager tests ---===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -12,7 +11,6 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Lex/HeaderSearch.h"
@@ -61,11 +59,10 @@
SourceMgr.setMainFileID(mainFileID);
TrivialModuleLoader ModLoader;
- MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, &*Target);
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
- SourceMgr, PCMCache, HeaderInfo, ModLoader,
+ SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
@@ -230,11 +227,10 @@
SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
TrivialModuleLoader ModLoader;
- MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, &*Target);
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
- SourceMgr, PCMCache, HeaderInfo, ModLoader,
+ SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
@@ -349,11 +345,10 @@
SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
TrivialModuleLoader ModLoader;
- MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, &*Target);
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
- SourceMgr, PCMCache, HeaderInfo, ModLoader,
+ SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
diff --git a/src/llvm-project/clang/unittests/CMakeLists.txt b/src/llvm-project/clang/unittests/CMakeLists.txt
index 6eff599..9a41000 100644
--- a/src/llvm-project/clang/unittests/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/CMakeLists.txt
@@ -30,5 +30,7 @@
if(NOT WIN32 AND CLANG_TOOL_LIBCLANG_BUILD)
add_subdirectory(libclang)
endif()
+add_subdirectory(DirectoryWatcher)
add_subdirectory(Rename)
add_subdirectory(Index)
+add_subdirectory(Serialization)
diff --git a/src/llvm-project/clang/unittests/CodeGen/BufferSourceTest.cpp b/src/llvm-project/clang/unittests/CodeGen/BufferSourceTest.cpp
index 1934e66..c1c2bf8 100644
--- a/src/llvm-project/clang/unittests/CodeGen/BufferSourceTest.cpp
+++ b/src/llvm-project/clang/unittests/CodeGen/BufferSourceTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/CodeGen/BufferSourceTest.cpp - MemoryBuffer source tests -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/CodeGen/CMakeLists.txt b/src/llvm-project/clang/unittests/CodeGen/CMakeLists.txt
index e4e7588..c4c8a5c 100644
--- a/src/llvm-project/clang/unittests/CodeGen/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/CodeGen/CMakeLists.txt
@@ -10,7 +10,7 @@
TBAAMetadataTest.cpp
)
-target_link_libraries(ClangCodeGenTests
+clang_target_link_libraries(ClangCodeGenTests
PRIVATE
clangAST
clangBasic
diff --git a/src/llvm-project/clang/unittests/CodeGen/CodeGenExternalTest.cpp b/src/llvm-project/clang/unittests/CodeGen/CodeGenExternalTest.cpp
index bcec3ea..8dff45c 100644
--- a/src/llvm-project/clang/unittests/CodeGen/CodeGenExternalTest.cpp
+++ b/src/llvm-project/clang/unittests/CodeGen/CodeGenExternalTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/CodeGen/CodeGenExternalTest.cpp - test external CodeGen -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/CodeGen/IRMatchers.h b/src/llvm-project/clang/unittests/CodeGen/IRMatchers.h
index 5150ca4..9cc2a31 100644
--- a/src/llvm-project/clang/unittests/CodeGen/IRMatchers.h
+++ b/src/llvm-project/clang/unittests/CodeGen/IRMatchers.h
@@ -1,9 +1,8 @@
//=== unittests/CodeGen/IRMatchers.h - Match on the LLVM IR -----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
diff --git a/src/llvm-project/clang/unittests/CodeGen/IncrementalProcessingTest.cpp b/src/llvm-project/clang/unittests/CodeGen/IncrementalProcessingTest.cpp
index 40b814b..045ed9b 100644
--- a/src/llvm-project/clang/unittests/CodeGen/IncrementalProcessingTest.cpp
+++ b/src/llvm-project/clang/unittests/CodeGen/IncrementalProcessingTest.cpp
@@ -1,9 +1,8 @@
//=== unittests/CodeGen/IncrementalProcessingTest.cpp - IncrementalCodeGen ===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/CodeGen/TBAAMetadataTest.cpp b/src/llvm-project/clang/unittests/CodeGen/TBAAMetadataTest.cpp
index 7514160..6535fe2 100644
--- a/src/llvm-project/clang/unittests/CodeGen/TBAAMetadataTest.cpp
+++ b/src/llvm-project/clang/unittests/CodeGen/TBAAMetadataTest.cpp
@@ -1,9 +1,8 @@
//=== unittests/CodeGen/TBAAMetadataTest.cpp - Checks metadata generation -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/CrossTU/CMakeLists.txt b/src/llvm-project/clang/unittests/CrossTU/CMakeLists.txt
index 73047b7..222b7e8 100644
--- a/src/llvm-project/clang/unittests/CrossTU/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/CrossTU/CMakeLists.txt
@@ -7,7 +7,7 @@
CrossTranslationUnitTest.cpp
)
-target_link_libraries(CrossTUTests
+clang_target_link_libraries(CrossTUTests
PRIVATE
clangAST
clangBasic
diff --git a/src/llvm-project/clang/unittests/CrossTU/CrossTranslationUnitTest.cpp b/src/llvm-project/clang/unittests/CrossTU/CrossTranslationUnitTest.cpp
index dd82743..b3e7243 100644
--- a/src/llvm-project/clang/unittests/CrossTU/CrossTranslationUnitTest.cpp
+++ b/src/llvm-project/clang/unittests/CrossTU/CrossTranslationUnitTest.cpp
@@ -1,13 +1,13 @@
//===- unittest/Tooling/CrossTranslationUnitTest.cpp - Tooling unit tests -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "clang/CrossTU/CrossTranslationUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h"
@@ -71,12 +71,14 @@
EXPECT_TRUE(llvm::sys::fs::exists(ASTFileName));
// Load the definition from the AST file.
- llvm::Expected<const FunctionDecl *> NewFDorError =
- CTU.getCrossTUDefinition(FD, "", IndexFileName);
- EXPECT_TRUE((bool)NewFDorError);
- const FunctionDecl *NewFD = *NewFDorError;
+ llvm::Expected<const FunctionDecl *> NewFDorError = handleExpected(
+ CTU.getCrossTUDefinition(FD, "", IndexFileName, false),
+ []() { return nullptr; }, [](IndexError &) {});
- *Success = NewFD && NewFD->hasBody() && !OrigFDHasBody;
+ if (NewFDorError) {
+ const FunctionDecl *NewFD = *NewFDorError;
+ *Success = NewFD && NewFD->hasBody() && !OrigFDHasBody;
+ }
}
private:
@@ -86,26 +88,37 @@
class CTUAction : public clang::ASTFrontendAction {
public:
- CTUAction(bool *Success) : Success(Success) {}
+ CTUAction(bool *Success, unsigned OverrideLimit)
+ : Success(Success), OverrideLimit(OverrideLimit) {}
protected:
std::unique_ptr<clang::ASTConsumer>
CreateASTConsumer(clang::CompilerInstance &CI, StringRef) override {
+ CI.getAnalyzerOpts()->CTUImportThreshold = OverrideLimit;
return llvm::make_unique<CTUASTConsumer>(CI, Success);
}
private:
bool *Success;
+ const unsigned OverrideLimit;
};
} // end namespace
TEST(CrossTranslationUnit, CanLoadFunctionDefinition) {
bool Success = false;
- EXPECT_TRUE(tooling::runToolOnCode(new CTUAction(&Success), "int f(int);"));
+ EXPECT_TRUE(
+ tooling::runToolOnCode(new CTUAction(&Success, 1u), "int f(int);"));
EXPECT_TRUE(Success);
}
+TEST(CrossTranslationUnit, RespectsLoadThreshold) {
+ bool Success = false;
+ EXPECT_TRUE(
+ tooling::runToolOnCode(new CTUAction(&Success, 0u), "int f(int);"));
+ EXPECT_FALSE(Success);
+}
+
TEST(CrossTranslationUnit, IndexFormatCanBeParsed) {
llvm::StringMap<std::string> Index;
Index["a"] = "/b/f1";
diff --git a/src/llvm-project/clang/unittests/DirectoryWatcher/CMakeLists.txt b/src/llvm-project/clang/unittests/DirectoryWatcher/CMakeLists.txt
new file mode 100644
index 0000000..fc93323
--- /dev/null
+++ b/src/llvm-project/clang/unittests/DirectoryWatcher/CMakeLists.txt
@@ -0,0 +1,17 @@
+if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "Linux")
+
+ set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+ add_clang_unittest(DirectoryWatcherTests
+ DirectoryWatcherTest.cpp
+ )
+
+ target_link_libraries(DirectoryWatcherTests
+ PRIVATE
+ clangDirectoryWatcher
+ clangBasic
+ )
+
+endif()
\ No newline at end of file
diff --git a/src/llvm-project/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp b/src/llvm-project/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp
new file mode 100644
index 0000000..a6b48e5
--- /dev/null
+++ b/src/llvm-project/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp
@@ -0,0 +1,433 @@
+//===- unittests/DirectoryWatcher/DirectoryWatcherTest.cpp ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/DirectoryWatcher/DirectoryWatcher.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+#include <condition_variable>
+#include <future>
+#include <mutex>
+#include <thread>
+
+using namespace llvm;
+using namespace llvm::sys;
+using namespace llvm::sys::fs;
+using namespace clang;
+
+namespace clang {
+static bool operator==(const DirectoryWatcher::Event &lhs,
+ const DirectoryWatcher::Event &rhs) {
+ return lhs.Filename == rhs.Filename &&
+ static_cast<int>(lhs.Kind) == static_cast<int>(rhs.Kind);
+}
+} // namespace clang
+
+namespace {
+
+typedef DirectoryWatcher::Event::EventKind EventKind;
+
+struct DirectoryWatcherTestFixture {
+ std::string TestRootDir;
+ std::string TestWatchedDir;
+
+ DirectoryWatcherTestFixture() {
+ SmallString<128> pathBuf;
+#ifndef NDEBUG
+ std::error_code UniqDirRes =
+#endif
+ createUniqueDirectory("dirwatcher", pathBuf);
+ assert(!UniqDirRes);
+ TestRootDir = pathBuf.str();
+ path::append(pathBuf, "watch");
+ TestWatchedDir = pathBuf.str();
+#ifndef NDEBUG
+ std::error_code CreateDirRes =
+#endif
+ create_directory(TestWatchedDir, false);
+ assert(!CreateDirRes);
+ }
+
+ ~DirectoryWatcherTestFixture() { remove_directories(TestRootDir); }
+
+ SmallString<128> getPathInWatched(const std::string &testFile) {
+ SmallString<128> pathBuf;
+ pathBuf = TestWatchedDir;
+ path::append(pathBuf, testFile);
+ return pathBuf;
+ }
+
+ void addFile(const std::string &testFile) {
+ Expected<file_t> ft = openNativeFileForWrite(getPathInWatched(testFile),
+ CD_CreateNew, OF_None);
+ if (ft) {
+ closeFile(*ft);
+ } else {
+ llvm::errs() << llvm::toString(ft.takeError()) << "\n";
+ llvm::errs() << getPathInWatched(testFile) << "\n";
+ llvm_unreachable("Couldn't create test file.");
+ }
+ }
+
+ void deleteFile(const std::string &testFile) {
+ std::error_code EC =
+ remove(getPathInWatched(testFile), /*IgnoreNonExisting=*/false);
+ ASSERT_FALSE(EC);
+ }
+};
+
+std::string eventKindToString(const EventKind K) {
+ switch (K) {
+ case EventKind::Removed:
+ return "Removed";
+ case EventKind::Modified:
+ return "Modified";
+ case EventKind::WatchedDirRemoved:
+ return "WatchedDirRemoved";
+ case EventKind::WatcherGotInvalidated:
+ return "WatcherGotInvalidated";
+ }
+ llvm_unreachable("unknown event kind");
+}
+
+struct VerifyingConsumer {
+ std::vector<DirectoryWatcher::Event> ExpectedInitial;
+ const std::vector<DirectoryWatcher::Event> ExpectedInitialCopy;
+ std::vector<DirectoryWatcher::Event> ExpectedNonInitial;
+ const std::vector<DirectoryWatcher::Event> ExpectedNonInitialCopy;
+ std::vector<DirectoryWatcher::Event> OptionalNonInitial;
+ std::vector<DirectoryWatcher::Event> UnexpectedInitial;
+ std::vector<DirectoryWatcher::Event> UnexpectedNonInitial;
+ std::mutex Mtx;
+ std::condition_variable ResultIsReady;
+
+ VerifyingConsumer(
+ const std::vector<DirectoryWatcher::Event> &ExpectedInitial,
+ const std::vector<DirectoryWatcher::Event> &ExpectedNonInitial,
+ const std::vector<DirectoryWatcher::Event> &OptionalNonInitial = {})
+ : ExpectedInitial(ExpectedInitial), ExpectedInitialCopy(ExpectedInitial),
+ ExpectedNonInitial(ExpectedNonInitial), ExpectedNonInitialCopy(ExpectedNonInitial),
+ OptionalNonInitial(OptionalNonInitial) {}
+
+ // This method is used by DirectoryWatcher.
+ void consume(DirectoryWatcher::Event E, bool IsInitial) {
+ if (IsInitial)
+ consumeInitial(E);
+ else
+ consumeNonInitial(E);
+ }
+
+ void consumeInitial(DirectoryWatcher::Event E) {
+ std::unique_lock<std::mutex> L(Mtx);
+ auto It = std::find(ExpectedInitial.begin(), ExpectedInitial.end(), E);
+ if (It == ExpectedInitial.end()) {
+ UnexpectedInitial.push_back(E);
+ } else {
+ ExpectedInitial.erase(It);
+ }
+ if (result())
+ ResultIsReady.notify_one();
+ }
+
+ void consumeNonInitial(DirectoryWatcher::Event E) {
+ std::unique_lock<std::mutex> L(Mtx);
+ auto It =
+ std::find(ExpectedNonInitial.begin(), ExpectedNonInitial.end(), E);
+ if (It == ExpectedNonInitial.end()) {
+ auto OptIt =
+ std::find(OptionalNonInitial.begin(), OptionalNonInitial.end(), E);
+ if (OptIt != OptionalNonInitial.end()) {
+ OptionalNonInitial.erase(OptIt);
+ } else {
+ UnexpectedNonInitial.push_back(E);
+ }
+ } else {
+ ExpectedNonInitial.erase(It);
+ }
+ if (result())
+ ResultIsReady.notify_one();
+ }
+
+ // This method is used by DirectoryWatcher.
+ void consume(llvm::ArrayRef<DirectoryWatcher::Event> Es, bool IsInitial) {
+ for (const auto &E : Es)
+ consume(E, IsInitial);
+ }
+
+ // Not locking - caller has to lock Mtx.
+ llvm::Optional<bool> result() const {
+ if (ExpectedInitial.empty() && ExpectedNonInitial.empty() &&
+ UnexpectedInitial.empty() && UnexpectedNonInitial.empty())
+ return true;
+ if (!UnexpectedInitial.empty() || !UnexpectedNonInitial.empty())
+ return false;
+ return llvm::None;
+ }
+
+ // This method is used by tests.
+ // \returns true on success
+ bool blockUntilResult() {
+ std::unique_lock<std::mutex> L(Mtx);
+ while (true) {
+ if (result())
+ return *result();
+
+ ResultIsReady.wait(L, [this]() { return result().hasValue(); });
+ }
+ return false; // Just to make compiler happy.
+ }
+
+ void printUnmetExpectations(llvm::raw_ostream &OS) {
+ // If there was any issue, print the expected state
+ if (
+ !ExpectedInitial.empty()
+ ||
+ !ExpectedNonInitial.empty()
+ ||
+ !UnexpectedInitial.empty()
+ ||
+ !UnexpectedNonInitial.empty()
+ ) {
+ OS << "Expected initial events: \n";
+ for (const auto &E : ExpectedInitialCopy) {
+ OS << eventKindToString(E.Kind) << " " << E.Filename << "\n";
+ }
+ OS << "Expected non-initial events: \n";
+ for (const auto &E : ExpectedNonInitialCopy) {
+ OS << eventKindToString(E.Kind) << " " << E.Filename << "\n";
+ }
+ }
+
+ if (!ExpectedInitial.empty()) {
+ OS << "Expected but not seen initial events: \n";
+ for (const auto &E : ExpectedInitial) {
+ OS << eventKindToString(E.Kind) << " " << E.Filename << "\n";
+ }
+ }
+ if (!ExpectedNonInitial.empty()) {
+ OS << "Expected but not seen non-initial events: \n";
+ for (const auto &E : ExpectedNonInitial) {
+ OS << eventKindToString(E.Kind) << " " << E.Filename << "\n";
+ }
+ }
+ if (!UnexpectedInitial.empty()) {
+ OS << "Unexpected initial events seen: \n";
+ for (const auto &E : UnexpectedInitial) {
+ OS << eventKindToString(E.Kind) << " " << E.Filename << "\n";
+ }
+ }
+ if (!UnexpectedNonInitial.empty()) {
+ OS << "Unexpected non-initial events seen: \n";
+ for (const auto &E : UnexpectedNonInitial) {
+ OS << eventKindToString(E.Kind) << " " << E.Filename << "\n";
+ }
+ }
+ }
+};
+
+void checkEventualResultWithTimeout(VerifyingConsumer &TestConsumer) {
+ std::packaged_task<int(void)> task(
+ [&TestConsumer]() { return TestConsumer.blockUntilResult(); });
+ std::future<int> WaitForExpectedStateResult = task.get_future();
+ std::thread worker(std::move(task));
+ worker.detach();
+
+ EXPECT_TRUE(WaitForExpectedStateResult.wait_for(std::chrono::seconds(3)) ==
+ std::future_status::ready)
+ << "The expected result state wasn't reached before the time-out.";
+ std::unique_lock<std::mutex> L(TestConsumer.Mtx);
+ EXPECT_TRUE(TestConsumer.result().hasValue());
+ if (TestConsumer.result().hasValue()) {
+ EXPECT_TRUE(*TestConsumer.result());
+ }
+ if ((TestConsumer.result().hasValue() && !TestConsumer.result().getValue()) ||
+ !TestConsumer.result().hasValue())
+ TestConsumer.printUnmetExpectations(llvm::outs());
+}
+} // namespace
+
+TEST(DirectoryWatcherTest, InitialScanSync) {
+ DirectoryWatcherTestFixture fixture;
+
+ fixture.addFile("a");
+ fixture.addFile("b");
+ fixture.addFile("c");
+
+ VerifyingConsumer TestConsumer{
+ {{EventKind::Modified, "a"},
+ {EventKind::Modified, "b"},
+ {EventKind::Modified, "c"}},
+ {},
+ // We have to ignore these as it's a race between the test process
+ // which is scanning the directory and kernel which is sending
+ // notification.
+ {{EventKind::Modified, "a"},
+ {EventKind::Modified, "b"},
+ {EventKind::Modified, "c"}}
+ };
+
+ auto DW = DirectoryWatcher::create(
+ fixture.TestWatchedDir,
+ [&TestConsumer](llvm::ArrayRef<DirectoryWatcher::Event> Events,
+ bool IsInitial) {
+ TestConsumer.consume(Events, IsInitial);
+ },
+ /*waitForInitialSync=*/true);
+
+ checkEventualResultWithTimeout(TestConsumer);
+}
+
+TEST(DirectoryWatcherTest, InitialScanAsync) {
+ DirectoryWatcherTestFixture fixture;
+
+ fixture.addFile("a");
+ fixture.addFile("b");
+ fixture.addFile("c");
+
+ VerifyingConsumer TestConsumer{
+ {{EventKind::Modified, "a"},
+ {EventKind::Modified, "b"},
+ {EventKind::Modified, "c"}},
+ {},
+ // We have to ignore these as it's a race between the test process
+ // which is scanning the directory and kernel which is sending
+ // notification.
+ {{EventKind::Modified, "a"},
+ {EventKind::Modified, "b"},
+ {EventKind::Modified, "c"}}
+ };
+
+ auto DW = DirectoryWatcher::create(
+ fixture.TestWatchedDir,
+ [&TestConsumer](llvm::ArrayRef<DirectoryWatcher::Event> Events,
+ bool IsInitial) {
+ TestConsumer.consume(Events, IsInitial);
+ },
+ /*waitForInitialSync=*/false);
+
+ checkEventualResultWithTimeout(TestConsumer);
+}
+
+TEST(DirectoryWatcherTest, AddFiles) {
+ DirectoryWatcherTestFixture fixture;
+
+ VerifyingConsumer TestConsumer{
+ {},
+ {{EventKind::Modified, "a"},
+ {EventKind::Modified, "b"},
+ {EventKind::Modified, "c"}}};
+
+ auto DW = DirectoryWatcher::create(
+ fixture.TestWatchedDir,
+ [&TestConsumer](llvm::ArrayRef<DirectoryWatcher::Event> Events,
+ bool IsInitial) {
+ TestConsumer.consume(Events, IsInitial);
+ },
+ /*waitForInitialSync=*/true);
+
+ fixture.addFile("a");
+ fixture.addFile("b");
+ fixture.addFile("c");
+
+ checkEventualResultWithTimeout(TestConsumer);
+}
+
+TEST(DirectoryWatcherTest, ModifyFile) {
+ DirectoryWatcherTestFixture fixture;
+
+ fixture.addFile("a");
+
+ VerifyingConsumer TestConsumer{
+ {{EventKind::Modified, "a"}},
+ {{EventKind::Modified, "a"}},
+ {{EventKind::Modified, "a"}}};
+
+ auto DW = DirectoryWatcher::create(
+ fixture.TestWatchedDir,
+ [&TestConsumer](llvm::ArrayRef<DirectoryWatcher::Event> Events,
+ bool IsInitial) {
+ TestConsumer.consume(Events, IsInitial);
+ },
+ /*waitForInitialSync=*/true);
+
+ // modify the file
+ {
+ std::error_code error;
+ llvm::raw_fd_ostream bStream(fixture.getPathInWatched("a"), error,
+ CD_OpenExisting);
+ assert(!error);
+ bStream << "foo";
+ }
+
+ checkEventualResultWithTimeout(TestConsumer);
+}
+
+TEST(DirectoryWatcherTest, DeleteFile) {
+ DirectoryWatcherTestFixture fixture;
+
+ fixture.addFile("a");
+
+ VerifyingConsumer TestConsumer{
+ {{EventKind::Modified, "a"}},
+ {{EventKind::Removed, "a"}},
+ {{EventKind::Modified, "a"}}};
+
+ auto DW = DirectoryWatcher::create(
+ fixture.TestWatchedDir,
+ [&TestConsumer](llvm::ArrayRef<DirectoryWatcher::Event> Events,
+ bool IsInitial) {
+ TestConsumer.consume(Events, IsInitial);
+ },
+ /*waitForInitialSync=*/true);
+
+ fixture.deleteFile("a");
+
+ checkEventualResultWithTimeout(TestConsumer);
+}
+
+TEST(DirectoryWatcherTest, DeleteWatchedDir) {
+ DirectoryWatcherTestFixture fixture;
+
+ VerifyingConsumer TestConsumer{
+ {},
+ {{EventKind::WatchedDirRemoved, ""},
+ {EventKind::WatcherGotInvalidated, ""}}};
+
+ auto DW = DirectoryWatcher::create(
+ fixture.TestWatchedDir,
+ [&TestConsumer](llvm::ArrayRef<DirectoryWatcher::Event> Events,
+ bool IsInitial) {
+ TestConsumer.consume(Events, IsInitial);
+ },
+ /*waitForInitialSync=*/true);
+
+ remove_directories(fixture.TestWatchedDir);
+
+ checkEventualResultWithTimeout(TestConsumer);
+}
+
+TEST(DirectoryWatcherTest, InvalidatedWatcher) {
+ DirectoryWatcherTestFixture fixture;
+
+ VerifyingConsumer TestConsumer{
+ {}, {{EventKind::WatcherGotInvalidated, ""}}};
+
+ {
+ auto DW = DirectoryWatcher::create(
+ fixture.TestWatchedDir,
+ [&TestConsumer](llvm::ArrayRef<DirectoryWatcher::Event> Events,
+ bool IsInitial) {
+ TestConsumer.consume(Events, IsInitial);
+ },
+ /*waitForInitialSync=*/true);
+ } // DW is destructed here.
+
+ checkEventualResultWithTimeout(TestConsumer);
+}
\ No newline at end of file
diff --git a/src/llvm-project/clang/unittests/Driver/CMakeLists.txt b/src/llvm-project/clang/unittests/Driver/CMakeLists.txt
index 82dc0ff..55b8a74 100644
--- a/src/llvm-project/clang/unittests/Driver/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/Driver/CMakeLists.txt
@@ -11,7 +11,7 @@
MultilibTest.cpp
)
-target_link_libraries(ClangDriverTests
+clang_target_link_libraries(ClangDriverTests
PRIVATE
clangDriver
clangBasic
diff --git a/src/llvm-project/clang/unittests/Driver/DistroTest.cpp b/src/llvm-project/clang/unittests/Driver/DistroTest.cpp
index bc1863c..d0c86d1 100644
--- a/src/llvm-project/clang/unittests/Driver/DistroTest.cpp
+++ b/src/llvm-project/clang/unittests/Driver/DistroTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Driver/DistroTest.cpp --- ToolChains tests ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/Driver/ModuleCacheTest.cpp b/src/llvm-project/clang/unittests/Driver/ModuleCacheTest.cpp
index 7340889..db3395f 100644
--- a/src/llvm-project/clang/unittests/Driver/ModuleCacheTest.cpp
+++ b/src/llvm-project/clang/unittests/Driver/ModuleCacheTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Driver/ModuleCacheTest.cpp -------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/Driver/MultilibTest.cpp b/src/llvm-project/clang/unittests/Driver/MultilibTest.cpp
index c5e8e09..0731c81 100644
--- a/src/llvm-project/clang/unittests/Driver/MultilibTest.cpp
+++ b/src/llvm-project/clang/unittests/Driver/MultilibTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Driver/MultilibTest.cpp --- Multilib tests ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -350,3 +349,27 @@
Latte.combineWith(Milk);
ASSERT_EQ(Latte.size(), (unsigned)2);
}
+
+TEST(MultilibTest, SetPriority) {
+ MultilibSet MS;
+ MS.push_back(Multilib("foo", {}, {}, 1).flag("+foo"));
+ MS.push_back(Multilib("bar", {}, {}, 2).flag("+bar"));
+
+ Multilib::flags_list Flags1;
+ Flags1.push_back("+foo");
+ Flags1.push_back("-bar");
+ Multilib Selection1;
+ ASSERT_TRUE(MS.select(Flags1, Selection1))
+ << "Flag set was {\"+foo\"}, but selection not found";
+ ASSERT_TRUE(Selection1.gccSuffix() == "/foo")
+ << "Selection picked " << Selection1 << " which was not expected";
+
+ Multilib::flags_list Flags2;
+ Flags2.push_back("+foo");
+ Flags2.push_back("+bar");
+ Multilib Selection2;
+ ASSERT_TRUE(MS.select(Flags2, Selection2))
+ << "Flag set was {\"+bar\"}, but selection not found";
+ ASSERT_TRUE(Selection2.gccSuffix() == "/bar")
+ << "Selection picked " << Selection2 << " which was not expected";
+}
diff --git a/src/llvm-project/clang/unittests/Driver/ToolChainTest.cpp b/src/llvm-project/clang/unittests/Driver/ToolChainTest.cpp
index f118107..80938c8 100644
--- a/src/llvm-project/clang/unittests/Driver/ToolChainTest.cpp
+++ b/src/llvm-project/clang/unittests/Driver/ToolChainTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Driver/ToolChainTest.cpp --- ToolChain tests -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/Format/CMakeLists.txt b/src/llvm-project/clang/unittests/Format/CMakeLists.txt
index 015c25e..d02734a 100644
--- a/src/llvm-project/clang/unittests/Format/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/Format/CMakeLists.txt
@@ -6,6 +6,7 @@
CleanupTest.cpp
FormatTest.cpp
FormatTestComments.cpp
+ FormatTestCSharp.cpp
FormatTestJS.cpp
FormatTestJava.cpp
FormatTestObjC.cpp
@@ -21,7 +22,7 @@
UsingDeclarationsSorterTest.cpp
)
-target_link_libraries(FormatTests
+clang_target_link_libraries(FormatTests
PRIVATE
clangBasic
clangFormat
diff --git a/src/llvm-project/clang/unittests/Format/CleanupTest.cpp b/src/llvm-project/clang/unittests/Format/CleanupTest.cpp
index f4a36d8..0628c38 100644
--- a/src/llvm-project/clang/unittests/Format/CleanupTest.cpp
+++ b/src/llvm-project/clang/unittests/Format/CleanupTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Format/CleanupTest.cpp - Code cleanup unit tests ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -421,8 +420,10 @@
TEST_F(CleanUpReplacementsTest, InsertMultipleNewHeadersAndSortGoogle) {
std::string Code = "\nint x;";
std::string Expected = "\n#include \"fix.h\"\n"
+ "\n"
"#include <list>\n"
"#include <vector>\n"
+ "\n"
"#include \"a.h\"\n"
"#include \"b.h\"\n"
"#include \"c.h\"\n"
diff --git a/src/llvm-project/clang/unittests/Format/FormatTest.cpp b/src/llvm-project/clang/unittests/Format/FormatTest.cpp
index c05fceb..c1cec11 100644
--- a/src/llvm-project/clang/unittests/Format/FormatTest.cpp
+++ b/src/llvm-project/clang/unittests/Format/FormatTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Format/FormatTest.cpp - Formatting unit tests -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -121,6 +120,15 @@
EXPECT_EQ("a\n#b c d\ne", test::messUp("a\n#b\\\nc\\\nd\ne"));
}
+TEST_F(FormatTest, DefaultLLVMStyleIsCpp) {
+ EXPECT_EQ(FormatStyle::LK_Cpp, getLLVMStyle().Language);
+}
+
+TEST_F(FormatTest, LLVMStyleOverride) {
+ EXPECT_EQ(FormatStyle::LK_Proto,
+ getLLVMStyle(FormatStyle::LK_Proto).Language);
+}
+
//===----------------------------------------------------------------------===//
// Basic function tests.
//===----------------------------------------------------------------------===//
@@ -431,7 +439,8 @@
FormatStyle AllowsMergedIf = getLLVMStyle();
AllowsMergedIf.AlignEscapedNewlines = FormatStyle::ENAS_Left;
- AllowsMergedIf.AllowShortIfStatementsOnASingleLine = true;
+ AllowsMergedIf.AllowShortIfStatementsOnASingleLine =
+ FormatStyle::SIS_WithoutElse;
verifyFormat("if (a)\n"
" // comment\n"
" f();",
@@ -479,6 +488,41 @@
verifyFormat("if (a)\n return;", AllowsMergedIf);
}
+TEST_F(FormatTest, FormatIfWithoutCompoundStatementButElseWith) {
+ FormatStyle AllowsMergedIf = getLLVMStyle();
+ AllowsMergedIf.AlignEscapedNewlines = FormatStyle::ENAS_Left;
+ AllowsMergedIf.AllowShortIfStatementsOnASingleLine =
+ FormatStyle::SIS_WithoutElse;
+ verifyFormat("if (a)\n"
+ " f();\n"
+ "else {\n"
+ " g();\n"
+ "}",
+ AllowsMergedIf);
+ verifyFormat("if (a)\n"
+ " f();\n"
+ "else\n"
+ " g();\n",
+ AllowsMergedIf);
+
+ AllowsMergedIf.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Always;
+
+ verifyFormat("if (a) f();\n"
+ "else {\n"
+ " g();\n"
+ "}",
+ AllowsMergedIf);
+ verifyFormat("if (a) f();\n"
+ "else {\n"
+ " if (a) f();\n"
+ " else {\n"
+ " g();\n"
+ " }\n"
+ " g();\n"
+ "}",
+ AllowsMergedIf);
+}
+
TEST_F(FormatTest, FormatLoopsWithoutCompoundStatement) {
FormatStyle AllowsMergedLoops = getLLVMStyle();
AllowsMergedLoops.AllowShortLoopsOnASingleLine = true;
@@ -507,7 +551,8 @@
AllowSimpleBracedStatements.ColumnLimit = 40;
AllowSimpleBracedStatements.AllowShortBlocksOnASingleLine = true;
- AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine = true;
+ AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine =
+ FormatStyle::SIS_WithoutElse;
AllowSimpleBracedStatements.AllowShortLoopsOnASingleLine = true;
AllowSimpleBracedStatements.BreakBeforeBraces = FormatStyle::BS_Custom;
@@ -555,7 +600,8 @@
"};",
AllowSimpleBracedStatements);
- AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine = false;
+ AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine =
+ FormatStyle::SIS_Never;
verifyFormat("if (true) {}", AllowSimpleBracedStatements);
verifyFormat("if (true) {\n"
" f();\n"
@@ -580,7 +626,8 @@
"}",
AllowSimpleBracedStatements);
- AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine = true;
+ AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine =
+ FormatStyle::SIS_WithoutElse;
AllowSimpleBracedStatements.AllowShortLoopsOnASingleLine = true;
AllowSimpleBracedStatements.BraceWrapping.AfterControlStatement = true;
@@ -617,7 +664,8 @@
"}",
AllowSimpleBracedStatements);
- AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine = false;
+ AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine =
+ FormatStyle::SIS_Never;
verifyFormat("if (true) {}", AllowSimpleBracedStatements);
verifyFormat("if (true)\n"
"{\n"
@@ -651,7 +699,7 @@
TEST_F(FormatTest, ShortBlocksInMacrosDontMergeWithCodeAfterMacro) {
FormatStyle Style = getLLVMStyleWithColumns(60);
Style.AllowShortBlocksOnASingleLine = true;
- Style.AllowShortIfStatementsOnASingleLine = true;
+ Style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_WithoutElse;
Style.BreakBeforeBraces = FormatStyle::BS_Allman;
EXPECT_EQ("#define A \\\n"
" if (HANDLEwernufrnuLwrmviferuvnierv) \\\n"
@@ -1069,6 +1117,7 @@
Style.IndentCaseLabels = true;
Style.AllowShortBlocksOnASingleLine = false;
Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+ Style.BraceWrapping.AfterCaseLabel = true;
Style.BraceWrapping.AfterControlStatement = true;
EXPECT_EQ("switch (n)\n"
"{\n"
@@ -1090,6 +1139,27 @@
" }\n"
"}",
Style));
+ Style.BraceWrapping.AfterCaseLabel = false;
+ EXPECT_EQ("switch (n)\n"
+ "{\n"
+ " case 0: {\n"
+ " return false;\n"
+ " }\n"
+ " default: {\n"
+ " return true;\n"
+ " }\n"
+ "}",
+ format("switch (n) {\n"
+ " case 0:\n"
+ " {\n"
+ " return false;\n"
+ " }\n"
+ " default:\n"
+ " {\n"
+ " return true;\n"
+ " }\n"
+ "}",
+ Style));
}
TEST_F(FormatTest, CaseRanges) {
@@ -1243,6 +1313,7 @@
Style));
Style.AllowShortCaseLabelsOnASingleLine = true;
Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+ Style.BraceWrapping.AfterCaseLabel = true;
Style.BraceWrapping.AfterControlStatement = true;
EXPECT_EQ("switch (n)\n"
"{\n"
@@ -1799,9 +1870,117 @@
Style));
}
+TEST_F(FormatTest, NamespaceMacros) {
+ FormatStyle Style = getLLVMStyle();
+ Style.NamespaceMacros.push_back("TESTSUITE");
+
+ verifyFormat("TESTSUITE(A) {\n"
+ "int foo();\n"
+ "} // TESTSUITE(A)",
+ Style);
+
+ verifyFormat("TESTSUITE(A, B) {\n"
+ "int foo();\n"
+ "} // TESTSUITE(A)",
+ Style);
+
+ // Properly indent according to NamespaceIndentation style
+ Style.NamespaceIndentation = FormatStyle::NI_All;
+ verifyFormat("TESTSUITE(A) {\n"
+ " int foo();\n"
+ "} // TESTSUITE(A)",
+ Style);
+ verifyFormat("TESTSUITE(A) {\n"
+ " namespace B {\n"
+ " int foo();\n"
+ " } // namespace B\n"
+ "} // TESTSUITE(A)",
+ Style);
+ verifyFormat("namespace A {\n"
+ " TESTSUITE(B) {\n"
+ " int foo();\n"
+ " } // TESTSUITE(B)\n"
+ "} // namespace A",
+ Style);
+
+ Style.NamespaceIndentation = FormatStyle::NI_Inner;
+ verifyFormat("TESTSUITE(A) {\n"
+ "TESTSUITE(B) {\n"
+ " int foo();\n"
+ "} // TESTSUITE(B)\n"
+ "} // TESTSUITE(A)",
+ Style);
+ verifyFormat("TESTSUITE(A) {\n"
+ "namespace B {\n"
+ " int foo();\n"
+ "} // namespace B\n"
+ "} // TESTSUITE(A)",
+ Style);
+ verifyFormat("namespace A {\n"
+ "TESTSUITE(B) {\n"
+ " int foo();\n"
+ "} // TESTSUITE(B)\n"
+ "} // namespace A",
+ Style);
+
+ // Properly merge namespace-macros blocks in CompactNamespaces mode
+ Style.NamespaceIndentation = FormatStyle::NI_None;
+ Style.CompactNamespaces = true;
+ verifyFormat("TESTSUITE(A) { TESTSUITE(B) {\n"
+ "}} // TESTSUITE(A::B)",
+ Style);
+
+ EXPECT_EQ("TESTSUITE(out) { TESTSUITE(in) {\n"
+ "}} // TESTSUITE(out::in)",
+ format("TESTSUITE(out) {\n"
+ "TESTSUITE(in) {\n"
+ "} // TESTSUITE(in)\n"
+ "} // TESTSUITE(out)",
+ Style));
+
+ EXPECT_EQ("TESTSUITE(out) { TESTSUITE(in) {\n"
+ "}} // TESTSUITE(out::in)",
+ format("TESTSUITE(out) {\n"
+ "TESTSUITE(in) {\n"
+ "} // TESTSUITE(in)\n"
+ "} // TESTSUITE(out)",
+ Style));
+
+ // Do not merge different namespaces/macros
+ EXPECT_EQ("namespace out {\n"
+ "TESTSUITE(in) {\n"
+ "} // TESTSUITE(in)\n"
+ "} // namespace out",
+ format("namespace out {\n"
+ "TESTSUITE(in) {\n"
+ "} // TESTSUITE(in)\n"
+ "} // namespace out",
+ Style));
+ EXPECT_EQ("TESTSUITE(out) {\n"
+ "namespace in {\n"
+ "} // namespace in\n"
+ "} // TESTSUITE(out)",
+ format("TESTSUITE(out) {\n"
+ "namespace in {\n"
+ "} // namespace in\n"
+ "} // TESTSUITE(out)",
+ Style));
+ Style.NamespaceMacros.push_back("FOOBAR");
+ EXPECT_EQ("TESTSUITE(out) {\n"
+ "FOOBAR(in) {\n"
+ "} // FOOBAR(in)\n"
+ "} // TESTSUITE(out)",
+ format("TESTSUITE(out) {\n"
+ "FOOBAR(in) {\n"
+ "} // FOOBAR(in)\n"
+ "} // TESTSUITE(out)",
+ Style));
+}
+
TEST_F(FormatTest, FormatsCompactNamespaces) {
FormatStyle Style = getLLVMStyle();
Style.CompactNamespaces = true;
+ Style.NamespaceMacros.push_back("TESTSUITE");
verifyFormat("namespace A { namespace B {\n"
"}} // namespace A::B",
@@ -2397,6 +2576,12 @@
TEST_F(FormatTest, RespectWhitespaceInMacroDefinitions) {
EXPECT_EQ("#define A (x)", format("#define A (x)"));
EXPECT_EQ("#define A(x)", format("#define A(x)"));
+
+ FormatStyle Style = getLLVMStyle();
+ Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
+ verifyFormat("#define true ((foo)1)", Style);
+ Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
+ verifyFormat("#define false((foo)0)", Style);
}
TEST_F(FormatTest, EmptyLinesInMacroDefinitions) {
@@ -2507,6 +2692,12 @@
verifyFormat("VISIT_GL_CALL(GenBuffers, void, (GLsizei n, GLuint* buffers), "
"(n, buffers))\n",
getChromiumStyle(FormatStyle::LK_Cpp));
+
+ // See PR41483
+ EXPECT_EQ("/**/ FOO(a)\n"
+ "FOO(b)",
+ format("/**/ FOO(a)\n"
+ "FOO(b)"));
}
TEST_F(FormatTest, MacroCallsWithoutTrailingSemicolon) {
@@ -2945,22 +3136,25 @@
EXPECT_EQ(Expected, format(ToFormat, Style));
EXPECT_EQ(Expected, format(Expected, Style));
}
- // Test with tabs.
- Style.UseTab = FormatStyle::UT_Always;
- Style.IndentWidth = 8;
- Style.TabWidth = 8;
- verifyFormat("#ifdef _WIN32\n"
- "#\tdefine A 0\n"
- "#\tifdef VAR2\n"
- "#\t\tdefine B 1\n"
- "#\t\tinclude <someheader.h>\n"
- "#\t\tdefine MACRO \\\n"
- "\t\t\tsome_very_long_func_aaaaaaaaaa();\n"
- "#\tendif\n"
- "#else\n"
- "#\tdefine A 1\n"
- "#endif",
- Style);
+ // Test AfterHash with tabs.
+ {
+ FormatStyle Tabbed = Style;
+ Tabbed.UseTab = FormatStyle::UT_Always;
+ Tabbed.IndentWidth = 8;
+ Tabbed.TabWidth = 8;
+ verifyFormat("#ifdef _WIN32\n"
+ "#\tdefine A 0\n"
+ "#\tifdef VAR2\n"
+ "#\t\tdefine B 1\n"
+ "#\t\tinclude <someheader.h>\n"
+ "#\t\tdefine MACRO \\\n"
+ "\t\t\tsome_very_long_func_aaaaaaaaaa();\n"
+ "#\tendif\n"
+ "#else\n"
+ "#\tdefine A 1\n"
+ "#endif",
+ Tabbed);
+ }
// Regression test: Multiline-macro inside include guards.
verifyFormat("#ifndef HEADER_H\n"
@@ -2970,6 +3164,102 @@
" int j;\n"
"#endif // HEADER_H",
getLLVMStyleWithColumns(20));
+
+ Style.IndentPPDirectives = FormatStyle::PPDIS_BeforeHash;
+ // Basic before hash indent tests
+ verifyFormat("#ifdef _WIN32\n"
+ " #define A 0\n"
+ " #ifdef VAR2\n"
+ " #define B 1\n"
+ " #include <someheader.h>\n"
+ " #define MACRO \\\n"
+ " some_very_long_func_aaaaaaaaaa();\n"
+ " #endif\n"
+ "#else\n"
+ " #define A 1\n"
+ "#endif",
+ Style);
+ verifyFormat("#if A\n"
+ " #define MACRO \\\n"
+ " void a(int x) { \\\n"
+ " b(); \\\n"
+ " c(); \\\n"
+ " d(); \\\n"
+ " e(); \\\n"
+ " f(); \\\n"
+ " }\n"
+ "#endif",
+ Style);
+ // Keep comments aligned with indented directives. These
+ // tests cannot use verifyFormat because messUp manipulates leading
+ // whitespace.
+ {
+ const char *Expected = "void f() {\n"
+ "// Aligned to preprocessor.\n"
+ "#if 1\n"
+ " // Aligned to code.\n"
+ " int a;\n"
+ " #if 1\n"
+ " // Aligned to preprocessor.\n"
+ " #define A 0\n"
+ " // Aligned to code.\n"
+ " int b;\n"
+ " #endif\n"
+ "#endif\n"
+ "}";
+ const char *ToFormat = "void f() {\n"
+ "// Aligned to preprocessor.\n"
+ "#if 1\n"
+ "// Aligned to code.\n"
+ "int a;\n"
+ "#if 1\n"
+ "// Aligned to preprocessor.\n"
+ "#define A 0\n"
+ "// Aligned to code.\n"
+ "int b;\n"
+ "#endif\n"
+ "#endif\n"
+ "}";
+ EXPECT_EQ(Expected, format(ToFormat, Style));
+ EXPECT_EQ(Expected, format(Expected, Style));
+ }
+ {
+ const char *Expected = "void f() {\n"
+ "/* Aligned to preprocessor. */\n"
+ "#if 1\n"
+ " /* Aligned to code. */\n"
+ " int a;\n"
+ " #if 1\n"
+ " /* Aligned to preprocessor. */\n"
+ " #define A 0\n"
+ " /* Aligned to code. */\n"
+ " int b;\n"
+ " #endif\n"
+ "#endif\n"
+ "}";
+ const char *ToFormat = "void f() {\n"
+ "/* Aligned to preprocessor. */\n"
+ "#if 1\n"
+ "/* Aligned to code. */\n"
+ "int a;\n"
+ "#if 1\n"
+ "/* Aligned to preprocessor. */\n"
+ "#define A 0\n"
+ "/* Aligned to code. */\n"
+ "int b;\n"
+ "#endif\n"
+ "#endif\n"
+ "}";
+ EXPECT_EQ(Expected, format(ToFormat, Style));
+ EXPECT_EQ(Expected, format(Expected, Style));
+ }
+
+ // Test single comment before preprocessor
+ verifyFormat("// Comment\n"
+ "\n"
+ "#if 1\n"
+ "#endif",
+ Style);
}
TEST_F(FormatTest, FormatHashIfNotAtStartOfLine) {
@@ -3149,7 +3439,7 @@
TEST_F(FormatTest, FormatsJoinedLinesOnSubsequentRuns) {
FormatStyle SingleLine = getLLVMStyle();
- SingleLine.AllowShortIfStatementsOnASingleLine = true;
+ SingleLine.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_WithoutElse;
verifyFormat("#if 0\n"
"#elif 1\n"
"#endif\n"
@@ -3809,6 +4099,191 @@
" aaaa(aaaa) {}"));
}
+TEST_F(FormatTest, AllowAllConstructorInitializersOnNextLine) {
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
+ Style.ColumnLimit = 60;
+ Style.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
+ Style.AllowAllConstructorInitializersOnNextLine = true;
+ Style.BinPackParameters = false;
+
+ for (int i = 0; i < 4; ++i) {
+ // Test all combinations of parameters that should not have an effect.
+ Style.AllowAllParametersOfDeclarationOnNextLine = i & 1;
+ Style.AllowAllArgumentsOnNextLine = i & 2;
+
+ Style.AllowAllConstructorInitializersOnNextLine = true;
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
+ verifyFormat("Constructor()\n"
+ " : aaaaaaaaaaaaaaaaaaaa(a), bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+ verifyFormat("Constructor() : a(a), b(b) {}", Style);
+
+ Style.AllowAllConstructorInitializersOnNextLine = false;
+ verifyFormat("Constructor()\n"
+ " : aaaaaaaaaaaaaaaaaaaa(a)\n"
+ " , bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+ verifyFormat("Constructor() : a(a), b(b) {}", Style);
+
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
+ Style.AllowAllConstructorInitializersOnNextLine = true;
+ verifyFormat("Constructor()\n"
+ " : aaaaaaaaaaaaaaaaaaaa(a), bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+
+ Style.AllowAllConstructorInitializersOnNextLine = false;
+ verifyFormat("Constructor()\n"
+ " : aaaaaaaaaaaaaaaaaaaa(a),\n"
+ " bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_AfterColon;
+ Style.AllowAllConstructorInitializersOnNextLine = true;
+ verifyFormat("Constructor() :\n"
+ " aaaaaaaaaaaaaaaaaa(a), bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+
+ Style.AllowAllConstructorInitializersOnNextLine = false;
+ verifyFormat("Constructor() :\n"
+ " aaaaaaaaaaaaaaaaaa(a),\n"
+ " bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+ }
+
+ // Test interactions between AllowAllParametersOfDeclarationOnNextLine and
+ // AllowAllConstructorInitializersOnNextLine in all
+ // BreakConstructorInitializers modes
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
+ Style.AllowAllParametersOfDeclarationOnNextLine = true;
+ Style.AllowAllConstructorInitializersOnNextLine = false;
+ verifyFormat("SomeClassWithALongName::Constructor(\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaaa, int bbbbbbbbbbbbb)\n"
+ " : aaaaaaaaaaaaaaaaaaaa(a)\n"
+ " , bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+
+ Style.AllowAllConstructorInitializersOnNextLine = true;
+ verifyFormat("SomeClassWithALongName::Constructor(\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " int bbbbbbbbbbbbb,\n"
+ " int cccccccccccccccc)\n"
+ " : aaaaaaaaaaaaaaaaaaaa(a), bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+
+ Style.AllowAllParametersOfDeclarationOnNextLine = false;
+ Style.AllowAllConstructorInitializersOnNextLine = false;
+ verifyFormat("SomeClassWithALongName::Constructor(\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " int bbbbbbbbbbbbb)\n"
+ " : aaaaaaaaaaaaaaaaaaaa(a)\n"
+ " , bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
+
+ Style.AllowAllParametersOfDeclarationOnNextLine = true;
+ verifyFormat("SomeClassWithALongName::Constructor(\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaaa, int bbbbbbbbbbbbb)\n"
+ " : aaaaaaaaaaaaaaaaaaaa(a),\n"
+ " bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+
+ Style.AllowAllConstructorInitializersOnNextLine = true;
+ verifyFormat("SomeClassWithALongName::Constructor(\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " int bbbbbbbbbbbbb,\n"
+ " int cccccccccccccccc)\n"
+ " : aaaaaaaaaaaaaaaaaaaa(a), bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+
+ Style.AllowAllParametersOfDeclarationOnNextLine = false;
+ Style.AllowAllConstructorInitializersOnNextLine = false;
+ verifyFormat("SomeClassWithALongName::Constructor(\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " int bbbbbbbbbbbbb)\n"
+ " : aaaaaaaaaaaaaaaaaaaa(a),\n"
+ " bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_AfterColon;
+ Style.AllowAllParametersOfDeclarationOnNextLine = true;
+ verifyFormat("SomeClassWithALongName::Constructor(\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaaa, int bbbbbbbbbbbbb) :\n"
+ " aaaaaaaaaaaaaaaaaaaa(a),\n"
+ " bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+
+ Style.AllowAllConstructorInitializersOnNextLine = true;
+ verifyFormat("SomeClassWithALongName::Constructor(\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " int bbbbbbbbbbbbb,\n"
+ " int cccccccccccccccc) :\n"
+ " aaaaaaaaaaaaaaaaaaaa(a), bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+
+ Style.AllowAllParametersOfDeclarationOnNextLine = false;
+ Style.AllowAllConstructorInitializersOnNextLine = false;
+ verifyFormat("SomeClassWithALongName::Constructor(\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " int bbbbbbbbbbbbb) :\n"
+ " aaaaaaaaaaaaaaaaaaaa(a),\n"
+ " bbbbbbbbbbbbbbbbbbbbb(b) {}",
+ Style);
+}
+
+TEST_F(FormatTest, AllowAllArgumentsOnNextLine) {
+ FormatStyle Style = getLLVMStyle();
+ Style.ColumnLimit = 60;
+ Style.BinPackArguments = false;
+ for (int i = 0; i < 4; ++i) {
+ // Test all combinations of parameters that should not have an effect.
+ Style.AllowAllParametersOfDeclarationOnNextLine = i & 1;
+ Style.AllowAllConstructorInitializersOnNextLine = i & 2;
+
+ Style.AllowAllArgumentsOnNextLine = true;
+ verifyFormat("void foo() {\n"
+ " FunctionCallWithReallyLongName(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbb);\n"
+ "}",
+ Style);
+ Style.AllowAllArgumentsOnNextLine = false;
+ verifyFormat("void foo() {\n"
+ " FunctionCallWithReallyLongName(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " bbbbbbbbbbbb);\n"
+ "}",
+ Style);
+
+ Style.AllowAllArgumentsOnNextLine = true;
+ verifyFormat("void foo() {\n"
+ " auto VariableWithReallyLongName = {\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbb};\n"
+ "}",
+ Style);
+ Style.AllowAllArgumentsOnNextLine = false;
+ verifyFormat("void foo() {\n"
+ " auto VariableWithReallyLongName = {\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " bbbbbbbbbbbb};\n"
+ "}",
+ Style);
+ }
+
+ // This parameter should not affect declarations.
+ Style.BinPackParameters = false;
+ Style.AllowAllArgumentsOnNextLine = false;
+ Style.AllowAllParametersOfDeclarationOnNextLine = true;
+ verifyFormat("void FunctionCallWithReallyLongName(\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaa, int bbbbbbbbbbbb);",
+ Style);
+ Style.AllowAllParametersOfDeclarationOnNextLine = false;
+ verifyFormat("void FunctionCallWithReallyLongName(\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " int bbbbbbbbbbbb);",
+ Style);
+}
+
TEST_F(FormatTest, BreakConstructorInitializersAfterColon) {
FormatStyle Style = getLLVMStyle();
Style.BreakConstructorInitializers = FormatStyle::BCIS_AfterColon;
@@ -3826,17 +4301,23 @@
verifyFormat("template <typename T>\n"
"Constructor() : Initializer(FitsOnTheLine) {}",
getStyleWithColumns(Style, 50));
-
+ Style.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
verifyFormat(
"SomeClass::Constructor() :\n"
" aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaaaa(aaaaaaaaaaaa) {}",
- Style);
+ Style);
+
+ Style.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
+ verifyFormat(
+ "SomeClass::Constructor() :\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaaaa(aaaaaaaaaaaa) {}",
+ Style);
verifyFormat(
"SomeClass::Constructor() :\n"
" aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
" aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}",
- Style);
+ Style);
verifyFormat(
"SomeClass::Constructor() :\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
@@ -3882,7 +4363,7 @@
FormatStyle OnePerLine = Style;
OnePerLine.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
- OnePerLine.AllowAllParametersOfDeclarationOnNextLine = false;
+ OnePerLine.AllowAllConstructorInitializersOnNextLine = false;
verifyFormat("SomeClass::Constructor() :\n"
" aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
" aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
@@ -4184,6 +4665,18 @@
Style);
}
+TEST_F(FormatTest, DontBreakBeforeQualifiedOperator) {
+ // Regression test for https://bugs.llvm.org/show_bug.cgi?id=40516:
+ // Prefer keeping `::` followed by `operator` together.
+ EXPECT_EQ("const aaaa::bbbbbbb &\n"
+ "ccccccccc::operator++() {\n"
+ " stuff();\n"
+ "}",
+ format("const aaaa::bbbbbbb\n"
+ "&ccccccccc::operator++() { stuff(); }",
+ getLLVMStyleWithColumns(40)));
+}
+
TEST_F(FormatTest, TrailingReturnType) {
verifyFormat("auto foo() -> int;\n");
verifyFormat("struct S {\n"
@@ -5359,6 +5852,62 @@
"}\n"
"template <class T> T *f(T &c);\n", // No break here.
Style);
+ verifyFormat("int\n"
+ "foo(A<bool> a)\n"
+ "{\n"
+ " return a;\n"
+ "}\n",
+ Style);
+ verifyFormat("int\n"
+ "foo(A<8> a)\n"
+ "{\n"
+ " return a;\n"
+ "}\n",
+ Style);
+ verifyFormat("int\n"
+ "foo(A<B<bool>, 8> a)\n"
+ "{\n"
+ " return a;\n"
+ "}\n",
+ Style);
+ verifyFormat("int\n"
+ "foo(A<B<8>, bool> a)\n"
+ "{\n"
+ " return a;\n"
+ "}\n",
+ Style);
+ verifyFormat("int\n"
+ "foo(A<B<bool>, bool> a)\n"
+ "{\n"
+ " return a;\n"
+ "}\n",
+ Style);
+ verifyFormat("int\n"
+ "foo(A<B<8>, 8> a)\n"
+ "{\n"
+ " return a;\n"
+ "}\n",
+ Style);
+
+ Style = getGNUStyle();
+
+ // Test for comments at the end of function declarations.
+ verifyFormat("void\n"
+ "foo (int a, /*abc*/ int b) // def\n"
+ "{\n"
+ "}\n",
+ Style);
+
+ verifyFormat("void\n"
+ "foo (int a, /* abc */ int b) /* def */\n"
+ "{\n"
+ "}\n",
+ Style);
+
+ // Definitions that should not break after return type
+ verifyFormat("void foo (int a, int b); // def\n", Style);
+ verifyFormat("void foo (int a, int b); /* def */\n", Style);
+ verifyFormat("void foo (int a, int b);\n", Style);
}
TEST_F(FormatTest, AlwaysBreakBeforeMultilineStrings) {
@@ -6478,6 +7027,12 @@
// On the other hand, we still need to correctly find array subscripts.
verifyFormat("int a = std::vector<int>{1, 2, 3}[0];");
+ // Make sure that we do not mistake Objective-C method inside array literals
+ // as attributes, even if those method names are also keywords.
+ verifyFormat("@[ [foo bar] ];");
+ verifyFormat("@[ [NSArray class] ];");
+ verifyFormat("@[ [foo enum] ];");
+
// Make sure we do not parse attributes as lambda introducers.
FormatStyle MultiLineFunctions = getLLVMStyle();
MultiLineFunctions.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
@@ -7980,7 +8535,8 @@
TEST_F(FormatTest, MergeHandlingInTheFaceOfPreprocessorDirectives) {
FormatStyle AllowsMergedIf = getGoogleStyle();
- AllowsMergedIf.AllowShortIfStatementsOnASingleLine = true;
+ AllowsMergedIf.AllowShortIfStatementsOnASingleLine =
+ FormatStyle::SIS_WithoutElse;
verifyFormat("void f() { f(); }\n#error E", AllowsMergedIf);
verifyFormat("if (true) return 42;\n#error E", AllowsMergedIf);
verifyFormat("if (true)\n#error E\n return 42;", AllowsMergedIf);
@@ -8740,6 +9296,9 @@
"\t\t parameter2); \\\n"
"\t}",
Tab);
+ verifyFormat("int a;\t // x\n"
+ "int bbbbbbbb; // x\n",
+ Tab);
Tab.TabWidth = 4;
Tab.IndentWidth = 8;
@@ -9224,6 +9783,7 @@
verifyFormat("typedef void (*cb)(int);", NoSpace);
verifyFormat("T A::operator()();", NoSpace);
verifyFormat("X A::operator++(T);", NoSpace);
+ verifyFormat("auto lambda = []() { return 0; };", NoSpace);
FormatStyle Space = getLLVMStyle();
Space.SpaceBeforeParens = FormatStyle::SBPO_Always;
@@ -9271,6 +9831,72 @@
verifyFormat("typedef void (*cb) (int);", Space);
verifyFormat("T A::operator() ();", Space);
verifyFormat("X A::operator++ (T);", Space);
+ verifyFormat("auto lambda = [] () { return 0; };", Space);
+ verifyFormat("int x = int (y);", Space);
+
+ FormatStyle SomeSpace = getLLVMStyle();
+ SomeSpace.SpaceBeforeParens = FormatStyle::SBPO_NonEmptyParentheses;
+
+ verifyFormat("[]() -> float {}", SomeSpace);
+ verifyFormat("[] (auto foo) {}", SomeSpace);
+ verifyFormat("[foo]() -> int {}", SomeSpace);
+ verifyFormat("int f();", SomeSpace);
+ verifyFormat("void f (int a, T b) {\n"
+ " while (true)\n"
+ " continue;\n"
+ "}",
+ SomeSpace);
+ verifyFormat("if (true)\n"
+ " f();\n"
+ "else if (true)\n"
+ " f();",
+ SomeSpace);
+ verifyFormat("do {\n"
+ " do_something();\n"
+ "} while (something());",
+ SomeSpace);
+ verifyFormat("switch (x) {\n"
+ "default:\n"
+ " break;\n"
+ "}",
+ SomeSpace);
+ verifyFormat("A::A() : a (1) {}", SomeSpace);
+ verifyFormat("void f() __attribute__ ((asdf));", SomeSpace);
+ verifyFormat("*(&a + 1);\n"
+ "&((&a)[1]);\n"
+ "a[(b + c) * d];\n"
+ "(((a + 1) * 2) + 3) * 4;",
+ SomeSpace);
+ verifyFormat("#define A(x) x", SomeSpace);
+ verifyFormat("#define A (x) x", SomeSpace);
+ verifyFormat("#if defined(x)\n"
+ "#endif",
+ SomeSpace);
+ verifyFormat("auto i = std::make_unique<int> (5);", SomeSpace);
+ verifyFormat("size_t x = sizeof (x);", SomeSpace);
+ verifyFormat("auto f (int x) -> decltype (x);", SomeSpace);
+ verifyFormat("int f (T x) noexcept (x.create());", SomeSpace);
+ verifyFormat("alignas (128) char a[128];", SomeSpace);
+ verifyFormat("size_t x = alignof (MyType);", SomeSpace);
+ verifyFormat("static_assert (sizeof (char) == 1, \"Impossible!\");",
+ SomeSpace);
+ verifyFormat("int f() throw (Deprecated);", SomeSpace);
+ verifyFormat("typedef void (*cb) (int);", SomeSpace);
+ verifyFormat("T A::operator()();", SomeSpace);
+ verifyFormat("X A::operator++ (T);", SomeSpace);
+ verifyFormat("int x = int (y);", SomeSpace);
+ verifyFormat("auto lambda = []() { return 0; };", SomeSpace);
+}
+
+TEST_F(FormatTest, SpaceAfterLogicalNot) {
+ FormatStyle Spaces = getLLVMStyle();
+ Spaces.SpaceAfterLogicalNot = true;
+
+ verifyFormat("bool x = ! y", Spaces);
+ verifyFormat("if (! isFailure())", Spaces);
+ verifyFormat("if (! (a && b))", Spaces);
+ verifyFormat("\"Error!\"", Spaces);
+ verifyFormat("! ! x", Spaces);
}
TEST_F(FormatTest, ConfigurableSpacesInParentheses) {
@@ -9545,8 +10171,104 @@
NoSpaceStyle);
}
+TEST_F(FormatTest, AlignConsecutiveMacros) {
+ FormatStyle Style = getLLVMStyle();
+ Style.AlignConsecutiveAssignments = true;
+ Style.AlignConsecutiveDeclarations = true;
+ Style.AlignConsecutiveMacros = false;
+
+ verifyFormat("#define a 3\n"
+ "#define bbbb 4\n"
+ "#define ccc (5)",
+ Style);
+
+ verifyFormat("#define f(x) (x * x)\n"
+ "#define fff(x, y, z) (x * y + z)\n"
+ "#define ffff(x, y) (x - y)",
+ Style);
+
+ verifyFormat("#define foo(x, y) (x + y)\n"
+ "#define bar (5, 6)(2 + 2)",
+ Style);
+
+ verifyFormat("#define a 3\n"
+ "#define bbbb 4\n"
+ "#define ccc (5)\n"
+ "#define f(x) (x * x)\n"
+ "#define fff(x, y, z) (x * y + z)\n"
+ "#define ffff(x, y) (x - y)",
+ Style);
+
+ Style.AlignConsecutiveMacros = true;
+ verifyFormat("#define a 3\n"
+ "#define bbbb 4\n"
+ "#define ccc (5)",
+ Style);
+
+ verifyFormat("#define f(x) (x * x)\n"
+ "#define fff(x, y, z) (x * y + z)\n"
+ "#define ffff(x, y) (x - y)",
+ Style);
+
+ verifyFormat("#define foo(x, y) (x + y)\n"
+ "#define bar (5, 6)(2 + 2)",
+ Style);
+
+ verifyFormat("#define a 3\n"
+ "#define bbbb 4\n"
+ "#define ccc (5)\n"
+ "#define f(x) (x * x)\n"
+ "#define fff(x, y, z) (x * y + z)\n"
+ "#define ffff(x, y) (x - y)",
+ Style);
+
+ verifyFormat("#define a 5\n"
+ "#define foo(x, y) (x + y)\n"
+ "#define CCC (6)\n"
+ "auto lambda = []() {\n"
+ " auto ii = 0;\n"
+ " float j = 0;\n"
+ " return 0;\n"
+ "};\n"
+ "int i = 0;\n"
+ "float i2 = 0;\n"
+ "auto v = type{\n"
+ " i = 1, //\n"
+ " (i = 2), //\n"
+ " i = 3 //\n"
+ "};",
+ Style);
+
+ Style.AlignConsecutiveMacros = false;
+ Style.ColumnLimit = 20;
+
+ verifyFormat("#define a \\\n"
+ " \"aabbbbbbbbbbbb\"\n"
+ "#define D \\\n"
+ " \"aabbbbbbbbbbbb\" \\\n"
+ " \"ccddeeeeeeeee\"\n"
+ "#define B \\\n"
+ " \"QQQQQQQQQQQQQ\" \\\n"
+ " \"FFFFFFFFFFFFF\" \\\n"
+ " \"LLLLLLLL\"\n",
+ Style);
+
+ Style.AlignConsecutiveMacros = true;
+ verifyFormat("#define a \\\n"
+ " \"aabbbbbbbbbbbb\"\n"
+ "#define D \\\n"
+ " \"aabbbbbbbbbbbb\" \\\n"
+ " \"ccddeeeeeeeee\"\n"
+ "#define B \\\n"
+ " \"QQQQQQQQQQQQQ\" \\\n"
+ " \"FFFFFFFFFFFFF\" \\\n"
+ " \"LLLLLLLL\"\n",
+ Style);
+}
+
TEST_F(FormatTest, AlignConsecutiveAssignments) {
FormatStyle Alignment = getLLVMStyle();
+ Alignment.AlignConsecutiveMacros = true;
Alignment.AlignConsecutiveAssignments = false;
verifyFormat("int a = 5;\n"
"int oneTwoThree = 123;",
@@ -9736,6 +10458,7 @@
TEST_F(FormatTest, AlignConsecutiveDeclarations) {
FormatStyle Alignment = getLLVMStyle();
+ Alignment.AlignConsecutiveMacros = true;
Alignment.AlignConsecutiveDeclarations = false;
verifyFormat("float const a = 5;\n"
"int oneTwoThree = 123;",
@@ -10069,6 +10792,13 @@
" unsigned c;\n"
"}",
Alignment);
+
+ // See PR37175
+ FormatStyle Style = getMozillaStyle();
+ Style.AlignConsecutiveDeclarations = true;
+ EXPECT_EQ("DECOR1 /**/ int8_t /**/ DECOR2 /**/\n"
+ "foo(int a);",
+ format("DECOR1 /**/ int8_t /**/ DECOR2 /**/ foo (int a);", Style));
}
TEST_F(FormatTest, LinuxBraceBreaking) {
@@ -10400,7 +11130,8 @@
AllmanBraceStyle.ColumnLimit = 80;
FormatStyle BreakBeforeBraceShortIfs = AllmanBraceStyle;
- BreakBeforeBraceShortIfs.AllowShortIfStatementsOnASingleLine = true;
+ BreakBeforeBraceShortIfs.AllowShortIfStatementsOnASingleLine =
+ FormatStyle::SIS_WithoutElse;
BreakBeforeBraceShortIfs.AllowShortLoopsOnASingleLine = true;
verifyFormat("void f(bool b)\n"
"{\n"
@@ -10630,6 +11361,24 @@
FormatStyle Style = getLLVMStyle();
Style.ColumnLimit = 20;
+ // See PR41213
+ EXPECT_EQ("/*\n"
+ " *\t9012345\n"
+ " * /8901\n"
+ " */",
+ format("/*\n"
+ " *\t9012345 /8901\n"
+ " */",
+ Style));
+ EXPECT_EQ("/*\n"
+ " *345678\n"
+ " *\t/8901\n"
+ " */",
+ format("/*\n"
+ " *345678\t/8901\n"
+ " */",
+ Style));
+
verifyFormat("int a; // the\n"
" // comment", Style);
EXPECT_EQ("int a; /* first line\n"
@@ -10859,10 +11608,12 @@
CHECK_PARSE_BOOL(AlignTrailingComments);
CHECK_PARSE_BOOL(AlignConsecutiveAssignments);
CHECK_PARSE_BOOL(AlignConsecutiveDeclarations);
+ CHECK_PARSE_BOOL(AlignConsecutiveMacros);
+ CHECK_PARSE_BOOL(AllowAllArgumentsOnNextLine);
+ CHECK_PARSE_BOOL(AllowAllConstructorInitializersOnNextLine);
CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine);
CHECK_PARSE_BOOL(AllowShortBlocksOnASingleLine);
CHECK_PARSE_BOOL(AllowShortCaseLabelsOnASingleLine);
- CHECK_PARSE_BOOL(AllowShortIfStatementsOnASingleLine);
CHECK_PARSE_BOOL(AllowShortLoopsOnASingleLine);
CHECK_PARSE_BOOL(BinPackArguments);
CHECK_PARSE_BOOL(BinPackParameters);
@@ -10891,12 +11642,14 @@
CHECK_PARSE_BOOL(SpacesInCStyleCastParentheses);
CHECK_PARSE_BOOL(SpaceAfterCStyleCast);
CHECK_PARSE_BOOL(SpaceAfterTemplateKeyword);
+ CHECK_PARSE_BOOL(SpaceAfterLogicalNot);
CHECK_PARSE_BOOL(SpaceBeforeAssignmentOperators);
CHECK_PARSE_BOOL(SpaceBeforeCpp11BracedList);
CHECK_PARSE_BOOL(SpaceBeforeCtorInitializerColon);
CHECK_PARSE_BOOL(SpaceBeforeInheritanceColon);
CHECK_PARSE_BOOL(SpaceBeforeRangeBasedForLoopColon);
+ CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterCaseLabel);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterClass);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterControlStatement);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterEnum);
@@ -11055,6 +11808,8 @@
FormatStyle::SBPO_Always);
CHECK_PARSE("SpaceBeforeParens: ControlStatements", SpaceBeforeParens,
FormatStyle::SBPO_ControlStatements);
+ CHECK_PARSE("SpaceBeforeParens: NonEmptyParentheses", SpaceBeforeParens,
+ FormatStyle::SBPO_NonEmptyParentheses);
// For backward compatibility:
CHECK_PARSE("SpaceAfterControlStatementKeyword: false", SpaceBeforeParens,
FormatStyle::SBPO_Never);
@@ -11125,6 +11880,20 @@
CHECK_PARSE("NamespaceIndentation: All", NamespaceIndentation,
FormatStyle::NI_All);
+ Style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Always;
+ CHECK_PARSE("AllowShortIfStatementsOnASingleLine: Never",
+ AllowShortIfStatementsOnASingleLine, FormatStyle::SIS_Never);
+ CHECK_PARSE("AllowShortIfStatementsOnASingleLine: WithoutElse",
+ AllowShortIfStatementsOnASingleLine,
+ FormatStyle::SIS_WithoutElse);
+ CHECK_PARSE("AllowShortIfStatementsOnASingleLine: Always",
+ AllowShortIfStatementsOnASingleLine, FormatStyle::SIS_Always);
+ CHECK_PARSE("AllowShortIfStatementsOnASingleLine: false",
+ AllowShortIfStatementsOnASingleLine, FormatStyle::SIS_Never);
+ CHECK_PARSE("AllowShortIfStatementsOnASingleLine: true",
+ AllowShortIfStatementsOnASingleLine,
+ FormatStyle::SIS_WithoutElse);
+
// FIXME: This is required because parsing a configuration simply overwrites
// the first N elements of the list instead of resetting it.
Style.ForEachMacros.clear();
@@ -11143,6 +11912,12 @@
CHECK_PARSE("StatementMacros: [QUNUSED, QT_REQUIRE_VERSION]", StatementMacros,
std::vector<std::string>({"QUNUSED", "QT_REQUIRE_VERSION"}));
+ Style.NamespaceMacros.clear();
+ CHECK_PARSE("NamespaceMacros: [TESTSUITE]", NamespaceMacros,
+ std::vector<std::string>{"TESTSUITE"});
+ CHECK_PARSE("NamespaceMacros: [TESTSUITE, SUITE]", NamespaceMacros,
+ std::vector<std::string>({"TESTSUITE", "SUITE"}));
+
Style.IncludeStyle.IncludeCategories.clear();
std::vector<tooling::IncludeStyle::IncludeCategory> ExpectedCategories = {
{"abc/.*", 2}, {".*", 1}};
@@ -11482,6 +12257,13 @@
"bool smaller = 1 < bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
Style);
+
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_AfterColon;
+ verifyFormat(
+ "SomeClass::Constructor() :\n"
+ "aaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaa),\n"
+ "aaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaa) {}",
+ Style);
}
TEST_F(FormatTest, BreakConstructorInitializersBeforeComma) {
@@ -11726,6 +12508,8 @@
TEST_F(FormatTest, FormatsLambdas) {
verifyFormat("int c = [b]() mutable { return [&b] { return b++; }(); }();\n");
+ verifyFormat(
+ "int c = [b]() mutable noexcept { return [&b] { return b++; }(); }();\n");
verifyFormat("int c = [&] { [=] { return b++; }(); }();\n");
verifyFormat("int c = [&, &a, a] { [=, c, &d] { return b++; }(); }();\n");
verifyFormat("int c = [&a, &a, a] { [=, a, b, &c] { return b++; }(); }();\n");
@@ -11819,6 +12603,111 @@
verifyGoogleFormat("auto a = [&b, c](D* d) -> D& {};");
verifyGoogleFormat("auto a = [&b, c](D* d) -> const D* {};");
verifyFormat("[a, a]() -> a<1> {};");
+ verifyFormat("[]() -> foo<5 + 2> { return {}; };");
+ verifyFormat("[]() -> foo<5 - 2> { return {}; };");
+ verifyFormat("[]() -> foo<5 / 2> { return {}; };");
+ verifyFormat("[]() -> foo<5 * 2> { return {}; };");
+ verifyFormat("[]() -> foo<5 % 2> { return {}; };");
+ verifyFormat("[]() -> foo<5 << 2> { return {}; };");
+ verifyFormat("[]() -> foo<!5> { return {}; };");
+ verifyFormat("[]() -> foo<~5> { return {}; };");
+ verifyFormat("[]() -> foo<5 | 2> { return {}; };");
+ verifyFormat("[]() -> foo<5 || 2> { return {}; };");
+ verifyFormat("[]() -> foo<5 & 2> { return {}; };");
+ verifyFormat("[]() -> foo<5 && 2> { return {}; };");
+ verifyFormat("[]() -> foo<5 == 2> { return {}; };");
+ verifyFormat("[]() -> foo<5 != 2> { return {}; };");
+ verifyFormat("[]() -> foo<5 >= 2> { return {}; };");
+ verifyFormat("[]() -> foo<5 <= 2> { return {}; };");
+ verifyFormat("[]() -> foo<5 < 2> { return {}; };");
+ verifyFormat("[]() -> foo<2 ? 1 : 0> { return {}; };");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 + 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 - 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 / 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 * 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 % 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 << 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<!5> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<~5> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 | 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 || 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 & 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 && 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 == 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 != 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 >= 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 <= 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<5 < 2> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("namespace bar {\n"
+ "// broken:\n"
+ "auto foo{[]() -> foo<2 ? 1 : 0> { return {}; }};\n"
+ "} // namespace bar");
+ verifyFormat("[]() -> a<1> {};");
+ verifyFormat("[]() -> a<1> { ; };");
+ verifyFormat("[]() -> a<1> { ; }();");
+ verifyFormat("[a, a]() -> a<true> {};");
+ verifyFormat("[]() -> a<true> {};");
+ verifyFormat("[]() -> a<true> { ; };");
+ verifyFormat("[]() -> a<true> { ; }();");
+ verifyFormat("[a, a]() -> a<false> {};");
+ verifyFormat("[]() -> a<false> {};");
+ verifyFormat("[]() -> a<false> { ; };");
+ verifyFormat("[]() -> a<false> { ; }();");
+ verifyFormat("auto foo{[]() -> foo<false> { ; }};");
+ verifyFormat("namespace bar {\n"
+ "auto foo{[]() -> foo<false> { ; }};\n"
+ "} // namespace bar");
verifyFormat("auto aaaaaaaa = [](int i, // break for some reason\n"
" int j) -> int {\n"
" return ffffffffffffffffffffffffffffffffffffffffffff(i * j);\n"
@@ -11953,6 +12842,43 @@
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> {\n"
" //\n"
" });");
+
+ FormatStyle DoNotMerge = getLLVMStyle();
+ DoNotMerge.AllowShortLambdasOnASingleLine = FormatStyle::SLS_None;
+ verifyFormat("auto c = []() {\n"
+ " return b;\n"
+ "};",
+ "auto c = []() { return b; };", DoNotMerge);
+ verifyFormat("auto c = []() {\n"
+ "};",
+ " auto c = []() {};", DoNotMerge);
+
+ FormatStyle MergeEmptyOnly = getLLVMStyle();
+ MergeEmptyOnly.AllowShortLambdasOnASingleLine = FormatStyle::SLS_Empty;
+ verifyFormat("auto c = []() {\n"
+ " return b;\n"
+ "};",
+ "auto c = []() {\n"
+ " return b;\n"
+ " };",
+ MergeEmptyOnly);
+ verifyFormat("auto c = []() {};",
+ "auto c = []() {\n"
+ "};",
+ MergeEmptyOnly);
+
+ FormatStyle MergeInline = getLLVMStyle();
+ MergeInline.AllowShortLambdasOnASingleLine = FormatStyle::SLS_Inline;
+ verifyFormat("auto c = []() {\n"
+ " return b;\n"
+ "};",
+ "auto c = []() { return b; };", MergeInline);
+ verifyFormat("function([]() { return b; })", "function([]() { return b; })",
+ MergeInline);
+ verifyFormat("function([]() { return b; }, a)",
+ "function([]() { return b; }, a)", MergeInline);
+ verifyFormat("function(a, []() { return b; })",
+ "function(a, []() { return b; })", MergeInline);
}
TEST_F(FormatTest, EmptyLinesInLambdas) {
@@ -12180,6 +13106,12 @@
"should not introduce\r\n"
"an extra carriage return\r\n"
"*/\r\n"));
+ EXPECT_EQ("/*\r\n"
+ "\r\n"
+ "*/",
+ format("/*\r\n"
+ " \r\r\r\n"
+ "*/"));
}
TEST_F(FormatTest, MunchSemicolonAfterBlocks) {
@@ -12207,6 +13139,22 @@
format("int i = longFunction(arg);", SixIndent));
}
+TEST_F(FormatTest, WrappedClosingParenthesisIndent) {
+ FormatStyle Style = getLLVMStyle();
+ verifyFormat("int Foo::getter(\n"
+ " //\n"
+ ") const {\n"
+ " return foo;\n"
+ "}",
+ Style);
+ verifyFormat("void Foo::setter(\n"
+ " //\n"
+ ") {\n"
+ " foo = 1;\n"
+ "}",
+ Style);
+}
+
TEST_F(FormatTest, SpacesInAngles) {
FormatStyle Spaces = getLLVMStyle();
Spaces.SpacesInAngles = true;
@@ -12527,6 +13475,11 @@
auto Style7 = getStyle("file", "/d/.clang-format", "LLVM", "", &FS);
ASSERT_FALSE((bool)Style7);
llvm::consumeError(Style7.takeError());
+
+ // Test 8: inferred per-language defaults apply.
+ auto StyleTd = getStyle("file", "x.td", "llvm", "", &FS);
+ ASSERT_TRUE((bool)StyleTd);
+ ASSERT_EQ(*StyleTd, getLLVMStyle(FormatStyle::LK_TableGen));
}
TEST_F(ReplacementTest, FormatCodeAfterReplacements) {
@@ -12734,6 +13687,9 @@
guessLanguage("foo.h", "[[using gsl: suppress(\"type\")]];"));
EXPECT_EQ(
FormatStyle::LK_Cpp,
+ guessLanguage("foo.h", "for (auto &&[endpoint, stream] : streams_)"));
+ EXPECT_EQ(
+ FormatStyle::LK_Cpp,
guessLanguage("foo.h",
"[[clang::callable_when(\"unconsumed\", \"unknown\")]]"));
EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
@@ -12807,6 +13763,35 @@
guessLanguage("foo.h", "#define FOO ({ foo(); ({ NSString *s; }) })"));
}
+TEST_F(FormatTest, TypenameMacros) {
+ std::vector<std::string> TypenameMacros = {"STACK_OF", "LIST", "TAILQ_ENTRY"};
+
+ // Test case reported in https://bugs.llvm.org/show_bug.cgi?id=30353
+ FormatStyle Google = getGoogleStyleWithColumns(0);
+ Google.TypenameMacros = TypenameMacros;
+ verifyFormat("struct foo {\n"
+ " int bar;\n"
+ " TAILQ_ENTRY(a) bleh;\n"
+ "};", Google);
+
+ FormatStyle Macros = getLLVMStyle();
+ Macros.TypenameMacros = TypenameMacros;
+
+ verifyFormat("STACK_OF(int) a;", Macros);
+ verifyFormat("STACK_OF(int) *a;", Macros);
+ verifyFormat("STACK_OF(int const *) *a;", Macros);
+ verifyFormat("STACK_OF(int *const) *a;", Macros);
+ verifyFormat("STACK_OF(int, string) a;", Macros);
+ verifyFormat("STACK_OF(LIST(int)) a;", Macros);
+ verifyFormat("STACK_OF(LIST(int)) a, b;", Macros);
+ verifyFormat("for (LIST(int) *a = NULL; a;) {\n}", Macros);
+ verifyFormat("STACK_OF(int) f(LIST(int) *arg);", Macros);
+
+ Macros.PointerAlignment = FormatStyle::PAS_Left;
+ verifyFormat("STACK_OF(int)* a;", Macros);
+ verifyFormat("STACK_OF(int*)* a;", Macros);
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
diff --git a/src/llvm-project/clang/unittests/Format/FormatTestCSharp.cpp b/src/llvm-project/clang/unittests/Format/FormatTestCSharp.cpp
new file mode 100644
index 0000000..801adb2
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Format/FormatTestCSharp.cpp
@@ -0,0 +1,184 @@
+//===- unittest/Format/FormatTestCSharp.cpp - Formatting tests for CSharp -===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "FormatTestUtils.h"
+#include "clang/Format/Format.h"
+#include "llvm/Support/Debug.h"
+#include "gtest/gtest.h"
+
+#define DEBUG_TYPE "format-test"
+
+namespace clang {
+namespace format {
+
+class FormatTestCSharp : public ::testing::Test {
+protected:
+ static std::string format(llvm::StringRef Code, unsigned Offset,
+ unsigned Length, const FormatStyle &Style) {
+ LLVM_DEBUG(llvm::errs() << "---\n");
+ LLVM_DEBUG(llvm::errs() << Code << "\n\n");
+ std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
+ tooling::Replacements Replaces = reformat(Style, Code, Ranges);
+ auto Result = applyAllReplacements(Code, Replaces);
+ EXPECT_TRUE(static_cast<bool>(Result));
+ LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
+ return *Result;
+ }
+
+ static std::string
+ format(llvm::StringRef Code,
+ const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_CSharp)) {
+ return format(Code, 0, Code.size(), Style);
+ }
+
+ static FormatStyle getStyleWithColumns(unsigned ColumnLimit) {
+ FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
+ Style.ColumnLimit = ColumnLimit;
+ return Style;
+ }
+
+ static void verifyFormat(
+ llvm::StringRef Code,
+ const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_CSharp)) {
+ EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable";
+ EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
+ }
+};
+
+TEST_F(FormatTestCSharp, CSharpClass) {
+ verifyFormat("public class SomeClass {\n"
+ " void f() {}\n"
+ " int g() { return 0; }\n"
+ " void h() {\n"
+ " while (true) f();\n"
+ " for (;;) f();\n"
+ " if (true) f();\n"
+ " }\n"
+ "}");
+}
+
+TEST_F(FormatTestCSharp, AccessModifiers) {
+ verifyFormat("public String toString() {}");
+ verifyFormat("private String toString() {}");
+ verifyFormat("protected String toString() {}");
+ verifyFormat("internal String toString() {}");
+
+ verifyFormat("public override String toString() {}");
+ verifyFormat("private override String toString() {}");
+ verifyFormat("protected override String toString() {}");
+ verifyFormat("internal override String toString() {}");
+
+ verifyFormat("internal static String toString() {}");
+}
+
+TEST_F(FormatTestCSharp, NoStringLiteralBreaks) {
+ verifyFormat("foo("
+ "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa\");");
+}
+
+TEST_F(FormatTestCSharp, CSharpVerbatiumStringLiterals) {
+ verifyFormat("foo(@\"aaaaaaaa\\abc\\aaaa\");");
+ // @"ABC\" + ToString("B") - handle embedded \ in literal string at
+ // the end
+ //
+ /*
+ * After removal of Lexer change we are currently not able
+ * To handle these cases
+ verifyFormat("string s = @\"ABC\\\" + ToString(\"B\");");
+ verifyFormat("string s = @\"ABC\"\"DEF\"\"GHI\"");
+ verifyFormat("string s = @\"ABC\"\"DEF\"\"\"");
+ verifyFormat("string s = @\"ABC\"\"DEF\"\"\" + abc");
+ */
+}
+
+TEST_F(FormatTestCSharp, CSharpInterpolatedStringLiterals) {
+ verifyFormat("foo($\"aaaaaaaa{aaa}aaaa\");");
+ verifyFormat("foo($\"aaaa{A}\");");
+ verifyFormat(
+ "foo($\"aaaa{A}"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\");");
+ verifyFormat("Name = $\"{firstName} {lastName}\";");
+
+ // $"ABC\" + ToString("B") - handle embedded \ in literal string at
+ // the end
+ verifyFormat("string s = $\"A{abc}BC\" + ToString(\"B\");");
+ verifyFormat("$\"{domain}\\\\{user}\"");
+ verifyFormat(
+ "var verbatimInterpolated = $@\"C:\\Users\\{userName}\\Documents\\\";");
+}
+
+TEST_F(FormatTestCSharp, CSharpFatArrows) {
+ verifyFormat("Task serverTask = Task.Run(async() => {");
+ verifyFormat("public override string ToString() => \"{Name}\\{Age}\";");
+}
+
+TEST_F(FormatTestCSharp, CSharpNullConditional) {
+ verifyFormat(
+ "public Person(string firstName, string lastName, int? age=null)");
+
+ verifyFormat("switch(args?.Length)");
+
+ verifyFormat("public static void Main(string[] args) { string dirPath "
+ "= args?[0]; }");
+}
+
+TEST_F(FormatTestCSharp, Attributes) {
+ verifyFormat("[STAThread]\n"
+ "static void\n"
+ "Main(string[] args) {}");
+
+ verifyFormat("[TestMethod]\n"
+ "private class Test {}");
+
+ verifyFormat("[TestMethod]\n"
+ "protected class Test {}");
+
+ verifyFormat("[TestMethod]\n"
+ "internal class Test {}");
+
+ verifyFormat("[TestMethod]\n"
+ "class Test {}");
+
+ verifyFormat("[TestMethod]\n"
+ "[DeploymentItem(\"Test.txt\")]\n"
+ "public class Test {}");
+
+ verifyFormat("[System.AttributeUsage(System.AttributeTargets.Method)]\n"
+ "[System.Runtime.InteropServices.ComVisible(true)]\n"
+ "public sealed class STAThreadAttribute : Attribute {}");
+
+ verifyFormat("[Verb(\"start\", HelpText = \"Starts the server listening on "
+ "provided port\")]\n"
+ "class Test {}");
+
+ verifyFormat("[TestMethod]\n"
+ "public string Host {\n set;\n get;\n}");
+
+ verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
+ "listening on provided host\")]\n"
+ "public string Host {\n set;\n get;\n}");
+}
+
+TEST_F(FormatTestCSharp, CSharpRegions) {
+ verifyFormat("#region aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa "
+ "aaaaaaaaaaaaaaa long region");
+}
+
+TEST_F(FormatTestCSharp, CSharpKeyWordEscaping) {
+ verifyFormat("public enum var { none, @string, bool, @enum }");
+}
+
+TEST_F(FormatTestCSharp, CSharpNullCoalescing) {
+ verifyFormat("var test = ABC ?? DEF");
+ verifyFormat("string myname = name ?? \"ABC\";");
+ verifyFormat("return _name ?? \"DEF\";");
+}
+
+} // namespace format
+} // end namespace clang
diff --git a/src/llvm-project/clang/unittests/Format/FormatTestComments.cpp b/src/llvm-project/clang/unittests/Format/FormatTestComments.cpp
index 9f43677..6dbc364 100644
--- a/src/llvm-project/clang/unittests/Format/FormatTestComments.cpp
+++ b/src/llvm-project/clang/unittests/Format/FormatTestComments.cpp
@@ -1,9 +1,8 @@
//===- unittest/Format/FormatTestComments.cpp - Formatting unit tests -----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Format/FormatTestJS.cpp b/src/llvm-project/clang/unittests/Format/FormatTestJS.cpp
index 67b99ba..b332f1b 100644
--- a/src/llvm-project/clang/unittests/Format/FormatTestJS.cpp
+++ b/src/llvm-project/clang/unittests/Format/FormatTestJS.cpp
@@ -1,9 +1,8 @@
//===- unittest/Format/FormatTestJS.cpp - Formatting unit tests for JS ----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -1963,6 +1962,12 @@
TEST_F(FormatTestJS, TaggedTemplateStrings) {
verifyFormat("var x = html`<ul>`;");
verifyFormat("yield `hello`;");
+ verifyFormat("var f = {\n"
+ " param: longTagName`This is a ${\n"
+ " 'really'} long line`\n"
+ "};",
+ "var f = {param: longTagName`This is a ${'really'} long line`};",
+ getGoogleJSStyleWithColumns(40));
}
TEST_F(FormatTestJS, CastSyntax) {
@@ -2329,5 +2334,27 @@
" never) extends((k: infer I) => void) ? I : never;");
}
-} // end namespace tooling
+TEST_F(FormatTestJS, SupportPrivateFieldsAndMethods) {
+ verifyFormat("class Example {\n"
+ " pub = 1;\n"
+ " #priv = 2;\n"
+ " static pub2 = 'foo';\n"
+ " static #priv2 = 'bar';\n"
+ " method() {\n"
+ " this.#priv = 5;\n"
+ " }\n"
+ " static staticMethod() {\n"
+ " switch (this.#priv) {\n"
+ " case '1':\n"
+ " #priv = 3;\n"
+ " break;\n"
+ " }\n"
+ " }\n"
+ " #privateMethod() {\n"
+ " this.#privateMethod(); // infinite loop\n"
+ " }\n"
+ " static #staticPrivateMethod() {}\n");
+}
+
+} // namespace format
} // end namespace clang
diff --git a/src/llvm-project/clang/unittests/Format/FormatTestJava.cpp b/src/llvm-project/clang/unittests/Format/FormatTestJava.cpp
index f12d7fb..a4936e0 100644
--- a/src/llvm-project/clang/unittests/Format/FormatTestJava.cpp
+++ b/src/llvm-project/clang/unittests/Format/FormatTestJava.cpp
@@ -1,9 +1,8 @@
//===- unittest/Format/FormatTestJava.cpp - Formatting tests for Java -----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Format/FormatTestObjC.cpp b/src/llvm-project/clang/unittests/Format/FormatTestObjC.cpp
index a417b67..b859d92 100644
--- a/src/llvm-project/clang/unittests/Format/FormatTestObjC.cpp
+++ b/src/llvm-project/clang/unittests/Format/FormatTestObjC.cpp
@@ -1,9 +1,8 @@
//===- unittest/Format/FormatTestObjC.cpp - Formatting unit tests----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -166,6 +165,20 @@
EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
}
+TEST(FormatTestObjCStyle, AvoidDetectingDesignatedInitializersAsObjCInHeaders) {
+ auto Style = getStyle("LLVM", "a.h", "none",
+ "static const char *names[] = {[0] = \"foo\",\n"
+ "[kBar] = \"bar\"};");
+ ASSERT_TRUE((bool)Style);
+ EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language);
+
+ Style = getStyle("LLVM", "a.h", "none",
+ "static const char *names[] = {[0] EQ \"foo\",\n"
+ "[kBar] EQ \"bar\"};");
+ ASSERT_TRUE((bool)Style);
+ EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language);
+}
+
TEST_F(FormatTestObjC, FormatObjCTryCatch) {
verifyFormat("@try {\n"
" f();\n"
@@ -598,6 +611,7 @@
TEST_F(FormatTestObjC, FormatObjCMethodExpr) {
verifyFormat("[foo bar:baz];");
+ verifyFormat("[foo bar]->baz;");
verifyFormat("return [foo bar:baz];");
verifyFormat("return (a)[foo bar:baz];");
verifyFormat("f([foo bar:baz]);");
@@ -1315,6 +1329,58 @@
" @\"fffff\"];");
}
+TEST_F(FormatTestObjC, DisambiguatesCallsFromCppLambdas) {
+ verifyFormat("x = ([a foo:bar] && b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] + b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] + !b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] + ~b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] - b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] / b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] % b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] | b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] || b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] && b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] == b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] != b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] <= b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] >= b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] << b->c == 'd');");
+ verifyFormat("x = ([a foo:bar] ? b->c == 'd' : 'e');");
+ // FIXME: The following are wrongly classified as C++ lambda expressions.
+ // For example this code:
+ // x = ([a foo:bar] & b->c == 'd');
+ // is formatted as:
+ // x = ([a foo:bar] & b -> c == 'd');
+ // verifyFormat("x = ([a foo:bar] & b->c == 'd');");
+ // verifyFormat("x = ([a foo:bar] > b->c == 'd');");
+ // verifyFormat("x = ([a foo:bar] < b->c == 'd');");
+ // verifyFormat("x = ([a foo:bar] >> b->c == 'd');");
+}
+
+TEST_F(FormatTestObjC, DisambiguatesCallsFromStructuredBindings) {
+ verifyFormat("int f() {\n"
+ " if (a && [f arg])\n"
+ " return 0;\n"
+ "}");
+ verifyFormat("int f() {\n"
+ " if (a & [f arg])\n"
+ " return 0;\n"
+ "}");
+ verifyFormat("int f() {\n"
+ " for (auto &[elem] : list)\n"
+ " return 0;\n"
+ "}");
+ verifyFormat("int f() {\n"
+ " for (auto &&[elem] : list)\n"
+ " return 0;\n"
+ "}");
+ verifyFormat(
+ "int f() {\n"
+ " for (auto /**/ const /**/ volatile /**/ && /**/ [elem] : list)\n"
+ " return 0;\n"
+ "}");
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
diff --git a/src/llvm-project/clang/unittests/Format/FormatTestProto.cpp b/src/llvm-project/clang/unittests/Format/FormatTestProto.cpp
index 70ef2d2..4258c16 100644
--- a/src/llvm-project/clang/unittests/Format/FormatTestProto.cpp
+++ b/src/llvm-project/clang/unittests/Format/FormatTestProto.cpp
@@ -1,9 +1,8 @@
//===- unittest/Format/FormatTestProto.cpp --------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -108,6 +107,12 @@
"};");
}
+TEST_F(FormatTestProto, EnumAsFieldName) {
+ verifyFormat("message SomeMessage {\n"
+ " required int32 enum = 1;\n"
+ "}");
+}
+
TEST_F(FormatTestProto, UnderstandsReturns) {
verifyFormat("rpc Search(SearchRequest) returns (SearchResponse);");
}
@@ -188,6 +193,10 @@
"\"some.really.long.package.that.exceeds.the.column.limit\";"));
}
+TEST_F(FormatTestProto, TrailingCommentAfterFileOption) {
+ verifyFormat("option java_package = \"foo.pkg\"; // comment\n");
+}
+
TEST_F(FormatTestProto, FormatsOptions) {
verifyFormat("option (MyProto.options) = {\n"
" field_a: OK\n"
@@ -388,6 +397,16 @@
"};");
}
+TEST_F(FormatTestProto, DoesntWrapPackageStatements) {
+ verifyFormat(
+ "package"
+ " some.really.long.package.that.exceeds.the.column.limit00000000;");
+}
+
+TEST_F(FormatTestProto, TrailingCommentAfterPackage) {
+ verifyFormat("package foo.pkg; // comment\n");
+}
+
TEST_F(FormatTestProto, FormatsService) {
verifyFormat("service SearchService {\n"
" rpc Search(SearchRequest) returns (SearchResponse) {\n"
diff --git a/src/llvm-project/clang/unittests/Format/FormatTestRawStrings.cpp b/src/llvm-project/clang/unittests/Format/FormatTestRawStrings.cpp
index 2a8a43d..dc2f6b5 100644
--- a/src/llvm-project/clang/unittests/Format/FormatTestRawStrings.cpp
+++ b/src/llvm-project/clang/unittests/Format/FormatTestRawStrings.cpp
@@ -1,9 +1,8 @@
//===- unittest/Format/FormatTestRawStrings.cpp - Formatting unit tests ---===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -982,6 +981,20 @@
})test", Style));
}
+TEST_F(FormatTestRawStrings, IndentsLastParamAfterNewline) {
+ FormatStyle Style = getRawStringPbStyleWithColumns(60);
+ expect_eq(R"test(
+fffffffffffffffffffff("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ R"pb(
+ b: c
+ )pb");)test",
+ format(R"test(
+fffffffffffffffffffff("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ R"pb(
+ b: c
+ )pb");)test",
+ Style));
+}
} // end namespace
} // end namespace format
} // end namespace clang
diff --git a/src/llvm-project/clang/unittests/Format/FormatTestSelective.cpp b/src/llvm-project/clang/unittests/Format/FormatTestSelective.cpp
index 36d9089..f031a3d 100644
--- a/src/llvm-project/clang/unittests/Format/FormatTestSelective.cpp
+++ b/src/llvm-project/clang/unittests/Format/FormatTestSelective.cpp
@@ -1,9 +1,8 @@
//===- unittest/Format/FormatTestSelective.cpp - Formatting unit tests ----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -99,7 +98,7 @@
}
TEST_F(FormatTestSelective, FormatsIfWithoutCompoundStatement) {
- Style.AllowShortIfStatementsOnASingleLine = true;
+ Style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_WithoutElse;
EXPECT_EQ("if (a) return;", format("if(a)\nreturn;", 7, 1));
EXPECT_EQ("if (a) return; // comment",
format("if(a)\nreturn; // comment", 20, 1));
diff --git a/src/llvm-project/clang/unittests/Format/FormatTestTableGen.cpp b/src/llvm-project/clang/unittests/Format/FormatTestTableGen.cpp
index 820ea78..06029bd 100644
--- a/src/llvm-project/clang/unittests/Format/FormatTestTableGen.cpp
+++ b/src/llvm-project/clang/unittests/Format/FormatTestTableGen.cpp
@@ -1,9 +1,8 @@
//===- unittest/Format/FormatTestTableGen.cpp -----------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -52,5 +51,9 @@
" \"very long help string\">;\n");
}
+TEST_F(FormatTestTableGen, NoSpacesInSquareBracketLists) {
+ verifyFormat("def flag : Flag<[\"-\", \"--\"], \"foo\">;\n");
+}
+
} // namespace format
} // end namespace clang
diff --git a/src/llvm-project/clang/unittests/Format/FormatTestTextProto.cpp b/src/llvm-project/clang/unittests/Format/FormatTestTextProto.cpp
index 44431e4..dba81fc 100644
--- a/src/llvm-project/clang/unittests/Format/FormatTestTextProto.cpp
+++ b/src/llvm-project/clang/unittests/Format/FormatTestTextProto.cpp
@@ -1,9 +1,8 @@
//===- unittest/Format/FormatTestTextProto.cpp ----------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Format/FormatTestUtils.h b/src/llvm-project/clang/unittests/Format/FormatTestUtils.h
index d82d84e..fb75070d 100644
--- a/src/llvm-project/clang/unittests/Format/FormatTestUtils.h
+++ b/src/llvm-project/clang/unittests/Format/FormatTestUtils.h
@@ -1,9 +1,8 @@
//===- unittest/Format/FormatTestUtils.h - Formatting unit tests ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp b/src/llvm-project/clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp
index ee083b8..44cb4ef 100644
--- a/src/llvm-project/clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp
+++ b/src/llvm-project/clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp
@@ -1,9 +1,8 @@
//===- NamespaceEndCommentsFixerTest.cpp - Formatting unit tests ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -46,124 +45,125 @@
TEST_F(NamespaceEndCommentsFixerTest, AddsEndComment) {
EXPECT_EQ("namespace {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}// namespace",
fixNamespaceEndComments("namespace {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}"));
+
EXPECT_EQ("namespace {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}// namespace\n",
fixNamespaceEndComments("namespace {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}\n"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}// namespace A",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}"));
EXPECT_EQ("inline namespace A {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}// namespace A",
fixNamespaceEndComments("inline namespace A {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}"));
EXPECT_EQ("namespace ::A {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}// namespace ::A",
fixNamespaceEndComments("namespace ::A {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}"));
EXPECT_EQ("namespace ::A::B {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}// namespace ::A::B",
fixNamespaceEndComments("namespace ::A::B {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}"));
EXPECT_EQ("namespace /**/::/**/A/**/::/**/B/**/ {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}// namespace ::A::B",
fixNamespaceEndComments("namespace /**/::/**/A/**/::/**/B/**/ {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}"));
EXPECT_EQ("namespace A {\n"
"namespace B {\n"
- " int i;\n"
+ "int i;\n"
"}\n"
"}// namespace A",
fixNamespaceEndComments("namespace A {\n"
"namespace B {\n"
- " int i;\n"
+ "int i;\n"
"}\n"
"}"));
EXPECT_EQ("namespace A {\n"
"namespace B {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}// namespace B\n"
"}// namespace A",
fixNamespaceEndComments("namespace A {\n"
"namespace B {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}\n"
"}"));
EXPECT_EQ("namespace A {\n"
- " int a;\n"
- " int b;\n"
+ "int a;\n"
+ "int b;\n"
"}// namespace A\n"
"namespace B {\n"
- " int b;\n"
- " int a;\n"
+ "int b;\n"
+ "int a;\n"
"}// namespace B",
fixNamespaceEndComments("namespace A {\n"
- " int a;\n"
- " int b;\n"
+ "int a;\n"
+ "int b;\n"
"}\n"
"namespace B {\n"
- " int b;\n"
- " int a;\n"
+ "int b;\n"
+ "int a;\n"
"}"));
EXPECT_EQ("namespace A {\n"
- " int a1;\n"
- " int a2;\n"
+ "int a1;\n"
+ "int a2;\n"
"}// namespace A\n"
"namespace A {\n"
- " int a2;\n"
- " int a1;\n"
+ "int a2;\n"
+ "int a1;\n"
"}// namespace A",
fixNamespaceEndComments("namespace A {\n"
- " int a1;\n"
- " int a2;\n"
+ "int a1;\n"
+ "int a2;\n"
"}\n"
"namespace A {\n"
- " int a2;\n"
- " int a1;\n"
+ "int a2;\n"
+ "int a1;\n"
"}"));
EXPECT_EQ("namespace A {\n"
- " int a;\n"
- " int b;\n"
+ "int a;\n"
+ "int b;\n"
"}// namespace A\n"
"// comment about b\n"
"int b;",
fixNamespaceEndComments("namespace A {\n"
- " int a;\n"
- " int b;\n"
+ "int a;\n"
+ "int b;\n"
"}\n"
"// comment about b\n"
"int b;"));
@@ -222,84 +222,163 @@
// Adds an end comment after a semicolon.
EXPECT_EQ("namespace {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"};// namespace",
fixNamespaceEndComments("namespace {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"};"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"};// namespace A",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"};"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"};// namespace A\n"
"// unrelated",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"};\n"
"// unrelated"));
}
+TEST_F(NamespaceEndCommentsFixerTest, AddsMacroEndComment) {
+ FormatStyle Style = getLLVMStyle();
+ Style.NamespaceMacros.push_back("TESTSUITE");
+
+ EXPECT_EQ("TESTSUITE() {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// TESTSUITE()",
+ fixNamespaceEndComments("TESTSUITE() {\n"
+ "int i;\n"
+ "int j;\n"
+ "}",
+ Style));
+
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}",
+ Style));
+ EXPECT_EQ("inline TESTSUITE(A) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// TESTSUITE(A)",
+ fixNamespaceEndComments("inline TESTSUITE(A) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}",
+ Style));
+ EXPECT_EQ("TESTSUITE(::A) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// TESTSUITE(::A)",
+ fixNamespaceEndComments("TESTSUITE(::A) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}",
+ Style));
+ EXPECT_EQ("TESTSUITE(::A::B) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// TESTSUITE(::A::B)",
+ fixNamespaceEndComments("TESTSUITE(::A::B) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}",
+ Style));
+ EXPECT_EQ("TESTSUITE(/**/::/**/A/**/::/**/B/**/) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// TESTSUITE(::A::B)",
+ fixNamespaceEndComments("TESTSUITE(/**/::/**/A/**/::/**/B/**/) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}",
+ Style));
+ EXPECT_EQ("TESTSUITE(A, B) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A, B) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}",
+ Style));
+ EXPECT_EQ("TESTSUITE(\"Test1\") {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// TESTSUITE(\"Test1\")",
+ fixNamespaceEndComments("TESTSUITE(\"Test1\") {\n"
+ "int i;\n"
+ "int j;\n"
+ "}",
+ Style));
+}
+
TEST_F(NamespaceEndCommentsFixerTest, AddsNewlineIfNeeded) {
EXPECT_EQ("namespace A {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}// namespace A\n"
" int k;",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"} int k;"));
EXPECT_EQ("namespace {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}// namespace\n"
" int k;",
fixNamespaceEndComments("namespace {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"} int k;"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}// namespace A\n"
" namespace B {\n"
- " int j;\n"
- " int k;\n"
+ "int j;\n"
+ "int k;\n"
"}// namespace B",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"} namespace B {\n"
- " int j;\n"
- " int k;\n"
+ "int j;\n"
+ "int k;\n"
"}"));
EXPECT_EQ("namespace {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"};// namespace\n"
"int k;",
fixNamespaceEndComments("namespace {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"};int k;"));
EXPECT_EQ("namespace {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"};// namespace\n"
";",
fixNamespaceEndComments("namespace {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"};;"));
}
@@ -314,18 +393,18 @@
TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddCommentAfterUnaffectedRBrace) {
EXPECT_EQ("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"}",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"}",
// The range (16, 3) spans the 'int' above.
/*Ranges=*/{1, tooling::Range(16, 3)}));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"};",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"};",
// The range (16, 3) spans the 'int' above.
/*Ranges=*/{1, tooling::Range(16, 3)}));
@@ -334,89 +413,138 @@
TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddCommentAfterRBraceInPPDirective) {
EXPECT_EQ("#define SAD \\\n"
"namespace A { \\\n"
- " int i; \\\n"
+ "int i; \\\n"
"}",
fixNamespaceEndComments("#define SAD \\\n"
"namespace A { \\\n"
- " int i; \\\n"
+ "int i; \\\n"
"}"));
}
TEST_F(NamespaceEndCommentsFixerTest, KeepsValidEndComment) {
EXPECT_EQ("namespace {\n"
- " int i;\n"
+ "int i;\n"
"} // end anonymous namespace",
fixNamespaceEndComments("namespace {\n"
- " int i;\n"
+ "int i;\n"
"} // end anonymous namespace"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} /* end of namespace A */",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} /* end of namespace A */"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} // namespace A"));
EXPECT_EQ("namespace A::B {\n"
- " int i;\n"
+ "int i;\n"
"} // end namespace A::B",
fixNamespaceEndComments("namespace A::B {\n"
- " int i;\n"
+ "int i;\n"
"} // end namespace A::B"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"}; // end namespace A",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"}; // end namespace A"));
EXPECT_EQ("namespace {\n"
- " int i;\n"
+ "int i;\n"
"}; /* unnamed namespace */",
fixNamespaceEndComments("namespace {\n"
- " int i;\n"
+ "int i;\n"
"}; /* unnamed namespace */"));
}
+TEST_F(NamespaceEndCommentsFixerTest, KeepsValidMacroEndComment) {
+ FormatStyle Style = getLLVMStyle();
+ Style.NamespaceMacros.push_back("TESTSUITE");
+
+ EXPECT_EQ("TESTSUITE() {\n"
+ "int i;\n"
+ "} // end anonymous TESTSUITE()",
+ fixNamespaceEndComments("TESTSUITE() {\n"
+ "int i;\n"
+ "} // end anonymous TESTSUITE()",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} /* end of TESTSUITE(A) */",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} /* end of TESTSUITE(A) */",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} // TESTSUITE(A)",
+ Style));
+ EXPECT_EQ("TESTSUITE(A::B) {\n"
+ "int i;\n"
+ "} // end TESTSUITE(A::B)",
+ fixNamespaceEndComments("TESTSUITE(A::B) {\n"
+ "int i;\n"
+ "} // end TESTSUITE(A::B)",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "}; // end TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "}; // end TESTSUITE(A)",
+ Style));
+ EXPECT_EQ("TESTSUITE() {\n"
+ "int i;\n"
+ "}; /* unnamed TESTSUITE() */",
+ fixNamespaceEndComments("TESTSUITE() {\n"
+ "int i;\n"
+ "}; /* unnamed TESTSUITE() */",
+ Style));
+}
+
TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndLineComment) {
EXPECT_EQ("namespace {\n"
- " int i;\n"
+ "int i;\n"
"} // namespace",
fixNamespaceEndComments("namespace {\n"
- " int i;\n"
+ "int i;\n"
"} // namespace A"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} // namespace"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} //"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
- "} // namespace A",
- fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
- "} //"));
- EXPECT_EQ("namespace A {\n"
- " int i;\n"
- "} // namespace A",
- fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
- "} // banamespace A"));
- EXPECT_EQ("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"}; // namespace A",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
+ "int i;\n"
+ "}; //"));
+
+ EXPECT_EQ("namespace A {\n"
+ "int i;\n"
+ "} // namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ "int i;\n"
+ "} // banamespace A"));
+ EXPECT_EQ("namespace A {\n"
+ "int i;\n"
+ "}; // namespace A",
+ fixNamespaceEndComments("namespace A {\n"
+ "int i;\n"
"}; // banamespace A"));
// Updates invalid line comments even for short namespaces.
EXPECT_EQ("namespace A {} // namespace A",
@@ -446,42 +574,132 @@
CompactNamespacesStyle));
}
+TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidMacroEndLineComment) {
+ FormatStyle Style = getLLVMStyle();
+ Style.NamespaceMacros.push_back("TESTSUITE");
+
+ EXPECT_EQ("TESTSUITE() {\n"
+ "int i;\n"
+ "} // TESTSUITE()",
+ fixNamespaceEndComments("TESTSUITE() {\n"
+ "int i;\n"
+ "} // TESTSUITE(A)",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} // TESTSUITE()",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} //",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "}; // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "}; //",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} // TESTSUITE A",
+ Style));
+ EXPECT_EQ("TESTSUITE() {\n"
+ "int i;\n"
+ "} // TESTSUITE()",
+ fixNamespaceEndComments("TESTSUITE() {\n"
+ "int i;\n"
+ "} // TESTSUITE",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} // TOASTSUITE(A)",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "}; // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "}; // TOASTSUITE(A)",
+ Style));
+ // Updates invalid line comments even for short namespaces.
+ EXPECT_EQ("TESTSUITE(A) {} // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {} // TESTSUITE()", Style));
+ EXPECT_EQ("TESTSUITE(A) {}; // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {}; // TESTSUITE()", Style));
+
+ // Update invalid comments for compacted namespaces.
+ FormatStyle CompactNamespacesStyle = getLLVMStyle();
+ CompactNamespacesStyle.CompactNamespaces = true;
+ CompactNamespacesStyle.NamespaceMacros.push_back("TESTSUITE");
+
+ EXPECT_EQ("TESTSUITE(out) { TESTSUITE(in) {\n"
+ "}} // TESTSUITE(out::in)",
+ fixNamespaceEndComments("TESTSUITE(out) { TESTSUITE(in) {\n"
+ "}} // TESTSUITE(out)",
+ CompactNamespacesStyle));
+ EXPECT_EQ("TESTSUITE(out) { TESTSUITE(in) {\n"
+ "}} // TESTSUITE(out::in)",
+ fixNamespaceEndComments("TESTSUITE(out) { TESTSUITE(in) {\n"
+ "}} // TESTSUITE(in)",
+ CompactNamespacesStyle));
+ EXPECT_EQ("TESTSUITE(out) { TESTSUITE(in) {\n"
+ "}\n"
+ "} // TESTSUITE(out::in)",
+ fixNamespaceEndComments("TESTSUITE(out) { TESTSUITE(in) {\n"
+ "}// TAOSTSUITE(in)\n"
+ "} // TESTSUITE(out)",
+ CompactNamespacesStyle));
+}
+
TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndBlockComment) {
EXPECT_EQ("namespace {\n"
- " int i;\n"
+ "int i;\n"
"} // namespace",
fixNamespaceEndComments("namespace {\n"
- " int i;\n"
+ "int i;\n"
"} /* namespace A */"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} /* end namespace */"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} /**/"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} /* end unnamed namespace */"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} // namespace A",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"} /* banamespace A */"));
EXPECT_EQ("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"}; // namespace A",
fixNamespaceEndComments("namespace A {\n"
- " int i;\n"
+ "int i;\n"
"}; /* banamespace A */"));
EXPECT_EQ("namespace A {} // namespace A",
fixNamespaceEndComments("namespace A {} /**/"));
@@ -489,6 +707,58 @@
fixNamespaceEndComments("namespace A {}; /**/"));
}
+TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidMacroEndBlockComment) {
+ FormatStyle Style = getLLVMStyle();
+ Style.NamespaceMacros.push_back("TESTSUITE");
+
+ EXPECT_EQ("TESTSUITE() {\n"
+ "int i;\n"
+ "} // TESTSUITE()",
+ fixNamespaceEndComments("TESTSUITE() {\n"
+ "int i;\n"
+ "} /* TESTSUITE(A) */",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} /* end TESTSUITE() */",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} /**/",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} /* end unnamed TESTSUITE() */",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "} /* TOASTSUITE(A) */",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {\n"
+ "int i;\n"
+ "}; // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {\n"
+ "int i;\n"
+ "}; /* TAOSTSUITE(A) */",
+ Style));
+ EXPECT_EQ("TESTSUITE(A) {} // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {} /**/", Style));
+ EXPECT_EQ("TESTSUITE(A) {}; // TESTSUITE(A)",
+ fixNamespaceEndComments("TESTSUITE(A) {}; /**/", Style));
+}
+
TEST_F(NamespaceEndCommentsFixerTest,
DoesNotAddEndCommentForNamespacesControlledByMacros) {
EXPECT_EQ("#ifdef 1\n"
@@ -496,7 +766,7 @@
"#elseif\n"
"namespace B {\n"
"#endif\n"
- " int i;\n"
+ "int i;\n"
"}\n"
"}\n",
fixNamespaceEndComments("#ifdef 1\n"
@@ -504,7 +774,7 @@
"#elseif\n"
"namespace B {\n"
"#endif\n"
- " int i;\n"
+ "int i;\n"
"}\n"
"}\n"));
}
@@ -644,7 +914,7 @@
"#elseif\n"
"namespace B {\n"
"#endif\n"
- " int i;\n"
+ "int i;\n"
"}\n"
"}\n",
fixNamespaceEndComments("#ifdef 1\n"
@@ -652,26 +922,26 @@
"#elseif\n"
"namespace B {\n"
"#endif\n"
- " int i;\n"
+ "int i;\n"
"}\n"
"}\n"));
EXPECT_EQ("namespace {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}// namespace\n"
"#if A\n"
- " int i;\n"
+ "int i;\n"
"#else\n"
- " int j;\n"
+ "int j;\n"
"#endif",
fixNamespaceEndComments("namespace {\n"
- " int i;\n"
- " int j;\n"
+ "int i;\n"
+ "int j;\n"
"}\n"
"#if A\n"
- " int i;\n"
+ "int i;\n"
"#else\n"
- " int j;\n"
+ "int j;\n"
"#endif"));
EXPECT_EQ("#if A\n"
"namespace A {\n"
@@ -758,11 +1028,11 @@
TEST_F(NamespaceEndCommentsFixerTest,
DoesNotAddEndCommentForUnbalancedRBracesAfterNamespaceEnd) {
EXPECT_EQ("namespace {\n"
- " int i;\n"
+ "int i;\n"
"} // namespace\n"
"}",
fixNamespaceEndComments("namespace {\n"
- " int i;\n"
+ "int i;\n"
"} // namespace\n"
"}"));
}
diff --git a/src/llvm-project/clang/unittests/Format/SortImportsTestJS.cpp b/src/llvm-project/clang/unittests/Format/SortImportsTestJS.cpp
index 91be031..72c79ac 100644
--- a/src/llvm-project/clang/unittests/Format/SortImportsTestJS.cpp
+++ b/src/llvm-project/clang/unittests/Format/SortImportsTestJS.cpp
@@ -1,9 +1,8 @@
//===- unittest/Format/SortImportsTestJS.cpp - JS import sort unit tests --===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Format/SortImportsTestJava.cpp b/src/llvm-project/clang/unittests/Format/SortImportsTestJava.cpp
index 3bcf809..d2826a2 100644
--- a/src/llvm-project/clang/unittests/Format/SortImportsTestJava.cpp
+++ b/src/llvm-project/clang/unittests/Format/SortImportsTestJava.cpp
@@ -262,6 +262,29 @@
"import org.a;"));
}
+TEST_F(SortImportsTestJava, ImportNamedFunction) {
+ EXPECT_EQ("import X;\n"
+ "class C {\n"
+ " void m() {\n"
+ " importFile();\n"
+ " }\n"
+ "}\n",
+ sort("import X;\n"
+ "class C {\n"
+ " void m() {\n"
+ " importFile();\n"
+ " }\n"
+ "}\n"));
+}
+
+TEST_F(SortImportsTestJava, NoReplacementsForValidImports) {
+ // Identical #includes have led to a failure with an unstable sort.
+ std::string Code = "import org.a;\n"
+ "import org.b;\n";
+ EXPECT_TRUE(
+ sortIncludes(FmtStyle, Code, GetCodeRange(Code), "input.java").empty());
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
diff --git a/src/llvm-project/clang/unittests/Format/SortIncludesTest.cpp b/src/llvm-project/clang/unittests/Format/SortIncludesTest.cpp
index dde8800..c00d3cb 100644
--- a/src/llvm-project/clang/unittests/Format/SortIncludesTest.cpp
+++ b/src/llvm-project/clang/unittests/Format/SortIncludesTest.cpp
@@ -1,14 +1,14 @@
//===- unittest/Format/SortIncludesTest.cpp - Include sort unit tests -----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "FormatTestUtils.h"
#include "clang/Format/Format.h"
+#include "llvm/ADT/None.h"
#include "llvm/Support/Debug.h"
#include "gtest/gtest.h"
@@ -25,9 +25,11 @@
}
std::string sort(StringRef Code, std::vector<tooling::Range> Ranges,
- StringRef FileName = "input.cc") {
+ StringRef FileName = "input.cc",
+ unsigned ExpectedNumRanges = 1) {
auto Replaces = sortIncludes(FmtStyle, Code, Ranges, FileName);
Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges);
+ EXPECT_EQ(ExpectedNumRanges, Replaces.size());
auto Sorted = applyAllReplacements(Code, Replaces);
EXPECT_TRUE(static_cast<bool>(Sorted));
auto Result = applyAllReplacements(
@@ -36,8 +38,10 @@
return *Result;
}
- std::string sort(StringRef Code, StringRef FileName = "input.cpp") {
- return sort(Code, GetCodeRange(Code), FileName);
+ std::string sort(StringRef Code,
+ StringRef FileName = "input.cpp",
+ unsigned ExpectedNumRanges = 1) {
+ return sort(Code, GetCodeRange(Code), FileName, ExpectedNumRanges);
}
unsigned newCursor(llvm::StringRef Code, unsigned Cursor) {
@@ -118,6 +122,43 @@
"// clang-format on\n"));
}
+TEST_F(SortIncludesTest, SupportClangFormatOffCStyle) {
+ EXPECT_EQ("#include <a>\n"
+ "#include <b>\n"
+ "#include <c>\n"
+ "/* clang-format off */\n"
+ "#include <b>\n"
+ "#include <a>\n"
+ "#include <c>\n"
+ "/* clang-format on */\n",
+ sort("#include <b>\n"
+ "#include <a>\n"
+ "#include <c>\n"
+ "/* clang-format off */\n"
+ "#include <b>\n"
+ "#include <a>\n"
+ "#include <c>\n"
+ "/* clang-format on */\n"));
+
+ // Not really turning it off
+ EXPECT_EQ("#include <a>\n"
+ "#include <b>\n"
+ "#include <c>\n"
+ "/* clang-format offically */\n"
+ "#include <a>\n"
+ "#include <b>\n"
+ "#include <c>\n"
+ "/* clang-format onwards */\n",
+ sort("#include <b>\n"
+ "#include <a>\n"
+ "#include <c>\n"
+ "/* clang-format offically */\n"
+ "#include <b>\n"
+ "#include <a>\n"
+ "#include <c>\n"
+ "/* clang-format onwards */\n", "input.h", 2));
+}
+
TEST_F(SortIncludesTest, IncludeSortingCanBeDisabled) {
FmtStyle.SortIncludes = false;
EXPECT_EQ("#include \"a.h\"\n"
@@ -125,7 +166,8 @@
"#include \"b.h\"\n",
sort("#include \"a.h\"\n"
"#include \"c.h\"\n"
- "#include \"b.h\"\n"));
+ "#include \"b.h\"\n",
+ "input.h", 0));
}
TEST_F(SortIncludesTest, MixIncludeAndImport) {
@@ -178,7 +220,7 @@
sort("#include \"a.h\"\n"
"#include \"c.h\"\n"
"\n"
- "#include \"b.h\"\n"));
+ "#include \"b.h\"\n", "input.h", 0));
}
TEST_F(SortIncludesTest, SortsAllBlocksWhenMerging) {
@@ -226,9 +268,13 @@
TEST_F(SortIncludesTest, HandlesAngledIncludesAsSeparateBlocks) {
EXPECT_EQ("#include \"a.h\"\n"
"#include \"c.h\"\n"
+ "#include <array>\n"
"#include <b.h>\n"
- "#include <d.h>\n",
- sort("#include <d.h>\n"
+ "#include <d.h>\n"
+ "#include <vector>\n",
+ sort("#include <vector>\n"
+ "#include <d.h>\n"
+ "#include <array>\n"
"#include <b.h>\n"
"#include \"c.h\"\n"
"#include \"a.h\"\n"));
@@ -236,9 +282,15 @@
FmtStyle = getGoogleStyle(FormatStyle::LK_Cpp);
EXPECT_EQ("#include <b.h>\n"
"#include <d.h>\n"
+ "\n"
+ "#include <array>\n"
+ "#include <vector>\n"
+ "\n"
"#include \"a.h\"\n"
"#include \"c.h\"\n",
- sort("#include <d.h>\n"
+ sort("#include <vector>\n"
+ "#include <d.h>\n"
+ "#include <array>\n"
"#include <b.h>\n"
"#include \"c.h\"\n"
"#include \"a.h\"\n"));
@@ -412,7 +464,7 @@
sort("#include \"important_os_header.h\"\n"
"#include \"c_main.h\"\n"
"#include \"a_other.h\"\n",
- "c_main.cc"));
+ "c_main.cc", 0));
}
TEST_F(SortIncludesTest, PriorityGroupsAreSeparatedWhenRegroupping) {
@@ -440,7 +492,7 @@
"#include \"c_main.h\"\n"
"\n"
"#include \"a_other.h\"\n",
- "c_main.cc"));
+ "c_main.cc", 0));
}
TEST_F(SortIncludesTest, CalculatesCorrectCursorPosition) {
@@ -588,7 +640,29 @@
sort("<!--;\n"
"#include <b>\n"
"#include <a>\n"
- "-->"));
+ "-->", "input.h", 0));
+}
+
+TEST_F(SortIncludesTest, DoNotOutputReplacementsForSortedBlocksWithRegrouping) {
+ Style.IncludeBlocks = Style.IBS_Regroup;
+ std::string Code = R"(
+#include "b.h"
+
+#include <a.h>
+)";
+ EXPECT_EQ(Code, sort(Code, "input.h", 0));
+}
+
+
+TEST_F(SortIncludesTest, DoNotRegroupGroupsInGoogleObjCStyle) {
+ FmtStyle = getGoogleStyle(FormatStyle::LK_ObjC);
+
+ EXPECT_EQ("#include <a.h>\n"
+ "#include <b.h>\n"
+ "#include \"a.h\"",
+ sort("#include <b.h>\n"
+ "#include <a.h>\n"
+ "#include \"a.h\""));
}
} // end namespace
diff --git a/src/llvm-project/clang/unittests/Format/UsingDeclarationsSorterTest.cpp b/src/llvm-project/clang/unittests/Format/UsingDeclarationsSorterTest.cpp
index 2ba6520..0f517d0 100644
--- a/src/llvm-project/clang/unittests/Format/UsingDeclarationsSorterTest.cpp
+++ b/src/llvm-project/clang/unittests/Format/UsingDeclarationsSorterTest.cpp
@@ -1,9 +1,8 @@
//===- UsingDeclarationsSorterTest.cpp - Formatting unit tests ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Frontend/ASTUnitTest.cpp b/src/llvm-project/clang/unittests/Frontend/ASTUnitTest.cpp
index c60004e..9232b7b 100644
--- a/src/llvm-project/clang/unittests/Frontend/ASTUnitTest.cpp
+++ b/src/llvm-project/clang/unittests/Frontend/ASTUnitTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Frontend/ASTUnitTest.cpp - ASTUnit tests -----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -52,8 +51,8 @@
PCHContainerOps = std::make_shared<PCHContainerOperations>();
return ASTUnit::LoadFromCompilerInvocation(
- CInvok, PCHContainerOps, Diags, FileMgr, false, false, 0, TU_Complete,
- false, false, isVolatile);
+ CInvok, PCHContainerOps, Diags, FileMgr, false, CaptureDiagsKind::None,
+ 0, TU_Complete, false, false, isVolatile);
}
};
diff --git a/src/llvm-project/clang/unittests/Frontend/CMakeLists.txt b/src/llvm-project/clang/unittests/Frontend/CMakeLists.txt
index c7851bb..cde19e9 100644
--- a/src/llvm-project/clang/unittests/Frontend/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/Frontend/CMakeLists.txt
@@ -12,7 +12,7 @@
PCHPreambleTest.cpp
OutputStreamTest.cpp
)
-target_link_libraries(FrontendTests
+clang_target_link_libraries(FrontendTests
PRIVATE
clangAST
clangBasic
diff --git a/src/llvm-project/clang/unittests/Frontend/CodeGenActionTest.cpp b/src/llvm-project/clang/unittests/Frontend/CodeGenActionTest.cpp
index d90c2bc..7576c91 100644
--- a/src/llvm-project/clang/unittests/Frontend/CodeGenActionTest.cpp
+++ b/src/llvm-project/clang/unittests/Frontend/CodeGenActionTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Frontend/CodeGenActionTest.cpp --- FrontendAction tests --===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/Frontend/CompilerInstanceTest.cpp b/src/llvm-project/clang/unittests/Frontend/CompilerInstanceTest.cpp
index b2d9f8b..4935853 100644
--- a/src/llvm-project/clang/unittests/Frontend/CompilerInstanceTest.cpp
+++ b/src/llvm-project/clang/unittests/Frontend/CompilerInstanceTest.cpp
@@ -1,14 +1,14 @@
//===- unittests/Frontend/CompilerInstanceTest.cpp - CI tests -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ToolOutputFile.h"
@@ -71,4 +71,24 @@
ASSERT_TRUE(Instance.getFileManager().getFile("vfs-virtual.file"));
}
+TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) {
+ auto DiagOpts = new DiagnosticOptions();
+ // Tell the diagnostics engine to emit the diagnostic log to STDERR. This
+ // ensures that a chained diagnostic consumer is created so that the test can
+ // exercise the unowned diagnostic consumer in a chained consumer.
+ DiagOpts->DiagnosticLogFile = "-";
+
+ // Create the diagnostic engine with unowned consumer.
+ std::string DiagnosticOutput;
+ llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
+ auto DiagPrinter = llvm::make_unique<TextDiagnosticPrinter>(
+ DiagnosticsOS, new DiagnosticOptions());
+ CompilerInstance Instance;
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags = Instance.createDiagnostics(
+ DiagOpts, DiagPrinter.get(), /*ShouldOwnClient=*/false);
+
+ Diags->Report(diag::err_expected) << "no crash";
+ ASSERT_EQ(DiagnosticsOS.str(), "error: expected no crash\n");
+}
+
} // anonymous namespace
diff --git a/src/llvm-project/clang/unittests/Frontend/FrontendActionTest.cpp b/src/llvm-project/clang/unittests/Frontend/FrontendActionTest.cpp
index ce01445..20356c6 100644
--- a/src/llvm-project/clang/unittests/Frontend/FrontendActionTest.cpp
+++ b/src/llvm-project/clang/unittests/Frontend/FrontendActionTest.cpp
@@ -1,24 +1,25 @@
//===- unittests/Frontend/FrontendActionTest.cpp - FrontendAction tests ---===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+#include "clang/Frontend/FrontendAction.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
-#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Sema/Sema.h"
+#include "clang/Serialization/InMemoryModuleCache.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/ToolOutputFile.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -254,4 +255,40 @@
EXPECT_EQ("This is a note", TDC->Note.str().str());
}
+TEST(GeneratePCHFrontendAction, CacheGeneratedPCH) {
+ // Create a temporary file for writing out the PCH that will be cleaned up.
+ int PCHFD;
+ llvm::SmallString<128> PCHFilename;
+ ASSERT_FALSE(
+ llvm::sys::fs::createTemporaryFile("test.h", "pch", PCHFD, PCHFilename));
+ llvm::ToolOutputFile PCHFile(PCHFilename, PCHFD);
+
+ for (bool ShouldCache : {false, true}) {
+ auto Invocation = std::make_shared<CompilerInvocation>();
+ Invocation->getLangOpts()->CacheGeneratedPCH = ShouldCache;
+ Invocation->getPreprocessorOpts().addRemappedFile(
+ "test.h",
+ MemoryBuffer::getMemBuffer("int foo(void) { return 1; }\n").release());
+ Invocation->getFrontendOpts().Inputs.push_back(
+ FrontendInputFile("test.h", InputKind::C));
+ Invocation->getFrontendOpts().OutputFile = StringRef(PCHFilename);
+ Invocation->getFrontendOpts().ProgramAction = frontend::GeneratePCH;
+ Invocation->getTargetOpts().Triple = "x86_64-apple-darwin19.0.0";
+ CompilerInstance Compiler;
+ Compiler.setInvocation(std::move(Invocation));
+ Compiler.createDiagnostics();
+
+ GeneratePCHAction TestAction;
+ ASSERT_TRUE(Compiler.ExecuteAction(TestAction));
+
+ // Check whether the PCH was cached.
+ if (ShouldCache)
+ EXPECT_EQ(InMemoryModuleCache::Final,
+ Compiler.getModuleCache().getPCMState(PCHFilename));
+ else
+ EXPECT_EQ(InMemoryModuleCache::Unknown,
+ Compiler.getModuleCache().getPCMState(PCHFilename));
+ }
+}
+
} // anonymous namespace
diff --git a/src/llvm-project/clang/unittests/Frontend/OutputStreamTest.cpp b/src/llvm-project/clang/unittests/Frontend/OutputStreamTest.cpp
index ff03650..1ac875f 100644
--- a/src/llvm-project/clang/unittests/Frontend/OutputStreamTest.cpp
+++ b/src/llvm-project/clang/unittests/Frontend/OutputStreamTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Frontend/OutputStreamTest.cpp --- FrontendAction tests --===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Frontend/PCHPreambleTest.cpp b/src/llvm-project/clang/unittests/Frontend/PCHPreambleTest.cpp
index 162a281..6136b09 100644
--- a/src/llvm-project/clang/unittests/Frontend/PCHPreambleTest.cpp
+++ b/src/llvm-project/clang/unittests/Frontend/PCHPreambleTest.cpp
@@ -1,9 +1,8 @@
//====-- unittests/Frontend/PCHPreambleTest.cpp - FrontendAction tests ---====//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -53,7 +52,10 @@
FileSystemOptions FSOpts;
public:
- void SetUp() override {
+ void SetUp() override { ResetVFS(); }
+ void TearDown() override {}
+
+ void ResetVFS() {
VFS = new ReadCountingInMemoryFileSystem();
// We need the working directory to be set to something absolute,
// otherwise it ends up being inadvertently set to the current
@@ -64,9 +66,6 @@
VFS->setCurrentWorkingDirectory("//./");
}
- void TearDown() override {
- }
-
void AddFile(const std::string &Filename, const std::string &Contents) {
::time_t now;
::time(&now);
@@ -97,8 +96,8 @@
FileManager *FileMgr = new FileManager(FSOpts, VFS);
std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
- CI, PCHContainerOpts, Diags, FileMgr, false, false,
- /*PrecompilePreambleAfterNParses=*/1);
+ CI, PCHContainerOpts, Diags, FileMgr, false, CaptureDiagsKind::None,
+ /*PrecompilePreambleAfterNParses=*/1);
return AST;
}
@@ -124,6 +123,72 @@
}
};
+TEST_F(PCHPreambleTest, ReparseReusesPreambleWithUnsavedFileNotExistingOnDisk) {
+ std::string Header1 = "//./header1.h";
+ std::string MainName = "//./main.cpp";
+ AddFile(MainName, R"cpp(
+#include "//./header1.h"
+int main() { return ZERO; }
+)cpp");
+ RemapFile(Header1, "#define ZERO 0\n");
+
+ // Parse with header file provided as unsaved file, which does not exist on
+ // disk.
+ std::unique_ptr<ASTUnit> AST(ParseAST(MainName));
+ ASSERT_TRUE(AST.get());
+ ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred());
+
+ // Reparse and check that the preamble was reused.
+ ASSERT_TRUE(ReparseAST(AST));
+ ASSERT_EQ(AST->getPreambleCounterForTests(), 1U);
+}
+
+TEST_F(PCHPreambleTest, ReparseReusesPreambleAfterUnsavedFileWasCreatedOnDisk) {
+ std::string Header1 = "//./header1.h";
+ std::string MainName = "//./main.cpp";
+ AddFile(MainName, R"cpp(
+#include "//./header1.h"
+int main() { return ZERO; }
+)cpp");
+ RemapFile(Header1, "#define ZERO 0\n");
+
+ // Parse with header file provided as unsaved file, which does not exist on
+ // disk.
+ std::unique_ptr<ASTUnit> AST(ParseAST(MainName));
+ ASSERT_TRUE(AST.get());
+ ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred());
+
+ // Create the unsaved file also on disk and check that preamble was reused.
+ AddFile(Header1, "#define ZERO 0\n");
+ ASSERT_TRUE(ReparseAST(AST));
+ ASSERT_EQ(AST->getPreambleCounterForTests(), 1U);
+}
+
+TEST_F(PCHPreambleTest,
+ ReparseReusesPreambleAfterUnsavedFileWasRemovedFromDisk) {
+ std::string Header1 = "//./foo/header1.h";
+ std::string MainName = "//./main.cpp";
+ std::string MainFileContent = R"cpp(
+#include "//./foo/header1.h"
+int main() { return ZERO; }
+)cpp";
+ AddFile(MainName, MainFileContent);
+ AddFile(Header1, "#define ZERO 0\n");
+ RemapFile(Header1, "#define ZERO 0\n");
+
+ // Parse with header file provided as unsaved file, which exists on disk.
+ std::unique_ptr<ASTUnit> AST(ParseAST(MainName));
+ ASSERT_TRUE(AST.get());
+ ASSERT_FALSE(AST->getDiagnostics().hasErrorOccurred());
+ ASSERT_EQ(AST->getPreambleCounterForTests(), 1U);
+
+ // Remove the unsaved file from disk and check that the preamble was reused.
+ ResetVFS();
+ AddFile(MainName, MainFileContent);
+ ASSERT_TRUE(ReparseAST(AST));
+ ASSERT_EQ(AST->getPreambleCounterForTests(), 1U);
+}
+
TEST_F(PCHPreambleTest, ReparseWithOverriddenFileDoesNotInvalidatePreamble) {
std::string Header1 = "//./header1.h";
std::string Header2 = "//./header2.h";
diff --git a/src/llvm-project/clang/unittests/Frontend/ParsedSourceLocationTest.cpp b/src/llvm-project/clang/unittests/Frontend/ParsedSourceLocationTest.cpp
index 0cbdc7e..1539005 100644
--- a/src/llvm-project/clang/unittests/Frontend/ParsedSourceLocationTest.cpp
+++ b/src/llvm-project/clang/unittests/Frontend/ParsedSourceLocationTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Frontend/ParsedSourceLocationTest.cpp - ------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Index/CMakeLists.txt b/src/llvm-project/clang/unittests/Index/CMakeLists.txt
index 2756fad..ea940e9 100644
--- a/src/llvm-project/clang/unittests/Index/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/Index/CMakeLists.txt
@@ -7,7 +7,7 @@
IndexTests.cpp
)
-target_link_libraries(IndexTests
+clang_target_link_libraries(IndexTests
PRIVATE
clangAST
clangBasic
diff --git a/src/llvm-project/clang/unittests/Index/IndexTests.cpp b/src/llvm-project/clang/unittests/Index/IndexTests.cpp
index 2d4463d..bbd5db3 100644
--- a/src/llvm-project/clang/unittests/Index/IndexTests.cpp
+++ b/src/llvm-project/clang/unittests/Index/IndexTests.cpp
@@ -1,14 +1,16 @@
//===--- IndexTests.cpp - Test indexing actions -----------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Index/IndexDataConsumer.h"
@@ -24,40 +26,86 @@
namespace clang {
namespace index {
+namespace {
+struct Position {
+ size_t Line = 0;
+ size_t Column = 0;
+
+ Position(size_t Line = 0, size_t Column = 0) : Line(Line), Column(Column) {}
+
+ static Position fromSourceLocation(SourceLocation Loc,
+ const SourceManager &SM) {
+ FileID FID;
+ unsigned Offset;
+ std::tie(FID, Offset) = SM.getDecomposedSpellingLoc(Loc);
+ Position P;
+ P.Line = SM.getLineNumber(FID, Offset);
+ P.Column = SM.getColumnNumber(FID, Offset);
+ return P;
+ }
+};
+
+bool operator==(const Position &LHS, const Position &RHS) {
+ return std::tie(LHS.Line, LHS.Column) == std::tie(RHS.Line, RHS.Column);
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Position &Pos) {
+ return OS << Pos.Line << ':' << Pos.Column;
+}
struct TestSymbol {
std::string QName;
+ Position WrittenPos;
+ Position DeclPos;
+ SymbolInfo SymInfo;
+ SymbolRoleSet Roles;
// FIXME: add more information.
};
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TestSymbol &S) {
- return OS << S.QName;
+ return OS << S.QName << '[' << S.WrittenPos << ']' << '@' << S.DeclPos << '('
+ << static_cast<unsigned>(S.SymInfo.Kind) << ')';
}
-namespace {
class Indexer : public IndexDataConsumer {
public:
+ void initialize(ASTContext &Ctx) override {
+ AST = &Ctx;
+ IndexDataConsumer::initialize(Ctx);
+ }
+
bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles,
- ArrayRef<SymbolRelation>, SourceLocation,
+ ArrayRef<SymbolRelation>, SourceLocation Loc,
ASTNodeInfo) override {
const auto *ND = llvm::dyn_cast<NamedDecl>(D);
if (!ND)
return true;
TestSymbol S;
+ S.SymInfo = getSymbolInfo(D);
S.QName = ND->getQualifiedNameAsString();
+ S.WrittenPos = Position::fromSourceLocation(Loc, AST->getSourceManager());
+ S.DeclPos =
+ Position::fromSourceLocation(D->getLocation(), AST->getSourceManager());
+ S.Roles = Roles;
Symbols.push_back(std::move(S));
return true;
}
- bool handleMacroOccurence(const IdentifierInfo *Name, const MacroInfo *,
- SymbolRoleSet, SourceLocation) override {
+ bool handleMacroOccurence(const IdentifierInfo *Name, const MacroInfo *MI,
+ SymbolRoleSet Roles, SourceLocation Loc) override {
TestSymbol S;
+ S.SymInfo = getSymbolInfoForMacro(*MI);
S.QName = Name->getName();
+ S.WrittenPos = Position::fromSourceLocation(Loc, AST->getSourceManager());
+ S.DeclPos = Position::fromSourceLocation(MI->getDefinitionLoc(),
+ AST->getSourceManager());
+ S.Roles = Roles;
Symbols.push_back(std::move(S));
return true;
}
std::vector<TestSymbol> Symbols;
+ const ASTContext *AST = nullptr;
};
class IndexAction : public ASTFrontendAction {
@@ -94,11 +142,16 @@
IndexingOptions Opts;
};
+using testing::AllOf;
using testing::Contains;
using testing::Not;
using testing::UnorderedElementsAre;
MATCHER_P(QName, Name, "") { return arg.QName == Name; }
+MATCHER_P(WrittenAt, Pos, "") { return arg.WrittenPos == Pos; }
+MATCHER_P(DeclAt, Pos, "") { return arg.DeclPos == Pos; }
+MATCHER_P(Kind, SymKind, "") { return arg.SymInfo.Kind == SymKind; }
+MATCHER_P(HasRole, Role, "") { return arg.Roles & static_cast<unsigned>(Role); }
TEST(IndexTest, Simple) {
auto Index = std::make_shared<Indexer>();
@@ -120,6 +173,125 @@
EXPECT_THAT(Index->Symbols, UnorderedElementsAre());
}
+TEST(IndexTest, IndexParametersInDecls) {
+ std::string Code = "void foo(int bar);";
+ auto Index = std::make_shared<Indexer>();
+ IndexingOptions Opts;
+ Opts.IndexFunctionLocals = true;
+ Opts.IndexParametersInDeclarations = true;
+ tooling::runToolOnCode(new IndexAction(Index, Opts), Code);
+ EXPECT_THAT(Index->Symbols, Contains(QName("bar")));
+
+ Opts.IndexParametersInDeclarations = false;
+ Index->Symbols.clear();
+ tooling::runToolOnCode(new IndexAction(Index, Opts), Code);
+ EXPECT_THAT(Index->Symbols, Not(Contains(QName("bar"))));
+}
+
+TEST(IndexTest, IndexExplicitTemplateInstantiation) {
+ std::string Code = R"cpp(
+ template <typename T>
+ struct Foo { void bar() {} };
+ template <>
+ struct Foo<int> { void bar() {} };
+ void foo() {
+ Foo<char> abc;
+ Foo<int> b;
+ }
+ )cpp";
+ auto Index = std::make_shared<Indexer>();
+ IndexingOptions Opts;
+ tooling::runToolOnCode(new IndexAction(Index, Opts), Code);
+ EXPECT_THAT(Index->Symbols,
+ AllOf(Contains(AllOf(QName("Foo"), WrittenAt(Position(8, 7)),
+ DeclAt(Position(5, 12)))),
+ Contains(AllOf(QName("Foo"), WrittenAt(Position(7, 7)),
+ DeclAt(Position(3, 12))))));
+}
+
+TEST(IndexTest, IndexTemplateInstantiationPartial) {
+ std::string Code = R"cpp(
+ template <typename T1, typename T2>
+ struct Foo { void bar() {} };
+ template <typename T>
+ struct Foo<T, int> { void bar() {} };
+ void foo() {
+ Foo<char, char> abc;
+ Foo<int, int> b;
+ }
+ )cpp";
+ auto Index = std::make_shared<Indexer>();
+ IndexingOptions Opts;
+ tooling::runToolOnCode(new IndexAction(Index, Opts), Code);
+ EXPECT_THAT(Index->Symbols,
+ Contains(AllOf(QName("Foo"), WrittenAt(Position(8, 7)),
+ DeclAt(Position(5, 12)))));
+}
+
+TEST(IndexTest, IndexTypeParmDecls) {
+ std::string Code = R"cpp(
+ template <typename T, int I, template<typename> class C, typename NoRef>
+ struct Foo {
+ T t = I;
+ C<int> x;
+ };
+ )cpp";
+ auto Index = std::make_shared<Indexer>();
+ IndexingOptions Opts;
+ tooling::runToolOnCode(new IndexAction(Index, Opts), Code);
+ EXPECT_THAT(Index->Symbols, AllOf(Not(Contains(QName("Foo::T"))),
+ Not(Contains(QName("Foo::I"))),
+ Not(Contains(QName("Foo::C"))),
+ Not(Contains(QName("Foo::NoRef")))));
+
+ Opts.IndexTemplateParameters = true;
+ Index->Symbols.clear();
+ tooling::runToolOnCode(new IndexAction(Index, Opts), Code);
+ EXPECT_THAT(Index->Symbols,
+ AllOf(Contains(QName("Foo::T")), Contains(QName("Foo::I")),
+ Contains(QName("Foo::C")), Contains(QName("Foo::NoRef"))));
+}
+
+TEST(IndexTest, UsingDecls) {
+ std::string Code = R"cpp(
+ void foo(int bar);
+ namespace std {
+ using ::foo;
+ }
+ )cpp";
+ auto Index = std::make_shared<Indexer>();
+ IndexingOptions Opts;
+ tooling::runToolOnCode(new IndexAction(Index, Opts), Code);
+ EXPECT_THAT(Index->Symbols,
+ Contains(AllOf(QName("std::foo"), Kind(SymbolKind::Using))));
+}
+
+TEST(IndexTest, Constructors) {
+ std::string Code = R"cpp(
+ struct Foo {
+ Foo(int);
+ ~Foo();
+ };
+ )cpp";
+ auto Index = std::make_shared<Indexer>();
+ IndexingOptions Opts;
+ tooling::runToolOnCode(new IndexAction(Index, Opts), Code);
+ EXPECT_THAT(
+ Index->Symbols,
+ UnorderedElementsAre(
+ AllOf(QName("Foo"), Kind(SymbolKind::Struct),
+ WrittenAt(Position(2, 12))),
+ AllOf(QName("Foo::Foo"), Kind(SymbolKind::Constructor),
+ WrittenAt(Position(3, 7))),
+ AllOf(QName("Foo"), Kind(SymbolKind::Struct),
+ HasRole(SymbolRole::NameReference), WrittenAt(Position(3, 7))),
+ AllOf(QName("Foo::~Foo"), Kind(SymbolKind::Destructor),
+ WrittenAt(Position(4, 7))),
+ AllOf(QName("Foo"), Kind(SymbolKind::Struct),
+ HasRole(SymbolRole::NameReference),
+ WrittenAt(Position(4, 8)))));
+}
+
} // namespace
} // namespace index
} // namespace clang
diff --git a/src/llvm-project/clang/unittests/Lex/CMakeLists.txt b/src/llvm-project/clang/unittests/Lex/CMakeLists.txt
index bb0f66d..97a4e5e 100644
--- a/src/llvm-project/clang/unittests/Lex/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/Lex/CMakeLists.txt
@@ -3,6 +3,7 @@
)
add_clang_unittest(LexTests
+ DependencyDirectivesSourceMinimizerTest.cpp
HeaderMapTest.cpp
HeaderSearchTest.cpp
LexerTest.cpp
@@ -10,7 +11,7 @@
PPConditionalDirectiveRecordTest.cpp
)
-target_link_libraries(LexTests
+clang_target_link_libraries(LexTests
PRIVATE
clangAST
clangBasic
diff --git a/src/llvm-project/clang/unittests/Lex/DependencyDirectivesSourceMinimizerTest.cpp b/src/llvm-project/clang/unittests/Lex/DependencyDirectivesSourceMinimizerTest.cpp
new file mode 100644
index 0000000..cfa3ec9
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Lex/DependencyDirectivesSourceMinimizerTest.cpp
@@ -0,0 +1,547 @@
+//===- unittests/Lex/DependencyDirectivesSourceMinimizer.cpp - -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/DependencyDirectivesSourceMinimizer.h"
+#include "llvm/ADT/SmallString.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+using namespace clang::minimize_source_to_dependency_directives;
+
+namespace clang {
+
+bool minimizeSourceToDependencyDirectives(StringRef Input,
+ SmallVectorImpl<char> &Out) {
+ SmallVector<minimize_source_to_dependency_directives::Token, 32> Tokens;
+ return minimizeSourceToDependencyDirectives(Input, Out, Tokens);
+}
+
+} // end namespace clang
+
+namespace {
+
+TEST(MinimizeSourceToDependencyDirectivesTest, Empty) {
+ SmallVector<char, 128> Out;
+ SmallVector<Token, 4> Tokens;
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("", Out, Tokens));
+ EXPECT_TRUE(Out.empty());
+ ASSERT_EQ(1u, Tokens.size());
+ ASSERT_EQ(pp_eof, Tokens.back().K);
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("abc def\nxyz", Out, Tokens));
+ EXPECT_TRUE(Out.empty());
+ ASSERT_EQ(1u, Tokens.size());
+ ASSERT_EQ(pp_eof, Tokens.back().K);
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, AllTokens) {
+ SmallVector<char, 128> Out;
+ SmallVector<Token, 4> Tokens;
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define A\n"
+ "#undef A\n"
+ "#endif\n"
+ "#if A\n"
+ "#ifdef A\n"
+ "#ifndef A\n"
+ "#elif A\n"
+ "#else\n"
+ "#include <A>\n"
+ "#include_next <A>\n"
+ "#__include_macros <A>\n"
+ "#import <A>\n"
+ "@import A;\n"
+ "#pragma clang module import A\n",
+ Out, Tokens));
+ EXPECT_EQ(pp_define, Tokens[0].K);
+ EXPECT_EQ(pp_undef, Tokens[1].K);
+ EXPECT_EQ(pp_endif, Tokens[2].K);
+ EXPECT_EQ(pp_if, Tokens[3].K);
+ EXPECT_EQ(pp_ifdef, Tokens[4].K);
+ EXPECT_EQ(pp_ifndef, Tokens[5].K);
+ EXPECT_EQ(pp_elif, Tokens[6].K);
+ EXPECT_EQ(pp_else, Tokens[7].K);
+ EXPECT_EQ(pp_include, Tokens[8].K);
+ EXPECT_EQ(pp_include_next, Tokens[9].K);
+ EXPECT_EQ(pp___include_macros, Tokens[10].K);
+ EXPECT_EQ(pp_import, Tokens[11].K);
+ EXPECT_EQ(decl_at_import, Tokens[12].K);
+ EXPECT_EQ(pp_pragma_import, Tokens[13].K);
+ EXPECT_EQ(pp_eof, Tokens[14].K);
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, Define) {
+ SmallVector<char, 128> Out;
+ SmallVector<Token, 4> Tokens;
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define MACRO", Out, Tokens));
+ EXPECT_STREQ("#define MACRO\n", Out.data());
+ ASSERT_EQ(2u, Tokens.size());
+ ASSERT_EQ(pp_define, Tokens.front().K);
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, DefineSpacing) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define MACRO\n\n\n", Out));
+ EXPECT_STREQ("#define MACRO\n", Out.data());
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define MACRO \n\n\n", Out));
+ EXPECT_STREQ("#define MACRO\n", Out.data());
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define MACRO a \n\n\n", Out));
+ EXPECT_STREQ("#define MACRO a\n", Out.data());
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define MACRO\n\n\n", Out));
+ EXPECT_STREQ("#define MACRO\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, DefineMacroArguments) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define MACRO()", Out));
+ EXPECT_STREQ("#define MACRO()\n", Out.data());
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define MACRO(a, b...)", Out));
+ EXPECT_STREQ("#define MACRO(a,b...)\n", Out.data());
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define MACRO content", Out));
+ EXPECT_STREQ("#define MACRO content\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(
+ "#define MACRO con tent ", Out));
+ EXPECT_STREQ("#define MACRO con tent\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(
+ "#define MACRO() con tent ", Out));
+ EXPECT_STREQ("#define MACRO() con tent\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, DefineInvalidMacroArguments) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define MACRO((a))", Out));
+ EXPECT_STREQ("#define MACRO(/* invalid */\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define MACRO(", Out));
+ EXPECT_STREQ("#define MACRO(/* invalid */\n", Out.data());
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define MACRO(a * b)", Out));
+ EXPECT_STREQ("#define MACRO(/* invalid */\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, DefineHorizontalWhitespace) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(
+ "#define MACRO(\t)\tcon \t tent\t", Out));
+ EXPECT_STREQ("#define MACRO() con \t tent\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(
+ "#define MACRO(\f)\fcon \f tent\f", Out));
+ EXPECT_STREQ("#define MACRO() con \f tent\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(
+ "#define MACRO(\v)\vcon \v tent\v", Out));
+ EXPECT_STREQ("#define MACRO() con \v tent\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(
+ "#define MACRO \t\v\f\v\t con\f\t\vtent\v\f \v", Out));
+ EXPECT_STREQ("#define MACRO con\f\t\vtent\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, DefineMultilineArgs) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define MACRO(a \\\n"
+ " )",
+ Out));
+ EXPECT_STREQ("#define MACRO(a)\n", Out.data());
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define MACRO(a, \\\n"
+ " b) \\\n"
+ " call((a), \\\n"
+ " (b))",
+ Out));
+ EXPECT_STREQ("#define MACRO(a,b) call((a),(b))\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest,
+ DefineMultilineArgsCarriageReturn) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define MACRO(a, \\\r"
+ " b) \\\r"
+ " call((a), \\\r"
+ " (b))",
+ Out));
+ EXPECT_STREQ("#define MACRO(a,b) call((a),(b))\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest,
+ DefineMultilineArgsCarriageReturnNewline) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define MACRO(a, \\\r\n"
+ " b) \\\r\n"
+ " call((a), \\\r\n"
+ " (b))",
+ Out));
+ EXPECT_STREQ("#define MACRO(a,b) call((a),(b))\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest,
+ DefineMultilineArgsNewlineCarriageReturn) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define MACRO(a, \\\n\r"
+ " b) \\\n\r"
+ " call((a), \\\n\r"
+ " (b))",
+ Out));
+ EXPECT_STREQ("#define MACRO(a,b) call((a),(b))\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, DefineNumber) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_TRUE(minimizeSourceToDependencyDirectives("#define 0\n", Out));
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, DefineNoName) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_TRUE(minimizeSourceToDependencyDirectives("#define &\n", Out));
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, DefineNoWhitespace) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define AND&\n", Out));
+ EXPECT_STREQ("#define AND &\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define AND\\\n"
+ "&\n",
+ Out));
+ EXPECT_STREQ("#define AND &\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, MultilineComment) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#define MACRO a/*\n"
+ " /*\n"
+ "#define MISSING abc\n"
+ " /*\n"
+ " /* something */ \n"
+ "#include /* \"def\" */ <abc> \n",
+ Out));
+ EXPECT_STREQ("#define MACRO a\n"
+ "#include <abc>\n",
+ Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, MultilineCommentInStrings) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define MACRO1 \"/*\"\n"
+ "#define MACRO2 \"*/\"\n",
+ Out));
+ EXPECT_STREQ("#define MACRO1 \"/*\"\n"
+ "#define MACRO2 \"*/\"\n",
+ Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, Ifdef) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#ifdef A\n"
+ "#define B\n"
+ "#endif\n",
+ Out));
+ EXPECT_STREQ("#ifdef A\n"
+ "#define B\n"
+ "#endif\n",
+ Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#ifdef A\n"
+ "#define B\n"
+ "#elif B\n"
+ "#define C\n"
+ "#elif C\n"
+ "#define D\n"
+ "#else\n"
+ "#define E\n"
+ "#endif\n",
+ Out));
+ EXPECT_STREQ("#ifdef A\n"
+ "#define B\n"
+ "#elif B\n"
+ "#define C\n"
+ "#elif C\n"
+ "#define D\n"
+ "#else\n"
+ "#define E\n"
+ "#endif\n",
+ Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, EmptyIfdef) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#ifdef A\n"
+ "#elif B\n"
+ "#elif C\n"
+ "#else D\n"
+ "#endif\n",
+ Out));
+ EXPECT_STREQ("", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, Pragma) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#pragma A\n", Out));
+ EXPECT_STREQ("", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#pragma clang\n", Out));
+ EXPECT_STREQ("", Out.data());
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#pragma clang module\n", Out));
+ EXPECT_STREQ("", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(
+ "#pragma clang module impor\n", Out));
+ EXPECT_STREQ("", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(
+ "#pragma clang module import\n", Out));
+ EXPECT_STREQ("#pragma clang module import\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, Include) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#include \"A\"\n", Out));
+ EXPECT_STREQ("#include \"A\"\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#include <A>\n", Out));
+ EXPECT_STREQ("#include <A>\n", Out.data());
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#include_next <A>\n", Out));
+ EXPECT_STREQ("#include_next <A>\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#import <A>\n", Out));
+ EXPECT_STREQ("#import <A>\n", Out.data());
+
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives("#__include_macros <A>\n", Out));
+ EXPECT_STREQ("#__include_macros <A>\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, AtImport) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("@import A;\n", Out));
+ EXPECT_STREQ("@import A;\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(" @ import A;\n", Out));
+ EXPECT_STREQ("@import A;\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("@import A\n;", Out));
+ EXPECT_STREQ("@import A;\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("@import A.B;\n", Out));
+ EXPECT_STREQ("@import A.B;\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(
+ "@import /*x*/ A /*x*/ . /*x*/ B /*x*/ \n /*x*/ ; /*x*/", Out));
+ EXPECT_STREQ("@import A.B;\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, AtImportFailures) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_TRUE(minimizeSourceToDependencyDirectives("@import A\n", Out));
+ ASSERT_TRUE(minimizeSourceToDependencyDirectives("@import MACRO(A);\n", Out));
+ ASSERT_TRUE(minimizeSourceToDependencyDirectives("@import \" \";\n", Out));
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, RawStringLiteral) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#ifndef GUARD\n"
+ "#define GUARD\n"
+ "R\"()\"\n"
+ "#endif\n",
+ Out));
+ EXPECT_STREQ("#ifndef GUARD\n"
+ "#define GUARD\n"
+ "#endif\n",
+ Out.data());
+
+ bool RawStringLiteralResult = minimizeSourceToDependencyDirectives(
+ "#ifndef GUARD\n"
+ "#define GUARD\n"
+ R"raw(static constexpr char bytes[] = R"(-?:\,[]{}#&*!|>'"%@`)";)raw"
+ "\n"
+ "#endif\n",
+ Out);
+ ASSERT_FALSE(RawStringLiteralResult);
+ EXPECT_STREQ("#ifndef GUARD\n"
+ "#define GUARD\n"
+ "#endif\n",
+ Out.data());
+
+ bool RawStringLiteralResult2 = minimizeSourceToDependencyDirectives(
+ "#ifndef GUARD\n"
+ "#define GUARD\n"
+ R"raw(static constexpr char bytes[] = R"abc(-?:\,[]{}#&*!|>'"%@`)abc";)raw"
+ "\n"
+ "#endif\n",
+ Out);
+ ASSERT_FALSE(RawStringLiteralResult2);
+ EXPECT_STREQ("#ifndef GUARD\n"
+ "#define GUARD\n"
+ "#endif\n",
+ Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, SplitIdentifier) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#if\\\n"
+ "ndef GUARD\n"
+ "#define GUARD\n"
+ "#endif\n",
+ Out));
+ EXPECT_STREQ("#ifndef GUARD\n"
+ "#define GUARD\n"
+ "#endif\n",
+ Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define GUA\\\n"
+ "RD\n",
+ Out));
+ EXPECT_STREQ("#define GUARD\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define GUA\\\r"
+ "RD\n",
+ Out));
+ EXPECT_STREQ("#define GUARD\n", Out.data());
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define GUA\\\n"
+ " RD\n",
+ Out));
+ EXPECT_STREQ("#define GUA RD\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, PoundWarningAndError) {
+ SmallVector<char, 128> Out;
+
+ for (auto Source : {
+ "#warning '\n#include <t.h>\n",
+ "#warning \"\n#include <t.h>\n",
+ "#warning /*\n#include <t.h>\n",
+ "#warning \\\n#include <t.h>\n#include <t.h>\n",
+ "#error '\n#include <t.h>\n",
+ "#error \"\n#include <t.h>\n",
+ "#error /*\n#include <t.h>\n",
+ "#error \\\n#include <t.h>\n#include <t.h>\n",
+ }) {
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
+ EXPECT_STREQ("#include <t.h>\n", Out.data());
+ }
+
+ for (auto Source : {
+ "#warning \\\n#include <t.h>\n",
+ "#error \\\n#include <t.h>\n",
+ "#if MACRO\n#warning '\n#endif\n",
+ "#if MACRO\n#warning \"\n#endif\n",
+ "#if MACRO\n#warning /*\n#endif\n",
+ "#if MACRO\n#error '\n#endif\n",
+ "#if MACRO\n#error \"\n#endif\n",
+ "#if MACRO\n#error /*\n#endif\n",
+ }) {
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
+ EXPECT_STREQ("", Out.data());
+ }
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, CharacterLiteral) {
+ SmallVector<char, 128> Out;
+
+ StringRef Source = R"(
+#include <bob>
+int a = 0'1;
+int b = 0xfa'af'fa;
+int c = 12 ' ';
+#include <foo>
+)";
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
+ EXPECT_STREQ("#include <bob>\n#include <foo>\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, CharacterLiteralPrefixL) {
+ SmallVector<char, 128> Out;
+
+ StringRef Source = R"(L'P'
+#if DEBUG
+// '
+#endif
+#include <test.h>
+)";
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
+ EXPECT_STREQ("#include <test.h>\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, CharacterLiteralPrefixU) {
+ SmallVector<char, 128> Out;
+
+ StringRef Source = R"(int x = U'P';
+#include <test.h>
+// '
+)";
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
+ EXPECT_STREQ("#include <test.h>\n", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest, CharacterLiteralPrefixu) {
+ SmallVector<char, 128> Out;
+
+ StringRef Source = R"(int x = u'b';
+int y = u8'a';
+int z = 128'78;
+#include <test.h>
+// '
+)";
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
+ EXPECT_STREQ("#include <test.h>\n", Out.data());
+}
+
+} // end anonymous namespace
diff --git a/src/llvm-project/clang/unittests/Lex/HeaderMapTest.cpp b/src/llvm-project/clang/unittests/Lex/HeaderMapTest.cpp
index d16efe8..c18ce79 100644
--- a/src/llvm-project/clang/unittests/Lex/HeaderMapTest.cpp
+++ b/src/llvm-project/clang/unittests/Lex/HeaderMapTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Lex/HeaderMapTest.cpp - HeaderMap tests ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===--------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Lex/HeaderSearchTest.cpp b/src/llvm-project/clang/unittests/Lex/HeaderSearchTest.cpp
index 060135b..626cfad 100644
--- a/src/llvm-project/clang/unittests/Lex/HeaderSearchTest.cpp
+++ b/src/llvm-project/clang/unittests/Lex/HeaderSearchTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Lex/HeaderSearchTest.cpp ------ HeaderSearch tests -------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -12,12 +11,12 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Serialization/InMemoryModuleCache.h"
#include "gtest/gtest.h"
namespace clang {
@@ -60,37 +59,82 @@
TEST_F(HeaderSearchTest, NoSearchDir) {
EXPECT_EQ(Search.search_dir_size(), 0u);
- EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/z", /*WorkingDir=*/""),
+ EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/z", /*WorkingDir=*/"",
+ /*MainFile=*/""),
"/x/y/z");
}
TEST_F(HeaderSearchTest, SimpleShorten) {
addSearchDir("/x");
addSearchDir("/x/y");
- EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/z", /*WorkingDir=*/""),
+ EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/z", /*WorkingDir=*/"",
+ /*MainFile=*/""),
"z");
addSearchDir("/a/b/");
- EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c", /*WorkingDir=*/""),
+ EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c", /*WorkingDir=*/"",
+ /*MainFile=*/""),
"c");
}
TEST_F(HeaderSearchTest, ShortenWithWorkingDir) {
addSearchDir("x/y");
EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c/x/y/z",
- /*WorkingDir=*/"/a/b/c"),
+ /*WorkingDir=*/"/a/b/c",
+ /*MainFile=*/""),
"z");
}
TEST_F(HeaderSearchTest, Dots) {
addSearchDir("/x/./y/");
EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/./z",
- /*WorkingDir=*/""),
+ /*WorkingDir=*/"",
+ /*MainFile=*/""),
"z");
addSearchDir("a/.././c/");
EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/m/n/./c/z",
- /*WorkingDir=*/"/m/n/"),
+ /*WorkingDir=*/"/m/n/",
+ /*MainFile=*/""),
"z");
}
+#ifdef _WIN32
+TEST_F(HeaderSearchTest, BackSlash) {
+ addSearchDir("C:\\x\\y\\");
+ EXPECT_EQ(Search.suggestPathToFileForDiagnostics("C:\\x\\y\\z\\t",
+ /*WorkingDir=*/"",
+ /*MainFile=*/""),
+ "z/t");
+}
+
+TEST_F(HeaderSearchTest, BackSlashWithDotDot) {
+ addSearchDir("..\\y");
+ EXPECT_EQ(Search.suggestPathToFileForDiagnostics("C:\\x\\y\\z\\t",
+ /*WorkingDir=*/"C:/x/y/",
+ /*MainFile=*/""),
+ "z/t");
+}
+#endif
+
+TEST_F(HeaderSearchTest, DotDotsWithAbsPath) {
+ addSearchDir("/x/../y/");
+ EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z",
+ /*WorkingDir=*/"",
+ /*MainFile=*/""),
+ "z");
+}
+
+TEST_F(HeaderSearchTest, IncludeFromSameDirectory) {
+ EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z/t.h",
+ /*WorkingDir=*/"",
+ /*MainFile=*/"/y/a.cc"),
+ "z/t.h");
+
+ addSearchDir("/");
+ EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z/t.h",
+ /*WorkingDir=*/"",
+ /*MainFile=*/"/y/a.cc"),
+ "y/z/t.h");
+}
+
} // namespace
} // namespace clang
diff --git a/src/llvm-project/clang/unittests/Lex/LexerTest.cpp b/src/llvm-project/clang/unittests/Lex/LexerTest.cpp
index c913062..7b14f56 100644
--- a/src/llvm-project/clang/unittests/Lex/LexerTest.cpp
+++ b/src/llvm-project/clang/unittests/Lex/LexerTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Lex/LexerTest.cpp ------ Lexer tests ---------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -12,7 +11,6 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
@@ -49,12 +47,11 @@
llvm::MemoryBuffer::getMemBuffer(Source);
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
- MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
std::unique_ptr<Preprocessor> PP = llvm::make_unique<Preprocessor>(
std::make_shared<PreprocessorOptions>(), Diags, LangOpts, SourceMgr,
- PCMCache, HeaderInfo, ModLoader,
+ HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP->Initialize(*Target);
@@ -516,4 +513,23 @@
EXPECT_EQ(String6, R"(a\\\n\n\n \\\\b)");
}
+TEST_F(LexerTest, CharRangeOffByOne) {
+ std::vector<Token> toks = Lex(R"(#define MOO 1
+ void foo() { MOO; })");
+ const Token &moo = toks[5];
+
+ EXPECT_EQ(getSourceText(moo, moo), "MOO");
+
+ SourceRange R{moo.getLocation(), moo.getLocation()};
+
+ EXPECT_TRUE(
+ Lexer::isAtStartOfMacroExpansion(R.getBegin(), SourceMgr, LangOpts));
+ EXPECT_TRUE(
+ Lexer::isAtEndOfMacroExpansion(R.getEnd(), SourceMgr, LangOpts));
+
+ CharSourceRange CR = Lexer::getAsCharRange(R, SourceMgr, LangOpts);
+
+ EXPECT_EQ(Lexer::getSourceText(CR, SourceMgr, LangOpts), "MOO"); // Was "MO".
+}
+
} // anonymous namespace
diff --git a/src/llvm-project/clang/unittests/Lex/PPCallbacksTest.cpp b/src/llvm-project/clang/unittests/Lex/PPCallbacksTest.cpp
index 838e033..9176596 100644
--- a/src/llvm-project/clang/unittests/Lex/PPCallbacksTest.cpp
+++ b/src/llvm-project/clang/unittests/Lex/PPCallbacksTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Lex/PPCallbacksTest.cpp - PPCallbacks tests ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===--------------------------------------------------------------===//
@@ -14,7 +13,6 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
@@ -179,14 +177,13 @@
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
TrivialModuleLoader ModLoader;
- MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
- SourceMgr, PCMCache, HeaderInfo, ModLoader,
+ SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
return InclusionDirectiveCallback(PP)->FilenameRange;
@@ -199,14 +196,13 @@
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
TrivialModuleLoader ModLoader;
- MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
- SourceMgr, PCMCache, HeaderInfo, ModLoader,
+ SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
return InclusionDirectiveCallback(PP)->FileType;
@@ -234,14 +230,13 @@
std::vector<CondDirectiveCallbacks::Result>
DirectiveExprRange(StringRef SourceText) {
TrivialModuleLoader ModLoader;
- MemoryBufferCache PCMCache;
std::unique_ptr<llvm::MemoryBuffer> Buf =
llvm::MemoryBuffer::getMemBuffer(SourceText);
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
- SourceMgr, PCMCache, HeaderInfo, ModLoader,
+ SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
@@ -271,12 +266,11 @@
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
TrivialModuleLoader ModLoader;
- MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, OpenCLLangOpts, Target.get());
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags,
- OpenCLLangOpts, SourceMgr, PCMCache, HeaderInfo, ModLoader,
+ OpenCLLangOpts, SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
@@ -431,16 +425,69 @@
}
TEST_F(PPCallbacksTest, DirectiveExprRanges) {
+ const auto &Results1 = DirectiveExprRange("#if FLUZZY_FLOOF\n#endif\n");
+ EXPECT_EQ(Results1.size(), 1U);
+ EXPECT_EQ(
+ GetSourceStringToEnd(CharSourceRange(Results1[0].ConditionRange, false)),
+ "FLUZZY_FLOOF");
+
+ const auto &Results2 = DirectiveExprRange("#if 1 + 4 < 7\n#endif\n");
+ EXPECT_EQ(Results2.size(), 1U);
+ EXPECT_EQ(
+ GetSourceStringToEnd(CharSourceRange(Results2[0].ConditionRange, false)),
+ "1 + 4 < 7");
+
+ const auto &Results3 = DirectiveExprRange("#if 1 + \\\n 2\n#endif\n");
+ EXPECT_EQ(Results3.size(), 1U);
+ EXPECT_EQ(
+ GetSourceStringToEnd(CharSourceRange(Results3[0].ConditionRange, false)),
+ "1 + \\\n 2");
+
+ const auto &Results4 = DirectiveExprRange("#if 0\n#elif FLOOFY\n#endif\n");
+ EXPECT_EQ(Results4.size(), 2U);
+ EXPECT_EQ(
+ GetSourceStringToEnd(CharSourceRange(Results4[0].ConditionRange, false)),
+ "0");
+ EXPECT_EQ(
+ GetSourceStringToEnd(CharSourceRange(Results4[1].ConditionRange, false)),
+ "FLOOFY");
+
+ const auto &Results5 = DirectiveExprRange("#if 1\n#elif FLOOFY\n#endif\n");
+ EXPECT_EQ(Results5.size(), 2U);
+ EXPECT_EQ(
+ GetSourceStringToEnd(CharSourceRange(Results5[0].ConditionRange, false)),
+ "1");
+ EXPECT_EQ(
+ GetSourceStringToEnd(CharSourceRange(Results5[1].ConditionRange, false)),
+ "FLOOFY");
+
+ const auto &Results6 =
+ DirectiveExprRange("#if defined(FLUZZY_FLOOF)\n#endif\n");
+ EXPECT_EQ(Results6.size(), 1U);
+ EXPECT_EQ(
+ GetSourceStringToEnd(CharSourceRange(Results6[0].ConditionRange, false)),
+ "defined(FLUZZY_FLOOF)");
+
+ const auto &Results7 =
+ DirectiveExprRange("#if 1\n#elif defined(FLOOFY)\n#endif\n");
+ EXPECT_EQ(Results7.size(), 2U);
+ EXPECT_EQ(
+ GetSourceStringToEnd(CharSourceRange(Results7[0].ConditionRange, false)),
+ "1");
+ EXPECT_EQ(
+ GetSourceStringToEnd(CharSourceRange(Results7[1].ConditionRange, false)),
+ "defined(FLOOFY)");
+
const auto &Results8 =
DirectiveExprRange("#define FLOOFY 0\n#if __FILE__ > FLOOFY\n#endif\n");
EXPECT_EQ(Results8.size(), 1U);
EXPECT_EQ(
GetSourceStringToEnd(CharSourceRange(Results8[0].ConditionRange, false)),
- " __FILE__ > FLOOFY\n#");
+ "__FILE__ > FLOOFY");
EXPECT_EQ(
Lexer::getSourceText(CharSourceRange(Results8[0].ConditionRange, false),
SourceMgr, LangOpts),
- " __FILE__ > FLOOFY\n");
+ "__FILE__ > FLOOFY");
}
} // namespace
diff --git a/src/llvm-project/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp b/src/llvm-project/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
index f7b6f71..ba75639 100644
--- a/src/llvm-project/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
+++ b/src/llvm-project/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Lex/PPConditionalDirectiveRecordTest.cpp-PP directive tests =//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -12,7 +11,6 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/MemoryBufferCache.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
@@ -76,11 +74,10 @@
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
TrivialModuleLoader ModLoader;
- MemoryBufferCache PCMCache;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
- SourceMgr, PCMCache, HeaderInfo, ModLoader,
+ SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
diff --git a/src/llvm-project/clang/unittests/Rename/CMakeLists.txt b/src/llvm-project/clang/unittests/Rename/CMakeLists.txt
index f91021dd..a33d7d8 100644
--- a/src/llvm-project/clang/unittests/Rename/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/Rename/CMakeLists.txt
@@ -13,7 +13,7 @@
RenameFunctionTest.cpp
)
-target_link_libraries(ClangRenameTests
+clang_target_link_libraries(ClangRenameTests
PRIVATE
clangAST
clangASTMatchers
@@ -24,5 +24,5 @@
clangSerialization
clangTooling
clangToolingCore
- clangToolingRefactor
+ clangToolingRefactoring
)
diff --git a/src/llvm-project/clang/unittests/Rename/ClangRenameTest.h b/src/llvm-project/clang/unittests/Rename/ClangRenameTest.h
index 13906d1..9dfa6d9 100644
--- a/src/llvm-project/clang/unittests/Rename/ClangRenameTest.h
+++ b/src/llvm-project/clang/unittests/Rename/ClangRenameTest.h
@@ -1,9 +1,8 @@
//===-- ClangRenameTests.cpp - clang-rename unit tests --------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Rename/RenameAliasTest.cpp b/src/llvm-project/clang/unittests/Rename/RenameAliasTest.cpp
index 59becae..ad9ce65 100644
--- a/src/llvm-project/clang/unittests/Rename/RenameAliasTest.cpp
+++ b/src/llvm-project/clang/unittests/Rename/RenameAliasTest.cpp
@@ -1,9 +1,8 @@
//===-- RenameAliasTest.cpp - unit tests for renaming alias ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Rename/RenameClassTest.cpp b/src/llvm-project/clang/unittests/Rename/RenameClassTest.cpp
index 5845d63..04a9138 100644
--- a/src/llvm-project/clang/unittests/Rename/RenameClassTest.cpp
+++ b/src/llvm-project/clang/unittests/Rename/RenameClassTest.cpp
@@ -1,9 +1,8 @@
//===-- RenameClassTest.cpp - unit tests for renaming classes -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Rename/RenameFunctionTest.cpp b/src/llvm-project/clang/unittests/Rename/RenameFunctionTest.cpp
index b27bbe2..1c9b112 100644
--- a/src/llvm-project/clang/unittests/Rename/RenameFunctionTest.cpp
+++ b/src/llvm-project/clang/unittests/Rename/RenameFunctionTest.cpp
@@ -1,9 +1,8 @@
//===-- RenameFunctionTest.cpp - unit tests for renaming functions --------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Rename/RenameMemberTest.cpp b/src/llvm-project/clang/unittests/Rename/RenameMemberTest.cpp
index fb8d558..c9192c6 100644
--- a/src/llvm-project/clang/unittests/Rename/RenameMemberTest.cpp
+++ b/src/llvm-project/clang/unittests/Rename/RenameMemberTest.cpp
@@ -1,9 +1,8 @@
//===-- ClangMemberTests.cpp - unit tests for renaming class members ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Rewrite/CMakeLists.txt b/src/llvm-project/clang/unittests/Rewrite/CMakeLists.txt
index 8edd9ba..6594d8c 100644
--- a/src/llvm-project/clang/unittests/Rewrite/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/Rewrite/CMakeLists.txt
@@ -4,8 +4,12 @@
add_clang_unittest(RewriteTests
RewriteBufferTest.cpp
+ RewriterTest.cpp
)
-target_link_libraries(RewriteTests
+clang_target_link_libraries(RewriteTests
PRIVATE
+ clangFrontend
clangRewrite
+ clangSerialization
+ clangTooling
)
diff --git a/src/llvm-project/clang/unittests/Rewrite/RewriteBufferTest.cpp b/src/llvm-project/clang/unittests/Rewrite/RewriteBufferTest.cpp
index e3b7d1f..eb8d986c 100644
--- a/src/llvm-project/clang/unittests/Rewrite/RewriteBufferTest.cpp
+++ b/src/llvm-project/clang/unittests/Rewrite/RewriteBufferTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Rewrite/RewriteBufferTest.cpp - RewriteBuffer tests ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Rewrite/RewriterTest.cpp b/src/llvm-project/clang/unittests/Rewrite/RewriterTest.cpp
new file mode 100644
index 0000000..ca72dde
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Rewrite/RewriterTest.cpp
@@ -0,0 +1,80 @@
+//===- unittests/Rewrite/RewriterTest.cpp - Rewriter tests ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+
+namespace {
+
+struct RangeTypeTest {
+ std::unique_ptr<ASTUnit> AST;
+ Rewriter Rewrite;
+ SourceLocation FileStart;
+ CharSourceRange CRange; // covers exact char range
+ CharSourceRange TRange; // extends CRange to whole tokens
+ SourceRange SRange; // different type but behaves like TRange
+ SourceLocation makeLoc(int Off) { return FileStart.getLocWithOffset(Off); }
+ CharSourceRange makeCharRange(int StartOff, int EndOff) {
+ return CharSourceRange::getCharRange(makeLoc(StartOff), makeLoc(EndOff));
+ }
+ RangeTypeTest(StringRef Code, int StartOff, int EndOff) {
+ AST = tooling::buildASTFromCode(Code);
+ ASTContext &C = AST->getASTContext();
+ Rewrite = Rewriter(C.getSourceManager(), C.getLangOpts());
+ FileStart = AST->getStartOfMainFileID();
+ CRange = makeCharRange(StartOff, EndOff);
+ SRange = CRange.getAsRange();
+ TRange = CharSourceRange::getTokenRange(SRange);
+ }
+};
+
+TEST(Rewriter, GetRewrittenTextRangeTypes) {
+ // Check that correct text is retrieved for each range type. Check again
+ // after a modification. Ranges remain in terms of the original text but
+ // include the new text.
+ StringRef Code = "int main() { return 0; }";
+ // get char range ^~~ = "ret"
+ // get token range ^~~+++ = "return"
+ // get source range ^~~+++ = "return"
+ // insert "x" ^
+ // get char range ^~~ = "xret"
+ // get token range ^~~+++ = "xreturn"
+ // get source range ^~~+++ = "xreturn"
+ RangeTypeTest T(Code, 13, 16);
+ EXPECT_EQ(T.Rewrite.getRewrittenText(T.CRange), "ret");
+ EXPECT_EQ(T.Rewrite.getRewrittenText(T.TRange), "return");
+ EXPECT_EQ(T.Rewrite.getRewrittenText(T.SRange), "return");
+ T.Rewrite.InsertText(T.makeLoc(13), "x");
+ EXPECT_EQ(T.Rewrite.getRewrittenText(T.CRange), "xret");
+ EXPECT_EQ(T.Rewrite.getRewrittenText(T.TRange), "xreturn");
+ EXPECT_EQ(T.Rewrite.getRewrittenText(T.SRange), "xreturn");
+}
+
+TEST(Rewriter, ReplaceTextRangeTypes) {
+ // Check that correct text is replaced for each range type. Ranges remain in
+ // terms of the original text but include the new text.
+ StringRef Code = "int main(int argc, char *argv[]) { return argc; }";
+ // replace char range with "foo" ^~
+ // get ^~~~~ = "foogc;"
+ // replace token range with "bar" ^~++
+ // get ^~~~~ = "bar;"
+ // replace source range with "0" ^~++
+ // get ^~~~~ = "0;"
+ RangeTypeTest T(Code, 42, 44);
+ T.Rewrite.ReplaceText(T.CRange, "foo");
+ EXPECT_EQ(T.Rewrite.getRewrittenText(T.makeCharRange(42, 47)), "foogc;");
+ T.Rewrite.ReplaceText(T.TRange, "bar");
+ EXPECT_EQ(T.Rewrite.getRewrittenText(T.makeCharRange(42, 47)), "bar;");
+ T.Rewrite.ReplaceText(T.SRange, "0");
+ EXPECT_EQ(T.Rewrite.getRewrittenText(T.makeCharRange(42, 47)), "0;");
+}
+
+} // anonymous namespace
diff --git a/src/llvm-project/clang/unittests/Sema/CMakeLists.txt b/src/llvm-project/clang/unittests/Sema/CMakeLists.txt
index 7860104..51e8d6c 100644
--- a/src/llvm-project/clang/unittests/Sema/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/Sema/CMakeLists.txt
@@ -7,7 +7,7 @@
CodeCompleteTest.cpp
)
-target_link_libraries(SemaTests
+clang_target_link_libraries(SemaTests
PRIVATE
clangAST
clangBasic
@@ -17,3 +17,8 @@
clangSerialization
clangTooling
)
+
+target_link_libraries(SemaTests
+ PRIVATE
+ LLVMTestingSupport
+)
diff --git a/src/llvm-project/clang/unittests/Sema/CodeCompleteTest.cpp b/src/llvm-project/clang/unittests/Sema/CodeCompleteTest.cpp
index 28faa0c..1d0e732 100644
--- a/src/llvm-project/clang/unittests/Sema/CodeCompleteTest.cpp
+++ b/src/llvm-project/clang/unittests/Sema/CodeCompleteTest.cpp
@@ -1,9 +1,8 @@
//=== unittests/Sema/CodeCompleteTest.cpp - Code Complete tests ==============//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -14,6 +13,7 @@
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Tooling/Tooling.h"
+#include "llvm/Testing/Support/Annotations.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <cstddef>
@@ -39,9 +39,7 @@
class VisitedContextFinder : public CodeCompleteConsumer {
public:
VisitedContextFinder(CompletionContext &ResultCtx)
- : CodeCompleteConsumer(/*CodeCompleteOpts=*/{},
- /*CodeCompleteConsumer*/ false),
- ResultCtx(ResultCtx),
+ : CodeCompleteConsumer(/*CodeCompleteOpts=*/{}), ResultCtx(ResultCtx),
CCTUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {}
void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
@@ -110,41 +108,18 @@
return ResultCtx;
}
-struct ParsedAnnotations {
- std::vector<size_t> Points;
- std::string Code;
-};
-
-ParsedAnnotations parseAnnotations(StringRef AnnotatedCode) {
- ParsedAnnotations R;
- while (!AnnotatedCode.empty()) {
- size_t NextPoint = AnnotatedCode.find('^');
- if (NextPoint == StringRef::npos) {
- R.Code += AnnotatedCode;
- AnnotatedCode = "";
- break;
- }
- R.Code += AnnotatedCode.substr(0, NextPoint);
- R.Points.push_back(R.Code.size());
-
- AnnotatedCode = AnnotatedCode.substr(NextPoint + 1);
- }
- return R;
-}
-
CompletionContext runCodeCompleteOnCode(StringRef AnnotatedCode) {
- ParsedAnnotations P = parseAnnotations(AnnotatedCode);
- assert(P.Points.size() == 1 && "expected exactly one annotation point");
- return runCompletion(P.Code, P.Points.front());
+ llvm::Annotations A(AnnotatedCode);
+ return runCompletion(A.code(), A.point());
}
std::vector<std::string>
collectPreferredTypes(StringRef AnnotatedCode,
std::string *PtrDiffType = nullptr) {
- ParsedAnnotations P = parseAnnotations(AnnotatedCode);
+ llvm::Annotations A(AnnotatedCode);
std::vector<std::string> Types;
- for (size_t Point : P.Points) {
- auto Results = runCompletion(P.Code, Point);
+ for (size_t Point : A.points()) {
+ auto Results = runCompletion(A.code(), Point);
if (PtrDiffType) {
assert(PtrDiffType->empty() || *PtrDiffType == Results.PtrDiffType);
*PtrDiffType = Results.PtrDiffType;
@@ -174,12 +149,16 @@
"foo::(anonymous)"));
}
-TEST(SemaCodeCompleteTest, VisitedNSForInvalideQualifiedId) {
+TEST(SemaCodeCompleteTest, VisitedNSForInvalidQualifiedId) {
auto VisitedNS = runCodeCompleteOnCode(R"cpp(
- namespace ns { foo::^ }
+ namespace na {}
+ namespace ns1 {
+ using namespace na;
+ foo::^
+ }
)cpp")
.VisitedNamespaces;
- EXPECT_TRUE(VisitedNS.empty());
+ EXPECT_THAT(VisitedNS, UnorderedElementsAre("ns1", "na"));
}
TEST(SemaCodeCompleteTest, VisitedNSWithoutQualifier) {
@@ -340,4 +319,166 @@
EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
}
+TEST(PreferredTypeTest, Members) {
+ StringRef Code = R"cpp(
+ struct vector {
+ int *begin();
+ vector clone();
+ };
+
+ void test(int *a) {
+ a = ^vector().^clone().^begin();
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
+}
+
+TEST(PreferredTypeTest, Conditions) {
+ StringRef Code = R"cpp(
+ struct vector {
+ bool empty();
+ };
+
+ void test() {
+ if (^vector().^empty()) {}
+ while (^vector().^empty()) {}
+ for (; ^vector().^empty();) {}
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
+}
+
+TEST(PreferredTypeTest, InitAndAssignment) {
+ StringRef Code = R"cpp(
+ struct vector {
+ int* begin();
+ };
+
+ void test() {
+ const int* x = ^vector().^begin();
+ x = ^vector().^begin();
+
+ if (const int* y = ^vector().^begin()) {}
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
+}
+
+TEST(PreferredTypeTest, UnaryExprs) {
+ StringRef Code = R"cpp(
+ void test(long long a) {
+ a = +^a;
+ a = -^a
+ a = ++^a;
+ a = --^a;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("long long"));
+
+ Code = R"cpp(
+ void test(int a, int *ptr) {
+ !^a;
+ !^ptr;
+ !!!^a;
+
+ a = !^a;
+ a = !^ptr;
+ a = !!!^a;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
+
+ Code = R"cpp(
+ void test(int a) {
+ const int* x = &^a;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("const int"));
+
+ Code = R"cpp(
+ void test(int *a) {
+ int x = *^a;
+ int &r = *^a;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
+
+ Code = R"cpp(
+ void test(int a) {
+ *^a;
+ &^a;
+ }
+
+ )cpp";
+}
+
+TEST(PreferredTypeTest, ParenExpr) {
+ StringRef Code = R"cpp(
+ const int *i = ^(^(^(^10)));
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
+}
+
+TEST(PreferredTypeTest, FunctionArguments) {
+ StringRef Code = R"cpp(
+ void foo(const int*);
+
+ void bar(const int*);
+ void bar(const int*, int b);
+
+ struct vector {
+ const int *data();
+ };
+ void test() {
+ foo(^(^(^(^vec^tor^().^da^ta^()))));
+ bar(^(^(^(^vec^tor^().^da^ta^()))));
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
+
+ Code = R"cpp(
+ void bar(int, volatile double *);
+ void bar(int, volatile double *, int, int);
+
+ struct vector {
+ double *data();
+ };
+
+ struct class_members {
+ void bar(int, volatile double *);
+ void bar(int, volatile double *, int, int);
+ };
+ void test() {
+ bar(10, ^(^(^(^vec^tor^().^da^ta^()))));
+ class_members().bar(10, ^(^(^(^vec^tor^().^da^ta^()))));
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("volatile double *"));
+
+ Code = R"cpp(
+ namespace ns {
+ struct vector {
+ };
+ }
+ void accepts_vector(ns::vector);
+
+ void test() {
+ accepts_vector(^::^ns::^vector());
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("ns::vector"));
+
+ Code = R"cpp(
+ template <class T>
+ struct vector { using self = vector; };
+
+ void accepts_vector(vector<int>);
+ int foo(int);
+
+ void test() {
+ accepts_vector(^::^vector<decltype(foo(1))>::^self);
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("vector<int>"));
+}
} // namespace
diff --git a/src/llvm-project/clang/unittests/Sema/ExternalSemaSourceTest.cpp b/src/llvm-project/clang/unittests/Sema/ExternalSemaSourceTest.cpp
index d2cdd63..c591ccb 100644
--- a/src/llvm-project/clang/unittests/Sema/ExternalSemaSourceTest.cpp
+++ b/src/llvm-project/clang/unittests/Sema/ExternalSemaSourceTest.cpp
@@ -1,9 +1,8 @@
//=== unittests/Sema/ExternalSemaSourceTest.cpp - ExternalSemaSource tests ===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Serialization/CMakeLists.txt b/src/llvm-project/clang/unittests/Serialization/CMakeLists.txt
new file mode 100644
index 0000000..f143f28
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Serialization/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(LLVM_LINK_COMPONENTS
+ BitReader
+ BitstreamReader
+ Support
+ )
+
+add_clang_unittest(SerializationTests
+ InMemoryModuleCacheTest.cpp
+ )
+
+clang_target_link_libraries(SerializationTests
+ PRIVATE
+ clangAST
+ clangBasic
+ clangLex
+ clangSema
+ clangSerialization
+ )
diff --git a/src/llvm-project/clang/unittests/Serialization/InMemoryModuleCacheTest.cpp b/src/llvm-project/clang/unittests/Serialization/InMemoryModuleCacheTest.cpp
new file mode 100644
index 0000000..ed5e153
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Serialization/InMemoryModuleCacheTest.cpp
@@ -0,0 +1,119 @@
+//===- InMemoryModuleCacheTest.cpp - InMemoryModuleCache tests ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Serialization/InMemoryModuleCache.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+std::unique_ptr<MemoryBuffer> getBuffer(int I) {
+ SmallVector<char, 8> Bytes;
+ raw_svector_ostream(Bytes) << "data:" << I;
+ return MemoryBuffer::getMemBuffer(StringRef(Bytes.data(), Bytes.size()), "",
+ /* RequiresNullTerminator = */ false);
+}
+
+TEST(InMemoryModuleCacheTest, initialState) {
+ InMemoryModuleCache Cache;
+ EXPECT_EQ(InMemoryModuleCache::Unknown, Cache.getPCMState("B"));
+ EXPECT_FALSE(Cache.isPCMFinal("B"));
+ EXPECT_FALSE(Cache.shouldBuildPCM("B"));
+
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
+ EXPECT_DEATH(Cache.tryToDropPCM("B"), "PCM to remove is unknown");
+ EXPECT_DEATH(Cache.finalizePCM("B"), "PCM to finalize is unknown");
+#endif
+}
+
+TEST(InMemoryModuleCacheTest, addPCM) {
+ auto B = getBuffer(1);
+ auto *RawB = B.get();
+
+ InMemoryModuleCache Cache;
+ EXPECT_EQ(RawB, &Cache.addPCM("B", std::move(B)));
+ EXPECT_EQ(InMemoryModuleCache::Tentative, Cache.getPCMState("B"));
+ EXPECT_EQ(RawB, Cache.lookupPCM("B"));
+ EXPECT_FALSE(Cache.isPCMFinal("B"));
+ EXPECT_FALSE(Cache.shouldBuildPCM("B"));
+
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
+ EXPECT_DEATH(Cache.addPCM("B", getBuffer(2)), "Already has a PCM");
+ EXPECT_DEATH(Cache.addBuiltPCM("B", getBuffer(2)),
+ "Trying to override tentative PCM");
+#endif
+}
+
+TEST(InMemoryModuleCacheTest, addBuiltPCM) {
+ auto B = getBuffer(1);
+ auto *RawB = B.get();
+
+ InMemoryModuleCache Cache;
+ EXPECT_EQ(RawB, &Cache.addBuiltPCM("B", std::move(B)));
+ EXPECT_EQ(InMemoryModuleCache::Final, Cache.getPCMState("B"));
+ EXPECT_EQ(RawB, Cache.lookupPCM("B"));
+ EXPECT_TRUE(Cache.isPCMFinal("B"));
+ EXPECT_FALSE(Cache.shouldBuildPCM("B"));
+
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
+ EXPECT_DEATH(Cache.addPCM("B", getBuffer(2)), "Already has a PCM");
+ EXPECT_DEATH(Cache.addBuiltPCM("B", getBuffer(2)),
+ "Trying to override finalized PCM");
+#endif
+}
+
+TEST(InMemoryModuleCacheTest, tryToDropPCM) {
+ auto B1 = getBuffer(1);
+ auto B2 = getBuffer(2);
+ auto *RawB1 = B1.get();
+ auto *RawB2 = B2.get();
+ ASSERT_NE(RawB1, RawB2);
+
+ InMemoryModuleCache Cache;
+ EXPECT_EQ(InMemoryModuleCache::Unknown, Cache.getPCMState("B"));
+ EXPECT_EQ(RawB1, &Cache.addPCM("B", std::move(B1)));
+ EXPECT_FALSE(Cache.tryToDropPCM("B"));
+ EXPECT_EQ(nullptr, Cache.lookupPCM("B"));
+ EXPECT_EQ(InMemoryModuleCache::ToBuild, Cache.getPCMState("B"));
+ EXPECT_FALSE(Cache.isPCMFinal("B"));
+ EXPECT_TRUE(Cache.shouldBuildPCM("B"));
+
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
+ EXPECT_DEATH(Cache.addPCM("B", getBuffer(2)), "Already has a PCM");
+ EXPECT_DEATH(Cache.tryToDropPCM("B"),
+ "PCM to remove is scheduled to be built");
+ EXPECT_DEATH(Cache.finalizePCM("B"), "Trying to finalize a dropped PCM");
+#endif
+
+ // Add a new one.
+ EXPECT_EQ(RawB2, &Cache.addBuiltPCM("B", std::move(B2)));
+ EXPECT_TRUE(Cache.isPCMFinal("B"));
+
+ // Can try to drop again, but this should error and do nothing.
+ EXPECT_TRUE(Cache.tryToDropPCM("B"));
+ EXPECT_EQ(RawB2, Cache.lookupPCM("B"));
+}
+
+TEST(InMemoryModuleCacheTest, finalizePCM) {
+ auto B = getBuffer(1);
+ auto *RawB = B.get();
+
+ InMemoryModuleCache Cache;
+ EXPECT_EQ(InMemoryModuleCache::Unknown, Cache.getPCMState("B"));
+ EXPECT_EQ(RawB, &Cache.addPCM("B", std::move(B)));
+
+ // Call finalize.
+ Cache.finalizePCM("B");
+ EXPECT_EQ(InMemoryModuleCache::Final, Cache.getPCMState("B"));
+ EXPECT_TRUE(Cache.isPCMFinal("B"));
+}
+
+} // namespace
diff --git a/src/llvm-project/clang/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp b/src/llvm-project/clang/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp
index de41874..cd78014 100644
--- a/src/llvm-project/clang/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp
+++ b/src/llvm-project/clang/unittests/StaticAnalyzer/AnalyzerOptionsTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/StaticAnalyzer/AnalyzerOptionsTest.cpp - SA Options test --===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -49,28 +48,27 @@
}
};
- // Checker one has Option specified as true. It should read true regardless of
- // search mode.
+ // CheckerTwo one has Option specified as true. It should read true regardless
+ // of search mode.
CheckerOneMock CheckerOne;
- EXPECT_TRUE(Opts.getCheckerBooleanOption("Option", false, &CheckerOne));
+ EXPECT_TRUE(Opts.getCheckerBooleanOption(&CheckerOne, "Option"));
// The package option is overridden with a checker option.
- EXPECT_TRUE(Opts.getCheckerBooleanOption("Option", false, &CheckerOne,
- true));
+ EXPECT_TRUE(Opts.getCheckerBooleanOption(&CheckerOne, "Option", true));
// The Outer package option is overridden by the Inner package option. No
// package option is specified.
- EXPECT_TRUE(Opts.getCheckerBooleanOption("Option2", false, &CheckerOne,
- true));
- // No package option is specified and search in packages is turned off. The
- // default value should be returned.
- EXPECT_FALSE(Opts.getCheckerBooleanOption("Option2", false, &CheckerOne));
- EXPECT_TRUE(Opts.getCheckerBooleanOption("Option2", true, &CheckerOne));
+ EXPECT_TRUE(Opts.getCheckerBooleanOption(&CheckerOne, "Option2", true));
+ // No package option is specified and search in packages is turned off. We
+ // should assert here, but we can't test that.
+ //Opts.getCheckerBooleanOption(&CheckerOne, "Option2");
+ //Opts.getCheckerBooleanOption(&CheckerOne, "Option2");
- // Checker true has no option specified. It should get the default value when
- // search in parents turned off and false when search in parents turned on.
+ // Checker true has no option specified. It should get false when search in
+ // parents turned on.
CheckerTwoMock CheckerTwo;
- EXPECT_FALSE(Opts.getCheckerBooleanOption("Option", false, &CheckerTwo));
- EXPECT_TRUE(Opts.getCheckerBooleanOption("Option", true, &CheckerTwo));
- EXPECT_FALSE(Opts.getCheckerBooleanOption("Option", true, &CheckerTwo, true));
+ EXPECT_FALSE(Opts.getCheckerBooleanOption(&CheckerTwo, "Option", true));
+ // In any other case, we should assert, that we cannot test unfortunately.
+ //Opts.getCheckerBooleanOption(&CheckerTwo, "Option");
+ //Opts.getCheckerBooleanOption(&CheckerTwo, "Option");
}
TEST(StaticAnalyzerOptions, StringOptions) {
@@ -85,9 +83,15 @@
CheckerOneMock CheckerOne;
EXPECT_TRUE("StringValue" ==
- Opts.getCheckerStringOption("Option", "DefaultValue", &CheckerOne));
- EXPECT_TRUE("DefaultValue" ==
- Opts.getCheckerStringOption("Option2", "DefaultValue", &CheckerOne));
+ Opts.getCheckerStringOption(&CheckerOne, "Option"));
}
+
+TEST(StaticAnalyzerOptions, SubCheckerOptions) {
+ AnalyzerOptions Opts;
+ Opts.Config["Outer.Inner.CheckerOne:Option"] = "StringValue";
+ EXPECT_TRUE("StringValue" == Opts.getCheckerStringOption(
+ "Outer.Inner.CheckerOne", "Option"));
+}
+
} // end namespace ento
} // end namespace clang
diff --git a/src/llvm-project/clang/unittests/StaticAnalyzer/CMakeLists.txt b/src/llvm-project/clang/unittests/StaticAnalyzer/CMakeLists.txt
index 3036dec..ff92bdc 100644
--- a/src/llvm-project/clang/unittests/StaticAnalyzer/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/StaticAnalyzer/CMakeLists.txt
@@ -4,13 +4,19 @@
add_clang_unittest(StaticAnalysisTests
AnalyzerOptionsTest.cpp
+ CallDescriptionTest.cpp
+ StoreTest.cpp
RegisterCustomCheckersTest.cpp
+ SymbolReaperTest.cpp
)
-target_link_libraries(StaticAnalysisTests
+clang_target_link_libraries(StaticAnalysisTests
PRIVATE
clangBasic
clangAnalysis
+ clangAST
+ clangASTMatchers
+ clangCrossTU
clangFrontend
clangSerialization
clangStaticAnalyzerCore
diff --git a/src/llvm-project/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp b/src/llvm-project/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
new file mode 100644
index 0000000..9201922
--- /dev/null
+++ b/src/llvm-project/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
@@ -0,0 +1,162 @@
+//===- unittests/StaticAnalyzer/CallDescriptionTest.cpp -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Reusables.h"
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ento {
+namespace {
+
+// A wrapper around CallDescriptionMap<bool> that allows verifying that
+// all functions have been found. This is needed because CallDescriptionMap
+// isn't supposed to support iteration.
+class ResultMap {
+ size_t Found, Total;
+ CallDescriptionMap<bool> Impl;
+
+public:
+ ResultMap(std::initializer_list<std::pair<CallDescription, bool>> Data)
+ : Found(0),
+ Total(std::count_if(Data.begin(), Data.end(),
+ [](const std::pair<CallDescription, bool> &Pair) {
+ return Pair.second == true;
+ })),
+ Impl(std::move(Data)) {}
+
+ const bool *lookup(const CallEvent &Call) {
+ const bool *Result = Impl.lookup(Call);
+ // If it's a function we expected to find, remember that we've found it.
+ if (Result && *Result)
+ ++Found;
+ return Result;
+ }
+
+ // Fail the test if we haven't found all the true-calls we were looking for.
+ ~ResultMap() { EXPECT_EQ(Found, Total); }
+};
+
+// Scan the code body for call expressions and see if we find all calls that
+// we were supposed to find ("true" in the provided ResultMap) and that we
+// don't find the ones that we weren't supposed to find
+// ("false" in the ResultMap).
+class CallDescriptionConsumer : public ExprEngineConsumer {
+ ResultMap &RM;
+ void performTest(const Decl *D) {
+ using namespace ast_matchers;
+
+ if (!D->hasBody())
+ return;
+
+ const CallExpr *CE = findNode<CallExpr>(D, callExpr());
+ const StackFrameContext *SFC =
+ Eng.getAnalysisDeclContextManager().getStackFrame(D);
+ ProgramStateRef State = Eng.getInitialState(SFC);
+ CallEventRef<> Call =
+ Eng.getStateManager().getCallEventManager().getCall(CE, State, SFC);
+
+ const bool *LookupResult = RM.lookup(*Call);
+ // Check that we've found the function in the map
+ // with the correct description.
+ EXPECT_TRUE(LookupResult && *LookupResult);
+
+ // ResultMap is responsible for making sure that we've found *all* calls.
+ }
+
+public:
+ CallDescriptionConsumer(CompilerInstance &C,
+ ResultMap &RM)
+ : ExprEngineConsumer(C), RM(RM) {}
+
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ for (const auto *D : DG)
+ performTest(D);
+ return true;
+ }
+};
+
+class CallDescriptionAction : public ASTFrontendAction {
+ ResultMap RM;
+
+public:
+ CallDescriptionAction(
+ std::initializer_list<std::pair<CallDescription, bool>> Data)
+ : RM(Data) {}
+
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef File) override {
+ return llvm::make_unique<CallDescriptionConsumer>(Compiler, RM);
+ }
+};
+
+TEST(CallEvent, CallDescription) {
+ // Test simple name matching.
+ EXPECT_TRUE(tooling::runToolOnCode(
+ new CallDescriptionAction({
+ {{"bar"}, false}, // false: there's no call to 'bar' in this code.
+ {{"foo"}, true}, // true: there's a call to 'foo' in this code.
+ }), "void foo(); void bar() { foo(); }"));
+
+ // Test arguments check.
+ EXPECT_TRUE(tooling::runToolOnCode(
+ new CallDescriptionAction({
+ {{"foo", 1}, true},
+ {{"foo", 2}, false},
+ }), "void foo(int); void foo(int, int); void bar() { foo(1); }"));
+
+ // Test lack of arguments check.
+ EXPECT_TRUE(tooling::runToolOnCode(
+ new CallDescriptionAction({
+ {{"foo", None}, true},
+ {{"foo", 2}, false},
+ }), "void foo(int); void foo(int, int); void bar() { foo(1); }"));
+
+ // Test qualified names.
+ EXPECT_TRUE(tooling::runToolOnCode(
+ new CallDescriptionAction({
+ {{{"std", "basic_string", "c_str"}}, true},
+ }),
+ "namespace std { inline namespace __1 {"
+ " template<typename T> class basic_string {"
+ " public:"
+ " T *c_str();"
+ " };"
+ "}}"
+ "void foo() {"
+ " using namespace std;"
+ " basic_string<char> s;"
+ " s.c_str();"
+ "}"));
+
+ // A negative test for qualified names.
+ EXPECT_TRUE(tooling::runToolOnCode(
+ new CallDescriptionAction({
+ {{{"foo", "bar"}}, false},
+ {{{"bar", "foo"}}, false},
+ {{"foo"}, true},
+ }), "void foo(); struct bar { void foo(); }; void test() { foo(); }"));
+
+ // Test CDF_MaybeBuiltin - a flag that allows matching weird builtins.
+ EXPECT_TRUE(tooling::runToolOnCode(
+ new CallDescriptionAction({
+ {{"memset", 3}, false},
+ {{CDF_MaybeBuiltin, "memset", 3}, true}
+ }),
+ "void foo() {"
+ " int x;"
+ " __builtin___memset_chk(&x, 0, sizeof(x),"
+ " __builtin_object_size(&x, 0));"
+ "}"));
+}
+
+} // namespace
+} // namespace ento
+} // namespace clang
diff --git a/src/llvm-project/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp b/src/llvm-project/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
index 568a719..d8988a0 100644
--- a/src/llvm-project/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
+++ b/src/llvm-project/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -89,8 +88,9 @@
void checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
CheckerContext &C) const {
auto UnaryOp = dyn_cast<UnaryOperator>(S);
- if (UnaryOp && !IsLoad)
+ if (UnaryOp && !IsLoad) {
EXPECT_FALSE(UnaryOp->isIncrementOp());
+ }
}
};
diff --git a/src/llvm-project/clang/unittests/StaticAnalyzer/Reusables.h b/src/llvm-project/clang/unittests/StaticAnalyzer/Reusables.h
new file mode 100644
index 0000000..49b96f6
--- /dev/null
+++ b/src/llvm-project/clang/unittests/StaticAnalyzer/Reusables.h
@@ -0,0 +1,71 @@
+//===- unittests/StaticAnalyzer/Reusables.h -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_UNITTESTS_STATICANALYZER_REUSABLES_H
+#define LLVM_CLANG_UNITTESTS_STATICANALYZER_REUSABLES_H
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/CrossTU/CrossTranslationUnit.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+
+namespace clang {
+namespace ento {
+
+// Find a node in the current AST that matches a matcher.
+template <typename T, typename MatcherT>
+const T *findNode(const Decl *Where, MatcherT What) {
+ using namespace ast_matchers;
+ auto Matches = match(decl(hasDescendant(What.bind("root"))),
+ *Where, Where->getASTContext());
+ assert(Matches.size() <= 1 && "Ambiguous match!");
+ assert(Matches.size() >= 1 && "Match not found!");
+ const T *Node = selectFirst<T>("root", Matches);
+ assert(Node && "Type mismatch!");
+ return Node;
+}
+
+// Find a declaration in the current AST by name.
+template <typename T>
+const T *findDeclByName(const Decl *Where, StringRef Name) {
+ using namespace ast_matchers;
+ return findNode<T>(Where, namedDecl(hasName(Name)));
+}
+
+// A re-usable consumer that constructs ExprEngine out of CompilerInvocation.
+class ExprEngineConsumer : public ASTConsumer {
+protected:
+ CompilerInstance &C;
+
+private:
+ // We need to construct all of these in order to construct ExprEngine.
+ CheckerManager ChkMgr;
+ cross_tu::CrossTranslationUnitContext CTU;
+ PathDiagnosticConsumers Consumers;
+ AnalysisManager AMgr;
+ SetOfConstDecls VisitedCallees;
+ FunctionSummariesTy FS;
+
+protected:
+ ExprEngine Eng;
+
+public:
+ ExprEngineConsumer(CompilerInstance &C)
+ : C(C), ChkMgr(C.getASTContext(), *C.getAnalyzerOpts()), CTU(C),
+ Consumers(),
+ AMgr(C.getASTContext(), C.getDiagnostics(), Consumers,
+ CreateRegionStoreManager, CreateRangeConstraintManager, &ChkMgr,
+ *C.getAnalyzerOpts()),
+ VisitedCallees(), FS(),
+ Eng(CTU, AMgr, &VisitedCallees, &FS, ExprEngine::Inline_Regular) {}
+};
+
+} // namespace ento
+} // namespace clang
+
+#endif
diff --git a/src/llvm-project/clang/unittests/StaticAnalyzer/StoreTest.cpp b/src/llvm-project/clang/unittests/StaticAnalyzer/StoreTest.cpp
new file mode 100644
index 0000000..ab8c781
--- /dev/null
+++ b/src/llvm-project/clang/unittests/StaticAnalyzer/StoreTest.cpp
@@ -0,0 +1,105 @@
+//===- unittests/StaticAnalyzer/StoreTest.cpp -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Reusables.h"
+
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ento {
+namespace {
+
+// Test that we can put a value into an int-type variable and load it
+// back from that variable. Test what happens if default bindings are used.
+class VariableBindConsumer : public ExprEngineConsumer {
+ void performTest(const Decl *D) {
+ StoreManager &StMgr = Eng.getStoreManager();
+ SValBuilder &SVB = Eng.getSValBuilder();
+ MemRegionManager &MRMgr = StMgr.getRegionManager();
+ const ASTContext &ACtx = Eng.getContext();
+
+ const auto *VDX0 = findDeclByName<VarDecl>(D, "x0");
+ const auto *VDY0 = findDeclByName<VarDecl>(D, "y0");
+ const auto *VDZ0 = findDeclByName<VarDecl>(D, "z0");
+ const auto *VDX1 = findDeclByName<VarDecl>(D, "x1");
+ const auto *VDY1 = findDeclByName<VarDecl>(D, "y1");
+ assert(VDX0 && VDY0 && VDZ0 && VDX1 && VDY1);
+
+ const StackFrameContext *SFC =
+ Eng.getAnalysisDeclContextManager().getStackFrame(D);
+
+ Loc LX0 = loc::MemRegionVal(MRMgr.getVarRegion(VDX0, SFC));
+ Loc LY0 = loc::MemRegionVal(MRMgr.getVarRegion(VDY0, SFC));
+ Loc LZ0 = loc::MemRegionVal(MRMgr.getVarRegion(VDZ0, SFC));
+ Loc LX1 = loc::MemRegionVal(MRMgr.getVarRegion(VDX1, SFC));
+ Loc LY1 = loc::MemRegionVal(MRMgr.getVarRegion(VDY1, SFC));
+
+ Store StInit = StMgr.getInitialStore(SFC).getStore();
+ SVal Zero = SVB.makeZeroVal(ACtx.IntTy);
+ SVal One = SVB.makeIntVal(1, ACtx.IntTy);
+ SVal NarrowZero = SVB.makeZeroVal(ACtx.CharTy);
+
+ // Bind(Zero)
+ Store StX0 =
+ StMgr.Bind(StInit, LX0, Zero).getStore();
+ ASSERT_EQ(Zero, StMgr.getBinding(StX0, LX0, ACtx.IntTy));
+
+ // BindDefaultInitial(Zero)
+ Store StY0 =
+ StMgr.BindDefaultInitial(StInit, LY0.getAsRegion(), Zero).getStore();
+ ASSERT_EQ(Zero, StMgr.getBinding(StY0, LY0, ACtx.IntTy));
+ ASSERT_EQ(Zero, *StMgr.getDefaultBinding(StY0, LY0.getAsRegion()));
+
+ // BindDefaultZero()
+ Store StZ0 =
+ StMgr.BindDefaultZero(StInit, LZ0.getAsRegion()).getStore();
+ // BindDefaultZero wipes the region with '0 S8b', not with out Zero.
+ // Direct load, however, does give us back the object of the type
+ // that we specify for loading.
+ ASSERT_EQ(Zero, StMgr.getBinding(StZ0, LZ0, ACtx.IntTy));
+ ASSERT_EQ(NarrowZero, *StMgr.getDefaultBinding(StZ0, LZ0.getAsRegion()));
+
+ // Bind(One)
+ Store StX1 =
+ StMgr.Bind(StInit, LX1, One).getStore();
+ ASSERT_EQ(One, StMgr.getBinding(StX1, LX1, ACtx.IntTy));
+
+ // BindDefaultInitial(One)
+ Store StY1 =
+ StMgr.BindDefaultInitial(StInit, LY1.getAsRegion(), One).getStore();
+ ASSERT_EQ(One, StMgr.getBinding(StY1, LY1, ACtx.IntTy));
+ ASSERT_EQ(One, *StMgr.getDefaultBinding(StY1, LY1.getAsRegion()));
+ }
+
+public:
+ VariableBindConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
+
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ for (const auto *D : DG)
+ performTest(D);
+ return true;
+ }
+};
+
+class VariableBindAction : public ASTFrontendAction {
+public:
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef File) override {
+ return llvm::make_unique<VariableBindConsumer>(Compiler);
+ }
+};
+
+TEST(Store, VariableBind) {
+ EXPECT_TRUE(tooling::runToolOnCode(
+ new VariableBindAction, "void foo() { int x0, y0, z0, x1, y1; }"));
+}
+
+} // namespace
+} // namespace ento
+} // namespace clang
diff --git a/src/llvm-project/clang/unittests/StaticAnalyzer/SymbolReaperTest.cpp b/src/llvm-project/clang/unittests/StaticAnalyzer/SymbolReaperTest.cpp
new file mode 100644
index 0000000..5d9af31
--- /dev/null
+++ b/src/llvm-project/clang/unittests/StaticAnalyzer/SymbolReaperTest.cpp
@@ -0,0 +1,70 @@
+//===- unittests/StaticAnalyzer/SymbolReaperTest.cpp ----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Reusables.h"
+
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ento {
+namespace {
+
+class SuperRegionLivenessConsumer : public ExprEngineConsumer {
+ void performTest(const Decl *D) {
+ const auto *FD = findDeclByName<FieldDecl>(D, "x");
+ const auto *VD = findDeclByName<VarDecl>(D, "s");
+ assert(FD && VD);
+
+ // The variable must belong to a stack frame,
+ // otherwise SymbolReaper would think it's a global.
+ const StackFrameContext *SFC =
+ Eng.getAnalysisDeclContextManager().getStackFrame(D);
+
+ // Create regions for 's' and 's.x'.
+ const VarRegion *VR = Eng.getRegionManager().getVarRegion(VD, SFC);
+ const FieldRegion *FR = Eng.getRegionManager().getFieldRegion(FD, VR);
+
+ // Pass a null location context to the SymbolReaper so that
+ // it was thinking that the variable is dead.
+ SymbolReaper SymReaper((StackFrameContext *)nullptr, (Stmt *)nullptr,
+ Eng.getSymbolManager(), Eng.getStoreManager());
+
+ SymReaper.markLive(FR);
+ EXPECT_TRUE(SymReaper.isLiveRegion(VR));
+ }
+
+public:
+ SuperRegionLivenessConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
+ ~SuperRegionLivenessConsumer() override {}
+
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ for (const auto *D : DG)
+ performTest(D);
+ return true;
+ }
+};
+
+class SuperRegionLivenessAction : public ASTFrontendAction {
+public:
+ SuperRegionLivenessAction() {}
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef File) override {
+ return llvm::make_unique<SuperRegionLivenessConsumer>(Compiler);
+ }
+};
+
+// Test that marking s.x as live would also make s live.
+TEST(SymbolReaper, SuperRegionLiveness) {
+ EXPECT_TRUE(tooling::runToolOnCode(new SuperRegionLivenessAction,
+ "void foo() { struct S { int x; } s; }"));
+}
+
+} // namespace
+} // namespace ento
+} // namespace clang
diff --git a/src/llvm-project/clang/unittests/Tooling/ASTSelectionTest.cpp b/src/llvm-project/clang/unittests/Tooling/ASTSelectionTest.cpp
index 2f5df8f..7ad5148 100644
--- a/src/llvm-project/clang/unittests/Tooling/ASTSelectionTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/ASTSelectionTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/ASTSelectionTest.cpp ------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/CMakeLists.txt b/src/llvm-project/clang/unittests/Tooling/CMakeLists.txt
index 7619c7f..a10bff6 100644
--- a/src/llvm-project/clang/unittests/Tooling/CMakeLists.txt
+++ b/src/llvm-project/clang/unittests/Tooling/CMakeLists.txt
@@ -22,6 +22,7 @@
LexicallyOrderedRecursiveASTVisitorTest.cpp
LookupTest.cpp
QualTypeNamesTest.cpp
+ RangeSelectorTest.cpp
RecursiveASTVisitorTests/Attr.cpp
RecursiveASTVisitorTests/Class.cpp
RecursiveASTVisitorTests/ConstructExpr.cpp
@@ -37,6 +38,7 @@
RecursiveASTVisitorTests/IntegerLiteral.cpp
RecursiveASTVisitorTests/LambdaDefaultCapture.cpp
RecursiveASTVisitorTests/LambdaExpr.cpp
+ RecursiveASTVisitorTests/LambdaTemplateParams.cpp
RecursiveASTVisitorTests/NestedNameSpecifiers.cpp
RecursiveASTVisitorTests/ParenExpr.cpp
RecursiveASTVisitorTests/TemplateArgumentLocTraverser.cpp
@@ -49,10 +51,13 @@
RefactoringTest.cpp
ReplacementsYamlTest.cpp
RewriterTest.cpp
+ SourceCodeTest.cpp
+ StencilTest.cpp
ToolingTest.cpp
+ TransformerTest.cpp
)
-target_link_libraries(ToolingTests
+clang_target_link_libraries(ToolingTests
PRIVATE
clangAST
clangASTMatchers
@@ -65,5 +70,12 @@
clangTooling
clangToolingCore
clangToolingInclusions
- clangToolingRefactor
+ clangToolingRefactoring
)
+
+target_link_libraries(ToolingTests
+ PRIVATE
+ LLVMTestingSupport
+)
+
+add_subdirectory(Syntax)
diff --git a/src/llvm-project/clang/unittests/Tooling/CastExprTest.cpp b/src/llvm-project/clang/unittests/Tooling/CastExprTest.cpp
index 5310c21..a9e78d2 100644
--- a/src/llvm-project/clang/unittests/Tooling/CastExprTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/CastExprTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/CastExprTest.cpp ----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/CommentHandlerTest.cpp b/src/llvm-project/clang/unittests/Tooling/CommentHandlerTest.cpp
index 9c3abdc..5ceed95 100644
--- a/src/llvm-project/clang/unittests/Tooling/CommentHandlerTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/CommentHandlerTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/CommentHandlerTest.cpp -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/CompilationDatabaseTest.cpp b/src/llvm-project/clang/unittests/Tooling/CompilationDatabaseTest.cpp
index 949d6a3..fde9544 100644
--- a/src/llvm-project/clang/unittests/Tooling/CompilationDatabaseTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -1,19 +1,20 @@
//===- unittest/Tooling/CompilationDatabaseTest.cpp -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Frontend/FrontendAction.h"
+#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/FileMatchTrie.h"
#include "clang/Tooling/JSONCompilationDatabase.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/TargetSelect.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -89,12 +90,17 @@
expected_files.push_back(PathStorage.str());
llvm::sys::path::native("//net/dir/file2", PathStorage);
expected_files.push_back(PathStorage.str());
+ llvm::sys::path::native("//net/file1", PathStorage);
+ expected_files.push_back(PathStorage.str());
EXPECT_EQ(expected_files,
getAllFiles("[{\"directory\":\"//net/dir\","
"\"command\":\"command\","
"\"file\":\"file1\"},"
" {\"directory\":\"//net/dir\","
"\"command\":\"command\","
+ "\"file\":\"../file1\"},"
+ " {\"directory\":\"//net/dir\","
+ "\"command\":\"command\","
"\"file\":\"file2\"}]",
ErrorMessage, JSONCommandLineSyntax::Gnu))
<< ErrorMessage;
@@ -364,6 +370,33 @@
EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
}
+TEST(findCompileArgsInJsonDatabase, ParsesCompilerWrappers) {
+ StringRef Directory("//net/dir");
+ StringRef FileName("//net/dir/filename");
+ std::vector<std::pair<std::string, std::string>> Cases = {
+ {"distcc gcc foo.c", "gcc foo.c"},
+ {"gomacc clang++ foo.c", "clang++ foo.c"},
+ {"ccache gcc foo.c", "gcc foo.c"},
+ {"ccache.exe gcc foo.c", "gcc foo.c"},
+ {"ccache g++.exe foo.c", "g++.exe foo.c"},
+ {"ccache distcc gcc foo.c", "gcc foo.c"},
+
+ {"distcc foo.c", "distcc foo.c"},
+ {"distcc -I/foo/bar foo.c", "distcc -I/foo/bar foo.c"},
+ };
+ std::string ErrorMessage;
+
+ for (const auto &Case : Cases) {
+ std::string DB =
+ R"([{"directory":"//net/dir", "file":"//net/dir/foo.c", "command":")" +
+ Case.first + "\"}]";
+ CompileCommand FoundCommand =
+ findCompileArgsInJsonDatabase("//net/dir/foo.c", DB, ErrorMessage);
+ EXPECT_EQ(Case.second, llvm::join(FoundCommand.CommandLine, " "))
+ << Case.first;
+ }
+}
+
static std::vector<std::string> unescapeJsonCommandLine(StringRef Command) {
std::string JsonDatabase =
("[{\"directory\":\"//net/root\", \"file\":\"test\", \"command\": \"" +
@@ -628,7 +661,7 @@
}
};
-class InterpolateTest : public ::testing::Test {
+class MemDBTest : public ::testing::Test {
protected:
// Adds an entry to the underlying compilation database.
// A flag is injected: -D <File>, so the command used can be identified.
@@ -654,6 +687,11 @@
return Result.str();
}
+ MemCDB::EntryMap Entries;
+};
+
+class InterpolateTest : public MemDBTest {
+protected:
// Look up the command from a relative path, and return it in string form.
// The input file is not included in the returned command.
std::string getCommand(llvm::StringRef F) {
@@ -669,7 +707,26 @@
return llvm::join(Results[0].CommandLine, " ");
}
- MemCDB::EntryMap Entries;
+ // Parse the file whose command was used out of the Heuristic string.
+ std::string getProxy(llvm::StringRef F) {
+ auto Results =
+ inferMissingCompileCommands(llvm::make_unique<MemCDB>(Entries))
+ ->getCompileCommands(path(F));
+ if (Results.empty())
+ return "none";
+ StringRef Proxy = Results.front().Heuristic;
+ if (!Proxy.consume_front("inferred from "))
+ return "";
+ // We have a proxy file, convert back to a unix relative path.
+ // This is a bit messy, but we do need to test these strings somehow...
+ llvm::SmallString<32> TempDir;
+ llvm::sys::path::system_temp_directory(false, TempDir);
+ Proxy.consume_front(TempDir);
+ Proxy.consume_front(llvm::sys::path::get_separator());
+ llvm::SmallString<32> Result = Proxy;
+ llvm::sys::path::native(Result, llvm::sys::path::Style::posix);
+ return Result.str();
+ }
};
TEST_F(InterpolateTest, Nearby) {
@@ -678,18 +735,16 @@
add("an/other/foo.cpp");
// great: dir and name both match (prefix or full, case insensitive)
- EXPECT_EQ(getCommand("dir/f.cpp"), "clang -D dir/foo.cpp");
- EXPECT_EQ(getCommand("dir/FOO.cpp"), "clang -D dir/foo.cpp");
+ EXPECT_EQ(getProxy("dir/f.cpp"), "dir/foo.cpp");
+ EXPECT_EQ(getProxy("dir/FOO.cpp"), "dir/foo.cpp");
// no name match. prefer matching dir, break ties by alpha
- EXPECT_EQ(getCommand("dir/a.cpp"), "clang -D dir/bar.cpp");
+ EXPECT_EQ(getProxy("dir/a.cpp"), "dir/bar.cpp");
// an exact name match beats one segment of directory match
- EXPECT_EQ(getCommand("some/other/bar.h"),
- "clang -D dir/bar.cpp -x c++-header");
+ EXPECT_EQ(getProxy("some/other/bar.h"), "dir/bar.cpp");
// two segments of directory match beat a prefix name match
- EXPECT_EQ(getCommand("an/other/b.cpp"), "clang -D an/other/foo.cpp");
+ EXPECT_EQ(getProxy("an/other/b.cpp"), "an/other/foo.cpp");
// if nothing matches at all, we still get the closest alpha match
- EXPECT_EQ(getCommand("below/some/obscure/path.cpp"),
- "clang -D an/other/foo.cpp");
+ EXPECT_EQ(getProxy("below/some/obscure/path.cpp"), "an/other/foo.cpp");
}
TEST_F(InterpolateTest, Language) {
@@ -700,14 +755,17 @@
// .h is ambiguous, so we add explicit language flags
EXPECT_EQ(getCommand("foo.h"),
"clang -D dir/foo.cpp -x c++-header -std=c++17");
+ // Same thing if we have no extension. (again, we treat as header).
+ EXPECT_EQ(getCommand("foo"), "clang -D dir/foo.cpp -x c++-header -std=c++17");
+ // and invalid extensions.
+ EXPECT_EQ(getCommand("foo.cce"),
+ "clang -D dir/foo.cpp -x c++-header -std=c++17");
// and don't add -x if the inferred language is correct.
EXPECT_EQ(getCommand("foo.hpp"), "clang -D dir/foo.cpp -std=c++17");
// respect -x if it's already there.
EXPECT_EQ(getCommand("baz.h"), "clang -D dir/baz.cee -x c-header");
// prefer a worse match with the right extension.
EXPECT_EQ(getCommand("foo.c"), "clang -D dir/bar.c");
- // make sure we don't crash on queries with invalid extensions.
- EXPECT_EQ(getCommand("foo.cce"), "clang -D dir/foo.cpp");
Entries.erase(path(StringRef("dir/bar.c")));
// Now we transfer across languages, so drop -std too.
EXPECT_EQ(getCommand("foo.c"), "clang -D dir/foo.cpp");
@@ -723,7 +781,7 @@
add("FOO/BAR/BAZ/SHOUT.cc");
add("foo/bar/baz/quiet.cc");
// Case mismatches are completely ignored, so we choose the name match.
- EXPECT_EQ(getCommand("foo/bar/baz/shout.C"), "clang -D FOO/BAR/BAZ/SHOUT.cc");
+ EXPECT_EQ(getProxy("foo/bar/baz/shout.C"), "FOO/BAR/BAZ/SHOUT.cc");
}
TEST_F(InterpolateTest, Aliasing) {
@@ -778,5 +836,30 @@
EXPECT_TRUE(CCRef != CCTest);
}
+class TargetAndModeTest : public MemDBTest {
+public:
+ TargetAndModeTest() { llvm::InitializeAllTargetInfos(); }
+
+protected:
+ // Look up the command from a relative path, and return it in string form.
+ std::string getCommand(llvm::StringRef F) {
+ auto Results = inferTargetAndDriverMode(llvm::make_unique<MemCDB>(Entries))
+ ->getCompileCommands(path(F));
+ if (Results.empty())
+ return "none";
+ return llvm::join(Results[0].CommandLine, " ");
+ }
+};
+
+TEST_F(TargetAndModeTest, TargetAndMode) {
+ add("foo.cpp", "clang-cl", "");
+ add("bar.cpp", "clang++", "");
+
+ EXPECT_EQ(getCommand("foo.cpp"),
+ "clang-cl --driver-mode=cl foo.cpp -D foo.cpp");
+ EXPECT_EQ(getCommand("bar.cpp"),
+ "clang++ --driver-mode=g++ bar.cpp -D bar.cpp");
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/src/llvm-project/clang/unittests/Tooling/DiagnosticsYamlTest.cpp b/src/llvm-project/clang/unittests/Tooling/DiagnosticsYamlTest.cpp
index f4de53f..334c317 100644
--- a/src/llvm-project/clang/unittests/Tooling/DiagnosticsYamlTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/DiagnosticsYamlTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Tooling/DiagnosticsYamlTest.cpp - Serialization tests ---===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -21,11 +20,13 @@
using clang::tooling::Diagnostic;
static DiagnosticMessage makeMessage(const std::string &Message, int FileOffset,
- const std::string &FilePath) {
+ const std::string &FilePath,
+ const StringMap<Replacements> &Fix) {
DiagnosticMessage DiagMessage;
DiagMessage.Message = Message;
DiagMessage.FileOffset = FileOffset;
DiagMessage.FilePath = FilePath;
+ DiagMessage.Fix = Fix;
return DiagMessage;
}
@@ -33,10 +34,52 @@
const std::string &Message, int FileOffset,
const std::string &FilePath,
const StringMap<Replacements> &Fix) {
- return Diagnostic(DiagnosticName, makeMessage(Message, FileOffset, FilePath),
- Fix, {}, Diagnostic::Warning, "path/to/build/directory");
+ return Diagnostic(DiagnosticName,
+ makeMessage(Message, FileOffset, FilePath, Fix), {},
+ Diagnostic::Warning, "path/to/build/directory");
}
+static const char *YAMLContent =
+ "---\n"
+ "MainSourceFile: 'path/to/source.cpp'\n"
+ "Diagnostics:\n"
+ " - DiagnosticName: 'diagnostic#1\'\n"
+ " DiagnosticMessage:\n"
+ " Message: 'message #1'\n"
+ " FilePath: 'path/to/source.cpp'\n"
+ " FileOffset: 55\n"
+ " Replacements:\n"
+ " - FilePath: 'path/to/source.cpp'\n"
+ " Offset: 100\n"
+ " Length: 12\n"
+ " ReplacementText: 'replacement #1'\n"
+ " - DiagnosticName: 'diagnostic#2'\n"
+ " DiagnosticMessage:\n"
+ " Message: 'message #2'\n"
+ " FilePath: 'path/to/header.h'\n"
+ " FileOffset: 60\n"
+ " Replacements:\n"
+ " - FilePath: 'path/to/header.h'\n"
+ " Offset: 62\n"
+ " Length: 2\n"
+ " ReplacementText: 'replacement #2'\n"
+ " - DiagnosticName: 'diagnostic#3'\n"
+ " DiagnosticMessage:\n"
+ " Message: 'message #3'\n"
+ " FilePath: 'path/to/source2.cpp'\n"
+ " FileOffset: 72\n"
+ " Replacements: []\n"
+ " Notes:\n"
+ " - Message: Note1\n"
+ " FilePath: 'path/to/note1.cpp'\n"
+ " FileOffset: 88\n"
+ " Replacements: []\n"
+ " - Message: Note2\n"
+ " FilePath: 'path/to/note2.cpp'\n"
+ " FileOffset: 99\n"
+ " Replacements: []\n"
+ "...\n";
+
TEST(DiagnosticsYamlTest, serializesDiagnostics) {
TranslationUnitDiagnostics TUD;
TUD.MainSourceFile = "path/to/source.cpp";
@@ -56,9 +99,9 @@
TUD.Diagnostics.push_back(makeDiagnostic("diagnostic#3", "message #3", 72,
"path/to/source2.cpp", {}));
TUD.Diagnostics.back().Notes.push_back(
- makeMessage("Note1", 88, "path/to/note1.cpp"));
+ makeMessage("Note1", 88, "path/to/note1.cpp", {}));
TUD.Diagnostics.back().Notes.push_back(
- makeMessage("Note2", 99, "path/to/note2.cpp"));
+ makeMessage("Note2", 99, "path/to/note2.cpp", {}));
std::string YamlContent;
raw_string_ostream YamlContentStream(YamlContent);
@@ -66,80 +109,12 @@
yaml::Output YAML(YamlContentStream);
YAML << TUD;
- EXPECT_EQ("---\n"
- "MainSourceFile: 'path/to/source.cpp'\n"
- "Diagnostics: \n"
- " - DiagnosticName: 'diagnostic#1\'\n"
- " Message: 'message #1'\n"
- " FileOffset: 55\n"
- " FilePath: 'path/to/source.cpp'\n"
- " Replacements: \n"
- " - FilePath: 'path/to/source.cpp'\n"
- " Offset: 100\n"
- " Length: 12\n"
- " ReplacementText: 'replacement #1'\n"
- " - DiagnosticName: 'diagnostic#2'\n"
- " Message: 'message #2'\n"
- " FileOffset: 60\n"
- " FilePath: 'path/to/header.h'\n"
- " Replacements: \n"
- " - FilePath: 'path/to/header.h'\n"
- " Offset: 62\n"
- " Length: 2\n"
- " ReplacementText: 'replacement #2'\n"
- " - DiagnosticName: 'diagnostic#3'\n"
- " Message: 'message #3'\n"
- " FileOffset: 72\n"
- " FilePath: 'path/to/source2.cpp'\n"
- " Notes: \n"
- " - Message: Note1\n"
- " FilePath: 'path/to/note1.cpp'\n"
- " FileOffset: 88\n"
- " - Message: Note2\n"
- " FilePath: 'path/to/note2.cpp'\n"
- " FileOffset: 99\n"
- " Replacements: []\n"
- "...\n",
- YamlContentStream.str());
+ EXPECT_EQ(YAMLContent, YamlContentStream.str());
}
TEST(DiagnosticsYamlTest, deserializesDiagnostics) {
- std::string YamlContent = "---\n"
- "MainSourceFile: path/to/source.cpp\n"
- "Diagnostics: \n"
- " - DiagnosticName: 'diagnostic#1'\n"
- " Message: 'message #1'\n"
- " FileOffset: 55\n"
- " FilePath: path/to/source.cpp\n"
- " Replacements: \n"
- " - FilePath: path/to/source.cpp\n"
- " Offset: 100\n"
- " Length: 12\n"
- " ReplacementText: 'replacement #1'\n"
- " - DiagnosticName: 'diagnostic#2'\n"
- " Message: 'message #2'\n"
- " FileOffset: 60\n"
- " FilePath: path/to/header.h\n"
- " Replacements: \n"
- " - FilePath: path/to/header.h\n"
- " Offset: 62\n"
- " Length: 2\n"
- " ReplacementText: 'replacement #2'\n"
- " - DiagnosticName: 'diagnostic#3'\n"
- " Message: 'message #3'\n"
- " FileOffset: 98\n"
- " FilePath: path/to/source.cpp\n"
- " Notes:\n"
- " - Message: Note1\n"
- " FilePath: 'path/to/note1.cpp'\n"
- " FileOffset: 66\n"
- " - Message: Note2\n"
- " FilePath: 'path/to/note2.cpp'\n"
- " FileOffset: 77\n"
- " Replacements: []\n"
- "...\n";
TranslationUnitDiagnostics TUDActual;
- yaml::Input YAML(YamlContent);
+ yaml::Input YAML(YAMLContent);
YAML >> TUDActual;
ASSERT_FALSE(YAML.error());
@@ -161,7 +136,7 @@
EXPECT_EQ("message #1", D1.Message.Message);
EXPECT_EQ(55u, D1.Message.FileOffset);
EXPECT_EQ("path/to/source.cpp", D1.Message.FilePath);
- std::vector<Replacement> Fixes1 = getFixes(D1.Fix);
+ std::vector<Replacement> Fixes1 = getFixes(D1.Message.Fix);
ASSERT_EQ(1u, Fixes1.size());
EXPECT_EQ("path/to/source.cpp", Fixes1[0].getFilePath());
EXPECT_EQ(100u, Fixes1[0].getOffset());
@@ -173,7 +148,7 @@
EXPECT_EQ("message #2", D2.Message.Message);
EXPECT_EQ(60u, D2.Message.FileOffset);
EXPECT_EQ("path/to/header.h", D2.Message.FilePath);
- std::vector<Replacement> Fixes2 = getFixes(D2.Fix);
+ std::vector<Replacement> Fixes2 = getFixes(D2.Message.Fix);
ASSERT_EQ(1u, Fixes2.size());
EXPECT_EQ("path/to/header.h", Fixes2[0].getFilePath());
EXPECT_EQ(62u, Fixes2[0].getOffset());
@@ -183,15 +158,15 @@
Diagnostic D3 = TUDActual.Diagnostics[2];
EXPECT_EQ("diagnostic#3", D3.DiagnosticName);
EXPECT_EQ("message #3", D3.Message.Message);
- EXPECT_EQ(98u, D3.Message.FileOffset);
- EXPECT_EQ("path/to/source.cpp", D3.Message.FilePath);
+ EXPECT_EQ(72u, D3.Message.FileOffset);
+ EXPECT_EQ("path/to/source2.cpp", D3.Message.FilePath);
EXPECT_EQ(2u, D3.Notes.size());
EXPECT_EQ("Note1", D3.Notes[0].Message);
- EXPECT_EQ(66u, D3.Notes[0].FileOffset);
+ EXPECT_EQ(88u, D3.Notes[0].FileOffset);
EXPECT_EQ("path/to/note1.cpp", D3.Notes[0].FilePath);
EXPECT_EQ("Note2", D3.Notes[1].Message);
- EXPECT_EQ(77u, D3.Notes[1].FileOffset);
+ EXPECT_EQ(99u, D3.Notes[1].FileOffset);
EXPECT_EQ("path/to/note2.cpp", D3.Notes[1].FilePath);
- std::vector<Replacement> Fixes3 = getFixes(D3.Fix);
+ std::vector<Replacement> Fixes3 = getFixes(D3.Message.Fix);
EXPECT_TRUE(Fixes3.empty());
}
diff --git a/src/llvm-project/clang/unittests/Tooling/ExecutionTest.cpp b/src/llvm-project/clang/unittests/Tooling/ExecutionTest.cpp
index 785ec7c..31d5fe5 100644
--- a/src/llvm-project/clang/unittests/Tooling/ExecutionTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/ExecutionTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/ExecutionTest.cpp - Tool execution tests. --------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/FixItTest.cpp b/src/llvm-project/clang/unittests/Tooling/FixItTest.cpp
index 365180e..ec9801d 100644
--- a/src/llvm-project/clang/unittests/Tooling/FixItTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/FixItTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/FixitTest.cpp ------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/HeaderIncludesTest.cpp b/src/llvm-project/clang/unittests/Tooling/HeaderIncludesTest.cpp
index ff68f75..635d7eb 100644
--- a/src/llvm-project/clang/unittests/Tooling/HeaderIncludesTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/HeaderIncludesTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/CleanupTest.cpp - Include insertion/deletion tests ===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -15,9 +14,6 @@
#include "gtest/gtest.h"
-using clang::tooling::ReplacementTest;
-using clang::tooling::toReplacements;
-
namespace clang {
namespace tooling {
namespace {
@@ -316,6 +312,17 @@
EXPECT_EQ(Expected, insert(Code, "<vector>"));
}
+TEST_F(HeaderIncludesTest, PragmaOnce) {
+ std::string Code = "// comment \n"
+ "#pragma once\n"
+ "int x;\n";
+ std::string Expected = "// comment \n"
+ "#pragma once\n"
+ "#include <vector>\n"
+ "int x;\n";
+ EXPECT_EQ(Expected, insert(Code, "<vector>"));
+}
+
TEST_F(HeaderIncludesTest, IfNDefWithNoDefine) {
std::string Code = "// comment \n"
"#ifndef X\n"
diff --git a/src/llvm-project/clang/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp b/src/llvm-project/clang/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp
index 7387e9c..38079f7 100644
--- a/src/llvm-project/clang/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/LexicallyOrderedRecursiveASTVisitorTest.cpp -------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/LookupTest.cpp b/src/llvm-project/clang/unittests/Tooling/LookupTest.cpp
index a08b2b4..372cbbf 100644
--- a/src/llvm-project/clang/unittests/Tooling/LookupTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/LookupTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/LookupTest.cpp ------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -45,8 +44,8 @@
const auto *Callee = cast<DeclRefExpr>(Expr->getCallee()->IgnoreImplicit());
const ValueDecl *FD = Callee->getDecl();
return tooling::replaceNestedName(
- Callee->getQualifier(), Visitor.DeclStack.back()->getDeclContext(), FD,
- ReplacementString);
+ Callee->getQualifier(), Callee->getLocation(),
+ Visitor.DeclStack.back()->getDeclContext(), FD, ReplacementString);
};
Visitor.OnCall = [&](CallExpr *Expr) {
@@ -130,20 +129,38 @@
// If the shortest name is ambiguous, we need to add more qualifiers.
Visitor.OnCall = [&](CallExpr *Expr) {
- EXPECT_EQ("::a::y::bar", replaceCallExpr(Expr, "::a::y::bar"));
+ EXPECT_EQ("a::y::bar", replaceCallExpr(Expr, "::a::y::bar"));
};
Visitor.runOver(R"(
namespace a {
- namespace b {
- namespace x { void foo() {} }
- namespace y { void foo() {} }
- }
+ namespace b {
+ namespace x { void foo() {} }
+ namespace y { void foo() {} }
+ }
}
namespace a {
- namespace b {
- void f() { x::foo(); }
+ namespace b {
+ void f() { x::foo(); }
+ }
+ })");
+
+ Visitor.OnCall = [&](CallExpr *Expr) {
+ // y::bar would be ambiguous due to "a::b::y".
+ EXPECT_EQ("::y::bar", replaceCallExpr(Expr, "::y::bar"));
+ };
+ Visitor.runOver(R"(
+ namespace a {
+ namespace b {
+ void foo() {}
+ namespace y { }
+ }
}
+
+ namespace a {
+ namespace b {
+ void f() { foo(); }
+ }
})");
Visitor.OnCall = [&](CallExpr *Expr) {
@@ -164,12 +181,12 @@
TEST(LookupTest, replaceNestedClassName) {
GetDeclsVisitor Visitor;
- auto replaceRecordTypeLoc = [&](RecordTypeLoc Loc,
+ auto replaceRecordTypeLoc = [&](RecordTypeLoc TLoc,
StringRef ReplacementString) {
- const auto *FD = cast<CXXRecordDecl>(Loc.getDecl());
+ const auto *FD = cast<CXXRecordDecl>(TLoc.getDecl());
return tooling::replaceNestedName(
- nullptr, Visitor.DeclStack.back()->getDeclContext(), FD,
- ReplacementString);
+ nullptr, TLoc.getBeginLoc(), Visitor.DeclStack.back()->getDeclContext(),
+ FD, ReplacementString);
};
Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) {
@@ -194,6 +211,41 @@
};
Visitor.runOver("namespace a { namespace b { class Foo {}; } }\n"
"namespace c { using a::b::Foo; Foo f();; }\n");
+
+ // Rename TypeLoc `x::y::Old` to new name `x::Foo` at [0] and check that the
+ // type is replaced with "Foo" instead of "x::Foo". Although there is a symbol
+ // `x::y::Foo` in c.cc [1], it should not make "Foo" at [0] ambiguous because
+ // it's not visible at [0].
+ Visitor.OnRecordTypeLoc = [&](RecordTypeLoc Type) {
+ if (Type.getDecl()->getQualifiedNameAsString() == "x::y::Old") {
+ EXPECT_EQ("Foo", replaceRecordTypeLoc(Type, "::x::Foo"));
+ }
+ };
+ Visitor.runOver(R"(
+ // a.h
+ namespace x {
+ namespace y {
+ class Old {};
+ class Other {};
+ }
+ }
+
+ // b.h
+ namespace x {
+ namespace y {
+ // This is to be renamed to x::Foo
+ // The expected replacement is "Foo".
+ Old f; // [0].
+ }
+ }
+
+ // c.cc
+ namespace x {
+ namespace y {
+ using Foo = ::x::y::Other; // [1]
+ }
+ }
+ )");
}
} // end anonymous namespace
diff --git a/src/llvm-project/clang/unittests/Tooling/QualTypeNamesTest.cpp b/src/llvm-project/clang/unittests/Tooling/QualTypeNamesTest.cpp
index b4c56f7..b6c3029 100644
--- a/src/llvm-project/clang/unittests/Tooling/QualTypeNamesTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/QualTypeNamesTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/QualTypeNameTest.cpp ------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -195,6 +194,7 @@
GlobalNsPrefix.ExpectedQualTypeNames["ZVal"] = "::A::B::Y::Z";
GlobalNsPrefix.ExpectedQualTypeNames["GlobalZVal"] = "::Z";
GlobalNsPrefix.ExpectedQualTypeNames["CheckK"] = "D::aStruct";
+ GlobalNsPrefix.ExpectedQualTypeNames["YZMPtr"] = "::A::B::X ::A::B::Y::Z::*";
GlobalNsPrefix.runOver(
"namespace A {\n"
" namespace B {\n"
@@ -206,8 +206,9 @@
" template <typename T>\n"
" using Alias = CCC<T>;\n"
" Alias<int> IntAliasVal;\n"
- " struct Y { struct Z {}; };\n"
+ " struct Y { struct Z { X YZIPtr; }; };\n"
" Y::Z ZVal;\n"
+ " X Y::Z::*YZMPtr;\n"
" }\n"
"}\n"
"struct Z {};\n"
diff --git a/src/llvm-project/clang/unittests/Tooling/RangeSelectorTest.cpp b/src/llvm-project/clang/unittests/Tooling/RangeSelectorTest.cpp
new file mode 100644
index 0000000..38c15be
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Tooling/RangeSelectorTest.cpp
@@ -0,0 +1,549 @@
+//===- unittest/Tooling/RangeSelectorTest.cpp -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/RangeSelector.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Tooling/FixIt.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace tooling;
+using namespace ast_matchers;
+
+namespace {
+using ::llvm::Expected;
+using ::llvm::Failed;
+using ::llvm::HasValue;
+using ::llvm::StringError;
+using ::testing::AllOf;
+using ::testing::HasSubstr;
+using ::testing::Property;
+
+using MatchResult = MatchFinder::MatchResult;
+
+struct TestMatch {
+ // The AST unit from which `result` is built. We bundle it because it backs
+ // the result. Users are not expected to access it.
+ std::unique_ptr<clang::ASTUnit> ASTUnit;
+ // The result to use in the test. References `ast_unit`.
+ MatchResult Result;
+};
+
+template <typename M> TestMatch matchCode(StringRef Code, M Matcher) {
+ auto ASTUnit = buildASTFromCode(Code);
+ assert(ASTUnit != nullptr && "AST construction failed");
+
+ ASTContext &Context = ASTUnit->getASTContext();
+ assert(!Context.getDiagnostics().hasErrorOccurred() && "Compilation error");
+
+ auto Matches = ast_matchers::match(Matcher, Context);
+ // We expect a single, exact match.
+ assert(Matches.size() != 0 && "no matches found");
+ assert(Matches.size() == 1 && "too many matches");
+
+ return TestMatch{std::move(ASTUnit), MatchResult(Matches[0], &Context)};
+}
+
+// Applies \p Selector to \p Match and, on success, returns the selected source.
+Expected<StringRef> select(RangeSelector Selector, const TestMatch &Match) {
+ Expected<CharSourceRange> Range = Selector(Match.Result);
+ if (!Range)
+ return Range.takeError();
+ return fixit::internal::getText(*Range, *Match.Result.Context);
+}
+
+// Applies \p Selector to a trivial match with only a single bound node with id
+// "bound_node_id". For use in testing unbound-node errors.
+Expected<CharSourceRange> selectFromTrivial(const RangeSelector &Selector) {
+ // We need to bind the result to something, or the match will fail. Use a
+ // binding that is not used in the unbound node tests.
+ TestMatch Match =
+ matchCode("static int x = 0;", varDecl().bind("bound_node_id"));
+ return Selector(Match.Result);
+}
+
+// Matches the message expected for unbound-node failures.
+testing::Matcher<StringError> withUnboundNodeMessage() {
+ return testing::Property(
+ &StringError::getMessage,
+ AllOf(HasSubstr("unbound_id"), HasSubstr("not bound")));
+}
+
+// Applies \p Selector to code containing assorted node types, where the match
+// binds each one: a statement ("stmt"), a (non-member) ctor-initializer
+// ("init"), an expression ("expr") and a (nameless) declaration ("decl"). Used
+// to test failures caused by applying selectors to nodes of the wrong type.
+Expected<CharSourceRange> selectFromAssorted(RangeSelector Selector) {
+ StringRef Code = R"cc(
+ struct A {};
+ class F : public A {
+ public:
+ F(int) {}
+ };
+ void g() { F f(1); }
+ )cc";
+
+ auto Matcher =
+ compoundStmt(
+ hasDescendant(
+ cxxConstructExpr(
+ hasDeclaration(
+ decl(hasDescendant(cxxCtorInitializer(isBaseInitializer())
+ .bind("init")))
+ .bind("decl")))
+ .bind("expr")))
+ .bind("stmt");
+
+ return Selector(matchCode(Code, Matcher).Result);
+}
+
+// Matches the message expected for type-error failures.
+testing::Matcher<StringError> withTypeErrorMessage(StringRef NodeID) {
+ return testing::Property(
+ &StringError::getMessage,
+ AllOf(HasSubstr(NodeID), HasSubstr("mismatched type")));
+}
+
+TEST(RangeSelectorTest, UnboundNode) {
+ EXPECT_THAT_EXPECTED(selectFromTrivial(node("unbound_id")),
+ Failed<StringError>(withUnboundNodeMessage()));
+}
+
+MATCHER_P(EqualsCharSourceRange, Range, "") {
+ return Range.getAsRange() == arg.getAsRange() &&
+ Range.isTokenRange() == arg.isTokenRange();
+}
+
+// FIXME: here and elsewhere: use llvm::Annotations library to explicitly mark
+// points and ranges of interest, enabling more readable tests.
+TEST(RangeSelectorTest, BeforeOp) {
+ StringRef Code = R"cc(
+ int f(int x, int y, int z) { return 3; }
+ int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
+ )cc";
+ StringRef Call = "call";
+ TestMatch Match = matchCode(Code, callExpr().bind(Call));
+ const auto* E = Match.Result.Nodes.getNodeAs<Expr>(Call);
+ assert(E != nullptr);
+ auto ExprBegin = E->getSourceRange().getBegin();
+ EXPECT_THAT_EXPECTED(
+ before(node(Call))(Match.Result),
+ HasValue(EqualsCharSourceRange(
+ CharSourceRange::getCharRange(ExprBegin, ExprBegin))));
+}
+
+TEST(RangeSelectorTest, AfterOp) {
+ StringRef Code = R"cc(
+ int f(int x, int y, int z) { return 3; }
+ int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
+ )cc";
+ StringRef Call = "call";
+ TestMatch Match = matchCode(Code, callExpr().bind(Call));
+ const auto* E = Match.Result.Nodes.getNodeAs<Expr>(Call);
+ assert(E != nullptr);
+ const SourceRange Range = E->getSourceRange();
+ // The end token, a right paren, is one character wide, so advance by one,
+ // bringing us to the semicolon.
+ const SourceLocation SemiLoc = Range.getEnd().getLocWithOffset(1);
+ const auto ExpectedAfter = CharSourceRange::getCharRange(SemiLoc, SemiLoc);
+
+ // Test with a char range.
+ auto CharRange = CharSourceRange::getCharRange(Range.getBegin(), SemiLoc);
+ EXPECT_THAT_EXPECTED(after(charRange(CharRange))(Match.Result),
+ HasValue(EqualsCharSourceRange(ExpectedAfter)));
+
+ // Test with a token range.
+ auto TokenRange = CharSourceRange::getTokenRange(Range);
+ EXPECT_THAT_EXPECTED(after(charRange(TokenRange))(Match.Result),
+ HasValue(EqualsCharSourceRange(ExpectedAfter)));
+}
+
+TEST(RangeSelectorTest, RangeOp) {
+ StringRef Code = R"cc(
+ int f(int x, int y, int z) { return 3; }
+ int g() { return f(/* comment */ 3, 7 /* comment */, 9); }
+ )cc";
+ StringRef Arg0 = "a0";
+ StringRef Arg1 = "a1";
+ StringRef Call = "call";
+ auto Matcher = callExpr(hasArgument(0, expr().bind(Arg0)),
+ hasArgument(1, expr().bind(Arg1)))
+ .bind(Call);
+ TestMatch Match = matchCode(Code, Matcher);
+
+ // Node-id specific version:
+ EXPECT_THAT_EXPECTED(select(range(Arg0, Arg1), Match), HasValue("3, 7"));
+ // General version:
+ EXPECT_THAT_EXPECTED(select(range(node(Arg0), node(Arg1)), Match),
+ HasValue("3, 7"));
+}
+
+TEST(RangeSelectorTest, NodeOpStatement) {
+ StringRef Code = "int f() { return 3; }";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, returnStmt().bind(ID));
+ EXPECT_THAT_EXPECTED(select(node(ID), Match), HasValue("return 3;"));
+}
+
+TEST(RangeSelectorTest, NodeOpExpression) {
+ StringRef Code = "int f() { return 3; }";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, expr().bind(ID));
+ EXPECT_THAT_EXPECTED(select(node(ID), Match), HasValue("3"));
+}
+
+TEST(RangeSelectorTest, StatementOp) {
+ StringRef Code = "int f() { return 3; }";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, expr().bind(ID));
+ EXPECT_THAT_EXPECTED(select(statement(ID), Match), HasValue("3;"));
+}
+
+TEST(RangeSelectorTest, MemberOp) {
+ StringRef Code = R"cc(
+ struct S {
+ int member;
+ };
+ int g() {
+ S s;
+ return s.member;
+ }
+ )cc";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, memberExpr().bind(ID));
+ EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("member"));
+}
+
+// Tests that member does not select any qualifiers on the member name.
+TEST(RangeSelectorTest, MemberOpQualified) {
+ StringRef Code = R"cc(
+ struct S {
+ int member;
+ };
+ struct T : public S {
+ int field;
+ };
+ int g() {
+ T t;
+ return t.S::member;
+ }
+ )cc";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, memberExpr().bind(ID));
+ EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("member"));
+}
+
+TEST(RangeSelectorTest, MemberOpTemplate) {
+ StringRef Code = R"cc(
+ struct S {
+ template <typename T> T foo(T t);
+ };
+ int f(int x) {
+ S s;
+ return s.template foo<int>(3);
+ }
+ )cc";
+
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, memberExpr().bind(ID));
+ EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("foo"));
+}
+
+TEST(RangeSelectorTest, MemberOpOperator) {
+ StringRef Code = R"cc(
+ struct S {
+ int operator*();
+ };
+ int f(int x) {
+ S s;
+ return s.operator *();
+ }
+ )cc";
+
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, memberExpr().bind(ID));
+ EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("operator *"));
+}
+
+TEST(RangeSelectorTest, NameOpNamedDecl) {
+ StringRef Code = R"cc(
+ int myfun() {
+ return 3;
+ }
+ )cc";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, functionDecl().bind(ID));
+ EXPECT_THAT_EXPECTED(select(name(ID), Match), HasValue("myfun"));
+}
+
+TEST(RangeSelectorTest, NameOpDeclRef) {
+ StringRef Code = R"cc(
+ int foo(int x) {
+ return x;
+ }
+ int g(int x) { return foo(x) * x; }
+ )cc";
+ StringRef Ref = "ref";
+ TestMatch Match = matchCode(Code, declRefExpr(to(functionDecl())).bind(Ref));
+ EXPECT_THAT_EXPECTED(select(name(Ref), Match), HasValue("foo"));
+}
+
+TEST(RangeSelectorTest, NameOpCtorInitializer) {
+ StringRef Code = R"cc(
+ class C {
+ public:
+ C() : field(3) {}
+ int field;
+ };
+ )cc";
+ StringRef Init = "init";
+ TestMatch Match = matchCode(Code, cxxCtorInitializer().bind(Init));
+ EXPECT_THAT_EXPECTED(select(name(Init), Match), HasValue("field"));
+}
+
+TEST(RangeSelectorTest, NameOpErrors) {
+ EXPECT_THAT_EXPECTED(selectFromTrivial(name("unbound_id")),
+ Failed<StringError>(withUnboundNodeMessage()));
+ EXPECT_THAT_EXPECTED(selectFromAssorted(name("stmt")),
+ Failed<StringError>(withTypeErrorMessage("stmt")));
+}
+
+TEST(RangeSelectorTest, NameOpDeclRefError) {
+ StringRef Code = R"cc(
+ struct S {
+ int operator*();
+ };
+ int f(int x) {
+ S s;
+ return *s + x;
+ }
+ )cc";
+ StringRef Ref = "ref";
+ TestMatch Match = matchCode(Code, declRefExpr(to(functionDecl())).bind(Ref));
+ EXPECT_THAT_EXPECTED(
+ name(Ref)(Match.Result),
+ Failed<StringError>(testing::Property(
+ &StringError::getMessage,
+ AllOf(HasSubstr(Ref), HasSubstr("requires property 'identifier'")))));
+}
+
+TEST(RangeSelectorTest, CallArgsOp) {
+ const StringRef Code = R"cc(
+ struct C {
+ int bar(int, int);
+ };
+ int f() {
+ C x;
+ return x.bar(3, 4);
+ }
+ )cc";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, callExpr().bind(ID));
+ EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("3, 4"));
+}
+
+TEST(RangeSelectorTest, CallArgsOpNoArgs) {
+ const StringRef Code = R"cc(
+ struct C {
+ int bar();
+ };
+ int f() {
+ C x;
+ return x.bar();
+ }
+ )cc";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, callExpr().bind(ID));
+ EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue(""));
+}
+
+TEST(RangeSelectorTest, CallArgsOpNoArgsWithComments) {
+ const StringRef Code = R"cc(
+ struct C {
+ int bar();
+ };
+ int f() {
+ C x;
+ return x.bar(/*empty*/);
+ }
+ )cc";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, callExpr().bind(ID));
+ EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("/*empty*/"));
+}
+
+// Tests that arguments are extracted correctly when a temporary (with parens)
+// is used.
+TEST(RangeSelectorTest, CallArgsOpWithParens) {
+ const StringRef Code = R"cc(
+ struct C {
+ int bar(int, int) { return 3; }
+ };
+ int f() {
+ C x;
+ return C().bar(3, 4);
+ }
+ )cc";
+ StringRef ID = "id";
+ TestMatch Match =
+ matchCode(Code, callExpr(callee(functionDecl(hasName("bar")))).bind(ID));
+ EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("3, 4"));
+}
+
+TEST(RangeSelectorTest, CallArgsOpLeadingComments) {
+ const StringRef Code = R"cc(
+ struct C {
+ int bar(int, int) { return 3; }
+ };
+ int f() {
+ C x;
+ return x.bar(/*leading*/ 3, 4);
+ }
+ )cc";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, callExpr().bind(ID));
+ EXPECT_THAT_EXPECTED(select(callArgs(ID), Match),
+ HasValue("/*leading*/ 3, 4"));
+}
+
+TEST(RangeSelectorTest, CallArgsOpTrailingComments) {
+ const StringRef Code = R"cc(
+ struct C {
+ int bar(int, int) { return 3; }
+ };
+ int f() {
+ C x;
+ return x.bar(3 /*trailing*/, 4);
+ }
+ )cc";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, callExpr().bind(ID));
+ EXPECT_THAT_EXPECTED(select(callArgs(ID), Match),
+ HasValue("3 /*trailing*/, 4"));
+}
+
+TEST(RangeSelectorTest, CallArgsOpEolComments) {
+ const StringRef Code = R"cc(
+ struct C {
+ int bar(int, int) { return 3; }
+ };
+ int f() {
+ C x;
+ return x.bar( // Header
+ 1, // foo
+ 2 // bar
+ );
+ }
+ )cc";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, callExpr().bind(ID));
+ std::string ExpectedString = R"( // Header
+ 1, // foo
+ 2 // bar
+ )";
+ EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue(ExpectedString));
+}
+
+TEST(RangeSelectorTest, CallArgsErrors) {
+ EXPECT_THAT_EXPECTED(selectFromTrivial(callArgs("unbound_id")),
+ Failed<StringError>(withUnboundNodeMessage()));
+ EXPECT_THAT_EXPECTED(selectFromAssorted(callArgs("stmt")),
+ Failed<StringError>(withTypeErrorMessage("stmt")));
+}
+
+TEST(RangeSelectorTest, StatementsOp) {
+ StringRef Code = R"cc(
+ void g();
+ void f() { /* comment */ g(); /* comment */ g(); /* comment */ }
+ )cc";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, compoundStmt().bind(ID));
+ EXPECT_THAT_EXPECTED(
+ select(statements(ID), Match),
+ HasValue(" /* comment */ g(); /* comment */ g(); /* comment */ "));
+}
+
+TEST(RangeSelectorTest, StatementsOpEmptyList) {
+ StringRef Code = "void f() {}";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, compoundStmt().bind(ID));
+ EXPECT_THAT_EXPECTED(select(statements(ID), Match), HasValue(""));
+}
+
+TEST(RangeSelectorTest, StatementsOpErrors) {
+ EXPECT_THAT_EXPECTED(selectFromTrivial(statements("unbound_id")),
+ Failed<StringError>(withUnboundNodeMessage()));
+ EXPECT_THAT_EXPECTED(selectFromAssorted(statements("decl")),
+ Failed<StringError>(withTypeErrorMessage("decl")));
+}
+
+TEST(RangeSelectorTest, ElementsOp) {
+ StringRef Code = R"cc(
+ void f() {
+ int v[] = {/* comment */ 3, /* comment*/ 4 /* comment */};
+ (void)v;
+ }
+ )cc";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, initListExpr().bind(ID));
+ EXPECT_THAT_EXPECTED(
+ select(initListElements(ID), Match),
+ HasValue("/* comment */ 3, /* comment*/ 4 /* comment */"));
+}
+
+TEST(RangeSelectorTest, ElementsOpEmptyList) {
+ StringRef Code = R"cc(
+ void f() {
+ int v[] = {};
+ (void)v;
+ }
+ )cc";
+ StringRef ID = "id";
+ TestMatch Match = matchCode(Code, initListExpr().bind(ID));
+ EXPECT_THAT_EXPECTED(select(initListElements(ID), Match), HasValue(""));
+}
+
+TEST(RangeSelectorTest, ElementsOpErrors) {
+ EXPECT_THAT_EXPECTED(selectFromTrivial(initListElements("unbound_id")),
+ Failed<StringError>(withUnboundNodeMessage()));
+ EXPECT_THAT_EXPECTED(selectFromAssorted(initListElements("stmt")),
+ Failed<StringError>(withTypeErrorMessage("stmt")));
+}
+
+// Tests case where the matched node is the complete expanded text.
+TEST(RangeSelectorTest, ExpansionOp) {
+ StringRef Code = R"cc(
+#define BADDECL(E) int bad(int x) { return E; }
+ BADDECL(x * x)
+ )cc";
+
+ StringRef Fun = "Fun";
+ TestMatch Match = matchCode(Code, functionDecl(hasName("bad")).bind(Fun));
+ EXPECT_THAT_EXPECTED(select(expansion(node(Fun)), Match),
+ HasValue("BADDECL(x * x)"));
+}
+
+// Tests case where the matched node is (only) part of the expanded text.
+TEST(RangeSelectorTest, ExpansionOpPartial) {
+ StringRef Code = R"cc(
+#define BADDECL(E) int bad(int x) { return E; }
+ BADDECL(x * x)
+ )cc";
+
+ StringRef Ret = "Ret";
+ TestMatch Match = matchCode(Code, returnStmt().bind(Ret));
+ EXPECT_THAT_EXPECTED(select(expansion(node(Ret)), Match),
+ HasValue("BADDECL(x * x)"));
+}
+
+} // namespace
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp
index e91873c..e207f03 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTestDeclVisitor.cpp ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTestPostOrderVisitor.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTestPostOrderVisitor.cpp
index 2e7b398..965bb3d 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTestPostOrderVisitor.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTestPostOrderVisitor.cpp
@@ -1,9 +1,8 @@
//===- unittests/Tooling/RecursiveASTVisitorPostOrderASTVisitor.cpp -------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp
index dc2adaf..299e1b0 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTestTypeLocVisitor.cpp ---------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/Attr.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/Attr.cpp
index 33163c3..022ef8b 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/Attr.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/Attr.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/Attr.cpp -----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXBoolLiteralExpr.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXBoolLiteralExpr.cpp
index ca2e4a4..1fb192d 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXBoolLiteralExpr.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXBoolLiteralExpr.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/CXXBoolLiteralExpr.cpp ---===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXMemberCall.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXMemberCall.cpp
index a83e551..c7b31e0 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXMemberCall.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXMemberCall.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/CXXMemberCall.cpp --------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXOperatorCallExprTraverser.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXOperatorCallExprTraverser.cpp
index 414b0f0..91de8d1 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXOperatorCallExprTraverser.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/CXXOperatorCallExprTraverser.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/CXXOperatorCallExprTraverser.cpp -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/Class.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/Class.cpp
index 666c924..3ea5abd 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/Class.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/Class.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/Class.cpp ----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/ConstructExpr.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/ConstructExpr.cpp
index f775a31..b4f4f54 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/ConstructExpr.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/ConstructExpr.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/ConstructExpr.cpp --------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/DeclRefExpr.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/DeclRefExpr.cpp
index cd0e426..adc972e 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/DeclRefExpr.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/DeclRefExpr.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/DeclRefExpr.cpp ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/ImplicitCtor.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/ImplicitCtor.cpp
index c2194ab..27999e5 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/ImplicitCtor.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/ImplicitCtor.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/ImplicitCtor.cpp ---------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPostOrder.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPostOrder.cpp
index 396f25d..80d9c98 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPostOrder.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPostOrder.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/InitListExprPostOrder.cpp -==//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPostOrderNoQueue.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPostOrderNoQueue.cpp
index 587f84b..a15f4c8 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPostOrderNoQueue.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPostOrderNoQueue.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/InitListExprPostOrderNoQueue.cpp -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrder.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrder.cpp
index 01f6e19..401ae6b 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrder.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrder.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/InitListExprPreOrder.cpp -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrderNoQueue.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrderNoQueue.cpp
index d48b5a8..1dafeef 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrderNoQueue.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/InitListExprPreOrderNoQueue.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/InitListExprPreOrderNoQueue.cpp -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/IntegerLiteral.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/IntegerLiteral.cpp
index 218f7e0..3fc3cb1 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/IntegerLiteral.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/IntegerLiteral.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/IntegerLiteral.cpp -------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/LambdaDefaultCapture.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/LambdaDefaultCapture.cpp
index c3f8e4f..b1d6d59 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/LambdaDefaultCapture.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/LambdaDefaultCapture.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/LambdaDefaultCapture.cpp -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp
index d3a3eba..560cdf9 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp -----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/LambdaTemplateParams.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/LambdaTemplateParams.cpp
new file mode 100644
index 0000000..34b38f6
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/LambdaTemplateParams.cpp
@@ -0,0 +1,53 @@
+//===- unittest/Tooling/RecursiveASTVisitorTests/LambdaTemplateParams.cpp -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestVisitor.h"
+
+using namespace clang;
+
+namespace {
+
+// Matches (optional) explicit template parameters.
+class LambdaTemplateParametersVisitor
+ : public ExpectedLocationVisitor<LambdaTemplateParametersVisitor> {
+public:
+ bool shouldVisitImplicitCode() const { return false; }
+
+ bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+ EXPECT_FALSE(D->isImplicit());
+ Match(D->getName(), D->getBeginLoc());
+ return true;
+ }
+
+ bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ EXPECT_FALSE(D->isImplicit());
+ Match(D->getName(), D->getBeginLoc());
+ return true;
+ }
+
+ bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+ EXPECT_FALSE(D->isImplicit());
+ Match(D->getName(), D->getBeginLoc());
+ return true;
+ }
+};
+
+TEST(RecursiveASTVisitor, VisitsLambdaExplicitTemplateParameters) {
+ LambdaTemplateParametersVisitor Visitor;
+ Visitor.ExpectMatch("T", 2, 15);
+ Visitor.ExpectMatch("I", 2, 24);
+ Visitor.ExpectMatch("TT", 2, 31);
+ EXPECT_TRUE(Visitor.runOver(
+ "void f() { \n"
+ " auto l = []<class T, int I, template<class> class TT>(auto p) { }; \n"
+ "}",
+ LambdaTemplateParametersVisitor::Lang_CXX2a));
+}
+
+} // end anonymous namespace
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/NestedNameSpecifiers.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/NestedNameSpecifiers.cpp
index 23afda6..868a398 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/NestedNameSpecifiers.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/NestedNameSpecifiers.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/NestedNameSpecifiers.cpp -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/ParenExpr.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/ParenExpr.cpp
index b6a5a18..c316f98 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/ParenExpr.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/ParenExpr.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/ParenExpr.cpp ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/TemplateArgumentLocTraverser.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/TemplateArgumentLocTraverser.cpp
index 0c9cbf2..ae427a0 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/TemplateArgumentLocTraverser.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/TemplateArgumentLocTraverser.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/TemplateArgumentLocTraverser.cpp -===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/TraversalScope.cpp b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/TraversalScope.cpp
index 72f6c64..c05be7f 100644
--- a/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/TraversalScope.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/TraversalScope.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RecursiveASTVisitorTests/TraversalScope.cpp -------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RefactoringActionRulesTest.cpp b/src/llvm-project/clang/unittests/Tooling/RefactoringActionRulesTest.cpp
index acacfa0..b471cf2 100644
--- a/src/llvm-project/clang/unittests/Tooling/RefactoringActionRulesTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RefactoringActionRulesTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RefactoringTestActionRulesTest.cpp ----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -119,7 +118,7 @@
"Error: ''\n"
"InsertedHeaders: []\n"
"RemovedHeaders: []\n"
- "Replacements: \n" // Extra whitespace here!
+ "Replacements:\n"
" - FilePath: input.cpp\n"
" Offset: 30\n"
" Length: 1\n"
diff --git a/src/llvm-project/clang/unittests/Tooling/RefactoringCallbacksTest.cpp b/src/llvm-project/clang/unittests/Tooling/RefactoringCallbacksTest.cpp
index e226522..1663581 100644
--- a/src/llvm-project/clang/unittests/Tooling/RefactoringCallbacksTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RefactoringCallbacksTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RefactoringCallbacksTest.cpp ----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RefactoringTest.cpp b/src/llvm-project/clang/unittests/Tooling/RefactoringTest.cpp
index d618c0f..c51d738 100644
--- a/src/llvm-project/clang/unittests/Tooling/RefactoringTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RefactoringTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RefactoringTest.cpp - Refactoring unit tests ------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -1123,11 +1122,11 @@
"Key: 'input.cpp:20'\n"
"FilePath: input.cpp\n"
"Error: ''\n"
- "InsertedHeaders: \n" // Extra whitespace here!
+ "InsertedHeaders:\n"
" - a.h\n"
- "RemovedHeaders: \n" // Extra whitespace here!
+ "RemovedHeaders:\n"
" - b.h\n"
- "Replacements: \n" // Extra whitespace here!
+ "Replacements:\n"
" - FilePath: input.cpp\n"
" Offset: 20\n"
" Length: 0\n"
@@ -1145,11 +1144,11 @@
"Key: 'input.cpp:20'\n"
"FilePath: input.cpp\n"
"Error: 'ok'\n"
- "InsertedHeaders: \n" // Extra whitespace here!
+ "InsertedHeaders:\n"
" - a.h\n"
- "RemovedHeaders: \n" // Extra whitespace here!
+ "RemovedHeaders:\n"
" - b.h\n"
- "Replacements: \n" // Extra whitespace here!
+ "Replacements:\n"
" - FilePath: input.cpp\n"
" Offset: 20\n"
" Length: 0\n"
diff --git a/src/llvm-project/clang/unittests/Tooling/ReplacementTest.h b/src/llvm-project/clang/unittests/Tooling/ReplacementTest.h
index b6fe5c7..b97e0e7 100644
--- a/src/llvm-project/clang/unittests/Tooling/ReplacementTest.h
+++ b/src/llvm-project/clang/unittests/Tooling/ReplacementTest.h
@@ -1,9 +1,8 @@
//===- unittest/Tooling/ReplacementTest.h - Replacements related test------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/Tooling/ReplacementsYamlTest.cpp b/src/llvm-project/clang/unittests/Tooling/ReplacementsYamlTest.cpp
index 2e5a87a..c8fe9c4 100644
--- a/src/llvm-project/clang/unittests/Tooling/ReplacementsYamlTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/ReplacementsYamlTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/Tooling/ReplacementsYamlTest.cpp - Serialization tests ---===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -34,7 +33,7 @@
// NOTE: If this test starts to fail for no obvious reason, check whitespace.
ASSERT_STREQ("---\n"
"MainSourceFile: '/path/to/source.cpp'\n"
- "Replacements: \n" // Extra whitespace here!
+ "Replacements:\n"
" - FilePath: '/path/to/file1.h'\n"
" Offset: 232\n"
" Length: 56\n"
@@ -47,6 +46,30 @@
YamlContentStream.str().c_str());
}
+TEST(ReplacementsYamlTest, serializesNewLines) {
+ TranslationUnitReplacements Doc;
+
+ Doc.MainSourceFile = "/path/to/source.cpp";
+ Doc.Replacements.emplace_back("/path/to/file1.h", 0, 0, "#include <utility>\n");
+
+ std::string YamlContent;
+ llvm::raw_string_ostream YamlContentStream(YamlContent);
+
+ yaml::Output YAML(YamlContentStream);
+ YAML << Doc;
+
+ // NOTE: If this test starts to fail for no obvious reason, check whitespace.
+ ASSERT_STREQ("---\n"
+ "MainSourceFile: '/path/to/source.cpp'\n"
+ "Replacements:\n"
+ " - FilePath: '/path/to/file1.h'\n"
+ " Offset: 0\n"
+ " Length: 0\n"
+ " ReplacementText: '#include <utility>\n\n'\n"
+ "...\n",
+ YamlContentStream.str().c_str());
+}
+
TEST(ReplacementsYamlTest, deserializesReplacements) {
std::string YamlContent = "---\n"
"MainSourceFile: /path/to/source.cpp\n"
diff --git a/src/llvm-project/clang/unittests/Tooling/RewriterTest.cpp b/src/llvm-project/clang/unittests/Tooling/RewriterTest.cpp
index 4305d42..e744940 100644
--- a/src/llvm-project/clang/unittests/Tooling/RewriterTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/RewriterTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/RewriterTest.cpp ----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/src/llvm-project/clang/unittests/Tooling/RewriterTestContext.h b/src/llvm-project/clang/unittests/Tooling/RewriterTestContext.h
index 9e66484..ba919d6 100644
--- a/src/llvm-project/clang/unittests/Tooling/RewriterTestContext.h
+++ b/src/llvm-project/clang/unittests/Tooling/RewriterTestContext.h
@@ -1,9 +1,8 @@
//===--- RewriterTestContext.h ----------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/src/llvm-project/clang/unittests/Tooling/SourceCodeTest.cpp b/src/llvm-project/clang/unittests/Tooling/SourceCodeTest.cpp
new file mode 100644
index 0000000..258947a
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Tooling/SourceCodeTest.cpp
@@ -0,0 +1,97 @@
+//===- unittest/Tooling/SourceCodeTest.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestVisitor.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Tooling/Refactoring/SourceCode.h"
+
+using namespace clang;
+
+using tooling::getText;
+using tooling::getExtendedText;
+
+namespace {
+
+struct CallsVisitor : TestVisitor<CallsVisitor> {
+ bool VisitCallExpr(CallExpr *Expr) {
+ OnCall(Expr, Context);
+ return true;
+ }
+
+ std::function<void(CallExpr *, ASTContext *Context)> OnCall;
+};
+
+TEST(SourceCodeTest, getText) {
+ CallsVisitor Visitor;
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ EXPECT_EQ("foo(x, y)", getText(*CE, *Context));
+ };
+ Visitor.runOver("void foo(int x, int y) { foo(x, y); }");
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ EXPECT_EQ("APPLY(foo, x, y)", getText(*CE, *Context));
+ };
+ Visitor.runOver("#define APPLY(f, x, y) f(x, y)\n"
+ "void foo(int x, int y) { APPLY(foo, x, y); }");
+}
+
+TEST(SourceCodeTest, getTextWithMacro) {
+ CallsVisitor Visitor;
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ EXPECT_EQ("F OO", getText(*CE, *Context));
+ Expr *P0 = CE->getArg(0);
+ Expr *P1 = CE->getArg(1);
+ EXPECT_EQ("", getText(*P0, *Context));
+ EXPECT_EQ("", getText(*P1, *Context));
+ };
+ Visitor.runOver("#define F foo(\n"
+ "#define OO x, y)\n"
+ "void foo(int x, int y) { F OO ; }");
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ EXPECT_EQ("", getText(*CE, *Context));
+ Expr *P0 = CE->getArg(0);
+ Expr *P1 = CE->getArg(1);
+ EXPECT_EQ("x", getText(*P0, *Context));
+ EXPECT_EQ("y", getText(*P1, *Context));
+ };
+ Visitor.runOver("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n"
+ "void foo(int x, int y) { FOO(x,y) }");
+}
+
+TEST(SourceCodeTest, getExtendedText) {
+ CallsVisitor Visitor;
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ EXPECT_EQ("foo(x, y);",
+ getExtendedText(*CE, tok::TokenKind::semi, *Context));
+
+ Expr *P0 = CE->getArg(0);
+ Expr *P1 = CE->getArg(1);
+ EXPECT_EQ("x", getExtendedText(*P0, tok::TokenKind::semi, *Context));
+ EXPECT_EQ("x,", getExtendedText(*P0, tok::TokenKind::comma, *Context));
+ EXPECT_EQ("y", getExtendedText(*P1, tok::TokenKind::semi, *Context));
+ };
+ Visitor.runOver("void foo(int x, int y) { foo(x, y); }");
+ Visitor.runOver("void foo(int x, int y) { if (true) foo(x, y); }");
+ Visitor.runOver("int foo(int x, int y) { if (true) return 3 + foo(x, y); }");
+ Visitor.runOver("void foo(int x, int y) { for (foo(x, y);;) ++x; }");
+ Visitor.runOver(
+ "bool foo(int x, int y) { for (;foo(x, y);) x = 1; return true; }");
+
+ Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) {
+ EXPECT_EQ("foo()", getExtendedText(*CE, tok::TokenKind::semi, *Context));
+ };
+ Visitor.runOver("bool foo() { if (foo()) return true; return false; }");
+ Visitor.runOver("void foo() { int x; for (;; foo()) ++x; }");
+ Visitor.runOver("int foo() { return foo() + 3; }");
+}
+
+} // end anonymous namespace
diff --git a/src/llvm-project/clang/unittests/Tooling/StencilTest.cpp b/src/llvm-project/clang/unittests/Tooling/StencilTest.cpp
new file mode 100644
index 0000000..e5063e1
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Tooling/StencilTest.cpp
@@ -0,0 +1,224 @@
+//===- unittest/Tooling/StencilTest.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Stencil.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/FixIt.h"
+#include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace tooling;
+using namespace ast_matchers;
+
+namespace {
+using ::testing::AllOf;
+using ::testing::Eq;
+using ::testing::HasSubstr;
+using MatchResult = MatchFinder::MatchResult;
+using stencil::cat;
+using stencil::dPrint;
+using stencil::text;
+
+// In tests, we can't directly match on llvm::Expected since its accessors
+// mutate the object. So, we collapse it to an Optional.
+static llvm::Optional<std::string> toOptional(llvm::Expected<std::string> V) {
+ if (V)
+ return *V;
+ ADD_FAILURE() << "Losing error in conversion to IsSomething: "
+ << llvm::toString(V.takeError());
+ return llvm::None;
+}
+
+// A very simple matcher for llvm::Optional values.
+MATCHER_P(IsSomething, ValueMatcher, "") {
+ if (!arg)
+ return false;
+ return ::testing::ExplainMatchResult(ValueMatcher, *arg, result_listener);
+}
+
+// Create a valid translation-unit from a statement.
+static std::string wrapSnippet(llvm::Twine StatementCode) {
+ return ("auto stencil_test_snippet = []{" + StatementCode + "};").str();
+}
+
+static DeclarationMatcher wrapMatcher(const StatementMatcher &Matcher) {
+ return varDecl(hasName("stencil_test_snippet"),
+ hasDescendant(compoundStmt(hasAnySubstatement(Matcher))));
+}
+
+struct TestMatch {
+ // The AST unit from which `result` is built. We bundle it because it backs
+ // the result. Users are not expected to access it.
+ std::unique_ptr<ASTUnit> AstUnit;
+ // The result to use in the test. References `ast_unit`.
+ MatchResult Result;
+};
+
+// Matches `Matcher` against the statement `StatementCode` and returns the
+// result. Handles putting the statement inside a function and modifying the
+// matcher correspondingly. `Matcher` should match `StatementCode` exactly --
+// that is, produce exactly one match.
+static llvm::Optional<TestMatch> matchStmt(llvm::Twine StatementCode,
+ StatementMatcher Matcher) {
+ auto AstUnit = buildASTFromCode(wrapSnippet(StatementCode));
+ if (AstUnit == nullptr) {
+ ADD_FAILURE() << "AST construction failed";
+ return llvm::None;
+ }
+ ASTContext &Context = AstUnit->getASTContext();
+ auto Matches = ast_matchers::match(wrapMatcher(Matcher), Context);
+ // We expect a single, exact match for the statement.
+ if (Matches.size() != 1) {
+ ADD_FAILURE() << "Wrong number of matches: " << Matches.size();
+ return llvm::None;
+ }
+ return TestMatch{std::move(AstUnit), MatchResult(Matches[0], &Context)};
+}
+
+class StencilTest : public ::testing::Test {
+protected:
+ // Verifies that the given stencil fails when evaluated on a valid match
+ // result. Binds a statement to "stmt", a (non-member) ctor-initializer to
+ // "init", an expression to "expr" and a (nameless) declaration to "decl".
+ void testError(const Stencil &Stencil,
+ ::testing::Matcher<std::string> Matcher) {
+ const std::string Snippet = R"cc(
+ struct A {};
+ class F : public A {
+ public:
+ F(int) {}
+ };
+ F(1);
+ )cc";
+ auto StmtMatch = matchStmt(
+ Snippet,
+ stmt(hasDescendant(
+ cxxConstructExpr(
+ hasDeclaration(decl(hasDescendant(cxxCtorInitializer(
+ isBaseInitializer())
+ .bind("init")))
+ .bind("decl")))
+ .bind("expr")))
+ .bind("stmt"));
+ ASSERT_TRUE(StmtMatch);
+ if (auto ResultOrErr = Stencil.eval(StmtMatch->Result)) {
+ ADD_FAILURE() << "Expected failure but succeeded: " << *ResultOrErr;
+ } else {
+ auto Err = llvm::handleErrors(ResultOrErr.takeError(),
+ [&Matcher](const llvm::StringError &Err) {
+ EXPECT_THAT(Err.getMessage(), Matcher);
+ });
+ if (Err) {
+ ADD_FAILURE() << "Unhandled error: " << llvm::toString(std::move(Err));
+ }
+ }
+ }
+
+ // Tests failures caused by references to unbound nodes. `unbound_id` is the
+ // id that will cause the failure.
+ void testUnboundNodeError(const Stencil &Stencil, llvm::StringRef UnboundId) {
+ testError(Stencil, AllOf(HasSubstr(UnboundId), HasSubstr("not bound")));
+ }
+};
+
+TEST_F(StencilTest, SingleStatement) {
+ StringRef Condition("C"), Then("T"), Else("E");
+ const std::string Snippet = R"cc(
+ if (true)
+ return 1;
+ else
+ return 0;
+ )cc";
+ auto StmtMatch = matchStmt(
+ Snippet, ifStmt(hasCondition(expr().bind(Condition)),
+ hasThen(stmt().bind(Then)), hasElse(stmt().bind(Else))));
+ ASSERT_TRUE(StmtMatch);
+ // Invert the if-then-else.
+ auto Stencil = cat("if (!", node(Condition), ") ", statement(Else), " else ",
+ statement(Then));
+ EXPECT_THAT(toOptional(Stencil.eval(StmtMatch->Result)),
+ IsSomething(Eq("if (!true) return 0; else return 1;")));
+}
+
+TEST_F(StencilTest, SingleStatementCallOperator) {
+ StringRef Condition("C"), Then("T"), Else("E");
+ const std::string Snippet = R"cc(
+ if (true)
+ return 1;
+ else
+ return 0;
+ )cc";
+ auto StmtMatch = matchStmt(
+ Snippet, ifStmt(hasCondition(expr().bind(Condition)),
+ hasThen(stmt().bind(Then)), hasElse(stmt().bind(Else))));
+ ASSERT_TRUE(StmtMatch);
+ // Invert the if-then-else.
+ Stencil S = cat("if (!", node(Condition), ") ", statement(Else), " else ",
+ statement(Then));
+ EXPECT_THAT(toOptional(S(StmtMatch->Result)),
+ IsSomething(Eq("if (!true) return 0; else return 1;")));
+}
+
+TEST_F(StencilTest, UnboundNode) {
+ const std::string Snippet = R"cc(
+ if (true)
+ return 1;
+ else
+ return 0;
+ )cc";
+ auto StmtMatch = matchStmt(Snippet, ifStmt(hasCondition(stmt().bind("a1")),
+ hasThen(stmt().bind("a2"))));
+ ASSERT_TRUE(StmtMatch);
+ auto Stencil = cat("if(!", node("a1"), ") ", node("UNBOUND"), ";");
+ auto ResultOrErr = Stencil.eval(StmtMatch->Result);
+ EXPECT_TRUE(llvm::errorToBool(ResultOrErr.takeError()))
+ << "Expected unbound node, got " << *ResultOrErr;
+}
+
+// Tests that a stencil with a single parameter (`Id`) evaluates to the expected
+// string, when `Id` is bound to the expression-statement in `Snippet`.
+void testExpr(StringRef Id, StringRef Snippet, const Stencil &Stencil,
+ StringRef Expected) {
+ auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
+ ASSERT_TRUE(StmtMatch);
+ EXPECT_THAT(toOptional(Stencil.eval(StmtMatch->Result)),
+ IsSomething(Expected));
+}
+
+TEST_F(StencilTest, SelectionOp) {
+ StringRef Id = "id";
+ testExpr(Id, "3;", cat(node(Id)), "3");
+}
+
+TEST(StencilEqualityTest, Equality) {
+ auto Lhs = cat("foo", dPrint("dprint_id"));
+ auto Rhs = cat("foo", dPrint("dprint_id"));
+ EXPECT_EQ(Lhs, Rhs);
+}
+
+TEST(StencilEqualityTest, InEqualityDifferentOrdering) {
+ auto Lhs = cat("foo", dPrint("node"));
+ auto Rhs = cat(dPrint("node"), "foo");
+ EXPECT_NE(Lhs, Rhs);
+}
+
+TEST(StencilEqualityTest, InEqualityDifferentSizes) {
+ auto Lhs = cat("foo", dPrint("node"), "bar", "baz");
+ auto Rhs = cat("foo", dPrint("node"), "bar");
+ EXPECT_NE(Lhs, Rhs);
+}
+
+// node is opaque and therefore cannot be examined for equality.
+TEST(StencilEqualityTest, InEqualitySelection) {
+ auto S1 = cat(node("node"));
+ auto S2 = cat(node("node"));
+ EXPECT_NE(S1, S2);
+}
+} // namespace
diff --git a/src/llvm-project/clang/unittests/Tooling/Syntax/CMakeLists.txt b/src/llvm-project/clang/unittests/Tooling/Syntax/CMakeLists.txt
new file mode 100644
index 0000000..f9d079b
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Tooling/Syntax/CMakeLists.txt
@@ -0,0 +1,24 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_unittest(SyntaxTests
+ TreeTest.cpp
+ TokensTest.cpp
+)
+
+clang_target_link_libraries(SyntaxTests
+ PRIVATE
+ clangAST
+ clangBasic
+ clangFrontend
+ clangLex
+ clangSerialization
+ clangTooling
+ clangToolingSyntax
+ )
+
+target_link_libraries(SyntaxTests
+ PRIVATE
+ LLVMTestingSupport
+)
diff --git a/src/llvm-project/clang/unittests/Tooling/Syntax/TokensTest.cpp b/src/llvm-project/clang/unittests/Tooling/Syntax/TokensTest.cpp
new file mode 100644
index 0000000..a1398bd
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Tooling/Syntax/TokensTest.cpp
@@ -0,0 +1,758 @@
+//===- TokensTest.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Syntax/Tokens.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/Expr.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TokenKinds.def"
+#include "clang/Basic/TokenKinds.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Lex/Token.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/Support/raw_os_ostream.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Testing/Support/Annotations.h"
+#include "llvm/Testing/Support/SupportHelpers.h"
+#include <cassert>
+#include <cstdlib>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <memory>
+#include <ostream>
+#include <string>
+
+using namespace clang;
+using namespace clang::syntax;
+
+using llvm::ValueIs;
+using ::testing::AllOf;
+using ::testing::Contains;
+using ::testing::ElementsAre;
+using ::testing::Field;
+using ::testing::Matcher;
+using ::testing::Not;
+using ::testing::StartsWith;
+
+namespace {
+// Checks the passed ArrayRef<T> has the same begin() and end() iterators as the
+// argument.
+MATCHER_P(SameRange, A, "") {
+ return A.begin() == arg.begin() && A.end() == arg.end();
+}
+
+Matcher<TokenBuffer::Expansion>
+IsExpansion(Matcher<llvm::ArrayRef<syntax::Token>> Spelled,
+ Matcher<llvm::ArrayRef<syntax::Token>> Expanded) {
+ return AllOf(Field(&TokenBuffer::Expansion::Spelled, Spelled),
+ Field(&TokenBuffer::Expansion::Expanded, Expanded));
+}
+// Matchers for syntax::Token.
+MATCHER_P(Kind, K, "") { return arg.kind() == K; }
+MATCHER_P2(HasText, Text, SourceMgr, "") {
+ return arg.text(*SourceMgr) == Text;
+}
+/// Checks the start and end location of a token are equal to SourceRng.
+MATCHER_P(RangeIs, SourceRng, "") {
+ return arg.location() == SourceRng.first &&
+ arg.endLocation() == SourceRng.second;
+}
+
+class TokenCollectorTest : public ::testing::Test {
+public:
+ /// Run the clang frontend, collect the preprocessed tokens from the frontend
+ /// invocation and store them in this->Buffer.
+ /// This also clears SourceManager before running the compiler.
+ void recordTokens(llvm::StringRef Code) {
+ class RecordTokens : public ASTFrontendAction {
+ public:
+ explicit RecordTokens(TokenBuffer &Result) : Result(Result) {}
+
+ bool BeginSourceFileAction(CompilerInstance &CI) override {
+ assert(!Collector && "expected only a single call to BeginSourceFile");
+ Collector.emplace(CI.getPreprocessor());
+ return true;
+ }
+ void EndSourceFileAction() override {
+ assert(Collector && "BeginSourceFileAction was never called");
+ Result = std::move(*Collector).consume();
+ }
+
+ std::unique_ptr<ASTConsumer>
+ CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
+ return llvm::make_unique<ASTConsumer>();
+ }
+
+ private:
+ TokenBuffer &Result;
+ llvm::Optional<TokenCollector> Collector;
+ };
+
+ constexpr const char *FileName = "./input.cpp";
+ FS->addFile(FileName, time_t(), llvm::MemoryBuffer::getMemBufferCopy(""));
+ // Prepare to run a compiler.
+ if (!Diags->getClient())
+ Diags->setClient(new IgnoringDiagConsumer);
+ std::vector<const char *> Args = {"tok-test", "-std=c++03", "-fsyntax-only",
+ FileName};
+ auto CI = createInvocationFromCommandLine(Args, Diags, FS);
+ assert(CI);
+ CI->getFrontendOpts().DisableFree = false;
+ CI->getPreprocessorOpts().addRemappedFile(
+ FileName, llvm::MemoryBuffer::getMemBufferCopy(Code).release());
+ CompilerInstance Compiler;
+ Compiler.setInvocation(std::move(CI));
+ Compiler.setDiagnostics(Diags.get());
+ Compiler.setFileManager(FileMgr.get());
+ Compiler.setSourceManager(SourceMgr.get());
+
+ this->Buffer = TokenBuffer(*SourceMgr);
+ RecordTokens Recorder(this->Buffer);
+ ASSERT_TRUE(Compiler.ExecuteAction(Recorder))
+ << "failed to run the frontend";
+ }
+
+ /// Record the tokens and return a test dump of the resulting buffer.
+ std::string collectAndDump(llvm::StringRef Code) {
+ recordTokens(Code);
+ return Buffer.dumpForTests();
+ }
+
+ // Adds a file to the test VFS.
+ void addFile(llvm::StringRef Path, llvm::StringRef Contents) {
+ if (!FS->addFile(Path, time_t(),
+ llvm::MemoryBuffer::getMemBufferCopy(Contents))) {
+ ADD_FAILURE() << "could not add a file to VFS: " << Path;
+ }
+ }
+
+ /// Add a new file, run syntax::tokenize() on it and return the results.
+ std::vector<syntax::Token> tokenize(llvm::StringRef Text) {
+ // FIXME: pass proper LangOptions.
+ return syntax::tokenize(
+ SourceMgr->createFileID(llvm::MemoryBuffer::getMemBufferCopy(Text)),
+ *SourceMgr, LangOptions());
+ }
+
+ // Specialized versions of matchers that hide the SourceManager from clients.
+ Matcher<syntax::Token> HasText(std::string Text) const {
+ return ::HasText(Text, SourceMgr.get());
+ }
+ Matcher<syntax::Token> RangeIs(llvm::Annotations::Range R) const {
+ std::pair<SourceLocation, SourceLocation> Ls;
+ Ls.first = SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID())
+ .getLocWithOffset(R.Begin);
+ Ls.second = SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID())
+ .getLocWithOffset(R.End);
+ return ::RangeIs(Ls);
+ }
+
+ /// Finds a subrange in O(n * m).
+ template <class T, class U, class Eq>
+ llvm::ArrayRef<T> findSubrange(llvm::ArrayRef<U> Subrange,
+ llvm::ArrayRef<T> Range, Eq F) {
+ for (auto Begin = Range.begin(); Begin < Range.end(); ++Begin) {
+ auto It = Begin;
+ for (auto ItSub = Subrange.begin();
+ ItSub != Subrange.end() && It != Range.end(); ++ItSub, ++It) {
+ if (!F(*ItSub, *It))
+ goto continue_outer;
+ }
+ return llvm::makeArrayRef(Begin, It);
+ continue_outer:;
+ }
+ return llvm::makeArrayRef(Range.end(), Range.end());
+ }
+
+ /// Finds a subrange in \p Tokens that match the tokens specified in \p Query.
+ /// The match should be unique. \p Query is a whitespace-separated list of
+ /// tokens to search for.
+ llvm::ArrayRef<syntax::Token>
+ findTokenRange(llvm::StringRef Query, llvm::ArrayRef<syntax::Token> Tokens) {
+ llvm::SmallVector<llvm::StringRef, 8> QueryTokens;
+ Query.split(QueryTokens, ' ', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ if (QueryTokens.empty()) {
+ ADD_FAILURE() << "will not look for an empty list of tokens";
+ std::abort();
+ }
+ // An equality test for search.
+ auto TextMatches = [this](llvm::StringRef Q, const syntax::Token &T) {
+ return Q == T.text(*SourceMgr);
+ };
+ // Find a match.
+ auto Found =
+ findSubrange(llvm::makeArrayRef(QueryTokens), Tokens, TextMatches);
+ if (Found.begin() == Tokens.end()) {
+ ADD_FAILURE() << "could not find the subrange for " << Query;
+ std::abort();
+ }
+ // Check that the match is unique.
+ if (findSubrange(llvm::makeArrayRef(QueryTokens),
+ llvm::makeArrayRef(Found.end(), Tokens.end()), TextMatches)
+ .begin() != Tokens.end()) {
+ ADD_FAILURE() << "match is not unique for " << Query;
+ std::abort();
+ }
+ return Found;
+ };
+
+ // Specialized versions of findTokenRange for expanded and spelled tokens.
+ llvm::ArrayRef<syntax::Token> findExpanded(llvm::StringRef Query) {
+ return findTokenRange(Query, Buffer.expandedTokens());
+ }
+ llvm::ArrayRef<syntax::Token> findSpelled(llvm::StringRef Query,
+ FileID File = FileID()) {
+ if (!File.isValid())
+ File = SourceMgr->getMainFileID();
+ return findTokenRange(Query, Buffer.spelledTokens(File));
+ }
+
+ // Data fields.
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+ new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions);
+ IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS =
+ new llvm::vfs::InMemoryFileSystem;
+ llvm::IntrusiveRefCntPtr<FileManager> FileMgr =
+ new FileManager(FileSystemOptions(), FS);
+ llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr =
+ new SourceManager(*Diags, *FileMgr);
+ /// Contains last result of calling recordTokens().
+ TokenBuffer Buffer = TokenBuffer(*SourceMgr);
+};
+
+TEST_F(TokenCollectorTest, RawMode) {
+ EXPECT_THAT(tokenize("int main() {}"),
+ ElementsAre(Kind(tok::kw_int),
+ AllOf(HasText("main"), Kind(tok::identifier)),
+ Kind(tok::l_paren), Kind(tok::r_paren),
+ Kind(tok::l_brace), Kind(tok::r_brace)));
+ // Comments are ignored for now.
+ EXPECT_THAT(tokenize("/* foo */int a; // more comments"),
+ ElementsAre(Kind(tok::kw_int),
+ AllOf(HasText("a"), Kind(tok::identifier)),
+ Kind(tok::semi)));
+}
+
+TEST_F(TokenCollectorTest, Basic) {
+ std::pair</*Input*/ std::string, /*Expected*/ std::string> TestCases[] = {
+ {"int main() {}",
+ R"(expanded tokens:
+ int main ( ) { }
+file './input.cpp'
+ spelled tokens:
+ int main ( ) { }
+ no mappings.
+)"},
+ // All kinds of whitespace are ignored.
+ {"\t\n int\t\n main\t\n (\t\n )\t\n{\t\n }\t\n",
+ R"(expanded tokens:
+ int main ( ) { }
+file './input.cpp'
+ spelled tokens:
+ int main ( ) { }
+ no mappings.
+)"},
+ // Annotation tokens are ignored.
+ {R"cpp(
+ #pragma GCC visibility push (public)
+ #pragma GCC visibility pop
+ )cpp",
+ R"(expanded tokens:
+ <empty>
+file './input.cpp'
+ spelled tokens:
+ # pragma GCC visibility push ( public ) # pragma GCC visibility pop
+ mappings:
+ ['#'_0, '<eof>'_13) => ['<eof>'_0, '<eof>'_0)
+)"},
+ // Empty files should not crash.
+ {R"cpp()cpp", R"(expanded tokens:
+ <empty>
+file './input.cpp'
+ spelled tokens:
+ <empty>
+ no mappings.
+)"},
+ // Should not crash on errors inside '#define' directives. Error is that
+ // stringification (#B) does not refer to a macro parameter.
+ {
+ R"cpp(
+a
+#define MACRO() A #B
+)cpp",
+ R"(expanded tokens:
+ a
+file './input.cpp'
+ spelled tokens:
+ a # define MACRO ( ) A # B
+ mappings:
+ ['#'_1, '<eof>'_9) => ['<eof>'_1, '<eof>'_1)
+)"}};
+ for (auto &Test : TestCases)
+ EXPECT_EQ(collectAndDump(Test.first), Test.second)
+ << collectAndDump(Test.first);
+}
+
+TEST_F(TokenCollectorTest, Locations) {
+ // Check locations of the tokens.
+ llvm::Annotations Code(R"cpp(
+ $r1[[int]] $r2[[a]] $r3[[=]] $r4[["foo bar baz"]] $r5[[;]]
+ )cpp");
+ recordTokens(Code.code());
+ // Check expanded tokens.
+ EXPECT_THAT(
+ Buffer.expandedTokens(),
+ ElementsAre(AllOf(Kind(tok::kw_int), RangeIs(Code.range("r1"))),
+ AllOf(Kind(tok::identifier), RangeIs(Code.range("r2"))),
+ AllOf(Kind(tok::equal), RangeIs(Code.range("r3"))),
+ AllOf(Kind(tok::string_literal), RangeIs(Code.range("r4"))),
+ AllOf(Kind(tok::semi), RangeIs(Code.range("r5"))),
+ Kind(tok::eof)));
+ // Check spelled tokens.
+ EXPECT_THAT(
+ Buffer.spelledTokens(SourceMgr->getMainFileID()),
+ ElementsAre(AllOf(Kind(tok::kw_int), RangeIs(Code.range("r1"))),
+ AllOf(Kind(tok::identifier), RangeIs(Code.range("r2"))),
+ AllOf(Kind(tok::equal), RangeIs(Code.range("r3"))),
+ AllOf(Kind(tok::string_literal), RangeIs(Code.range("r4"))),
+ AllOf(Kind(tok::semi), RangeIs(Code.range("r5")))));
+}
+
+TEST_F(TokenCollectorTest, MacroDirectives) {
+ // Macro directives are not stored anywhere at the moment.
+ std::string Code = R"cpp(
+ #define FOO a
+ #include "unresolved_file.h"
+ #undef FOO
+ #ifdef X
+ #else
+ #endif
+ #ifndef Y
+ #endif
+ #if 1
+ #elif 2
+ #else
+ #endif
+ #pragma once
+ #pragma something lalala
+
+ int a;
+ )cpp";
+ std::string Expected =
+ "expanded tokens:\n"
+ " int a ;\n"
+ "file './input.cpp'\n"
+ " spelled tokens:\n"
+ " # define FOO a # include \"unresolved_file.h\" # undef FOO "
+ "# ifdef X # else # endif # ifndef Y # endif # if 1 # elif 2 # else "
+ "# endif # pragma once # pragma something lalala int a ;\n"
+ " mappings:\n"
+ " ['#'_0, 'int'_39) => ['int'_0, 'int'_0)\n";
+ EXPECT_EQ(collectAndDump(Code), Expected);
+}
+
+TEST_F(TokenCollectorTest, MacroReplacements) {
+ std::pair</*Input*/ std::string, /*Expected*/ std::string> TestCases[] = {
+ // A simple object-like macro.
+ {R"cpp(
+ #define INT int const
+ INT a;
+ )cpp",
+ R"(expanded tokens:
+ int const a ;
+file './input.cpp'
+ spelled tokens:
+ # define INT int const INT a ;
+ mappings:
+ ['#'_0, 'INT'_5) => ['int'_0, 'int'_0)
+ ['INT'_5, 'a'_6) => ['int'_0, 'a'_2)
+)"},
+ // A simple function-like macro.
+ {R"cpp(
+ #define INT(a) const int
+ INT(10+10) a;
+ )cpp",
+ R"(expanded tokens:
+ const int a ;
+file './input.cpp'
+ spelled tokens:
+ # define INT ( a ) const int INT ( 10 + 10 ) a ;
+ mappings:
+ ['#'_0, 'INT'_8) => ['const'_0, 'const'_0)
+ ['INT'_8, 'a'_14) => ['const'_0, 'a'_2)
+)"},
+ // Recursive macro replacements.
+ {R"cpp(
+ #define ID(X) X
+ #define INT int const
+ ID(ID(INT)) a;
+ )cpp",
+ R"(expanded tokens:
+ int const a ;
+file './input.cpp'
+ spelled tokens:
+ # define ID ( X ) X # define INT int const ID ( ID ( INT ) ) a ;
+ mappings:
+ ['#'_0, 'ID'_12) => ['int'_0, 'int'_0)
+ ['ID'_12, 'a'_19) => ['int'_0, 'a'_2)
+)"},
+ // A little more complicated recursive macro replacements.
+ {R"cpp(
+ #define ADD(X, Y) X+Y
+ #define MULT(X, Y) X*Y
+
+ int a = ADD(MULT(1,2), MULT(3,ADD(4,5)));
+ )cpp",
+ "expanded tokens:\n"
+ " int a = 1 * 2 + 3 * 4 + 5 ;\n"
+ "file './input.cpp'\n"
+ " spelled tokens:\n"
+ " # define ADD ( X , Y ) X + Y # define MULT ( X , Y ) X * Y int "
+ "a = ADD ( MULT ( 1 , 2 ) , MULT ( 3 , ADD ( 4 , 5 ) ) ) ;\n"
+ " mappings:\n"
+ " ['#'_0, 'int'_22) => ['int'_0, 'int'_0)\n"
+ " ['ADD'_25, ';'_46) => ['1'_3, ';'_12)\n"},
+ // Empty macro replacement.
+ // FIXME: the #define directives should not be glued together.
+ {R"cpp(
+ #define EMPTY
+ #define EMPTY_FUNC(X)
+ EMPTY
+ EMPTY_FUNC(1+2+3)
+ )cpp",
+ R"(expanded tokens:
+ <empty>
+file './input.cpp'
+ spelled tokens:
+ # define EMPTY # define EMPTY_FUNC ( X ) EMPTY EMPTY_FUNC ( 1 + 2 + 3 )
+ mappings:
+ ['#'_0, 'EMPTY'_9) => ['<eof>'_0, '<eof>'_0)
+ ['EMPTY'_9, 'EMPTY_FUNC'_10) => ['<eof>'_0, '<eof>'_0)
+ ['EMPTY_FUNC'_10, '<eof>'_18) => ['<eof>'_0, '<eof>'_0)
+)"},
+ // File ends with a macro replacement.
+ {R"cpp(
+ #define FOO 10+10;
+ int a = FOO
+ )cpp",
+ R"(expanded tokens:
+ int a = 10 + 10 ;
+file './input.cpp'
+ spelled tokens:
+ # define FOO 10 + 10 ; int a = FOO
+ mappings:
+ ['#'_0, 'int'_7) => ['int'_0, 'int'_0)
+ ['FOO'_10, '<eof>'_11) => ['10'_3, '<eof>'_7)
+)"}};
+
+ for (auto &Test : TestCases)
+ EXPECT_EQ(Test.second, collectAndDump(Test.first))
+ << collectAndDump(Test.first);
+}
+
+TEST_F(TokenCollectorTest, SpecialTokens) {
+ // Tokens coming from concatenations.
+ recordTokens(R"cpp(
+ #define CONCAT(a, b) a ## b
+ int a = CONCAT(1, 2);
+ )cpp");
+ EXPECT_THAT(std::vector<syntax::Token>(Buffer.expandedTokens()),
+ Contains(HasText("12")));
+ // Multi-line tokens with slashes at the end.
+ recordTokens("i\\\nn\\\nt");
+ EXPECT_THAT(Buffer.expandedTokens(),
+ ElementsAre(AllOf(Kind(tok::kw_int), HasText("i\\\nn\\\nt")),
+ Kind(tok::eof)));
+ // FIXME: test tokens with digraphs and UCN identifiers.
+}
+
+TEST_F(TokenCollectorTest, LateBoundTokens) {
+ // The parser eventually breaks the first '>>' into two tokens ('>' and '>'),
+ // but we choose to record them as a single token (for now).
+ llvm::Annotations Code(R"cpp(
+ template <class T>
+ struct foo { int a; };
+ int bar = foo<foo<int$br[[>>]]().a;
+ int baz = 10 $op[[>>]] 2;
+ )cpp");
+ recordTokens(Code.code());
+ EXPECT_THAT(std::vector<syntax::Token>(Buffer.expandedTokens()),
+ AllOf(Contains(AllOf(Kind(tok::greatergreater),
+ RangeIs(Code.range("br")))),
+ Contains(AllOf(Kind(tok::greatergreater),
+ RangeIs(Code.range("op"))))));
+}
+
+TEST_F(TokenCollectorTest, DelayedParsing) {
+ llvm::StringLiteral Code = R"cpp(
+ struct Foo {
+ int method() {
+ // Parser will visit method bodies and initializers multiple times, but
+ // TokenBuffer should only record the first walk over the tokens;
+ return 100;
+ }
+ int a = 10;
+
+ struct Subclass {
+ void foo() {
+ Foo().method();
+ }
+ };
+ };
+ )cpp";
+ std::string ExpectedTokens =
+ "expanded tokens:\n"
+ " struct Foo { int method ( ) { return 100 ; } int a = 10 ; struct "
+ "Subclass { void foo ( ) { Foo ( ) . method ( ) ; } } ; } ;\n";
+ EXPECT_THAT(collectAndDump(Code), StartsWith(ExpectedTokens));
+}
+
+TEST_F(TokenCollectorTest, MultiFile) {
+ addFile("./foo.h", R"cpp(
+ #define ADD(X, Y) X+Y
+ int a = 100;
+ #include "bar.h"
+ )cpp");
+ addFile("./bar.h", R"cpp(
+ int b = ADD(1, 2);
+ #define MULT(X, Y) X*Y
+ )cpp");
+ llvm::StringLiteral Code = R"cpp(
+ #include "foo.h"
+ int c = ADD(1, MULT(2,3));
+ )cpp";
+
+ std::string Expected = R"(expanded tokens:
+ int a = 100 ; int b = 1 + 2 ; int c = 1 + 2 * 3 ;
+file './input.cpp'
+ spelled tokens:
+ # include "foo.h" int c = ADD ( 1 , MULT ( 2 , 3 ) ) ;
+ mappings:
+ ['#'_0, 'int'_3) => ['int'_12, 'int'_12)
+ ['ADD'_6, ';'_17) => ['1'_15, ';'_20)
+file './foo.h'
+ spelled tokens:
+ # define ADD ( X , Y ) X + Y int a = 100 ; # include "bar.h"
+ mappings:
+ ['#'_0, 'int'_11) => ['int'_0, 'int'_0)
+ ['#'_16, '<eof>'_19) => ['int'_5, 'int'_5)
+file './bar.h'
+ spelled tokens:
+ int b = ADD ( 1 , 2 ) ; # define MULT ( X , Y ) X * Y
+ mappings:
+ ['ADD'_3, ';'_9) => ['1'_8, ';'_11)
+ ['#'_10, '<eof>'_21) => ['int'_12, 'int'_12)
+)";
+
+ EXPECT_EQ(Expected, collectAndDump(Code))
+ << "input: " << Code << "\nresults: " << collectAndDump(Code);
+}
+
+class TokenBufferTest : public TokenCollectorTest {};
+
+TEST_F(TokenBufferTest, SpelledByExpanded) {
+ recordTokens(R"cpp(
+ a1 a2 a3 b1 b2
+ )cpp");
+
+ // Sanity check: expanded and spelled tokens are stored separately.
+ EXPECT_THAT(findExpanded("a1 a2"), Not(SameRange(findSpelled("a1 a2"))));
+ // Searching for subranges of expanded tokens should give the corresponding
+ // spelled ones.
+ EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a1 a2 a3 b1 b2")),
+ ValueIs(SameRange(findSpelled("a1 a2 a3 b1 b2"))));
+ EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a1 a2 a3")),
+ ValueIs(SameRange(findSpelled("a1 a2 a3"))));
+ EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("b1 b2")),
+ ValueIs(SameRange(findSpelled("b1 b2"))));
+
+ // Test search on simple macro expansions.
+ recordTokens(R"cpp(
+ #define A a1 a2 a3
+ #define B b1 b2
+
+ A split B
+ )cpp");
+ EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a1 a2 a3 split b1 b2")),
+ ValueIs(SameRange(findSpelled("A split B"))));
+ EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a1 a2 a3")),
+ ValueIs(SameRange(findSpelled("A split").drop_back())));
+ EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("b1 b2")),
+ ValueIs(SameRange(findSpelled("split B").drop_front())));
+ // Ranges not fully covering macro invocations should fail.
+ EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("a1 a2")), llvm::None);
+ EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("b2")), llvm::None);
+ EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("a2 a3 split b1 b2")),
+ llvm::None);
+
+ // Recursive macro invocations.
+ recordTokens(R"cpp(
+ #define ID(x) x
+ #define B b1 b2
+
+ ID(ID(ID(a1) a2 a3)) split ID(B)
+ )cpp");
+
+ EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a1 a2 a3")),
+ ValueIs(SameRange(findSpelled("ID ( ID ( ID ( a1 ) a2 a3 ) )"))));
+ EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("b1 b2")),
+ ValueIs(SameRange(findSpelled("ID ( B )"))));
+ EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a1 a2 a3 split b1 b2")),
+ ValueIs(SameRange(findSpelled(
+ "ID ( ID ( ID ( a1 ) a2 a3 ) ) split ID ( B )"))));
+ // Ranges crossing macro call boundaries.
+ EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("a1 a2 a3 split b1")),
+ llvm::None);
+ EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("a2 a3 split b1")),
+ llvm::None);
+ // FIXME: next two examples should map to macro arguments, but currently they
+ // fail.
+ EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("a2")), llvm::None);
+ EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("a1 a2")), llvm::None);
+
+ // Empty macro expansions.
+ recordTokens(R"cpp(
+ #define EMPTY
+ #define ID(X) X
+
+ EMPTY EMPTY ID(1 2 3) EMPTY EMPTY split1
+ EMPTY EMPTY ID(4 5 6) split2
+ ID(7 8 9) EMPTY EMPTY
+ )cpp");
+ EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("1 2 3")),
+ ValueIs(SameRange(findSpelled("ID ( 1 2 3 )"))));
+ EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("4 5 6")),
+ ValueIs(SameRange(findSpelled("ID ( 4 5 6 )"))));
+ EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("7 8 9")),
+ ValueIs(SameRange(findSpelled("ID ( 7 8 9 )"))));
+
+ // Empty mappings coming from various directives.
+ recordTokens(R"cpp(
+ #define ID(X) X
+ ID(1)
+ #pragma lalala
+ not_mapped
+ )cpp");
+ EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("not_mapped")),
+ ValueIs(SameRange(findSpelled("not_mapped"))));
+}
+
+TEST_F(TokenBufferTest, ExpansionStartingAt) {
+ // Object-like macro expansions.
+ recordTokens(R"cpp(
+ #define FOO 3+4
+ int a = FOO 1;
+ int b = FOO 2;
+ )cpp");
+
+ llvm::ArrayRef<syntax::Token> Foo1 = findSpelled("FOO 1").drop_back();
+ EXPECT_THAT(
+ Buffer.expansionStartingAt(Foo1.data()),
+ ValueIs(IsExpansion(SameRange(Foo1),
+ SameRange(findExpanded("3 + 4 1").drop_back()))));
+
+ llvm::ArrayRef<syntax::Token> Foo2 = findSpelled("FOO 2").drop_back();
+ EXPECT_THAT(
+ Buffer.expansionStartingAt(Foo2.data()),
+ ValueIs(IsExpansion(SameRange(Foo2),
+ SameRange(findExpanded("3 + 4 2").drop_back()))));
+
+ // Function-like macro expansions.
+ recordTokens(R"cpp(
+ #define ID(X) X
+ int a = ID(1+2+3);
+ int b = ID(ID(2+3+4));
+ )cpp");
+
+ llvm::ArrayRef<syntax::Token> ID1 = findSpelled("ID ( 1 + 2 + 3 )");
+ EXPECT_THAT(Buffer.expansionStartingAt(&ID1.front()),
+ ValueIs(IsExpansion(SameRange(ID1),
+ SameRange(findExpanded("1 + 2 + 3")))));
+ // Only the first spelled token should be found.
+ for (const auto &T : ID1.drop_front())
+ EXPECT_EQ(Buffer.expansionStartingAt(&T), llvm::None);
+
+ llvm::ArrayRef<syntax::Token> ID2 = findSpelled("ID ( ID ( 2 + 3 + 4 ) )");
+ EXPECT_THAT(Buffer.expansionStartingAt(&ID2.front()),
+ ValueIs(IsExpansion(SameRange(ID2),
+ SameRange(findExpanded("2 + 3 + 4")))));
+ // Only the first spelled token should be found.
+ for (const auto &T : ID2.drop_front())
+ EXPECT_EQ(Buffer.expansionStartingAt(&T), llvm::None);
+
+ // PP directives.
+ recordTokens(R"cpp(
+#define FOO 1
+int a = FOO;
+#pragma once
+int b = 1;
+ )cpp");
+
+ llvm::ArrayRef<syntax::Token> DefineFoo = findSpelled("# define FOO 1");
+ EXPECT_THAT(
+ Buffer.expansionStartingAt(&DefineFoo.front()),
+ ValueIs(IsExpansion(SameRange(DefineFoo),
+ SameRange(findExpanded("int a").take_front(0)))));
+ // Only the first spelled token should be found.
+ for (const auto &T : DefineFoo.drop_front())
+ EXPECT_EQ(Buffer.expansionStartingAt(&T), llvm::None);
+
+ llvm::ArrayRef<syntax::Token> PragmaOnce = findSpelled("# pragma once");
+ EXPECT_THAT(
+ Buffer.expansionStartingAt(&PragmaOnce.front()),
+ ValueIs(IsExpansion(SameRange(PragmaOnce),
+ SameRange(findExpanded("int b").take_front(0)))));
+ // Only the first spelled token should be found.
+ for (const auto &T : PragmaOnce.drop_front())
+ EXPECT_EQ(Buffer.expansionStartingAt(&T), llvm::None);
+}
+
+TEST_F(TokenBufferTest, TokensToFileRange) {
+ addFile("./foo.h", "token_from_header");
+ llvm::Annotations Code(R"cpp(
+ #define FOO token_from_expansion
+ #include "./foo.h"
+ $all[[$i[[int]] a = FOO;]]
+ )cpp");
+ recordTokens(Code.code());
+
+ auto &SM = *SourceMgr;
+
+ // Two simple examples.
+ auto Int = findExpanded("int").front();
+ auto Semi = findExpanded(";").front();
+ EXPECT_EQ(Int.range(SM), FileRange(SM.getMainFileID(), Code.range("i").Begin,
+ Code.range("i").End));
+ EXPECT_EQ(syntax::Token::range(SM, Int, Semi),
+ FileRange(SM.getMainFileID(), Code.range("all").Begin,
+ Code.range("all").End));
+ // We don't test assertion failures because death tests are slow.
+}
+
+} // namespace
diff --git a/src/llvm-project/clang/unittests/Tooling/Syntax/TreeTest.cpp b/src/llvm-project/clang/unittests/Tooling/Syntax/TreeTest.cpp
new file mode 100644
index 0000000..1c42d29
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Tooling/Syntax/TreeTest.cpp
@@ -0,0 +1,160 @@
+//===- TreeTest.cpp -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Syntax/Tree.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/Decl.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Tooling/Syntax/BuildTree.h"
+#include "clang/Tooling/Syntax/Nodes.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <cstdlib>
+
+using namespace clang;
+
+namespace {
+class SyntaxTreeTest : public ::testing::Test {
+protected:
+ // Build a syntax tree for the code.
+ syntax::TranslationUnit *buildTree(llvm::StringRef Code) {
+ // FIXME: this code is almost the identical to the one in TokensTest. Share
+ // it.
+ class BuildSyntaxTree : public ASTConsumer {
+ public:
+ BuildSyntaxTree(syntax::TranslationUnit *&Root,
+ std::unique_ptr<syntax::Arena> &Arena,
+ std::unique_ptr<syntax::TokenCollector> Tokens)
+ : Root(Root), Arena(Arena), Tokens(std::move(Tokens)) {
+ assert(this->Tokens);
+ }
+
+ void HandleTranslationUnit(ASTContext &Ctx) override {
+ Arena = llvm::make_unique<syntax::Arena>(Ctx.getSourceManager(),
+ Ctx.getLangOpts(),
+ std::move(*Tokens).consume());
+ Tokens = nullptr; // make sure we fail if this gets called twice.
+ Root = syntax::buildSyntaxTree(*Arena, *Ctx.getTranslationUnitDecl());
+ }
+
+ private:
+ syntax::TranslationUnit *&Root;
+ std::unique_ptr<syntax::Arena> &Arena;
+ std::unique_ptr<syntax::TokenCollector> Tokens;
+ };
+
+ class BuildSyntaxTreeAction : public ASTFrontendAction {
+ public:
+ BuildSyntaxTreeAction(syntax::TranslationUnit *&Root,
+ std::unique_ptr<syntax::Arena> &Arena)
+ : Root(Root), Arena(Arena) {}
+
+ std::unique_ptr<ASTConsumer>
+ CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override {
+ // We start recording the tokens, ast consumer will take on the result.
+ auto Tokens =
+ llvm::make_unique<syntax::TokenCollector>(CI.getPreprocessor());
+ return llvm::make_unique<BuildSyntaxTree>(Root, Arena,
+ std::move(Tokens));
+ }
+
+ private:
+ syntax::TranslationUnit *&Root;
+ std::unique_ptr<syntax::Arena> &Arena;
+ };
+
+ constexpr const char *FileName = "./input.cpp";
+ FS->addFile(FileName, time_t(), llvm::MemoryBuffer::getMemBufferCopy(""));
+ if (!Diags->getClient())
+ Diags->setClient(new IgnoringDiagConsumer);
+ // Prepare to run a compiler.
+ std::vector<const char *> Args = {"syntax-test", "-std=c++11",
+ "-fsyntax-only", FileName};
+ auto CI = createInvocationFromCommandLine(Args, Diags, FS);
+ assert(CI);
+ CI->getFrontendOpts().DisableFree = false;
+ CI->getPreprocessorOpts().addRemappedFile(
+ FileName, llvm::MemoryBuffer::getMemBufferCopy(Code).release());
+ CompilerInstance Compiler;
+ Compiler.setInvocation(std::move(CI));
+ Compiler.setDiagnostics(Diags.get());
+ Compiler.setFileManager(FileMgr.get());
+ Compiler.setSourceManager(SourceMgr.get());
+
+ syntax::TranslationUnit *Root = nullptr;
+ BuildSyntaxTreeAction Recorder(Root, this->Arena);
+ if (!Compiler.ExecuteAction(Recorder)) {
+ ADD_FAILURE() << "failed to run the frontend";
+ std::abort();
+ }
+ return Root;
+ }
+
+ // Adds a file to the test VFS.
+ void addFile(llvm::StringRef Path, llvm::StringRef Contents) {
+ if (!FS->addFile(Path, time_t(),
+ llvm::MemoryBuffer::getMemBufferCopy(Contents))) {
+ ADD_FAILURE() << "could not add a file to VFS: " << Path;
+ }
+ }
+
+ // Data fields.
+ llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+ new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions);
+ IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS =
+ new llvm::vfs::InMemoryFileSystem;
+ llvm::IntrusiveRefCntPtr<FileManager> FileMgr =
+ new FileManager(FileSystemOptions(), FS);
+ llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr =
+ new SourceManager(*Diags, *FileMgr);
+ // Set after calling buildTree().
+ std::unique_ptr<syntax::Arena> Arena;
+};
+
+TEST_F(SyntaxTreeTest, Basic) {
+ std::pair</*Input*/ std::string, /*Expected*/ std::string> Cases[] = {
+ {
+ R"cpp(
+int main() {}
+void foo() {}
+ )cpp",
+ R"txt(
+*: TranslationUnit
+|-TopLevelDeclaration
+| |-int
+| |-main
+| |-(
+| |-)
+| `-CompoundStatement
+| |-2: {
+| `-3: }
+|-TopLevelDeclaration
+| |-void
+| |-foo
+| |-(
+| |-)
+| `-CompoundStatement
+| |-2: {
+| `-3: }
+`-<eof>
+)txt"},
+ };
+
+ for (const auto &T : Cases) {
+ auto *Root = buildTree(T.first);
+ std::string Expected = llvm::StringRef(T.second).trim().str();
+ std::string Actual = llvm::StringRef(Root->dump(*Arena)).trim();
+ EXPECT_EQ(Expected, Actual) << "the resulting dump is:\n" << Actual;
+ }
+}
+} // namespace
diff --git a/src/llvm-project/clang/unittests/Tooling/TestVisitor.h b/src/llvm-project/clang/unittests/Tooling/TestVisitor.h
index 1a22ae7..ff90a77 100644
--- a/src/llvm-project/clang/unittests/Tooling/TestVisitor.h
+++ b/src/llvm-project/clang/unittests/Tooling/TestVisitor.h
@@ -1,9 +1,8 @@
//===--- TestVisitor.h ------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
diff --git a/src/llvm-project/clang/unittests/Tooling/ToolingTest.cpp b/src/llvm-project/clang/unittests/Tooling/ToolingTest.cpp
index 5813552..f9f4de3 100644
--- a/src/llvm-project/clang/unittests/Tooling/ToolingTest.cpp
+++ b/src/llvm-project/clang/unittests/Tooling/ToolingTest.cpp
@@ -1,9 +1,8 @@
//===- unittest/Tooling/ToolingTest.cpp - Tooling unit tests --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -383,7 +382,7 @@
ArgumentsAdjuster CheckSyntaxOnlyAdjuster =
[&Found, &Ran](const CommandLineArguments &Args, StringRef /*unused*/) {
Ran = true;
- if (std::find(Args.begin(), Args.end(), "-fsyntax-only") != Args.end())
+ if (llvm::is_contained(Args, "-fsyntax-only"))
Found = true;
return Args;
};
@@ -401,6 +400,33 @@
EXPECT_FALSE(Found);
}
+TEST(ClangToolTest, NoDoubleSyntaxOnly) {
+ FixedCompilationDatabase Compilations("/", {"-fsyntax-only"});
+
+ ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
+ Tool.mapVirtualFile("/a.cc", "void a() {}");
+
+ std::unique_ptr<FrontendActionFactory> Action(
+ newFrontendActionFactory<SyntaxOnlyAction>());
+
+ size_t SyntaxOnlyCount = 0;
+ ArgumentsAdjuster CheckSyntaxOnlyAdjuster =
+ [&SyntaxOnlyCount](const CommandLineArguments &Args,
+ StringRef /*unused*/) {
+ for (llvm::StringRef Arg : Args) {
+ if (Arg == "-fsyntax-only")
+ ++SyntaxOnlyCount;
+ }
+ return Args;
+ };
+
+ Tool.clearArgumentsAdjusters();
+ Tool.appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
+ Tool.appendArgumentsAdjuster(CheckSyntaxOnlyAdjuster);
+ Tool.run(Action.get());
+ EXPECT_EQ(SyntaxOnlyCount, 1U);
+}
+
TEST(ClangToolTest, BaseVirtualFileSystemUsage) {
FixedCompilationDatabase Compilations("/", std::vector<std::string>());
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem(
@@ -441,8 +467,7 @@
Tool.run(Action.get());
auto HasFlag = [&FinalArgs](const std::string &Flag) {
- return std::find(FinalArgs.begin(), FinalArgs.end(), Flag) !=
- FinalArgs.end();
+ return llvm::find(FinalArgs, Flag) != FinalArgs.end();
};
EXPECT_FALSE(HasFlag("-MD"));
EXPECT_FALSE(HasFlag("-MMD"));
@@ -473,8 +498,7 @@
Tool.run(Action.get());
auto HasFlag = [&FinalArgs](const std::string &Flag) {
- return std::find(FinalArgs.begin(), FinalArgs.end(), Flag) !=
- FinalArgs.end();
+ return llvm::find(FinalArgs, Flag) != FinalArgs.end();
};
EXPECT_FALSE(HasFlag("-Xclang"));
EXPECT_FALSE(HasFlag("-add-plugin"));
diff --git a/src/llvm-project/clang/unittests/Tooling/TransformerTest.cpp b/src/llvm-project/clang/unittests/Tooling/TransformerTest.cpp
new file mode 100644
index 0000000..64f511b
--- /dev/null
+++ b/src/llvm-project/clang/unittests/Tooling/TransformerTest.cpp
@@ -0,0 +1,641 @@
+//===- unittest/Tooling/TransformerTest.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Refactoring/Transformer.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Refactoring/RangeSelector.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace tooling;
+using namespace ast_matchers;
+
+namespace {
+using ::testing::IsEmpty;
+
+constexpr char KHeaderContents[] = R"cc(
+ struct string {
+ string(const char*);
+ char* c_str();
+ int size();
+ };
+ int strlen(const char*);
+
+ namespace proto {
+ struct PCFProto {
+ int foo();
+ };
+ struct ProtoCommandLineFlag : PCFProto {
+ PCFProto& GetProto();
+ };
+ } // namespace proto
+ class Logger {};
+ void operator<<(Logger& l, string msg);
+ Logger& log(int level);
+)cc";
+
+static ast_matchers::internal::Matcher<clang::QualType>
+isOrPointsTo(const clang::ast_matchers::DeclarationMatcher &TypeMatcher) {
+ return anyOf(hasDeclaration(TypeMatcher), pointsTo(TypeMatcher));
+}
+
+static std::string format(StringRef Code) {
+ const std::vector<Range> Ranges(1, Range(0, Code.size()));
+ auto Style = format::getLLVMStyle();
+ const auto Replacements = format::reformat(Style, Code, Ranges);
+ auto Formatted = applyAllReplacements(Code, Replacements);
+ if (!Formatted) {
+ ADD_FAILURE() << "Could not format code: "
+ << llvm::toString(Formatted.takeError());
+ return std::string();
+ }
+ return *Formatted;
+}
+
+static void compareSnippets(StringRef Expected,
+ const llvm::Optional<std::string> &MaybeActual) {
+ ASSERT_TRUE(MaybeActual) << "Rewrite failed. Expecting: " << Expected;
+ auto Actual = *MaybeActual;
+ std::string HL = "#include \"header.h\"\n";
+ auto I = Actual.find(HL);
+ if (I != std::string::npos)
+ Actual.erase(I, HL.size());
+ EXPECT_EQ(format(Expected), format(Actual));
+}
+
+// FIXME: consider separating this class into its own file(s).
+class ClangRefactoringTestBase : public testing::Test {
+protected:
+ void appendToHeader(StringRef S) { FileContents[0].second += S; }
+
+ void addFile(StringRef Filename, StringRef Content) {
+ FileContents.emplace_back(Filename, Content);
+ }
+
+ llvm::Optional<std::string> rewrite(StringRef Input) {
+ std::string Code = ("#include \"header.h\"\n" + Input).str();
+ auto Factory = newFrontendActionFactory(&MatchFinder);
+ if (!runToolOnCodeWithArgs(
+ Factory->create(), Code, std::vector<std::string>(), "input.cc",
+ "clang-tool", std::make_shared<PCHContainerOperations>(),
+ FileContents)) {
+ llvm::errs() << "Running tool failed.\n";
+ return None;
+ }
+ if (ErrorCount != 0) {
+ llvm::errs() << "Generating changes failed.\n";
+ return None;
+ }
+ auto ChangedCode =
+ applyAtomicChanges("input.cc", Code, Changes, ApplyChangesSpec());
+ if (!ChangedCode) {
+ llvm::errs() << "Applying changes failed: "
+ << llvm::toString(ChangedCode.takeError()) << "\n";
+ return None;
+ }
+ return *ChangedCode;
+ }
+
+ Transformer::ChangeConsumer consumer() {
+ return [this](Expected<AtomicChange> C) {
+ if (C) {
+ Changes.push_back(std::move(*C));
+ } else {
+ consumeError(C.takeError());
+ ++ErrorCount;
+ }
+ };
+ }
+
+ template <typename R>
+ void testRule(R Rule, StringRef Input, StringRef Expected) {
+ Transformer T(std::move(Rule), consumer());
+ T.registerMatchers(&MatchFinder);
+ compareSnippets(Expected, rewrite(Input));
+ }
+
+ clang::ast_matchers::MatchFinder MatchFinder;
+ // Records whether any errors occurred in individual changes.
+ int ErrorCount = 0;
+ AtomicChanges Changes;
+
+private:
+ FileContentMappings FileContents = {{"header.h", ""}};
+};
+
+class TransformerTest : public ClangRefactoringTestBase {
+protected:
+ TransformerTest() { appendToHeader(KHeaderContents); }
+};
+
+// Given string s, change strlen($s.c_str()) to $s.size().
+static RewriteRule ruleStrlenSize() {
+ StringRef StringExpr = "strexpr";
+ auto StringType = namedDecl(hasAnyName("::basic_string", "::string"));
+ auto R = makeRule(
+ callExpr(callee(functionDecl(hasName("strlen"))),
+ hasArgument(0, cxxMemberCallExpr(
+ on(expr(hasType(isOrPointsTo(StringType)))
+ .bind(StringExpr)),
+ callee(cxxMethodDecl(hasName("c_str")))))),
+ change(text("REPLACED")), text("Use size() method directly on string."));
+ return R;
+}
+
+TEST_F(TransformerTest, StrlenSize) {
+ std::string Input = "int f(string s) { return strlen(s.c_str()); }";
+ std::string Expected = "int f(string s) { return REPLACED; }";
+ testRule(ruleStrlenSize(), Input, Expected);
+}
+
+// Tests that no change is applied when a match is not expected.
+TEST_F(TransformerTest, NoMatch) {
+ std::string Input = "int f(string s) { return s.size(); }";
+ testRule(ruleStrlenSize(), Input, Input);
+}
+
+// Tests that expressions in macro arguments are rewritten (when applicable).
+TEST_F(TransformerTest, StrlenSizeMacro) {
+ std::string Input = R"cc(
+#define ID(e) e
+ int f(string s) { return ID(strlen(s.c_str())); })cc";
+ std::string Expected = R"cc(
+#define ID(e) e
+ int f(string s) { return ID(REPLACED); })cc";
+ testRule(ruleStrlenSize(), Input, Expected);
+}
+
+// Tests replacing an expression.
+TEST_F(TransformerTest, Flag) {
+ StringRef Flag = "flag";
+ RewriteRule Rule = makeRule(
+ cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
+ hasName("proto::ProtoCommandLineFlag"))))
+ .bind(Flag)),
+ unless(callee(cxxMethodDecl(hasName("GetProto"))))),
+ change(node(Flag), text("EXPR")));
+
+ std::string Input = R"cc(
+ proto::ProtoCommandLineFlag flag;
+ int x = flag.foo();
+ int y = flag.GetProto().foo();
+ )cc";
+ std::string Expected = R"cc(
+ proto::ProtoCommandLineFlag flag;
+ int x = EXPR.foo();
+ int y = flag.GetProto().foo();
+ )cc";
+
+ testRule(std::move(Rule), Input, Expected);
+}
+
+TEST_F(TransformerTest, AddIncludeQuoted) {
+ RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
+ change(text("other()")));
+ addInclude(Rule, "clang/OtherLib.h");
+
+ std::string Input = R"cc(
+ int f(int x);
+ int h(int x) { return f(x); }
+ )cc";
+ std::string Expected = R"cc(#include "clang/OtherLib.h"
+
+ int f(int x);
+ int h(int x) { return other(); }
+ )cc";
+
+ testRule(Rule, Input, Expected);
+}
+
+TEST_F(TransformerTest, AddIncludeAngled) {
+ RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
+ change(text("other()")));
+ addInclude(Rule, "clang/OtherLib.h", IncludeFormat::Angled);
+
+ std::string Input = R"cc(
+ int f(int x);
+ int h(int x) { return f(x); }
+ )cc";
+ std::string Expected = R"cc(#include <clang/OtherLib.h>
+
+ int f(int x);
+ int h(int x) { return other(); }
+ )cc";
+
+ testRule(Rule, Input, Expected);
+}
+
+TEST_F(TransformerTest, NodePartNameNamedDecl) {
+ StringRef Fun = "fun";
+ RewriteRule Rule = makeRule(functionDecl(hasName("bad")).bind(Fun),
+ change(name(Fun), text("good")));
+
+ std::string Input = R"cc(
+ int bad(int x);
+ int bad(int x) { return x * x; }
+ )cc";
+ std::string Expected = R"cc(
+ int good(int x);
+ int good(int x) { return x * x; }
+ )cc";
+
+ testRule(Rule, Input, Expected);
+}
+
+TEST_F(TransformerTest, NodePartNameDeclRef) {
+ std::string Input = R"cc(
+ template <typename T>
+ T bad(T x) {
+ return x;
+ }
+ int neutral(int x) { return bad<int>(x) * x; }
+ )cc";
+ std::string Expected = R"cc(
+ template <typename T>
+ T bad(T x) {
+ return x;
+ }
+ int neutral(int x) { return good<int>(x) * x; }
+ )cc";
+
+ StringRef Ref = "ref";
+ testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref),
+ change(name(Ref), text("good"))),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, NodePartNameDeclRefFailure) {
+ std::string Input = R"cc(
+ struct Y {
+ int operator*();
+ };
+ int neutral(int x) {
+ Y y;
+ int (Y::*ptr)() = &Y::operator*;
+ return *y + x;
+ }
+ )cc";
+
+ StringRef Ref = "ref";
+ Transformer T(makeRule(declRefExpr(to(functionDecl())).bind(Ref),
+ change(name(Ref), text("good"))),
+ consumer());
+ T.registerMatchers(&MatchFinder);
+ EXPECT_FALSE(rewrite(Input));
+}
+
+TEST_F(TransformerTest, NodePartMember) {
+ StringRef E = "expr";
+ RewriteRule Rule = makeRule(memberExpr(member(hasName("bad"))).bind(E),
+ change(member(E), text("good")));
+
+ std::string Input = R"cc(
+ struct S {
+ int bad;
+ };
+ int g() {
+ S s;
+ return s.bad;
+ }
+ )cc";
+ std::string Expected = R"cc(
+ struct S {
+ int bad;
+ };
+ int g() {
+ S s;
+ return s.good;
+ }
+ )cc";
+
+ testRule(Rule, Input, Expected);
+}
+
+TEST_F(TransformerTest, NodePartMemberQualified) {
+ std::string Input = R"cc(
+ struct S {
+ int bad;
+ int good;
+ };
+ struct T : public S {
+ int bad;
+ };
+ int g() {
+ T t;
+ return t.S::bad;
+ }
+ )cc";
+ std::string Expected = R"cc(
+ struct S {
+ int bad;
+ int good;
+ };
+ struct T : public S {
+ int bad;
+ };
+ int g() {
+ T t;
+ return t.S::good;
+ }
+ )cc";
+
+ StringRef E = "expr";
+ testRule(makeRule(memberExpr().bind(E), change(member(E), text("good"))),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, NodePartMemberMultiToken) {
+ std::string Input = R"cc(
+ struct Y {
+ int operator*();
+ int good();
+ template <typename T> void foo(T t);
+ };
+ int neutral(int x) {
+ Y y;
+ y.template foo<int>(3);
+ return y.operator *();
+ }
+ )cc";
+ std::string Expected = R"cc(
+ struct Y {
+ int operator*();
+ int good();
+ template <typename T> void foo(T t);
+ };
+ int neutral(int x) {
+ Y y;
+ y.template good<int>(3);
+ return y.good();
+ }
+ )cc";
+
+ StringRef MemExpr = "member";
+ testRule(makeRule(memberExpr().bind(MemExpr),
+ change(member(MemExpr), text("good"))),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, InsertBeforeEdit) {
+ std::string Input = R"cc(
+ int f() {
+ return 7;
+ }
+ )cc";
+ std::string Expected = R"cc(
+ int f() {
+ int y = 3;
+ return 7;
+ }
+ )cc";
+
+ StringRef Ret = "return";
+ testRule(makeRule(returnStmt().bind(Ret),
+ insertBefore(statement(Ret), text("int y = 3;"))),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, InsertAfterEdit) {
+ std::string Input = R"cc(
+ int f() {
+ int x = 5;
+ return 7;
+ }
+ )cc";
+ std::string Expected = R"cc(
+ int f() {
+ int x = 5;
+ int y = 3;
+ return 7;
+ }
+ )cc";
+
+ StringRef Decl = "decl";
+ testRule(makeRule(declStmt().bind(Decl),
+ insertAfter(statement(Decl), text("int y = 3;"))),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, RemoveEdit) {
+ std::string Input = R"cc(
+ int f() {
+ int x = 5;
+ return 7;
+ }
+ )cc";
+ std::string Expected = R"cc(
+ int f() {
+ return 7;
+ }
+ )cc";
+
+ StringRef Decl = "decl";
+ testRule(makeRule(declStmt().bind(Decl), remove(statement(Decl))), Input,
+ Expected);
+}
+
+TEST_F(TransformerTest, MultiChange) {
+ std::string Input = R"cc(
+ void foo() {
+ if (10 > 1.0)
+ log(1) << "oh no!";
+ else
+ log(0) << "ok";
+ }
+ )cc";
+ std::string Expected = R"(
+ void foo() {
+ if (true) { /* then */ }
+ else { /* else */ }
+ }
+ )";
+
+ StringRef C = "C", T = "T", E = "E";
+ testRule(makeRule(ifStmt(hasCondition(expr().bind(C)),
+ hasThen(stmt().bind(T)), hasElse(stmt().bind(E))),
+ {change(node(C), text("true")),
+ change(statement(T), text("{ /* then */ }")),
+ change(statement(E), text("{ /* else */ }"))}),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, OrderedRuleUnrelated) {
+ StringRef Flag = "flag";
+ RewriteRule FlagRule = makeRule(
+ cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
+ hasName("proto::ProtoCommandLineFlag"))))
+ .bind(Flag)),
+ unless(callee(cxxMethodDecl(hasName("GetProto"))))),
+ change(node(Flag), text("PROTO")));
+
+ std::string Input = R"cc(
+ proto::ProtoCommandLineFlag flag;
+ int x = flag.foo();
+ int y = flag.GetProto().foo();
+ int f(string s) { return strlen(s.c_str()); }
+ )cc";
+ std::string Expected = R"cc(
+ proto::ProtoCommandLineFlag flag;
+ int x = PROTO.foo();
+ int y = flag.GetProto().foo();
+ int f(string s) { return REPLACED; }
+ )cc";
+
+ testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected);
+}
+
+// Version of ruleStrlenSizeAny that inserts a method with a different name than
+// ruleStrlenSize, so we can tell their effect apart.
+RewriteRule ruleStrlenSizeDistinct() {
+ StringRef S;
+ return makeRule(
+ callExpr(callee(functionDecl(hasName("strlen"))),
+ hasArgument(0, cxxMemberCallExpr(
+ on(expr().bind(S)),
+ callee(cxxMethodDecl(hasName("c_str")))))),
+ change(text("DISTINCT")));
+}
+
+TEST_F(TransformerTest, OrderedRuleRelated) {
+ std::string Input = R"cc(
+ namespace foo {
+ struct mystring {
+ char* c_str();
+ };
+ int f(mystring s) { return strlen(s.c_str()); }
+ } // namespace foo
+ int g(string s) { return strlen(s.c_str()); }
+ )cc";
+ std::string Expected = R"cc(
+ namespace foo {
+ struct mystring {
+ char* c_str();
+ };
+ int f(mystring s) { return DISTINCT; }
+ } // namespace foo
+ int g(string s) { return REPLACED; }
+ )cc";
+
+ testRule(applyFirst({ruleStrlenSize(), ruleStrlenSizeDistinct()}), Input,
+ Expected);
+}
+
+// Change the order of the rules to get a different result.
+TEST_F(TransformerTest, OrderedRuleRelatedSwapped) {
+ std::string Input = R"cc(
+ namespace foo {
+ struct mystring {
+ char* c_str();
+ };
+ int f(mystring s) { return strlen(s.c_str()); }
+ } // namespace foo
+ int g(string s) { return strlen(s.c_str()); }
+ )cc";
+ std::string Expected = R"cc(
+ namespace foo {
+ struct mystring {
+ char* c_str();
+ };
+ int f(mystring s) { return DISTINCT; }
+ } // namespace foo
+ int g(string s) { return DISTINCT; }
+ )cc";
+
+ testRule(applyFirst({ruleStrlenSizeDistinct(), ruleStrlenSize()}), Input,
+ Expected);
+}
+
+//
+// Negative tests (where we expect no transformation to occur).
+//
+
+// Tests for a conflict in edits from a single match for a rule.
+TEST_F(TransformerTest, TextGeneratorFailure) {
+ std::string Input = "int conflictOneRule() { return 3 + 7; }";
+ // Try to change the whole binary-operator expression AND one its operands:
+ StringRef O = "O";
+ auto AlwaysFail = [](const ast_matchers::MatchFinder::MatchResult &)
+ -> llvm::Expected<std::string> {
+ return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
+ };
+ Transformer T(makeRule(binaryOperator().bind(O), change(node(O), AlwaysFail)),
+ consumer());
+ T.registerMatchers(&MatchFinder);
+ EXPECT_FALSE(rewrite(Input));
+ EXPECT_THAT(Changes, IsEmpty());
+ EXPECT_EQ(ErrorCount, 1);
+}
+
+// Tests for a conflict in edits from a single match for a rule.
+TEST_F(TransformerTest, OverlappingEditsInRule) {
+ std::string Input = "int conflictOneRule() { return 3 + 7; }";
+ // Try to change the whole binary-operator expression AND one its operands:
+ StringRef O = "O", L = "L";
+ Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O),
+ {change(node(O), text("DELETE_OP")),
+ change(node(L), text("DELETE_LHS"))}),
+ consumer());
+ T.registerMatchers(&MatchFinder);
+ EXPECT_FALSE(rewrite(Input));
+ EXPECT_THAT(Changes, IsEmpty());
+ EXPECT_EQ(ErrorCount, 1);
+}
+
+// Tests for a conflict in edits across multiple matches (of the same rule).
+TEST_F(TransformerTest, OverlappingEditsMultipleMatches) {
+ std::string Input = "int conflictOneRule() { return -7; }";
+ // Try to change the whole binary-operator expression AND one its operands:
+ StringRef E = "E";
+ Transformer T(makeRule(expr().bind(E), change(node(E), text("DELETE_EXPR"))),
+ consumer());
+ T.registerMatchers(&MatchFinder);
+ // The rewrite process fails because the changes conflict with each other...
+ EXPECT_FALSE(rewrite(Input));
+ // ... but two changes were produced.
+ EXPECT_EQ(Changes.size(), 2u);
+ EXPECT_EQ(ErrorCount, 0);
+}
+
+TEST_F(TransformerTest, ErrorOccurredMatchSkipped) {
+ // Syntax error in the function body:
+ std::string Input = "void errorOccurred() { 3 }";
+ Transformer T(makeRule(functionDecl(hasName("errorOccurred")),
+ change(text("DELETED;"))),
+ consumer());
+ T.registerMatchers(&MatchFinder);
+ // The rewrite process itself fails...
+ EXPECT_FALSE(rewrite(Input));
+ // ... and no changes or errors are produced in the process.
+ EXPECT_THAT(Changes, IsEmpty());
+ EXPECT_EQ(ErrorCount, 0);
+}
+
+TEST_F(TransformerTest, NoTransformationInMacro) {
+ std::string Input = R"cc(
+#define MACRO(str) strlen((str).c_str())
+ int f(string s) { return MACRO(s); })cc";
+ testRule(ruleStrlenSize(), Input, Input);
+}
+
+// This test handles the corner case where a macro called within another macro
+// expands to matching code, but the matched code is an argument to the nested
+// macro. A simple check of isMacroArgExpansion() vs. isMacroBodyExpansion()
+// will get this wrong, and transform the code. This test verifies that no such
+// transformation occurs.
+TEST_F(TransformerTest, NoTransformationInNestedMacro) {
+ std::string Input = R"cc(
+#define NESTED(e) e
+#define MACRO(str) NESTED(strlen((str).c_str()))
+ int f(string s) { return MACRO(s); })cc";
+ testRule(ruleStrlenSize(), Input, Input);
+}
+} // namespace
diff --git a/src/llvm-project/clang/unittests/libclang/LibclangTest.cpp b/src/llvm-project/clang/unittests/libclang/LibclangTest.cpp
index b88b88d..b3ad5c7 100644
--- a/src/llvm-project/clang/unittests/libclang/LibclangTest.cpp
+++ b/src/llvm-project/clang/unittests/libclang/LibclangTest.cpp
@@ -1,9 +1,8 @@
//===- unittests/libclang/LibclangTest.cpp --- libclang tests -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//