forked from OSchip/llvm-project
240 lines
8.8 KiB
C++
240 lines
8.8 KiB
C++
//===- 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/AST/ASTImporterSharedState.h"
|
|
#include "clang/Frontend/ASTUnit.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "DeclMatcher.h"
|
|
#include "Language.h"
|
|
|
|
#include <sstream>
|
|
|
|
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;
|
|
|
|
// ODR handling type for the AST importer.
|
|
ASTImporter::ODRHandlingType ODRHandling;
|
|
|
|
// 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;
|
|
ASTImporter::ODRHandlingType ODRHandling;
|
|
|
|
TU(StringRef Code, StringRef FileName, ArgVector Args,
|
|
ImporterConstructor C = ImporterConstructor(),
|
|
ASTImporter::ODRHandlingType ODRHandling =
|
|
ASTImporter::ODRHandlingType::Conservative);
|
|
~TU();
|
|
|
|
void
|
|
lazyInitImporter(const std::shared_ptr<ASTImporterSharedState> &SharedState,
|
|
ASTUnit *ToAST);
|
|
Decl *import(const std::shared_ptr<ASTImporterSharedState> &SharedState,
|
|
ASTUnit *ToAST, Decl *FromDecl);
|
|
llvm::Expected<Decl *>
|
|
importOrError(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));
|
|
}
|
|
|
|
// Import the given Decl into the ToCtx.
|
|
// Same as Import but returns the result of the import which can be an error.
|
|
llvm::Expected<Decl *> importOrError(Decl *From, Language ToLang);
|
|
|
|
QualType ImportType(QualType FromType, Decl *TUDecl, Language ToLang);
|
|
|
|
ASTImporterTestBase()
|
|
: ODRHandling(ASTImporter::ODRHandlingType::Conservative) {}
|
|
~ASTImporterTestBase();
|
|
};
|
|
|
|
class ASTImporterOptionSpecificTestBase
|
|
: public ASTImporterTestBase,
|
|
public ::testing::WithParamInterface<ArgVector> {
|
|
protected:
|
|
ArgVector getExtraArgs() const override { return GetParam(); }
|
|
};
|
|
|
|
template <class T>
|
|
::testing::AssertionResult isSuccess(llvm::Expected<T> &ValOrErr) {
|
|
if (ValOrErr)
|
|
return ::testing::AssertionSuccess() << "Expected<> contains no error.";
|
|
else
|
|
return ::testing::AssertionFailure()
|
|
<< "Expected<> contains error: " << toString(ValOrErr.takeError());
|
|
}
|
|
|
|
template <class T>
|
|
::testing::AssertionResult isImportError(llvm::Expected<T> &ValOrErr,
|
|
ImportError::ErrorKind Kind) {
|
|
if (ValOrErr) {
|
|
return ::testing::AssertionFailure() << "Expected<> is expected to contain "
|
|
"error but does contain value \""
|
|
<< (*ValOrErr) << "\"";
|
|
} else {
|
|
std::ostringstream OS;
|
|
bool Result = false;
|
|
auto Err = llvm::handleErrors(
|
|
ValOrErr.takeError(), [&OS, &Result, Kind](clang::ImportError &IE) {
|
|
if (IE.Error == Kind) {
|
|
Result = true;
|
|
OS << "Expected<> contains an ImportError " << IE.toString();
|
|
} else {
|
|
OS << "Expected<> contains an ImportError " << IE.toString()
|
|
<< " instead of kind " << Kind;
|
|
}
|
|
});
|
|
if (Err) {
|
|
OS << "Expected<> contains unexpected error: "
|
|
<< toString(std::move(Err));
|
|
}
|
|
if (Result)
|
|
return ::testing::AssertionSuccess() << OS.str();
|
|
else
|
|
return ::testing::AssertionFailure() << OS.str();
|
|
}
|
|
}
|
|
|
|
} // end namespace ast_matchers
|
|
} // end namespace clang
|
|
|
|
#endif
|