Home | History | Annotate | Download | only in Lex
      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/AST/ASTConsumer.h"
     12 #include "clang/AST/ASTContext.h"
     13 #include "clang/Basic/Diagnostic.h"
     14 #include "clang/Basic/DiagnosticOptions.h"
     15 #include "clang/Basic/FileManager.h"
     16 #include "clang/Basic/LangOptions.h"
     17 #include "clang/Basic/SourceManager.h"
     18 #include "clang/Basic/TargetInfo.h"
     19 #include "clang/Basic/TargetOptions.h"
     20 #include "clang/Lex/HeaderSearch.h"
     21 #include "clang/Lex/HeaderSearchOptions.h"
     22 #include "clang/Lex/ModuleLoader.h"
     23 #include "clang/Lex/PreprocessorOptions.h"
     24 #include "clang/Parse/Parser.h"
     25 #include "clang/Sema/Sema.h"
     26 #include "llvm/ADT/SmallString.h"
     27 #include "llvm/Support/Path.h"
     28 #include "gtest/gtest.h"
     29 
     30 using namespace clang;
     31 
     32 namespace {
     33 
     34 // Stub out module loading.
     35 class VoidModuleLoader : public ModuleLoader {
     36   ModuleLoadResult loadModule(SourceLocation ImportLoc,
     37                               ModuleIdPath Path,
     38                               Module::NameVisibilityKind Visibility,
     39                               bool IsInclusionDirective) override {
     40     return ModuleLoadResult();
     41   }
     42 
     43   void makeModuleVisible(Module *Mod,
     44                          Module::NameVisibilityKind Visibility,
     45                          SourceLocation ImportLoc) override { }
     46 
     47   GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
     48     { return nullptr; }
     49   bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
     50     { return 0; }
     51 };
     52 
     53 // Stub to collect data from InclusionDirective callbacks.
     54 class InclusionDirectiveCallbacks : public PPCallbacks {
     55 public:
     56   void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
     57                           StringRef FileName, bool IsAngled,
     58                           CharSourceRange FilenameRange, const FileEntry *File,
     59                           StringRef SearchPath, StringRef RelativePath,
     60                           const Module *Imported) override {
     61       this->HashLoc = HashLoc;
     62       this->IncludeTok = IncludeTok;
     63       this->FileName = FileName.str();
     64       this->IsAngled = IsAngled;
     65       this->FilenameRange = FilenameRange;
     66       this->File = File;
     67       this->SearchPath = SearchPath.str();
     68       this->RelativePath = RelativePath.str();
     69       this->Imported = Imported;
     70   }
     71 
     72   SourceLocation HashLoc;
     73   Token IncludeTok;
     74   SmallString<16> FileName;
     75   bool IsAngled;
     76   CharSourceRange FilenameRange;
     77   const FileEntry* File;
     78   SmallString<16> SearchPath;
     79   SmallString<16> RelativePath;
     80   const Module* Imported;
     81 };
     82 
     83 // Stub to collect data from PragmaOpenCLExtension callbacks.
     84 class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
     85 public:
     86   typedef struct {
     87     SmallString<16> Name;
     88     unsigned State;
     89   } CallbackParameters;
     90 
     91   PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {}
     92 
     93   void PragmaOpenCLExtension(clang::SourceLocation NameLoc,
     94                              const clang::IdentifierInfo *Name,
     95                              clang::SourceLocation StateLoc,
     96                              unsigned State) override {
     97       this->NameLoc = NameLoc;
     98       this->Name = Name->getName();
     99       this->StateLoc = StateLoc;
    100       this->State = State;
    101   }
    102 
    103   SourceLocation NameLoc;
    104   SmallString<16> Name;
    105   SourceLocation StateLoc;
    106   unsigned State;
    107 };
    108 
    109 // PPCallbacks test fixture.
    110 class PPCallbacksTest : public ::testing::Test {
    111 protected:
    112   PPCallbacksTest()
    113       : InMemoryFileSystem(new vfs::InMemoryFileSystem),
    114         FileMgr(FileSystemOptions(), InMemoryFileSystem),
    115         DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
    116         Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
    117         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
    118     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
    119     Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
    120   }
    121 
    122   IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem;
    123   FileManager FileMgr;
    124   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
    125   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
    126   DiagnosticsEngine Diags;
    127   SourceManager SourceMgr;
    128   LangOptions LangOpts;
    129   std::shared_ptr<TargetOptions> TargetOpts;
    130   IntrusiveRefCntPtr<TargetInfo> Target;
    131 
    132   // Register a header path as a known file and add its location
    133   // to search path.
    134   void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath,
    135     bool IsSystemHeader) {
    136       // Tell FileMgr about header.
    137       InMemoryFileSystem->addFile(HeaderPath, 0,
    138                                   llvm::MemoryBuffer::getMemBuffer("\n"));
    139 
    140       // Add header's parent path to search path.
    141       StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);
    142       const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
    143       DirectoryLookup DL(DE, SrcMgr::C_User, false);
    144       HeaderInfo.AddSearchPath(DL, IsSystemHeader);
    145   }
    146 
    147   // Get the raw source string of the range.
    148   StringRef GetSourceString(CharSourceRange Range) {
    149     const char* B = SourceMgr.getCharacterData(Range.getBegin());
    150     const char* E = SourceMgr.getCharacterData(Range.getEnd());
    151 
    152     return StringRef(B, E - B);
    153   }
    154 
    155   // Run lexer over SourceText and collect FilenameRange from
    156   // the InclusionDirective callback.
    157   CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText,
    158       const char* HeaderPath, bool SystemHeader) {
    159     std::unique_ptr<llvm::MemoryBuffer> Buf =
    160         llvm::MemoryBuffer::getMemBuffer(SourceText);
    161     SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
    162 
    163     VoidModuleLoader ModLoader;
    164 
    165     IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions();
    166     HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts,
    167                             Target.get());
    168     AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
    169 
    170     IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions();
    171     Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
    172                     /*IILookup =*/nullptr,
    173                     /*OwnsHeaderSearch =*/false);
    174     PP.Initialize(*Target);
    175     InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
    176     PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
    177 
    178     // Lex source text.
    179     PP.EnterMainSourceFile();
    180 
    181     while (true) {
    182       Token Tok;
    183       PP.Lex(Tok);
    184       if (Tok.is(tok::eof))
    185         break;
    186     }
    187 
    188     // Callbacks have been executed at this point -- return filename range.
    189     return Callbacks->FilenameRange;
    190   }
    191 
    192   PragmaOpenCLExtensionCallbacks::CallbackParameters
    193   PragmaOpenCLExtensionCall(const char* SourceText) {
    194     LangOptions OpenCLLangOpts;
    195     OpenCLLangOpts.OpenCL = 1;
    196 
    197     std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
    198         llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
    199     SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
    200 
    201     VoidModuleLoader ModLoader;
    202     HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags,
    203                             OpenCLLangOpts, Target.get());
    204 
    205     Preprocessor PP(new PreprocessorOptions(), Diags, OpenCLLangOpts, SourceMgr,
    206                     HeaderInfo, ModLoader, /*IILookup =*/nullptr,
    207                     /*OwnsHeaderSearch =*/false);
    208     PP.Initialize(*Target);
    209 
    210     // parser actually sets correct pragma handlers for preprocessor
    211     // according to LangOptions, so we init Parser to register opencl
    212     // pragma handlers
    213     ASTContext Context(OpenCLLangOpts, SourceMgr,
    214                        PP.getIdentifierTable(), PP.getSelectorTable(),
    215                        PP.getBuiltinInfo());
    216     Context.InitBuiltinTypes(*Target);
    217 
    218     ASTConsumer Consumer;
    219     Sema S(PP, Context, Consumer);
    220     Parser P(PP, S, false);
    221     PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
    222     PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
    223 
    224     // Lex source text.
    225     PP.EnterMainSourceFile();
    226     while (true) {
    227       Token Tok;
    228       PP.Lex(Tok);
    229       if (Tok.is(tok::eof))
    230         break;
    231     }
    232 
    233     PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
    234       Callbacks->Name,
    235       Callbacks->State
    236     };
    237     return RetVal;
    238   }
    239 };
    240 
    241 TEST_F(PPCallbacksTest, QuotedFilename) {
    242   const char* Source =
    243     "#include \"quoted.h\"\n";
    244 
    245   CharSourceRange Range =
    246     InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
    247 
    248   ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
    249 }
    250 
    251 TEST_F(PPCallbacksTest, AngledFilename) {
    252   const char* Source =
    253     "#include <angled.h>\n";
    254 
    255   CharSourceRange Range =
    256     InclusionDirectiveFilenameRange(Source, "/angled.h", true);
    257 
    258   ASSERT_EQ("<angled.h>", GetSourceString(Range));
    259 }
    260 
    261 TEST_F(PPCallbacksTest, QuotedInMacro) {
    262   const char* Source =
    263     "#define MACRO_QUOTED \"quoted.h\"\n"
    264     "#include MACRO_QUOTED\n";
    265 
    266   CharSourceRange Range =
    267     InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
    268 
    269   ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
    270 }
    271 
    272 TEST_F(PPCallbacksTest, AngledInMacro) {
    273   const char* Source =
    274     "#define MACRO_ANGLED <angled.h>\n"
    275     "#include MACRO_ANGLED\n";
    276 
    277   CharSourceRange Range =
    278     InclusionDirectiveFilenameRange(Source, "/angled.h", true);
    279 
    280   ASSERT_EQ("<angled.h>", GetSourceString(Range));
    281 }
    282 
    283 TEST_F(PPCallbacksTest, StringizedMacroArgument) {
    284   const char* Source =
    285     "#define MACRO_STRINGIZED(x) #x\n"
    286     "#include MACRO_STRINGIZED(quoted.h)\n";
    287 
    288   CharSourceRange Range =
    289     InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
    290 
    291   ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
    292 }
    293 
    294 TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
    295   const char* Source =
    296     "#define MACRO_ANGLED <angled.h>\n"
    297     "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
    298     "#include MACRO_CONCAT(MACRO, ANGLED)\n";
    299 
    300   CharSourceRange Range =
    301     InclusionDirectiveFilenameRange(Source, "/angled.h", false);
    302 
    303   ASSERT_EQ("<angled.h>", GetSourceString(Range));
    304 }
    305 
    306 TEST_F(PPCallbacksTest, TrigraphFilename) {
    307   const char* Source =
    308     "#include \"tri\?\?-graph.h\"\n";
    309 
    310   CharSourceRange Range =
    311     InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
    312 
    313   ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
    314 }
    315 
    316 TEST_F(PPCallbacksTest, TrigraphInMacro) {
    317   const char* Source =
    318     "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
    319     "#include MACRO_TRIGRAPH\n";
    320 
    321   CharSourceRange Range =
    322     InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
    323 
    324   ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
    325 }
    326 
    327 TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
    328   const char* Source =
    329     "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
    330 
    331   PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
    332     PragmaOpenCLExtensionCall(Source);
    333 
    334   ASSERT_EQ("cl_khr_fp64", Parameters.Name);
    335   unsigned ExpectedState = 1;
    336   ASSERT_EQ(ExpectedState, Parameters.State);
    337 }
    338 
    339 TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
    340   const char* Source =
    341     "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
    342 
    343   PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
    344     PragmaOpenCLExtensionCall(Source);
    345 
    346   ASSERT_EQ("cl_khr_fp16", Parameters.Name);
    347   unsigned ExpectedState = 0;
    348   ASSERT_EQ(ExpectedState, Parameters.State);
    349 }
    350 
    351 } // anonoymous namespace
    352