diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2012-11-01 17:52:58 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2012-11-01 17:52:58 +0000 |
commit | 2edbc86809454ff66ccfd2737e7fd3dbe5343c84 (patch) | |
tree | e4eb8fb0989abddcc24dc1b73ae6087faeebae42 /clang/unittests | |
parent | 66e7ed959f9373f8596650e94b4176fe694be72a (diff) | |
download | bcm5719-llvm-2edbc86809454ff66ccfd2737e7fd3dbe5343c84.tar.gz bcm5719-llvm-2edbc86809454ff66ccfd2737e7fd3dbe5343c84.zip |
Make the FilenameRange of the InclusionDirective callback more accurate,
preserve the macro location of the range end if the filename came from a macro.
Patch by Kim Gräsman!
llvm-svn: 167239
Diffstat (limited to 'clang/unittests')
-rw-r--r-- | clang/unittests/Lex/CMakeLists.txt | 1 | ||||
-rw-r--r-- | clang/unittests/Lex/PPCallbacksTest.cpp | 248 |
2 files changed, 249 insertions, 0 deletions
diff --git a/clang/unittests/Lex/CMakeLists.txt b/clang/unittests/Lex/CMakeLists.txt index 10c936199d6..03c8cd5418a 100644 --- a/clang/unittests/Lex/CMakeLists.txt +++ b/clang/unittests/Lex/CMakeLists.txt @@ -1,6 +1,7 @@ add_clang_unittest(LexTests LexerTest.cpp PreprocessingRecordTest.cpp + PPCallbacksTest.cpp ) target_link_libraries(LexTests diff --git a/clang/unittests/Lex/PPCallbacksTest.cpp b/clang/unittests/Lex/PPCallbacksTest.cpp new file mode 100644 index 00000000000..ccb5f50a857 --- /dev/null +++ b/clang/unittests/Lex/PPCallbacksTest.cpp @@ -0,0 +1,248 @@ +//===- 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. +// +//===--------------------------------------------------------------===// + +#include "clang/Basic/Diagnostic.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/ModuleLoader.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/PathV2.h" + +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::sys; +using namespace clang; + +namespace { + +// Stub out module loading. +class VoidModuleLoader : public ModuleLoader { + virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective) { + return 0; + } +}; + +// Stub to collect data from InclusionDirective callbacks. +class InclusionDirectiveCallbacks : public PPCallbacks { +public: + void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + CharSourceRange FilenameRange, + const FileEntry *File, + StringRef SearchPath, + StringRef RelativePath, + const Module *Imported) { + this->HashLoc = HashLoc; + this->IncludeTok = IncludeTok; + this->FileName = FileName.str(); + this->IsAngled = IsAngled; + this->FilenameRange = FilenameRange; + this->File = File; + this->SearchPath = SearchPath.str(); + this->RelativePath = RelativePath.str(); + this->Imported = Imported; + } + + SourceLocation HashLoc; + Token IncludeTok; + SmallString<16> FileName; + bool IsAngled; + CharSourceRange FilenameRange; + const FileEntry* File; + SmallString<16> SearchPath; + SmallString<16> RelativePath; + const Module* Imported; +}; + +// PPCallbacks test fixture. +class PPCallbacksTest : public ::testing::Test { +protected: + PPCallbacksTest() + : FileMgr(FileMgrOpts), + DiagID(new DiagnosticIDs()), + DiagOpts(new DiagnosticOptions()), + Diags(DiagID, DiagOpts.getPtr(), new IgnoringDiagConsumer()), + SourceMgr(Diags, FileMgr) { + TargetOpts = new TargetOptions(); + TargetOpts->Triple = "x86_64-apple-darwin11.1.0"; + Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts); + } + + FileSystemOptions FileMgrOpts; + FileManager FileMgr; + IntrusiveRefCntPtr<DiagnosticIDs> DiagID; + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; + DiagnosticsEngine Diags; + SourceManager SourceMgr; + LangOptions LangOpts; + IntrusiveRefCntPtr<TargetOptions> TargetOpts; + IntrusiveRefCntPtr<TargetInfo> Target; + + // Register a header path as a known file and add its location + // to search path. + void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath, + bool IsSystemHeader) { + // Tell FileMgr about header. + FileMgr.getVirtualFile(HeaderPath, 0, 0); + + // Add header's parent path to search path. + StringRef SearchPath = path::parent_path(HeaderPath); + const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath); + DirectoryLookup DL(DE, SrcMgr::C_User, true, false); + HeaderInfo.AddSearchPath(DL, IsSystemHeader); + } + + // Get the raw source string of the range. + StringRef GetSourceString(CharSourceRange Range) { + const char* B = SourceMgr.getCharacterData(Range.getBegin()); + const char* E = SourceMgr.getCharacterData(Range.getEnd()); + + return StringRef(B, E - B); + } + + // Run lexer over SourceText and collect FilenameRange from + // the InclusionDirective callback. + CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText, + const char* HeaderPath, bool SystemHeader) { + MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(SourceText); + (void)SourceMgr.createMainFileIDForMemBuffer(Buf); + + VoidModuleLoader ModLoader; + + IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions(); + HeaderSearch HeaderInfo(HSOpts, FileMgr, Diags, LangOpts, Target.getPtr()); + AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader); + + IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions(); + Preprocessor PP(PPOpts, Diags, LangOpts, + Target.getPtr(), + SourceMgr, HeaderInfo, ModLoader, + /*IILookup =*/ 0, + /*OwnsHeaderSearch =*/false, + /*DelayInitialization =*/ false); + InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks; + PP.addPPCallbacks(Callbacks); // Takes ownership. + + // 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 filename range. + return Callbacks->FilenameRange; + } +}; + +TEST_F(PPCallbacksTest, QuotedFilename) { + const char* Source = + "#include \"quoted.h\"\n"; + + CharSourceRange Range = + InclusionDirectiveFilenameRange(Source, "/quoted.h", false); + + ASSERT_EQ("\"quoted.h\"", GetSourceString(Range)); +} + +TEST_F(PPCallbacksTest, AngledFilename) { + const char* Source = + "#include <angled.h>\n"; + + CharSourceRange Range = + InclusionDirectiveFilenameRange(Source, "/angled.h", true); + + ASSERT_EQ("<angled.h>", GetSourceString(Range)); +} + +TEST_F(PPCallbacksTest, QuotedInMacro) { + const char* Source = + "#define MACRO_QUOTED \"quoted.h\"\n" + "#include MACRO_QUOTED\n"; + + CharSourceRange Range = + InclusionDirectiveFilenameRange(Source, "/quoted.h", false); + + ASSERT_EQ("\"quoted.h\"", GetSourceString(Range)); +} + +TEST_F(PPCallbacksTest, AngledInMacro) { + const char* Source = + "#define MACRO_ANGLED <angled.h>\n" + "#include MACRO_ANGLED\n"; + + CharSourceRange Range = + InclusionDirectiveFilenameRange(Source, "/angled.h", true); + + ASSERT_EQ("<angled.h>", GetSourceString(Range)); +} + +TEST_F(PPCallbacksTest, StringizedMacroArgument) { + const char* Source = + "#define MACRO_STRINGIZED(x) #x\n" + "#include MACRO_STRINGIZED(quoted.h)\n"; + + CharSourceRange Range = + InclusionDirectiveFilenameRange(Source, "/quoted.h", false); + + ASSERT_EQ("\"quoted.h\"", GetSourceString(Range)); +} + +TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) { + const char* Source = + "#define MACRO_ANGLED <angled.h>\n" + "#define MACRO_CONCAT(x, y) x ## _ ## y\n" + "#include MACRO_CONCAT(MACRO, ANGLED)\n"; + + CharSourceRange Range = + InclusionDirectiveFilenameRange(Source, "/angled.h", false); + + ASSERT_EQ("<angled.h>", GetSourceString(Range)); +} + +#pragma clang diagnostic ignored "-Wtrigraphs" + +TEST_F(PPCallbacksTest, TrigraphFilename) { + const char* Source = + "#include \"tri??-graph.h\"\n"; + + CharSourceRange Range = + InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false); + + ASSERT_EQ("\"tri??-graph.h\"", GetSourceString(Range)); +} + +TEST_F(PPCallbacksTest, TrigraphInMacro) { + const char* Source = + "#define MACRO_TRIGRAPH \"tri??-graph.h\"\n" + "#include MACRO_TRIGRAPH\n"; + + CharSourceRange Range = + InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false); + + ASSERT_EQ("\"tri??-graph.h\"", GetSourceString(Range)); +} + +} // anonoymous namespace |