From: Argyrios Kyrtzidis Date: Thu, 1 Nov 2012 17:52:58 +0000 (+0000) Subject: Make the FilenameRange of the InclusionDirective callback more accurate, X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2edbc86809454ff66ccfd2737e7fd3dbe5343c84;p=platform%2Fupstream%2Fllvm.git 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 --- diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 9314517..b7c1846 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -1296,7 +1296,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, case tok::string_literal: Filename = getSpelling(FilenameTok, FilenameBuffer); End = FilenameTok.getLocation(); - CharEnd = End.getLocWithOffset(Filename.size()); + CharEnd = End.getLocWithOffset(FilenameTok.getLength()); break; case tok::less: @@ -1306,7 +1306,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, if (ConcatenateIncludeName(FilenameBuffer, End)) return; // Found but no ">"? Diagnostic already emitted. Filename = FilenameBuffer.str(); - CharEnd = getLocForEndOfToken(End); + CharEnd = End.getLocWithOffset(1); break; default: Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename); diff --git a/clang/unittests/Lex/CMakeLists.txt b/clang/unittests/Lex/CMakeLists.txt index 10c9361..03c8cd5 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 0000000..ccb5f50 --- /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 DiagID; + IntrusiveRefCntPtr DiagOpts; + DiagnosticsEngine Diags; + SourceManager SourceMgr; + LangOptions LangOpts; + IntrusiveRefCntPtr TargetOpts; + IntrusiveRefCntPtr 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 HSOpts = new HeaderSearchOptions(); + HeaderSearch HeaderInfo(HSOpts, FileMgr, Diags, LangOpts, Target.getPtr()); + AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader); + + IntrusiveRefCntPtr 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 \n"; + + CharSourceRange Range = + InclusionDirectiveFilenameRange(Source, "/angled.h", true); + + ASSERT_EQ("", 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 \n" + "#include MACRO_ANGLED\n"; + + CharSourceRange Range = + InclusionDirectiveFilenameRange(Source, "/angled.h", true); + + ASSERT_EQ("", 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 \n" + "#define MACRO_CONCAT(x, y) x ## _ ## y\n" + "#include MACRO_CONCAT(MACRO, ANGLED)\n"; + + CharSourceRange Range = + InclusionDirectiveFilenameRange(Source, "/angled.h", false); + + ASSERT_EQ("", 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