forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			251 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			251 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- 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/Lex/Preprocessor.h"
 | |
| #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/PreprocessorOptions.h"
 | |
| #include "llvm/ADT/SmallString.h"
 | |
| #include "llvm/Support/Path.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 ModuleLoadResult loadModule(SourceLocation ImportLoc, 
 | |
|                                       ModuleIdPath Path,
 | |
|                                       Module::NameVisibilityKind Visibility,
 | |
|                                       bool IsInclusionDirective) {
 | |
|     return ModuleLoadResult();
 | |
|   }
 | |
| 
 | |
|   virtual void makeModuleVisible(Module *Mod,
 | |
|                                  Module::NameVisibilityKind Visibility,
 | |
|                                  SourceLocation ImportLoc,
 | |
|                                  bool Complain) { }
 | |
| };
 | |
| 
 | |
| // 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, 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));
 | |
| }
 | |
| 
 | |
| 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
 |