Skip to content

Instantly share code, notes, and snippets.

@T35R6braPwgDJKq
Created August 26, 2021 07:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save T35R6braPwgDJKq/6439fda090e4ee8440d726f8dafa4dbb to your computer and use it in GitHub Desktop.
Save T35R6braPwgDJKq/6439fda090e4ee8440d726f8dafa4dbb to your computer and use it in GitHub Desktop.
//===- unittests/Analysis/MacroExpansionContextTest.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/Analysis/MacroExpansionContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Parse/Parser.h"
#include "llvm/ADT/SmallString.h"
#include "gtest/gtest.h"
// static bool HACK_EnableDebugInUnitTest = (::llvm::DebugFlag = true);
namespace clang {
namespace analysis {
namespace {
class MacroExpansionContextTest : public ::testing::Test {
protected:
MacroExpansionContextTest()
: InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
FileMgr(FileSystemOptions(), InMemoryFileSystem),
DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
TargetOpts->Triple = "x86_64-pc-linux-unknown";
Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
LangOpts.CPlusPlus20 = 1; // For __VA_OPT__
}
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
FileManager FileMgr;
IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
DiagnosticsEngine Diags;
SourceManager SourceMgr;
LangOptions LangOpts;
std::shared_ptr<TargetOptions> TargetOpts;
IntrusiveRefCntPtr<TargetInfo> Target;
std::unique_ptr<MacroExpansionContext>
getMacroExpansionContextFor(StringRef SourceText) {
std::unique_ptr<llvm::MemoryBuffer> Buf =
llvm::MemoryBuffer::getMemBuffer(SourceText);
SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
TrivialModuleLoader ModLoader;
HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
Diags, LangOpts, Target.get());
Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
SourceMgr, HeaderInfo, ModLoader,
/*IILookup =*/nullptr,
/*OwnsHeaderSearch =*/false);
PP.Initialize(*Target);
auto Ctx = std::make_unique<MacroExpansionContext>(LangOpts);
Ctx->registerForPreprocessor(PP);
// Lex source text.
PP.EnterMainSourceFile();
while (true) {
Token Tok;
PP.Lex(Tok);
if (Tok.is(tok::eof))
break;
}
// Callbacks have been executed at this point.
return Ctx;
}
/// Returns the expansion location to main file at the given row and column.
SourceLocation at(unsigned row, unsigned col) const {
SourceLocation Loc =
SourceMgr.translateLineCol(SourceMgr.getMainFileID(), row, col);
return SourceMgr.getExpansionLoc(Loc);
}
static std::string dumpExpandedTexts(const MacroExpansionContext &Ctx) {
std::string Buf;
llvm::raw_string_ostream OS{Buf};
Ctx.dumpExpandedTextsToStream(OS);
return OS.str();
}
static std::string dumpExpansionRanges(const MacroExpansionContext &Ctx) {
std::string Buf;
llvm::raw_string_ostream OS{Buf};
Ctx.dumpExpansionRangesToStream(OS);
return OS.str();
}
};
TEST_F(MacroExpansionContextTest, Custom) {
// From the GCC website.
const auto Ctx = getMacroExpansionContextFor(R"code(
#define CONCATMACRO(parm) L##parm
int f(wchar_t *b){}
int main()
{
int a= f(CONCATMACRO("TEST"));
int b= f(L"TEST");
return 0;
}
)code");
Ctx->dumpExpansionRanges();
//> :6:14, :6:33
Ctx->dumpExpandedTexts();
//> :6:14 -> 'L"TEST"'
printf("Exp: %s\n",Ctx->getExpandedText(at(6, 14)).getValue());
//Exp: L"TEST"
printf("Org: %s\n",Ctx->getOriginalText(at(6, 14)).getValue());
//Org: CONCATMACRO("TEST"));
// int b= f(L"TEST");
// return 0;
//}
StringRef sourceText = clang::Lexer::getSourceText(CharSourceRange(SourceRange(at(6, 14),at(6, 33)),false),SourceMgr, LangOpts);
printf("sourceText: %s\n",sourceText);
// sourceText: CONCATMACRO("TEST"));
// int b= f(L"TEST");
// return 0;
// }
}
/**
gcc mectest.cpp -lgtest -lstdc++ -lclang -lLLVM -lclang-cpp -g -o mectest
./mectest
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from MacroExpansionContextTest
[ RUN ] MacroExpansionContextTest.Custom
=============== ExpansionRanges ===============
> :6:14, :6:33
=============== ExpandedTokens ===============
> :6:14 -> 'L"TEST"'
Exp: L"TEST"
Org: CONCATMACRO("TEST"));
int b= f(L"TEST");
return 0;
}
sourceText: CONCATMACRO("TEST"));
int b= f(L"TEST");
return 0;
}
[ OK ] MacroExpansionContextTest.Custom (15 ms)
[----------] 1 test from MacroExpansionContextTest (15 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (15 ms total)
[ PASSED ] 1 test.
*/
} // namespace
} // namespace analysis
} // namespace clang
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment