Home | History | Annotate | Download | only in Basic
      1 //===- unittests/Basic/SourceManagerTest.cpp ------ SourceManager 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/Basic/SourceManager.h"
     11 #include "clang/Basic/Diagnostic.h"
     12 #include "clang/Basic/DiagnosticOptions.h"
     13 #include "clang/Basic/FileManager.h"
     14 #include "clang/Basic/LangOptions.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/Preprocessor.h"
     21 #include "clang/Lex/PreprocessorOptions.h"
     22 #include "llvm/ADT/SmallString.h"
     23 #include "llvm/Config/llvm-config.h"
     24 #include "gtest/gtest.h"
     25 
     26 using namespace llvm;
     27 using namespace clang;
     28 
     29 namespace {
     30 
     31 // The test fixture.
     32 class SourceManagerTest : public ::testing::Test {
     33 protected:
     34   SourceManagerTest()
     35     : FileMgr(FileMgrOpts),
     36       DiagID(new DiagnosticIDs()),
     37       Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
     38       SourceMgr(Diags, FileMgr),
     39       TargetOpts(new TargetOptions) {
     40     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     41     Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
     42   }
     43 
     44   FileSystemOptions FileMgrOpts;
     45   FileManager FileMgr;
     46   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
     47   DiagnosticsEngine Diags;
     48   SourceManager SourceMgr;
     49   LangOptions LangOpts;
     50   std::shared_ptr<TargetOptions> TargetOpts;
     51   IntrusiveRefCntPtr<TargetInfo> Target;
     52 };
     53 
     54 class VoidModuleLoader : public ModuleLoader {
     55   ModuleLoadResult loadModule(SourceLocation ImportLoc,
     56                               ModuleIdPath Path,
     57                               Module::NameVisibilityKind Visibility,
     58                               bool IsInclusionDirective) override {
     59     return ModuleLoadResult();
     60   }
     61 
     62   void makeModuleVisible(Module *Mod,
     63                          Module::NameVisibilityKind Visibility,
     64                          SourceLocation ImportLoc,
     65                          bool Complain) override { }
     66 
     67   GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
     68     { return nullptr; }
     69   bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
     70     { return 0; };
     71 };
     72 
     73 TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
     74   const char *source =
     75     "#define M(x) [x]\n"
     76     "M(foo)";
     77   std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(source);
     78   FileID mainFileID = SourceMgr.createFileID(std::move(Buf));
     79   SourceMgr.setMainFileID(mainFileID);
     80 
     81   VoidModuleLoader ModLoader;
     82   HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
     83                           &*Target);
     84   Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, SourceMgr,
     85                   HeaderInfo, ModLoader,
     86                   /*IILookup =*/nullptr,
     87                   /*OwnsHeaderSearch =*/false);
     88   PP.Initialize(*Target);
     89   PP.EnterMainSourceFile();
     90 
     91   std::vector<Token> toks;
     92   while (1) {
     93     Token tok;
     94     PP.Lex(tok);
     95     if (tok.is(tok::eof))
     96       break;
     97     toks.push_back(tok);
     98   }
     99 
    100   // Make sure we got the tokens that we expected.
    101   ASSERT_EQ(3U, toks.size());
    102   ASSERT_EQ(tok::l_square, toks[0].getKind());
    103   ASSERT_EQ(tok::identifier, toks[1].getKind());
    104   ASSERT_EQ(tok::r_square, toks[2].getKind());
    105 
    106   SourceLocation lsqrLoc = toks[0].getLocation();
    107   SourceLocation idLoc = toks[1].getLocation();
    108   SourceLocation rsqrLoc = toks[2].getLocation();
    109 
    110   SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1);
    111   SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6);
    112   ASSERT_TRUE(macroExpStartLoc.isFileID());
    113   ASSERT_TRUE(macroExpEndLoc.isFileID());
    114 
    115   SmallString<32> str;
    116   ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str));
    117   ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str));
    118 
    119   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc));
    120   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc));
    121   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc));
    122   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc));
    123 }
    124 
    125 TEST_F(SourceManagerTest, getColumnNumber) {
    126   const char *Source =
    127     "int x;\n"
    128     "int y;";
    129 
    130   std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Source);
    131   FileID MainFileID = SourceMgr.createFileID(std::move(Buf));
    132   SourceMgr.setMainFileID(MainFileID);
    133 
    134   bool Invalid;
    135 
    136   Invalid = false;
    137   EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, &Invalid));
    138   EXPECT_TRUE(!Invalid);
    139 
    140   Invalid = false;
    141   EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 4, &Invalid));
    142   EXPECT_TRUE(!Invalid);
    143 
    144   Invalid = false;
    145   EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 7, &Invalid));
    146   EXPECT_TRUE(!Invalid);
    147 
    148   Invalid = false;
    149   EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 11, &Invalid));
    150   EXPECT_TRUE(!Invalid);
    151 
    152   Invalid = false;
    153   EXPECT_EQ(7U, SourceMgr.getColumnNumber(MainFileID, strlen(Source),
    154                                          &Invalid));
    155   EXPECT_TRUE(!Invalid);
    156 
    157   Invalid = false;
    158   SourceMgr.getColumnNumber(MainFileID, strlen(Source)+1, &Invalid);
    159   EXPECT_TRUE(Invalid);
    160 
    161   // Test invalid files
    162   Invalid = false;
    163   SourceMgr.getColumnNumber(FileID(), 0, &Invalid);
    164   EXPECT_TRUE(Invalid);
    165 
    166   Invalid = false;
    167   SourceMgr.getColumnNumber(FileID(), 1, &Invalid);
    168   EXPECT_TRUE(Invalid);
    169 
    170   // Test with no invalid flag.
    171   EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, nullptr));
    172 }
    173 
    174 #if defined(LLVM_ON_UNIX)
    175 
    176 TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
    177   const char *header =
    178     "#define FM(x,y) x\n";
    179 
    180   const char *main =
    181     "#include \"/test-header.h\"\n"
    182     "#define VAL 0\n"
    183     "FM(VAL,0)\n"
    184     "FM(0,VAL)\n"
    185     "FM(FM(0,VAL),0)\n"
    186     "#define CONCAT(X, Y) X##Y\n"
    187     "CONCAT(1,1)\n";
    188 
    189   std::unique_ptr<MemoryBuffer> HeaderBuf = MemoryBuffer::getMemBuffer(header);
    190   std::unique_ptr<MemoryBuffer> MainBuf = MemoryBuffer::getMemBuffer(main);
    191   FileID mainFileID = SourceMgr.createFileID(std::move(MainBuf));
    192   SourceMgr.setMainFileID(mainFileID);
    193 
    194   const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
    195                                                  HeaderBuf->getBufferSize(), 0);
    196   SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
    197 
    198   VoidModuleLoader ModLoader;
    199   HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
    200                           &*Target);
    201   Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, SourceMgr,
    202                   HeaderInfo, ModLoader,
    203                   /*IILookup =*/nullptr,
    204                   /*OwnsHeaderSearch =*/false);
    205   PP.Initialize(*Target);
    206   PP.EnterMainSourceFile();
    207 
    208   std::vector<Token> toks;
    209   while (1) {
    210     Token tok;
    211     PP.Lex(tok);
    212     if (tok.is(tok::eof))
    213       break;
    214     toks.push_back(tok);
    215   }
    216 
    217   // Make sure we got the tokens that we expected.
    218   ASSERT_EQ(4U, toks.size());
    219   ASSERT_EQ(tok::numeric_constant, toks[0].getKind());
    220   ASSERT_EQ(tok::numeric_constant, toks[1].getKind());
    221   ASSERT_EQ(tok::numeric_constant, toks[2].getKind());
    222   ASSERT_EQ(tok::numeric_constant, toks[3].getKind());
    223 
    224   SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13);
    225   SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8);
    226   SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4);
    227   SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7);
    228   SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22);
    229   defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc);
    230   loc1 = SourceMgr.getMacroArgExpandedLocation(loc1);
    231   loc2 = SourceMgr.getMacroArgExpandedLocation(loc2);
    232   loc3 = SourceMgr.getMacroArgExpandedLocation(loc3);
    233   defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2);
    234 
    235   EXPECT_TRUE(defLoc.isFileID());
    236   EXPECT_TRUE(loc1.isFileID());
    237   EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2));
    238   EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3));
    239   EXPECT_EQ(loc2, toks[1].getLocation());
    240   EXPECT_EQ(loc3, toks[2].getLocation());
    241   EXPECT_TRUE(defLoc2.isFileID());
    242 }
    243 
    244 namespace {
    245 
    246 struct MacroAction {
    247   SourceLocation Loc;
    248   std::string Name;
    249   bool isDefinition; // if false, it is expansion.
    250 
    251   MacroAction(SourceLocation Loc, StringRef Name, bool isDefinition)
    252     : Loc(Loc), Name(Name), isDefinition(isDefinition) { }
    253 };
    254 
    255 class MacroTracker : public PPCallbacks {
    256   std::vector<MacroAction> &Macros;
    257 
    258 public:
    259   explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
    260 
    261   void MacroDefined(const Token &MacroNameTok,
    262                     const MacroDirective *MD) override {
    263     Macros.push_back(MacroAction(MD->getLocation(),
    264                                  MacroNameTok.getIdentifierInfo()->getName(),
    265                                  true));
    266   }
    267   void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
    268                     SourceRange Range, const MacroArgs *Args) override {
    269     Macros.push_back(MacroAction(MacroNameTok.getLocation(),
    270                                  MacroNameTok.getIdentifierInfo()->getName(),
    271                                  false));
    272   }
    273 };
    274 
    275 }
    276 
    277 TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
    278   const char *header =
    279     "#define MACRO_IN_INCLUDE 0\n";
    280 
    281   const char *main =
    282     "#define M(x) x\n"
    283     "#define INC \"/test-header.h\"\n"
    284     "#include M(INC)\n"
    285     "#define INC2 </test-header.h>\n"
    286     "#include M(INC2)\n";
    287 
    288   std::unique_ptr<MemoryBuffer> HeaderBuf = MemoryBuffer::getMemBuffer(header);
    289   std::unique_ptr<MemoryBuffer> MainBuf = MemoryBuffer::getMemBuffer(main);
    290   SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(MainBuf)));
    291 
    292   const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
    293                                                  HeaderBuf->getBufferSize(), 0);
    294   SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
    295 
    296   VoidModuleLoader ModLoader;
    297   HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
    298                           &*Target);
    299   Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, SourceMgr,
    300                   HeaderInfo, ModLoader,
    301                   /*IILookup =*/nullptr,
    302                   /*OwnsHeaderSearch =*/false);
    303   PP.Initialize(*Target);
    304 
    305   std::vector<MacroAction> Macros;
    306   PP.addPPCallbacks(llvm::make_unique<MacroTracker>(Macros));
    307 
    308   PP.EnterMainSourceFile();
    309 
    310   std::vector<Token> toks;
    311   while (1) {
    312     Token tok;
    313     PP.Lex(tok);
    314     if (tok.is(tok::eof))
    315       break;
    316     toks.push_back(tok);
    317   }
    318 
    319   // Make sure we got the tokens that we expected.
    320   ASSERT_EQ(0U, toks.size());
    321 
    322   ASSERT_EQ(9U, Macros.size());
    323   // #define M(x) x
    324   ASSERT_TRUE(Macros[0].isDefinition);
    325   ASSERT_EQ("M", Macros[0].Name);
    326   // #define INC "/test-header.h"
    327   ASSERT_TRUE(Macros[1].isDefinition);
    328   ASSERT_EQ("INC", Macros[1].Name);
    329   // M expansion in #include M(INC)
    330   ASSERT_FALSE(Macros[2].isDefinition);
    331   ASSERT_EQ("M", Macros[2].Name);
    332   // INC expansion in #include M(INC)
    333   ASSERT_FALSE(Macros[3].isDefinition);
    334   ASSERT_EQ("INC", Macros[3].Name);
    335   // #define MACRO_IN_INCLUDE 0
    336   ASSERT_TRUE(Macros[4].isDefinition);
    337   ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name);
    338   // #define INC2 </test-header.h>
    339   ASSERT_TRUE(Macros[5].isDefinition);
    340   ASSERT_EQ("INC2", Macros[5].Name);
    341   // M expansion in #include M(INC2)
    342   ASSERT_FALSE(Macros[6].isDefinition);
    343   ASSERT_EQ("M", Macros[6].Name);
    344   // INC2 expansion in #include M(INC2)
    345   ASSERT_FALSE(Macros[7].isDefinition);
    346   ASSERT_EQ("INC2", Macros[7].Name);
    347   // #define MACRO_IN_INCLUDE 0
    348   ASSERT_TRUE(Macros[8].isDefinition);
    349   ASSERT_EQ("MACRO_IN_INCLUDE", Macros[8].Name);
    350 
    351   // The INC expansion in #include M(INC) comes before the first
    352   // MACRO_IN_INCLUDE definition of the included file.
    353   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc));
    354 
    355   // The INC2 expansion in #include M(INC2) comes before the second
    356   // MACRO_IN_INCLUDE definition of the included file.
    357   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[7].Loc, Macros[8].Loc));
    358 }
    359 
    360 #endif
    361 
    362 } // anonymous namespace
    363