PPCallbacksTest.cpp revision 1a4191d0697098c424646654784399b839f87bc4
1//===- unittests/Lex/PPCallbacksTest.cpp - PPCallbacks tests ------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===--------------------------------------------------------------===// 9 10#include "clang/Lex/Preprocessor.h" 11#include "clang/Basic/Diagnostic.h" 12#include "clang/Basic/FileManager.h" 13#include "clang/Basic/LangOptions.h" 14#include "clang/Basic/SourceManager.h" 15#include "clang/Basic/TargetInfo.h" 16#include "clang/Basic/TargetOptions.h" 17#include "clang/Lex/HeaderSearch.h" 18#include "clang/Lex/HeaderSearchOptions.h" 19#include "clang/Lex/ModuleLoader.h" 20#include "clang/Lex/PreprocessorOptions.h" 21#include "llvm/ADT/SmallString.h" 22#include "llvm/Support/PathV2.h" 23#include "gtest/gtest.h" 24 25using namespace llvm; 26using namespace llvm::sys; 27using namespace clang; 28 29namespace { 30 31// Stub out module loading. 32class VoidModuleLoader : public ModuleLoader { 33 virtual ModuleLoadResult loadModule(SourceLocation ImportLoc, 34 ModuleIdPath Path, 35 Module::NameVisibilityKind Visibility, 36 bool IsInclusionDirective) { 37 return ModuleLoadResult(); 38 } 39 40 virtual void makeModuleVisible(Module *Mod, 41 Module::NameVisibilityKind Visibility) { } 42}; 43 44// Stub to collect data from InclusionDirective callbacks. 45class InclusionDirectiveCallbacks : public PPCallbacks { 46public: 47 void InclusionDirective(SourceLocation HashLoc, 48 const Token &IncludeTok, 49 StringRef FileName, 50 bool IsAngled, 51 CharSourceRange FilenameRange, 52 const FileEntry *File, 53 StringRef SearchPath, 54 StringRef RelativePath, 55 const Module *Imported) { 56 this->HashLoc = HashLoc; 57 this->IncludeTok = IncludeTok; 58 this->FileName = FileName.str(); 59 this->IsAngled = IsAngled; 60 this->FilenameRange = FilenameRange; 61 this->File = File; 62 this->SearchPath = SearchPath.str(); 63 this->RelativePath = RelativePath.str(); 64 this->Imported = Imported; 65 } 66 67 SourceLocation HashLoc; 68 Token IncludeTok; 69 SmallString<16> FileName; 70 bool IsAngled; 71 CharSourceRange FilenameRange; 72 const FileEntry* File; 73 SmallString<16> SearchPath; 74 SmallString<16> RelativePath; 75 const Module* Imported; 76}; 77 78// PPCallbacks test fixture. 79class PPCallbacksTest : public ::testing::Test { 80protected: 81 PPCallbacksTest() 82 : FileMgr(FileMgrOpts), 83 DiagID(new DiagnosticIDs()), 84 DiagOpts(new DiagnosticOptions()), 85 Diags(DiagID, DiagOpts.getPtr(), new IgnoringDiagConsumer()), 86 SourceMgr(Diags, FileMgr) { 87 TargetOpts = new TargetOptions(); 88 TargetOpts->Triple = "x86_64-apple-darwin11.1.0"; 89 Target = TargetInfo::CreateTargetInfo(Diags, &*TargetOpts); 90 } 91 92 FileSystemOptions FileMgrOpts; 93 FileManager FileMgr; 94 IntrusiveRefCntPtr<DiagnosticIDs> DiagID; 95 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; 96 DiagnosticsEngine Diags; 97 SourceManager SourceMgr; 98 LangOptions LangOpts; 99 IntrusiveRefCntPtr<TargetOptions> TargetOpts; 100 IntrusiveRefCntPtr<TargetInfo> Target; 101 102 // Register a header path as a known file and add its location 103 // to search path. 104 void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath, 105 bool IsSystemHeader) { 106 // Tell FileMgr about header. 107 FileMgr.getVirtualFile(HeaderPath, 0, 0); 108 109 // Add header's parent path to search path. 110 StringRef SearchPath = path::parent_path(HeaderPath); 111 const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath); 112 DirectoryLookup DL(DE, SrcMgr::C_User, true, false); 113 HeaderInfo.AddSearchPath(DL, IsSystemHeader); 114 } 115 116 // Get the raw source string of the range. 117 StringRef GetSourceString(CharSourceRange Range) { 118 const char* B = SourceMgr.getCharacterData(Range.getBegin()); 119 const char* E = SourceMgr.getCharacterData(Range.getEnd()); 120 121 return StringRef(B, E - B); 122 } 123 124 // Run lexer over SourceText and collect FilenameRange from 125 // the InclusionDirective callback. 126 CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText, 127 const char* HeaderPath, bool SystemHeader) { 128 MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(SourceText); 129 (void)SourceMgr.createMainFileIDForMemBuffer(Buf); 130 131 VoidModuleLoader ModLoader; 132 133 IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions(); 134 HeaderSearch HeaderInfo(HSOpts, FileMgr, Diags, LangOpts, Target.getPtr()); 135 AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader); 136 137 IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions(); 138 Preprocessor PP(PPOpts, Diags, LangOpts, 139 Target.getPtr(), 140 SourceMgr, HeaderInfo, ModLoader, 141 /*IILookup =*/ 0, 142 /*OwnsHeaderSearch =*/false, 143 /*DelayInitialization =*/ false); 144 InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks; 145 PP.addPPCallbacks(Callbacks); // Takes ownership. 146 147 // Lex source text. 148 PP.EnterMainSourceFile(); 149 150 while (true) { 151 Token Tok; 152 PP.Lex(Tok); 153 if (Tok.is(tok::eof)) 154 break; 155 } 156 157 // Callbacks have been executed at this point -- return filename range. 158 return Callbacks->FilenameRange; 159 } 160}; 161 162TEST_F(PPCallbacksTest, QuotedFilename) { 163 const char* Source = 164 "#include \"quoted.h\"\n"; 165 166 CharSourceRange Range = 167 InclusionDirectiveFilenameRange(Source, "/quoted.h", false); 168 169 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range)); 170} 171 172TEST_F(PPCallbacksTest, AngledFilename) { 173 const char* Source = 174 "#include <angled.h>\n"; 175 176 CharSourceRange Range = 177 InclusionDirectiveFilenameRange(Source, "/angled.h", true); 178 179 ASSERT_EQ("<angled.h>", GetSourceString(Range)); 180} 181 182TEST_F(PPCallbacksTest, QuotedInMacro) { 183 const char* Source = 184 "#define MACRO_QUOTED \"quoted.h\"\n" 185 "#include MACRO_QUOTED\n"; 186 187 CharSourceRange Range = 188 InclusionDirectiveFilenameRange(Source, "/quoted.h", false); 189 190 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range)); 191} 192 193TEST_F(PPCallbacksTest, AngledInMacro) { 194 const char* Source = 195 "#define MACRO_ANGLED <angled.h>\n" 196 "#include MACRO_ANGLED\n"; 197 198 CharSourceRange Range = 199 InclusionDirectiveFilenameRange(Source, "/angled.h", true); 200 201 ASSERT_EQ("<angled.h>", GetSourceString(Range)); 202} 203 204TEST_F(PPCallbacksTest, StringizedMacroArgument) { 205 const char* Source = 206 "#define MACRO_STRINGIZED(x) #x\n" 207 "#include MACRO_STRINGIZED(quoted.h)\n"; 208 209 CharSourceRange Range = 210 InclusionDirectiveFilenameRange(Source, "/quoted.h", false); 211 212 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range)); 213} 214 215TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) { 216 const char* Source = 217 "#define MACRO_ANGLED <angled.h>\n" 218 "#define MACRO_CONCAT(x, y) x ## _ ## y\n" 219 "#include MACRO_CONCAT(MACRO, ANGLED)\n"; 220 221 CharSourceRange Range = 222 InclusionDirectiveFilenameRange(Source, "/angled.h", false); 223 224 ASSERT_EQ("<angled.h>", GetSourceString(Range)); 225} 226 227TEST_F(PPCallbacksTest, TrigraphFilename) { 228 const char* Source = 229 "#include \"tri\?\?-graph.h\"\n"; 230 231 CharSourceRange Range = 232 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false); 233 234 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range)); 235} 236 237TEST_F(PPCallbacksTest, TrigraphInMacro) { 238 const char* Source = 239 "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n" 240 "#include MACRO_TRIGRAPH\n"; 241 242 CharSourceRange Range = 243 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false); 244 245 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range)); 246} 247 248} // anonoymous namespace 249