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