zcov: / lib/Frontend/ASTUnit.cpp


Files: 1 Branches Taken: 51.0% 26 / 51
Generated: 2010-02-10 01:31 Branches Executed: 80.4% 41 / 51
Line Coverage: 82.8% 125 / 151


Programs: 2 Runs 3018


       1                 : //===--- ASTUnit.cpp - ASTUnit utility ------------------------------------===//
       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                 : // ASTUnit Implementation.
      11                 : //
      12                 : //===----------------------------------------------------------------------===//
      13                 : 
      14                 : #include "clang/Frontend/ASTUnit.h"
      15                 : #include "clang/Frontend/PCHReader.h"
      16                 : #include "clang/AST/ASTContext.h"
      17                 : #include "clang/AST/ASTConsumer.h"
      18                 : #include "clang/AST/DeclVisitor.h"
      19                 : #include "clang/AST/StmtVisitor.h"
      20                 : #include "clang/Driver/Compilation.h"
      21                 : #include "clang/Driver/Driver.h"
      22                 : #include "clang/Driver/Job.h"
      23                 : #include "clang/Driver/Tool.h"
      24                 : #include "clang/Frontend/CompilerInstance.h"
      25                 : #include "clang/Frontend/FrontendActions.h"
      26                 : #include "clang/Frontend/FrontendDiagnostic.h"
      27                 : #include "clang/Frontend/FrontendOptions.h"
      28                 : #include "clang/Lex/HeaderSearch.h"
      29                 : #include "clang/Lex/Preprocessor.h"
      30                 : #include "clang/Basic/TargetOptions.h"
      31                 : #include "clang/Basic/TargetInfo.h"
      32                 : #include "clang/Basic/Diagnostic.h"
      33                 : #include "llvm/Support/MemoryBuffer.h"
      34                 : #include "llvm/System/Host.h"
      35                 : #include "llvm/System/Path.h"
      36                 : using namespace clang;
      37                 : 
      38               22: ASTUnit::ASTUnit(bool _MainFileIsAST)
      39               22:   : tempFile(false), MainFileIsAST(_MainFileIsAST) {
      40               22: }
      41               19: ASTUnit::~ASTUnit() {
                        1: branch 0 taken
                       18: branch 1 taken
                       18: branch 2 taken
                       18: branch 3 taken
      42               19:   if (tempFile)
      43                1:     llvm::sys::Path(getPCHFileName()).eraseFromDisk();
      44               19: }
      45                 : 
      46                 : namespace {
      47                 : 
      48                 : /// \brief Gathers information from PCHReader that will be used to initialize
      49                 : /// a Preprocessor.
                       10: branch 1 taken
                        0: branch 2 not taken
                        0: branch 5 not taken
                        0: branch 6 not taken
      50               10: class PCHInfoCollector : public PCHReaderListener {
      51                 :   LangOptions &LangOpt;
      52                 :   HeaderSearch &HSI;
      53                 :   std::string &TargetTriple;
      54                 :   std::string &Predefines;
      55                 :   unsigned &Counter;
      56                 : 
      57                 :   unsigned NumHeaderInfos;
      58                 : 
      59                 : public:
      60                 :   PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
      61                 :                    std::string &TargetTriple, std::string &Predefines,
      62               13:                    unsigned &Counter)
      63                 :     : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
      64               13:       Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {}
      65                 : 
      66               13:   virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
      67               13:     LangOpt = LangOpts;
      68               13:     return false;
      69                 :   }
      70                 : 
      71               13:   virtual bool ReadTargetTriple(llvm::StringRef Triple) {
      72               13:     TargetTriple = Triple;
      73               13:     return false;
      74                 :   }
      75                 : 
      76                 :   virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef,
      77                 :                                     FileID PCHBufferID,
      78                 :                                     llvm::StringRef OriginalFileName,
      79               13:                                     std::string &SuggestedPredefines) {
      80               13:     Predefines = PCHPredef;
      81               13:     return false;
      82                 :   }
      83                 : 
      84               17:   virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) {
      85               17:     HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
      86               17:   }
      87                 : 
      88                0:   virtual void ReadCounter(unsigned Value) {
      89                0:     Counter = Value;
      90                0:   }
      91                 : };
      92                 : 
      93                 : } // anonymous namespace
      94                 : 
      95                0: const std::string &ASTUnit::getOriginalSourceFileName() {
      96                0:   return OriginalSourceFile;
      97                 : }
      98                 : 
      99                1: const std::string &ASTUnit::getPCHFileName() {
                        1: branch 1 taken
                        0: branch 2 not taken
     100                1:   assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
                        1: branch 2 taken
                        0: branch 3 not taken
     101                2:   return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
     102                 : }
     103                 : 
     104                 : ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
     105                 :                                   Diagnostic &Diags,
     106                 :                                   bool OnlyLocalDecls,
     107                 :                                   bool UseBumpAllocator,
     108                 :                                   RemappedFile *RemappedFiles,
     109               13:                                   unsigned NumRemappedFiles) {
     110               13:   llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
     111               13:   AST->OnlyLocalDecls = OnlyLocalDecls;
     112               13:   AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
     113                 : 
                        1: branch 0 taken
                       13: branch 1 taken
     114               14:   for (unsigned I = 0; I != NumRemappedFiles; ++I) {
     115                 :     // Create the file entry for the file that we're mapping from.
     116                 :     const FileEntry *FromFile
     117                 :       = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
     118                 :                                     RemappedFiles[I].second->getBufferSize(),
     119                1:                                              0);
                        0: branch 0 not taken
                        1: branch 1 taken
     120                1:     if (!FromFile) {
     121                 :       Diags.Report(diag::err_fe_remap_missing_from_file)
     122                0:         << RemappedFiles[I].first;
     123                0:       continue;
     124                 :     }
     125                 :     
     126                 :     // Override the contents of the "from" file with the contents of
     127                 :     // the "to" file.
     128                 :     AST->getSourceManager().overrideFileContents(FromFile, 
     129                1:                                                  RemappedFiles[I].second);    
     130                 :   }
     131                 :   
     132                 :   // Gather Info for preprocessor construction later on.
     133                 : 
     134               13:   LangOptions LangInfo;
     135               13:   HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
     136               13:   std::string TargetTriple;
     137               13:   std::string Predefines;
     138                 :   unsigned Counter;
     139                 : 
     140               13:   llvm::OwningPtr<PCHReader> Reader;
     141               13:   llvm::OwningPtr<ExternalASTSource> Source;
     142                 : 
     143                 :   Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
     144               13:                              Diags));
     145                 :   Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
     146               13:                                            Predefines, Counter));
     147                 : 
                       13: branch 2 taken
                        0: branch 3 not taken
                        0: branch 4 not taken
     148               13:   switch (Reader->ReadPCH(Filename)) {
     149                 :   case PCHReader::Success:
     150               13:     break;
     151                 : 
     152                 :   case PCHReader::Failure:
     153                 :   case PCHReader::IgnorePCH:
     154                0:     Diags.Report(diag::err_fe_unable_to_load_pch);
     155                0:     return NULL;
     156                 :   }
     157                 : 
     158               13:   AST->OriginalSourceFile = Reader->getOriginalSourceFile();
     159                 : 
     160                 :   // PCH loaded successfully. Now create the preprocessor.
     161                 : 
     162                 :   // Get information about the target being compiled for.
     163                 :   //
     164                 :   // FIXME: This is broken, we should store the TargetOptions in the PCH.
     165               13:   TargetOptions TargetOpts;
     166               13:   TargetOpts.ABI = "";
     167               13:   TargetOpts.CPU = "";
     168               13:   TargetOpts.Features.clear();
     169               13:   TargetOpts.Triple = TargetTriple;
     170               13:   AST->Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts));
     171                 :   AST->PP.reset(new Preprocessor(Diags, LangInfo, *AST->Target.get(),
     172               13:                                  AST->getSourceManager(), HeaderInfo));
     173               13:   Preprocessor &PP = *AST->PP.get();
     174                 : 
     175               13:   PP.setPredefines(Reader->getSuggestedPredefines());
     176               13:   PP.setCounterValue(Counter);
     177               13:   Reader->setPreprocessor(PP);
     178                 : 
     179                 :   // Create and initialize the ASTContext.
     180                 : 
     181                 :   AST->Ctx.reset(new ASTContext(LangInfo,
     182                 :                                 AST->getSourceManager(),
     183                 :                                 *AST->Target.get(),
     184                 :                                 PP.getIdentifierTable(),
     185                 :                                 PP.getSelectorTable(),
     186                 :                                 PP.getBuiltinInfo(),
     187                 :                                 /* FreeMemory = */ !UseBumpAllocator,
     188               13:                                 /* size_reserve = */0));
     189               13:   ASTContext &Context = *AST->Ctx.get();
     190                 : 
     191               13:   Reader->InitializeContext(Context);
     192                 : 
     193                 :   // Attach the PCH reader to the AST context as an external AST
     194                 :   // source, so that declarations will be deserialized from the
     195                 :   // PCH file as needed.
                       13: branch 1 taken
                        0: branch 2 not taken
     196               13:   Source.reset(Reader.take());
     197               13:   Context.setExternalSource(Source);
     198                 : 
     199               13:   return AST.take();
     200                 : }
     201                 : 
     202                 : namespace {
     203                 : 
                        0: branch 1 not taken
                        0: branch 2 not taken
                        0: branch 5 not taken
                        0: branch 6 not taken
     204                0: class TopLevelDeclTrackerConsumer : public ASTConsumer {
     205                 :   ASTUnit &Unit;
     206                 : 
     207                 : public:
     208                9:   TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
     209                 : 
     210               23:   void HandleTopLevelDecl(DeclGroupRef D) {
                       23: branch 2 taken
                       23: branch 3 taken
     211               46:     for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
     212               23:       Unit.getTopLevelDecls().push_back(*it);
     213               23:   }
     214                 : };
     215                 : 
                        9: branch 1 taken
                        0: branch 2 not taken
                        0: branch 5 not taken
                        0: branch 6 not taken
     216                9: class TopLevelDeclTrackerAction : public ASTFrontendAction {
     217                 : public:
     218                 :   ASTUnit &Unit;
     219                 : 
     220                 :   virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
     221                9:                                          llvm::StringRef InFile) {
     222                9:     return new TopLevelDeclTrackerConsumer(Unit);
     223                 :   }
     224                 : 
     225                 : public:
     226                9:   TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
     227                 : 
     228                9:   virtual bool hasCodeCompletionSupport() const { return false; }
     229                 : };
     230                 : 
     231                 : }
     232                 : 
     233                 : ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
     234                 :                                              Diagnostic &Diags,
     235                9:                                              bool OnlyLocalDecls) {
     236                 :   // Create the compiler instance to use for building the AST.
     237                9:   CompilerInstance Clang;
     238                9:   llvm::OwningPtr<ASTUnit> AST;
     239                9:   llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
     240                 : 
     241                9:   Clang.setInvocation(const_cast<CompilerInvocation*>(&CI));
     242                 : 
     243                9:   Clang.setDiagnostics(&Diags);
     244                9:   Clang.setDiagnosticClient(Diags.getClient());
     245                 : 
     246                 :   // Create the target instance.
     247                 :   Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
     248                9:                                                Clang.getTargetOpts()));
                        9: branch 1 taken
                        0: branch 2 not taken
     249                9:   if (!Clang.hasTarget())
     250                0:     goto error;
     251                 : 
     252                 :   // Inform the target of the language options.
     253                 :   //
     254                 :   // FIXME: We shouldn't need to do this, the target should be immutable once
     255                 :   // created. This complexity should be lifted elsewhere.
     256                9:   Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
     257                 : 
     258                 :   assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
                        9: branch 2 taken
                        0: branch 3 not taken
     259                9:          "Invocation must have exactly one source file!");
     260                 :   assert(Clang.getFrontendOpts().Inputs[0].first != FrontendOptions::IK_AST &&
                        9: branch 2 taken
                        0: branch 3 not taken
     261                9:          "FIXME: AST inputs not yet supported here!");
     262                 : 
     263                 :   // Create the AST unit.
     264                9:   AST.reset(new ASTUnit(false));
     265                 : 
     266                9:   AST->OnlyLocalDecls = OnlyLocalDecls;
     267                9:   AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
     268                 : 
     269                 :   // Create a file manager object to provide access to and cache the filesystem.
     270                9:   Clang.setFileManager(&AST->getFileManager());
     271                 : 
     272                 :   // Create the source manager.
     273                9:   Clang.setSourceManager(&AST->getSourceManager());
     274                 : 
     275                 :   // Create the preprocessor.
     276                9:   Clang.createPreprocessor();
     277                 : 
     278                9:   Act.reset(new TopLevelDeclTrackerAction(*AST));
                        0: branch 5 not taken
                        9: branch 6 taken
     279                9:   if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
     280                 :                            /*IsAST=*/false))
     281                0:     goto error;
     282                 : 
     283                9:   Act->Execute();
     284                 : 
     285                 :   // Steal the created target, context, and preprocessor, and take back the
     286                 :   // source and file managers.
     287                9:   AST->Ctx.reset(Clang.takeASTContext());
     288                9:   AST->PP.reset(Clang.takePreprocessor());
     289                9:   Clang.takeSourceManager();
     290                9:   Clang.takeFileManager();
     291                9:   AST->Target.reset(Clang.takeTarget());
     292                 : 
     293                9:   Act->EndSourceFile();
     294                 : 
     295                9:   Clang.takeDiagnosticClient();
     296                9:   Clang.takeDiagnostics();
     297                9:   Clang.takeInvocation();
     298                 : 
     299                9:   return AST.take();
     300                 : 
     301                0: error:
     302                0:   Clang.takeSourceManager();
     303                0:   Clang.takeFileManager();
     304                0:   Clang.takeDiagnosticClient();
     305                0:   Clang.takeDiagnostics();
     306                0:   return 0;
     307                 : }
     308                 : 
     309                 : ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
     310                 :                                       const char **ArgEnd,
     311                 :                                       Diagnostic &Diags,
     312                 :                                       llvm::StringRef ResourceFilesPath,
     313                 :                                       bool OnlyLocalDecls,
     314                 :                                       bool UseBumpAllocator,
     315                 :                                       RemappedFile *RemappedFiles,
     316                9:                                       unsigned NumRemappedFiles) {
     317                9:   llvm::SmallVector<const char *, 16> Args;
     318                9:   Args.push_back("<clang>"); // FIXME: Remove dummy argument.
     319                9:   Args.insert(Args.end(), ArgBegin, ArgEnd);
     320                 : 
     321                 :   // FIXME: Find a cleaner way to force the driver into restricted modes. We
     322                 :   // also want to force it to use clang.
     323                9:   Args.push_back("-fsyntax-only");
     324                 : 
     325                 :   // FIXME: We shouldn't have to pass in the path info.
     326                 :   driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(),
     327                9:                            "a.out", false, Diags);
     328                 : 
     329                 :   // Don't check that inputs exist, they have been remapped.
     330                9:   TheDriver.setCheckInputsExist(false);
     331                 : 
     332                 :   llvm::OwningPtr<driver::Compilation> C(
     333                9:     TheDriver.BuildCompilation(Args.size(), Args.data()));
     334                 : 
     335                 :   // We expect to get back exactly one command job, if we didn't something
     336                 :   // failed.
     337                9:   const driver::JobList &Jobs = C->getJobs();
                        9: branch 1 taken
                        0: branch 2 not taken
                        0: branch 5 not taken
                        9: branch 6 taken
                        0: branch 7 not taken
                        9: branch 8 taken
     338                9:   if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
     339                0:     llvm::SmallString<256> Msg;
     340                0:     llvm::raw_svector_ostream OS(Msg);
     341                0:     C->PrintJob(OS, C->getJobs(), "; ", true);
     342                0:     Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
     343                0:     return 0;
     344                 :   }
     345                 : 
     346                9:   const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
                        0: branch 5 not taken
                        9: branch 6 taken
     347                9:   if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
     348                0:     Diags.Report(diag::err_fe_expected_clang_command);
     349                0:     return 0;
     350                 :   }
     351                 : 
     352                9:   const driver::ArgStringList &CCArgs = Cmd->getArguments();
     353                9:   llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
     354                 :   CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(),
     355                 :                                      (const char**) CCArgs.data()+CCArgs.size(),
     356                9:                                      Diags);
     357                 : 
     358                 :   // Override any files that need remapping
                        3: branch 0 taken
                        9: branch 1 taken
     359               12:   for (unsigned I = 0; I != NumRemappedFiles; ++I)
     360                 :     CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
     361                3:                                              RemappedFiles[I].second);
     362                 :   
     363                 :   // Override the resources path.
     364                9:   CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
     365                 : 
     366                9:   CI->getFrontendOpts().DisableFree = UseBumpAllocator;
     367                9:   ASTUnit *Unit = LoadFromCompilerInvocation(*CI, Diags, OnlyLocalDecls);
                        9: branch 0 taken
                        0: branch 1 not taken
     368                9:   if (Unit)
     369                9:     Unit->Invocation.reset(CI.take());
     370                 : 
     371                9:   return Unit;
     372                0: }

Generated: 2010-02-10 01:31 by zcov