Exemplo n.º 1
0
unique_ptr<Module>
#endif
compile(LLVMContext* context, const vector<Chars_const> compileArgs) {
  vector<Chars_const> args = {
    "-Xclang",
    "-resource-dir",
    "-Xclang",
    "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/6.0",
  };
  for (auto const& s : compileArgs) {
    args.push_back(s);
  }
  const IntrusiveRefCntPtr<clang::CompilerInvocation> invocation =
    clang::createInvocationFromCommandLine(args);

  clang::CompilerInstance compiler;
  compiler.setInvocation(invocation.get());
  
  auto diagConsumer = new clang::TextDiagnosticPrinter(errs(), &compiler.getDiagnosticOpts());
  compiler.createDiagnostics(diagConsumer, true); // shouldOwnClient=true.
  
  clang::EmitLLVMOnlyAction action(context);
  check(compiler.ExecuteAction(action), "ExecuteAction failed");
  return action.takeModule();
}
Exemplo n.º 2
0
TEST_F(VFSFromYAMLTest, CaseSensitive) {
  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  Lower->addRegularFile("//root/foo/bar/a");
  IntrusiveRefCntPtr<vfs::FileSystem> FS =
      getFromYAMLString("{ 'case-sensitive': 'true',\n"
                        "  'roots': [\n"
                        "{\n"
                        "  'type': 'directory',\n"
                        "  'name': '//root/',\n"
                        "  'contents': [ {\n"
                        "                  'type': 'file',\n"
                        "                  'name': 'XX',\n"
                        "                  'external-contents': '//root/foo/bar/a'\n"
                        "                }\n"
                        "              ]\n"
                        "}]}",
                        Lower);
  ASSERT_TRUE(FS.getPtr() != nullptr);

  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
      new vfs::OverlayFileSystem(Lower));
  O->pushOverlay(FS);

  ErrorOr<vfs::Status> SS = O->status("//root/xx");
  EXPECT_EQ(std::errc::no_such_file_or_directory, SS.getError());
  SS = O->status("//root/xX");
  EXPECT_EQ(std::errc::no_such_file_or_directory, SS.getError());
  SS = O->status("//root/Xx");
  EXPECT_EQ(std::errc::no_such_file_or_directory, SS.getError());
  EXPECT_EQ(0, NumDiagnostics);
}
Exemplo n.º 3
0
TEST(VirtualFileSystemTest, BasicRealFSIteration) {
  ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
  IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();

  std::error_code EC;
  vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
  ASSERT_FALSE(EC);
  EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty

  ScopedDir _a(TestDirectory+"/a");
  ScopedDir _ab(TestDirectory+"/a/b");
  ScopedDir _c(TestDirectory+"/c");
  ScopedDir _cd(TestDirectory+"/c/d");

  I = FS->dir_begin(Twine(TestDirectory), EC);
  ASSERT_FALSE(EC);
  ASSERT_NE(vfs::directory_iterator(), I);
  // Check either a or c, since we can't rely on the iteration order.
  EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
  I.increment(EC);
  ASSERT_FALSE(EC);
  ASSERT_NE(vfs::directory_iterator(), I);
  EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
  I.increment(EC);
  EXPECT_EQ(vfs::directory_iterator(), I);
}
Exemplo n.º 4
0
TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
  IntrusiveRefCntPtr<vfs::FileSystem> FS;
  FS = getFromYAMLString("");
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLString("[]");
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLString("'string'");
  EXPECT_EQ(nullptr, FS.getPtr());
  EXPECT_EQ(3, NumDiagnostics);
}
Exemplo n.º 5
0
TEST_F(VFSFromYAMLTest, MappedFiles) {
  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  Lower->addRegularFile("//root/foo/bar/a");
  IntrusiveRefCntPtr<vfs::FileSystem> FS =
      getFromYAMLString("{ 'roots': [\n"
                        "{\n"
                        "  'type': 'directory',\n"
                        "  'name': '//root/',\n"
                        "  'contents': [ {\n"
                        "                  'type': 'file',\n"
                        "                  'name': 'file1',\n"
                        "                  'external-contents': '//root/foo/bar/a'\n"
                        "                },\n"
                        "                {\n"
                        "                  'type': 'file',\n"
                        "                  'name': 'file2',\n"
                        "                  'external-contents': '//root/foo/b'\n"
                        "                }\n"
                        "              ]\n"
                        "}\n"
                        "]\n"
                        "}",
                        Lower);
  ASSERT_TRUE(FS.getPtr() != nullptr);

  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
      new vfs::OverlayFileSystem(Lower));
  O->pushOverlay(FS);

  // file
  ErrorOr<vfs::Status> S = O->status("//root/file1");
  ASSERT_FALSE(S.getError());
  EXPECT_EQ("//root/foo/bar/a", S->getName());

  ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
  EXPECT_EQ("//root/foo/bar/a", SLower->getName());
  EXPECT_TRUE(S->equivalent(*SLower));

  // directory
  S = O->status("//root/");
  ASSERT_FALSE(S.getError());
  EXPECT_TRUE(S->isDirectory());
  EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID

  // broken mapping
  EXPECT_EQ(std::errc::no_such_file_or_directory,
            O->status("//root/file2").getError());
  EXPECT_EQ(0, NumDiagnostics);
}
Exemplo n.º 6
0
TEST_F(VFSFromYAMLTest, DirectoryIteration) {
  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  Lower->addDirectory("//root/");
  Lower->addDirectory("//root/foo");
  Lower->addDirectory("//root/foo/bar");
  Lower->addRegularFile("//root/foo/bar/a");
  Lower->addRegularFile("//root/foo/bar/b");
  Lower->addRegularFile("//root/file3");
  IntrusiveRefCntPtr<vfs::FileSystem> FS =
  getFromYAMLString("{ 'use-external-names': false,\n"
                    "  'roots': [\n"
                    "{\n"
                    "  'type': 'directory',\n"
                    "  'name': '//root/',\n"
                    "  'contents': [ {\n"
                    "                  'type': 'file',\n"
                    "                  'name': 'file1',\n"
                    "                  'external-contents': '//root/foo/bar/a'\n"
                    "                },\n"
                    "                {\n"
                    "                  'type': 'file',\n"
                    "                  'name': 'file2',\n"
                    "                  'external-contents': '//root/foo/bar/b'\n"
                    "                }\n"
                    "              ]\n"
                    "}\n"
                    "]\n"
                    "}",
                    Lower);
  ASSERT_TRUE(FS.get() != NULL);

  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
      new vfs::OverlayFileSystem(Lower));
  O->pushOverlay(FS);

  std::error_code EC;
  {
    const char *Contents[] = {"//root/file1", "//root/file2", "//root/file3",
                              "//root/foo"};
    checkContents(O->dir_begin("//root/", EC), makeStringRefVector(Contents));
  }

  {
    const char *Contents[] = {"//root/foo/bar/a", "//root/foo/bar/b"};
    checkContents(O->dir_begin("//root/foo/bar", EC),
                  makeStringRefVector(Contents));
  }
}
Exemplo n.º 7
0
IntrusiveRefCntPtr<VarDecl> Parser::resolveLocal(
	IntrusiveRefCntPtr<Scope> sc,
	string const& name)
{
	if (!sc) return IntrusiveRefCntPtr<VarDecl>();
	return sc->resolveLocal(name);
}
Exemplo n.º 8
0
TEST_F(VFSFromYAMLTest, UseExternalName) {
  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  Lower->addRegularFile("//root/external/file");

  IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
      "{ 'roots': [\n"
      "  { 'type': 'file', 'name': '//root/A',\n"
      "    'external-contents': '//root/external/file'\n"
      "  },\n"
      "  { 'type': 'file', 'name': '//root/B',\n"
      "    'use-external-name': true,\n"
      "    'external-contents': '//root/external/file'\n"
      "  },\n"
      "  { 'type': 'file', 'name': '//root/C',\n"
      "    'use-external-name': false,\n"
      "    'external-contents': '//root/external/file'\n"
      "  }\n"
      "] }", Lower);
  ASSERT_TRUE(nullptr != FS.getPtr());

  // default true
  EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
  // explicit
  EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
  EXPECT_EQ("//root/C", FS->status("//root/C")->getName());

  // global configuration
  FS = getFromYAMLString(
      "{ 'use-external-names': false,\n"
      "  'roots': [\n"
      "  { 'type': 'file', 'name': '//root/A',\n"
      "    'external-contents': '//root/external/file'\n"
      "  },\n"
      "  { 'type': 'file', 'name': '//root/B',\n"
      "    'use-external-name': true,\n"
      "    'external-contents': '//root/external/file'\n"
      "  },\n"
      "  { 'type': 'file', 'name': '//root/C',\n"
      "    'use-external-name': false,\n"
      "    'external-contents': '//root/external/file'\n"
      "  }\n"
      "] }", Lower);
  ASSERT_TRUE(nullptr != FS.getPtr());

  // default
  EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
  // explicit
  EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
  EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
}
Exemplo n.º 9
0
TEST_F(VFSFromYAMLTest, TrailingSlashes) {
  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
  Lower->addRegularFile("//root/other");

  // file in roots
  IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
      "{ 'roots': [\n"
      "  { 'type': 'directory', 'name': '//root/path/to////',\n"
      "    'contents': [ { 'type': 'file', 'name': 'file',\n"
      "                    'external-contents': '//root/other' }]}]\n"
      "}", Lower);
  ASSERT_TRUE(nullptr != FS.getPtr());
  EXPECT_FALSE(FS->status("//root/path/to/file").getError());
  EXPECT_FALSE(FS->status("//root/path/to").getError());
  EXPECT_FALSE(FS->status("//root/path").getError());
  EXPECT_FALSE(FS->status("//root/").getError());
}
ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
    CompilerInstance *CI,
    IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS)
    : Recorder(llvm::make_unique<FileRecorder>()), Compiler(*CI),
      InMemoryFs(new llvm::vfs::InMemoryFileSystem),
      Sources(Compiler.getSourceManager()),
      // Forward the new diagnostics to the original DiagnosticConsumer.
      Diags(new DiagnosticIDs, new DiagnosticOptions,
            new ForwardingDiagnosticConsumer(Compiler.getDiagnosticClient())),
      LangOpts(Compiler.getLangOpts()) {
  // Add a FileSystem containing the extra files needed in place of modular
  // headers.
  OverlayFS->pushOverlay(InMemoryFs);

  Diags.setSourceManager(&Sources);

  LangOpts.Modules = false;

  auto HSO = std::make_shared<HeaderSearchOptions>();
  *HSO = Compiler.getHeaderSearchOpts();

  HeaderInfo = llvm::make_unique<HeaderSearch>(HSO, Sources, Diags, LangOpts,
                                               &Compiler.getTarget());

  auto PO = std::make_shared<PreprocessorOptions>();
  *PO = Compiler.getPreprocessorOpts();

  PP = llvm::make_unique<clang::Preprocessor>(PO, Diags, LangOpts, Sources,
                                              *HeaderInfo, ModuleLoader,
                                              /*IILookup=*/nullptr,
                                              /*OwnsHeaderSearch=*/false);
  PP->Initialize(Compiler.getTarget(), Compiler.getAuxTarget());
  InitializePreprocessor(*PP, *PO, Compiler.getPCHContainerReader(),
                         Compiler.getFrontendOpts());
  ApplyHeaderSearchOptions(*HeaderInfo, *HSO, LangOpts,
                           Compiler.getTarget().getTriple());
}
Exemplo n.º 11
0
TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());

  // invalid YAML at top-level
  IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  // invalid YAML in roots
  FS = getFromYAMLString("{ 'roots':[}", Lower);
  // invalid YAML in directory
  FS = getFromYAMLString(
      "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
      Lower);
  EXPECT_EQ(nullptr, FS.getPtr());

  // invalid configuration
  FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
  EXPECT_EQ(nullptr, FS.getPtr());

  // invalid roots
  FS = getFromYAMLString("{ 'roots':'' }", Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLString("{ 'roots':{} }", Lower);
  EXPECT_EQ(nullptr, FS.getPtr());

  // invalid entries
  FS = getFromYAMLString(
      "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
                         "'external-contents': 'other' }",
                         Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLString(
      "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
      Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLString(
      "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
      Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLString(
      "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
      Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLString(
      "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
      Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLString(
      "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
      Lower);
  EXPECT_EQ(nullptr, FS.getPtr());

  // missing mandatory fields
  FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLString(
      "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
  EXPECT_EQ(nullptr, FS.getPtr());

  // duplicate keys
  FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLString(
      "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
      Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  FS =
      getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
                        "'external-contents':'blah' } ] }",
                        Lower);
  EXPECT_EQ(nullptr, FS.getPtr());

  // missing version
  FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
  EXPECT_EQ(nullptr, FS.getPtr());

  // bad version number
  FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
  EXPECT_EQ(nullptr, FS.getPtr());
  EXPECT_EQ(24, NumDiagnostics);
}
/// \brief Compile a module file for the given module, using the options 
/// provided by the importing compiler instance.
static void compileModule(CompilerInstance &ImportingInstance,
                          SourceLocation ImportLoc,
                          Module *Module,
                          StringRef ModuleFileName) {
  llvm::LockFileManager Locked(ModuleFileName);
  switch (Locked) {
  case llvm::LockFileManager::LFS_Error:
    return;

  case llvm::LockFileManager::LFS_Owned:
    // We're responsible for building the module ourselves. Do so below.
    break;

  case llvm::LockFileManager::LFS_Shared:
    // Someone else is responsible for building the module. Wait for them to
    // finish.
    Locked.waitForUnlock();
    return;
  }

  ModuleMap &ModMap 
    = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
    
  // Construct a compiler invocation for creating this module.
  IntrusiveRefCntPtr<CompilerInvocation> Invocation
    (new CompilerInvocation(ImportingInstance.getInvocation()));

  PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
  
  // For any options that aren't intended to affect how a module is built,
  // reset them to their default values.
  Invocation->getLangOpts()->resetNonModularOptions();
  PPOpts.resetNonModularOptions();

  // Note the name of the module we're building.
  Invocation->getLangOpts()->CurrentModule = Module->getTopLevelModuleName();

  // Make sure that the failed-module structure has been allocated in
  // the importing instance, and propagate the pointer to the newly-created
  // instance.
  PreprocessorOptions &ImportingPPOpts
    = ImportingInstance.getInvocation().getPreprocessorOpts();
  if (!ImportingPPOpts.FailedModules)
    ImportingPPOpts.FailedModules = new PreprocessorOptions::FailedModulesSet;
  PPOpts.FailedModules = ImportingPPOpts.FailedModules;

  // If there is a module map file, build the module using the module map.
  // Set up the inputs/outputs so that we build the module from its umbrella
  // header.
  FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
  FrontendOpts.OutputFile = ModuleFileName.str();
  FrontendOpts.DisableFree = false;
  FrontendOpts.Inputs.clear();
  InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts());

  // Get or create the module map that we'll use to build this module.
  SmallString<128> TempModuleMapFileName;
  if (const FileEntry *ModuleMapFile
                                  = ModMap.getContainingModuleMapFile(Module)) {
    // Use the module map where this module resides.
    FrontendOpts.Inputs.push_back(FrontendInputFile(ModuleMapFile->getName(), 
                                                    IK));
  } else {
    // Create a temporary module map file.
    TempModuleMapFileName = Module->Name;
    TempModuleMapFileName += "-%%%%%%%%.map";
    int FD;
    if (llvm::sys::fs::unique_file(TempModuleMapFileName.str(), FD, 
                                   TempModuleMapFileName,
                                   /*makeAbsolute=*/true)
          != llvm::errc::success) {
      ImportingInstance.getDiagnostics().Report(diag::err_module_map_temp_file)
        << TempModuleMapFileName;
      return;
    }
    // Print the module map to this file.
    llvm::raw_fd_ostream OS(FD, /*shouldClose=*/true);
    Module->print(OS);
    FrontendOpts.Inputs.push_back(
      FrontendInputFile(TempModuleMapFileName.str().str(), IK));
  }

  // Don't free the remapped file buffers; they are owned by our caller.
  PPOpts.RetainRemappedFileBuffers = true;
    
  Invocation->getDiagnosticOpts().VerifyDiagnostics = 0;
  assert(ImportingInstance.getInvocation().getModuleHash() ==
         Invocation->getModuleHash() && "Module hash mismatch!");
  
  // Construct a compiler instance that will be used to actually create the
  // module.
  CompilerInstance Instance;
  Instance.setInvocation(&*Invocation);
  Instance.createDiagnostics(/*argc=*/0, /*argv=*/0,
                             &ImportingInstance.getDiagnosticClient(),
                             /*ShouldOwnClient=*/true,
                             /*ShouldCloneClient=*/true);

  // Note that this module is part of the module build stack, so that we
  // can detect cycles in the module graph.
  Instance.createFileManager(); // FIXME: Adopt file manager from importer?
  Instance.createSourceManager(Instance.getFileManager());
  SourceManager &SourceMgr = Instance.getSourceManager();
  SourceMgr.setModuleBuildStack(
    ImportingInstance.getSourceManager().getModuleBuildStack());
  SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(),
    FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager()));


  // Construct a module-generating action.
  GenerateModuleAction CreateModuleAction;
  
  // Execute the action to actually build the module in-place. Use a separate
  // thread so that we get a stack large enough.
  const unsigned ThreadStackSize = 8 << 20;
  llvm::CrashRecoveryContext CRC;
  CompileModuleMapData Data = { Instance, CreateModuleAction };
  CRC.RunSafelyOnThread(&doCompileMapModule, &Data, ThreadStackSize);
  
  // Delete the temporary module map file.
  // FIXME: Even though we're executing under crash protection, it would still
  // be nice to do this with RemoveFileOnSignal when we can. However, that
  // doesn't make sense for all clients, so clean this up manually.
  Instance.clearOutputFiles(/*EraseFiles=*/true);
  if (!TempModuleMapFileName.empty())
    llvm::sys::Path(TempModuleMapFileName).eraseFromDisk();
}
Exemplo n.º 13
0
void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
                                  const DiagnosticOptions &Opts,
                                  bool ReportDiags) {
  Diags.setSuppressSystemWarnings(true);  // Default to -Wno-system-headers
  Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
  Diags.setShowOverloads(Opts.getShowOverloads());

  Diags.setElideType(Opts.ElideType);
  Diags.setPrintTemplateTree(Opts.ShowTemplateTree);
  Diags.setWarnOnSpellCheck(Opts.WarnOnSpellCheck);
  Diags.setShowColors(Opts.ShowColors);
 
  // Handle -ferror-limit
  if (Opts.ErrorLimit)
    Diags.setErrorLimit(Opts.ErrorLimit);
  if (Opts.TemplateBacktraceLimit)
    Diags.setTemplateBacktraceLimit(Opts.TemplateBacktraceLimit);
  if (Opts.ConstexprBacktraceLimit)
    Diags.setConstexprBacktraceLimit(Opts.ConstexprBacktraceLimit);

  // If -pedantic or -pedantic-errors was specified, then we want to map all
  // extension diagnostics onto WARNING or ERROR unless the user has futz'd
  // around with them explicitly.
  if (Opts.PedanticErrors)
    Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Error);
  else if (Opts.Pedantic)
    Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Warn);
  else
    Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Ignore);

  SmallVector<diag::kind, 10> _Diags;
  const IntrusiveRefCntPtr< DiagnosticIDs > DiagIDs =
    Diags.getDiagnosticIDs();
  // We parse the warning options twice.  The first pass sets diagnostic state,
  // while the second pass reports warnings/errors.  This has the effect that
  // we follow the more canonical "last option wins" paradigm when there are 
  // conflicting options.
  for (unsigned Report = 0, ReportEnd = 2; Report != ReportEnd; ++Report) {
    bool SetDiagnostic = (Report == 0);

    // If we've set the diagnostic state and are not reporting diagnostics then
    // we're done.
    if (!SetDiagnostic && !ReportDiags)
      break;

    for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
      StringRef Opt = Opts.Warnings[i];
      StringRef OrigOpt = Opts.Warnings[i];

      // Treat -Wformat=0 as an alias for -Wno-format.
      if (Opt == "format=0")
        Opt = "no-format";

      // Check to see if this warning starts with "no-", if so, this is a
      // negative form of the option.
      bool isPositive = true;
      if (Opt.startswith("no-")) {
        isPositive = false;
        Opt = Opt.substr(3);
      }

      // Figure out how this option affects the warning.  If -Wfoo, map the
      // diagnostic to a warning, if -Wno-foo, map it to ignore.
      diag::Mapping Mapping = isPositive ? diag::MAP_WARNING : diag::MAP_IGNORE;
      
      // -Wsystem-headers is a special case, not driven by the option table.  It
      // cannot be controlled with -Werror.
      if (Opt == "system-headers") {
        if (SetDiagnostic)
          Diags.setSuppressSystemWarnings(!isPositive);
        continue;
      }
      
      // -Weverything is a special case as well.  It implicitly enables all
      // warnings, including ones not explicitly in a warning group.
      if (Opt == "everything") {
        if (SetDiagnostic) {
          if (isPositive) {
            Diags.setEnableAllWarnings(true);
          } else {
            Diags.setEnableAllWarnings(false);
            Diags.setMappingToAllDiagnostics(diag::MAP_IGNORE);
          }
        }
        continue;
      }
      
      // -Werror/-Wno-error is a special case, not controlled by the option 
      // table. It also has the "specifier" form of -Werror=foo and -Werror-foo.
      if (Opt.startswith("error")) {
        StringRef Specifier;
        if (Opt.size() > 5) {  // Specifier must be present.
          if ((Opt[5] != '=' && Opt[5] != '-') || Opt.size() == 6) {
            if (Report)
              Diags.Report(diag::warn_unknown_warning_specifier)
                << "-Werror" << ("-W" + OrigOpt.str());
            continue;
          }
          Specifier = Opt.substr(6);
        }
        
        if (Specifier.empty()) {
          if (SetDiagnostic)
            Diags.setWarningsAsErrors(isPositive);
          continue;
        }
        
        if (SetDiagnostic) {
          // Set the warning as error flag for this specifier.
          Diags.setDiagnosticGroupWarningAsError(Specifier, isPositive);
        } else if (DiagIDs->getDiagnosticsInGroup(Specifier, _Diags)) {
          EmitUnknownDiagWarning(Diags, "-Werror=", Specifier, isPositive);
        }
        continue;
      }
      
      // -Wfatal-errors is yet another special case.
      if (Opt.startswith("fatal-errors")) {
        StringRef Specifier;
        if (Opt.size() != 12) {
          if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) {
            if (Report)
              Diags.Report(diag::warn_unknown_warning_specifier)
                << "-Wfatal-errors" << ("-W" + OrigOpt.str());
            continue;
          }
          Specifier = Opt.substr(13);
        }

        if (Specifier.empty()) {
          if (SetDiagnostic)
            Diags.setErrorsAsFatal(isPositive);
          continue;
        }
        
        if (SetDiagnostic) {
          // Set the error as fatal flag for this specifier.
          Diags.setDiagnosticGroupErrorAsFatal(Specifier, isPositive);
        } else if (DiagIDs->getDiagnosticsInGroup(Specifier, _Diags)) {
          EmitUnknownDiagWarning(Diags, "-Wfatal-errors=", Specifier,
                                 isPositive);
        }
        continue;
      }
      
      if (Report) {
        if (DiagIDs->getDiagnosticsInGroup(Opt, _Diags))
          EmitUnknownDiagWarning(Diags, isPositive ? "-W" : "-Wno-", Opt,
                                 isPositive);
      } else {
        Diags.setDiagnosticGroupMapping(Opt, Mapping);
      }
    }
  }
}
Exemplo n.º 14
0
int ShowEnabledWarnings::run(unsigned int argc, char **argv, raw_ostream &Out) {
  // First check our one flag (--levels).
  bool ShouldShowLevels = true;
  if (argc > 0) {
    StringRef FirstArg(*argv);
    if (FirstArg.equals("--no-levels")) {
      ShouldShowLevels = false;
      --argc;
      ++argv;
    } else if (FirstArg.equals("--levels")) {
      ShouldShowLevels = true;
      --argc;
      ++argv;
    }
  }

  // Create the diagnostic engine.
  IntrusiveRefCntPtr<DiagnosticsEngine> Diags = createDiagnostics(argc, argv);
  if (!Diags) {
    printUsage();
    return EXIT_FAILURE;
  }

  // Now we have our diagnostics. Iterate through EVERY diagnostic and see
  // which ones are turned on.
  // FIXME: It would be very nice to print which flags are turning on which
  // diagnostics, but this can be done with a diff.
  ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName();
  std::vector<PrettyDiag> Active;

  for (ArrayRef<DiagnosticRecord>::iterator I = AllDiagnostics.begin(),
                                            E = AllDiagnostics.end();
       I != E; ++I) {
    unsigned DiagID = I->DiagID;
    
    if (DiagnosticIDs::isBuiltinNote(DiagID))
      continue;
    
    if (!DiagnosticIDs::isBuiltinWarningOrExtension(DiagID))
      continue;

    DiagnosticsEngine::Level DiagLevel =
      Diags->getDiagnosticLevel(DiagID, SourceLocation());
    if (DiagLevel == DiagnosticsEngine::Ignored)
      continue;

    StringRef WarningOpt = DiagnosticIDs::getWarningOptionForDiag(DiagID);
    Active.push_back(PrettyDiag(I->getName(), WarningOpt, DiagLevel));
  }

  // Print them all out.
  for (std::vector<PrettyDiag>::const_iterator I = Active.begin(),
       E = Active.end(); I != E; ++I) {
    if (ShouldShowLevels)
      Out << getCharForLevel(I->Level) << "  ";
    Out << I->Name;
    if (!I->Flag.empty())
      Out << " [-W" << I->Flag << "]";
    Out << '\n';
  }

  return EXIT_SUCCESS;
}
Exemplo n.º 15
0
ASTUnit* TranslationUnitManager::ParseProjectFile(ProjectFile* file,bool allowAdd)
{
    cbAssert (file && file->file.FileExists() && "File not exists");


    wxString fileName = file->file.GetFullPath();
    auto project = file->GetParentProject();

    {   //if the file is already being parsed return immediately.
        std::lock_guard<std::mutex> lock(m_FilesBeingParsedMutex);

        if (std::find(m_FilesBeingParsed.begin(), m_FilesBeingParsed.end(), file) != m_FilesBeingParsed.end())
            return nullptr;
        m_FilesBeingParsed.push_back(file);
    }


    auto iter = m_CompilationDatabases.find(project);

    if(iter == m_CompilationDatabases.end())
    {
        LoggerAccess::Get()->Log("Could not find the compilation database for project : " + project->GetTitle());
        return nullptr;
    }
    auto compileCommands = iter->second->getCompileCommands(wx2std(file->file.GetFullPath()));
    if (compileCommands.empty())
    {
        LoggerAccess::Get()->Log("No compile commands for the file" + file->file.GetName());
        return nullptr;
    }

    auto args = compileCommands[0].CommandLine;


    if (!Options::Get().ShouldSpellCheck())
        args.push_back("-fno-spell-checking");
    //Get Additional compile options from the config panel
    auto addOptions = Options::Get().GetCompilerOptions();
    args.insert(args.end(), addOptions.begin(), addOptions.end());

#ifdef CLANGCC_DEBUG_LOGGING
    wxString commandLine = "Command Line is ";
    std::for_each(args.begin(),args.end(), [&](const std::string s){ commandLine.Append(s); commandLine.append(' '); });
    LoggerAccess::Get()->Log(commandLine);
#endif

    //Parsing started event.
    ccEvent startEvent(ccEVT_PARSE_START, fileName, nullptr, file);
    AddPendingEvent(startEvent);

#ifdef CLANGCC_TIMING
    wxStopWatch watch;
#endif // CLANGCC_TIMING

    std::vector<const char*> argsinChar;
    argsinChar.reserve(args.size());
    std::transform(args.begin(), args.end(), std::back_inserter(argsinChar),
                        [](const std::string& strings){return strings.c_str();});

    DiagnosticOptions* diagOpts = new DiagnosticOptions();
    IntrusiveRefCntPtr<DiagnosticsEngine> diags = CompilerInstance::createDiagnostics(diagOpts,0);
    diags->setFatalsAsError(true);

    auto ast = ASTUnit::LoadFromCommandLine(&*argsinChar.begin(),&*argsinChar.end(),
                                            m_PCHContainerOps,
                                            diags,
                                            StringRef(),
                                            true, /* OnlyLocalDecls */
                                            true, /*CaptureDiagnostics*/
                                            None, /*Remapped Files*/
                                            true, /*RemappedFiles keep original name*/
                                            1, /*Precompile preamble*/
                                            TU_Complete,
                                            Options::Get().ShouldCacheCompletionResults(),/*CacheCodeCompletionResults*/
                                            true, /*Include Brief Comment*/
                                            true, /*allow pch with compiler errors*/
                                            Options::Get().ShouldSkipFunctionBodies(),
                                            true,
                                            false,
                                            m_PCHContainerOps->getRawReader().getFormat()
                                           );

#ifdef CLANGCC_TIMING
    LoggerAccess::Get()->Log(wxString::Format("Parsing %s completed in %ldms", file->file.GetFullName().c_str(), watch.Time()),Logger::info);
#endif // CLANGCC_TIMING
    if (!ast)
      LoggerAccess::Get()->Log("\t Cannot Create ASTUnit for " + file->file.GetFullName());
    if (ast)
    {
        if (allowAdd)
            AddASTUnitForProjectFile(file,ast);
    }

    {   //File is free again
        std::lock_guard<std::mutex> lock(m_FilesBeingParsedMutex);
        m_FilesBeingParsed.erase(std::remove(m_FilesBeingParsed.begin(), m_FilesBeingParsed.end(), file),m_FilesBeingParsed.end());
    }
    //Parsing ended event
    ccEvent endEvent(ccEVT_PARSE_END, fileName, ast, file);
    AddPendingEvent(endEvent);

    return ast;
}
Exemplo n.º 16
0
bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
                                     const FrontendInputFile &Input) {
  assert(!Instance && "Already processing a source file!");
  assert(!Input.isEmpty() && "Unexpected empty filename!");
  setCurrentInput(Input);
  setCompilerInstance(&CI);

  StringRef InputFile = Input.getFile();
  bool HasBegunSourceFile = false;
  if (!BeginInvocation(CI))
    goto failure;

  // AST files follow a very different path, since they share objects via the
  // AST unit.
  if (Input.getKind() == IK_AST) {
    assert(!usesPreprocessorOnly() &&
           "Attempt to pass AST file to preprocessor only action!");
    assert(hasASTFileSupport() &&
           "This action does not have AST file support!");

    IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());

    ASTUnit *AST = ASTUnit::LoadFromASTFile(InputFile, Diags,
                                            CI.getFileSystemOpts());
    if (!AST)
      goto failure;

    setCurrentInput(Input, AST);

    // Inform the diagnostic client we are processing a source file.
    CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
    HasBegunSourceFile = true;

    // Set the shared objects, these are reset when we finish processing the
    // file, otherwise the CompilerInstance will happily destroy them.
    CI.setFileManager(&AST->getFileManager());
    CI.setSourceManager(&AST->getSourceManager());
    CI.setPreprocessor(&AST->getPreprocessor());
    CI.setASTContext(&AST->getASTContext());

    // Initialize the action.
    if (!BeginSourceFileAction(CI, InputFile))
      goto failure;

    // Create the AST consumer.
    CI.setASTConsumer(CreateWrappedASTConsumer(CI, InputFile));
    if (!CI.hasASTConsumer())
      goto failure;

    return true;
  }

  if (!CI.hasVirtualFileSystem()) {
    if (IntrusiveRefCntPtr<vfs::FileSystem> VFS =
          createVFSFromCompilerInvocation(CI.getInvocation(),
                                          CI.getDiagnostics()))
      CI.setVirtualFileSystem(VFS);
    else
      goto failure;
  }

  // Set up the file and source managers, if needed.
  if (!CI.hasFileManager())
    CI.createFileManager();
  if (!CI.hasSourceManager())
    CI.createSourceManager(CI.getFileManager());

  // IR files bypass the rest of initialization.
  if (Input.getKind() == IK_LLVM_IR) {
    assert(hasIRSupport() &&
           "This action does not have IR file support!");

    // Inform the diagnostic client we are processing a source file.
    CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
    HasBegunSourceFile = true;

    // Initialize the action.
    if (!BeginSourceFileAction(CI, InputFile))
      goto failure;

    // Initialize the main file entry.
    if (!CI.InitializeSourceManager(CurrentInput))
      goto failure;

    return true;
  }

  // If the implicit PCH include is actually a directory, rather than
  // a single file, search for a suitable PCH file in that directory.
  if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
    FileManager &FileMgr = CI.getFileManager();
    PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
    StringRef PCHInclude = PPOpts.ImplicitPCHInclude;
    if (const DirectoryEntry *PCHDir = FileMgr.getDirectory(PCHInclude)) {
      llvm::error_code EC;
      SmallString<128> DirNative;
      llvm::sys::path::native(PCHDir->getName(), DirNative);
      bool Found = false;
      for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
           Dir != DirEnd && !EC; Dir.increment(EC)) {
        // Check whether this is an acceptable AST file.
        if (ASTReader::isAcceptableASTFile(Dir->path(), FileMgr,
                                           CI.getLangOpts(),
                                           CI.getTargetOpts(),
                                           CI.getPreprocessorOpts())) {
          PPOpts.ImplicitPCHInclude = Dir->path();
          Found = true;
          break;
        }
      }

      if (!Found) {
        CI.getDiagnostics().Report(diag::err_fe_no_pch_in_dir) << PCHInclude;
        return true;
      }
    }
  }

  // Set up the preprocessor.
  CI.createPreprocessor(getTranslationUnitKind());

  // Inform the diagnostic client we are processing a source file.
  CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
                                           &CI.getPreprocessor());
  HasBegunSourceFile = true;

  // Initialize the action.
  if (!BeginSourceFileAction(CI, InputFile))
    goto failure;

  // Initialize the main file entry. It is important that this occurs after
  // BeginSourceFileAction, which may change CurrentInput during module builds.
  if (!CI.InitializeSourceManager(CurrentInput))
    goto failure;

  // Create the AST context and consumer unless this is a preprocessor only
  // action.
  if (!usesPreprocessorOnly()) {
    CI.createASTContext();

    std::unique_ptr<ASTConsumer> Consumer(
        CreateWrappedASTConsumer(CI, InputFile));
    if (!Consumer)
      goto failure;

    CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
    
    if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
      // Convert headers to PCH and chain them.
      IntrusiveRefCntPtr<ChainedIncludesSource> source;
      source = ChainedIncludesSource::create(CI);
      if (!source)
        goto failure;
      CI.setModuleManager(static_cast<ASTReader*>(&source->getFinalReader()));
      CI.getASTContext().setExternalSource(source);

    } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
      // Use PCH.
      assert(hasPCHSupport() && "This action does not have PCH support!");
      ASTDeserializationListener *DeserialListener =
          Consumer->GetASTDeserializationListener();
      if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls)
        DeserialListener = new DeserializedDeclsDumper(DeserialListener);
      if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty())
        DeserialListener = new DeserializedDeclsChecker(CI.getASTContext(),
                         CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn,
                                                        DeserialListener);
      CI.createPCHExternalASTSource(
                                CI.getPreprocessorOpts().ImplicitPCHInclude,
                                CI.getPreprocessorOpts().DisablePCHValidation,
                            CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
                                DeserialListener);
      if (!CI.getASTContext().getExternalSource())
        goto failure;
    }

    CI.setASTConsumer(Consumer.release());
    if (!CI.hasASTConsumer())
      goto failure;
  }

  // Initialize built-in info as long as we aren't using an external AST
  // source.
  if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
    Preprocessor &PP = CI.getPreprocessor();
    PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
                                           PP.getLangOpts());
  }

  // If there is a layout overrides file, attach an external AST source that
  // provides the layouts from that file.
  if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() && 
      CI.hasASTContext() && !CI.getASTContext().getExternalSource()) {
    IntrusiveRefCntPtr<ExternalASTSource> 
      Override(new LayoutOverrideSource(
                     CI.getFrontendOpts().OverrideRecordLayoutsFile));
    CI.getASTContext().setExternalSource(Override);
  }
  
  return true;

  // If we failed, reset state since the client will not end up calling the
  // matching EndSourceFile().
  failure:
  if (isCurrentFileAST()) {
    CI.setASTContext(0);
    CI.setPreprocessor(0);
    CI.setSourceManager(0);
    CI.setFileManager(0);
  }

  if (HasBegunSourceFile)
    CI.getDiagnosticClient().EndSourceFile();
  CI.clearOutputFiles(/*EraseFiles=*/true);
  setCurrentInput(FrontendInputFile());
  setCompilerInstance(0);
  return false;
}
Exemplo n.º 17
0
void PlistDiagnostics::FlushDiagnosticsImpl(
                                    std::vector<const PathDiagnostic *> &Diags,
                                    FilesMade *filesMade) {
  // Build up a set of FIDs that we use by scanning the locations and
  // ranges of the diagnostics.
  FIDMap FM;
  SmallVector<FileID, 10> Fids;
  const SourceManager* SM = 0;

  if (!Diags.empty())
    SM = &(*(*Diags.begin())->path.begin())->getLocation().getManager();

  
  for (std::vector<const PathDiagnostic*>::iterator DI = Diags.begin(),
       DE = Diags.end(); DI != DE; ++DI) {

    const PathDiagnostic *D = *DI;

    llvm::SmallVector<const PathPieces *, 5> WorkList;
    WorkList.push_back(&D->path);

    while (!WorkList.empty()) {
      const PathPieces &path = *WorkList.back();
      WorkList.pop_back();
    
      for (PathPieces::const_iterator I = path.begin(), E = path.end();
           I!=E; ++I) {
        const PathDiagnosticPiece *piece = I->getPtr();
        AddFID(FM, Fids, SM, piece->getLocation().asLocation());
        ArrayRef<SourceRange> Ranges = piece->getRanges();
        for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
                                             E = Ranges.end(); I != E; ++I) {
          AddFID(FM, Fids, SM, I->getBegin());
          AddFID(FM, Fids, SM, I->getEnd());
        }

        if (const PathDiagnosticCallPiece *call =
            dyn_cast<PathDiagnosticCallPiece>(piece)) {
          IntrusiveRefCntPtr<PathDiagnosticEventPiece>
            callEnterWithin = call->getCallEnterWithinCallerEvent();
          if (callEnterWithin)
            AddFID(FM, Fids, SM, callEnterWithin->getLocation().asLocation());

          WorkList.push_back(&call->path);
        }
        else if (const PathDiagnosticMacroPiece *macro =
                 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
          WorkList.push_back(&macro->subPieces);
        }
      }
    }
  }

  // Open the file.
  std::string ErrMsg;
  llvm::raw_fd_ostream o(OutputFile.c_str(), ErrMsg);
  if (!ErrMsg.empty()) {
    llvm::errs() << "warning: could not create file: " << OutputFile << '\n';
    return;
  }

  // Write the plist header.
  o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
  "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
  "<plist version=\"1.0\">\n";

  // Write the root object: a <dict> containing...
  //  - "files", an <array> mapping from FIDs to file names
  //  - "diagnostics", an <array> containing the path diagnostics
  o << "<dict>\n"
       " <key>files</key>\n"
       " <array>\n";

  for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end();
       I!=E; ++I) {
    o << "  ";
    EmitString(o, SM->getFileEntryForID(*I)->getName()) << '\n';
  }

  o << " </array>\n"
       " <key>diagnostics</key>\n"
       " <array>\n";

  for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(),
       DE = Diags.end(); DI!=DE; ++DI) {

    o << "  <dict>\n"
         "   <key>path</key>\n";

    const PathDiagnostic *D = *DI;

    o << "   <array>\n";

    for (PathPieces::const_iterator I = D->path.begin(), E = D->path.end(); 
         I != E; ++I)
      ReportDiag(o, **I, FM, *SM, LangOpts);

    o << "   </array>\n";

    // Output the bug type and bug category.
    o << "   <key>description</key>";
    EmitString(o, D->getShortDescription()) << '\n';
    o << "   <key>category</key>";
    EmitString(o, D->getCategory()) << '\n';
    o << "   <key>type</key>";
    EmitString(o, D->getBugType()) << '\n';
    
    // Output information about the semantic context where
    // the issue occurred.
    if (const Decl *DeclWithIssue = D->getDeclWithIssue()) {
      // FIXME: handle blocks, which have no name.
      if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
        StringRef declKind;
        switch (ND->getKind()) {
          case Decl::CXXRecord:
            declKind = "C++ class";
            break;
          case Decl::CXXMethod:
            declKind = "C++ method";
            break;
          case Decl::ObjCMethod:
            declKind = "Objective-C method";
            break;
          case Decl::Function:
            declKind = "function";
            break;
          default:
            break;
        }
        if (!declKind.empty()) {
          const std::string &declName = ND->getDeclName().getAsString();
          o << "  <key>issue_context_kind</key>";
          EmitString(o, declKind) << '\n';
          o << "  <key>issue_context</key>";
          EmitString(o, declName) << '\n';
        }

        // Output the bug hash for issue unique-ing. Currently, it's just an
        // offset from the beginning of the function.
        if (const Stmt *Body = DeclWithIssue->getBody()) {
          FullSourceLoc Loc(SM->getExpansionLoc(D->getLocation().asLocation()),
                            *SM);
          FullSourceLoc FunLoc(SM->getExpansionLoc(Body->getLocStart()), *SM);
          o << "  <key>issue_hash</key><integer>"
              << Loc.getExpansionLineNumber() - FunLoc.getExpansionLineNumber()
              << "</integer>\n";
        }
      }
    }

    // Output the location of the bug.
    o << "  <key>location</key>\n";
    EmitLocation(o, *SM, LangOpts, D->getLocation(), FM, 2);

    // Output the diagnostic to the sub-diagnostic client, if any.
    if (!filesMade->empty()) {
      StringRef lastName;
      PDFileEntry::ConsumerFiles *files = filesMade->getFiles(*D);
      if (files) {
        for (PDFileEntry::ConsumerFiles::const_iterator CI = files->begin(),
                CE = files->end(); CI != CE; ++CI) {
          StringRef newName = CI->first;
          if (newName != lastName) {
            if (!lastName.empty()) {
              o << "  </array>\n";
            }
            lastName = newName;
            o <<  "  <key>" << lastName << "_files</key>\n";
            o << "  <array>\n";
          }
          o << "   <string>" << CI->second << "</string>\n";
        }
        o << "  </array>\n";
      }
    }

    // Close up the entry.
    o << "  </dict>\n";
  }

  o << " </array>\n";

  // Finish.
  o << "</dict>\n</plist>";  
}
Exemplo n.º 18
0
void PlistDiagnostics::FlushDiagnosticsImpl(
                                    std::vector<const PathDiagnostic *> &Diags,
                                    FilesMade *filesMade) {
  // Build up a set of FIDs that we use by scanning the locations and
  // ranges of the diagnostics.
  FIDMap FM;
  SmallVector<FileID, 10> Fids;
  const SourceManager* SM = nullptr;

  if (!Diags.empty())
    SM = &(*(*Diags.begin())->path.begin())->getLocation().getManager();


  for (std::vector<const PathDiagnostic*>::iterator DI = Diags.begin(),
       DE = Diags.end(); DI != DE; ++DI) {

    const PathDiagnostic *D = *DI;

    SmallVector<const PathPieces *, 5> WorkList;
    WorkList.push_back(&D->path);

    while (!WorkList.empty()) {
      const PathPieces &path = *WorkList.pop_back_val();

      for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E;
           ++I) {
        const PathDiagnosticPiece *piece = I->get();
        AddFID(FM, Fids, *SM, piece->getLocation().asLocation());
        ArrayRef<SourceRange> Ranges = piece->getRanges();
        for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
                                             E = Ranges.end(); I != E; ++I) {
          AddFID(FM, Fids, *SM, I->getBegin());
          AddFID(FM, Fids, *SM, I->getEnd());
        }

        if (const PathDiagnosticCallPiece *call =
            dyn_cast<PathDiagnosticCallPiece>(piece)) {
          IntrusiveRefCntPtr<PathDiagnosticEventPiece>
            callEnterWithin = call->getCallEnterWithinCallerEvent();
          if (callEnterWithin)
            AddFID(FM, Fids, *SM, callEnterWithin->getLocation().asLocation());

          WorkList.push_back(&call->path);
        }
        else if (const PathDiagnosticMacroPiece *macro =
                 dyn_cast<PathDiagnosticMacroPiece>(piece)) {
          WorkList.push_back(&macro->subPieces);
        }
      }
    }
  }

  // Open the file.
  std::error_code EC;
  llvm::raw_fd_ostream o(OutputFile, EC, llvm::sys::fs::F_Text);
  if (EC) {
    llvm::errs() << "warning: could not create file: " << EC.message() << '\n';
    return;
  }

  EmitPlistHeader(o);

  // Write the root object: a <dict> containing...
  //  - "clang_version", the string representation of clang version
  //  - "files", an <array> mapping from FIDs to file names
  //  - "diagnostics", an <array> containing the path diagnostics
  o << "<dict>\n" <<
       " <key>clang_version</key>\n";
  EmitString(o, getClangFullVersion()) << '\n';
  o << " <key>files</key>\n"
       " <array>\n";

  for (FileID FID : Fids)
    EmitString(o << "  ", SM->getFileEntryForID(FID)->getName()) << '\n';

  o << " </array>\n"
       " <key>diagnostics</key>\n"
       " <array>\n";

  for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(),
       DE = Diags.end(); DI!=DE; ++DI) {

    o << "  <dict>\n"
         "   <key>path</key>\n";

    const PathDiagnostic *D = *DI;

    o << "   <array>\n";

    for (PathPieces::const_iterator I = D->path.begin(), E = D->path.end();
         I != E; ++I)
      ReportDiag(o, **I, FM, *SM, LangOpts);

    o << "   </array>\n";

    // Output the bug type and bug category.
    o << "   <key>description</key>";
    EmitString(o, D->getShortDescription()) << '\n';
    o << "   <key>category</key>";
    EmitString(o, D->getCategory()) << '\n';
    o << "   <key>type</key>";
    EmitString(o, D->getBugType()) << '\n';
    o << "   <key>check_name</key>";
    EmitString(o, D->getCheckName()) << '\n';

    o << "   <!-- This hash is experimental and going to change! -->\n";
    o << "   <key>issue_hash_content_of_line_in_context</key>";
    PathDiagnosticLocation UPDLoc = D->getUniqueingLoc();
    FullSourceLoc L(SM->getExpansionLoc(UPDLoc.isValid()
                                            ? UPDLoc.asLocation()
                                            : D->getLocation().asLocation()),
                    *SM);
    const Decl *DeclWithIssue = D->getDeclWithIssue();
    EmitString(o, GetIssueHash(*SM, L, D->getCheckName(), D->getBugType(),
                               DeclWithIssue))
        << '\n';

    // Output information about the semantic context where
    // the issue occurred.
    if (const Decl *DeclWithIssue = D->getDeclWithIssue()) {
      // FIXME: handle blocks, which have no name.
      if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
        StringRef declKind;
        switch (ND->getKind()) {
          case Decl::CXXRecord:
            declKind = "C++ class";
            break;
          case Decl::CXXMethod:
            declKind = "C++ method";
            break;
          case Decl::ObjCMethod:
            declKind = "Objective-C method";
            break;
          case Decl::Function:
            declKind = "function";
            break;
          default:
            break;
        }
        if (!declKind.empty()) {
          const std::string &declName = ND->getDeclName().getAsString();
          o << "  <key>issue_context_kind</key>";
          EmitString(o, declKind) << '\n';
          o << "  <key>issue_context</key>";
          EmitString(o, declName) << '\n';
        }

        // Output the bug hash for issue unique-ing. Currently, it's just an
        // offset from the beginning of the function.
        if (const Stmt *Body = DeclWithIssue->getBody()) {

          // If the bug uniqueing location exists, use it for the hash.
          // For example, this ensures that two leaks reported on the same line
          // will have different issue_hashes and that the hash will identify
          // the leak location even after code is added between the allocation
          // site and the end of scope (leak report location).
          if (UPDLoc.isValid()) {
            FullSourceLoc UFunL(SM->getExpansionLoc(
              D->getUniqueingDecl()->getBody()->getLocStart()), *SM);
            o << "  <key>issue_hash_function_offset</key><string>"
              << L.getExpansionLineNumber() - UFunL.getExpansionLineNumber()
              << "</string>\n";

          // Otherwise, use the location on which the bug is reported.
          } else {
            FullSourceLoc FunL(SM->getExpansionLoc(Body->getLocStart()), *SM);
            o << "  <key>issue_hash_function_offset</key><string>"
              << L.getExpansionLineNumber() - FunL.getExpansionLineNumber()
              << "</string>\n";
          }

        }
      }
    }

    // Output the location of the bug.
    o << "  <key>location</key>\n";
    EmitLocation(o, *SM, D->getLocation().asLocation(), FM, 2);

    // Output the diagnostic to the sub-diagnostic client, if any.
    if (!filesMade->empty()) {
      StringRef lastName;
      PDFileEntry::ConsumerFiles *files = filesMade->getFiles(*D);
      if (files) {
        for (PDFileEntry::ConsumerFiles::const_iterator CI = files->begin(),
                CE = files->end(); CI != CE; ++CI) {
          StringRef newName = CI->first;
          if (newName != lastName) {
            if (!lastName.empty()) {
              o << "  </array>\n";
            }
            lastName = newName;
            o <<  "  <key>" << lastName << "_files</key>\n";
            o << "  <array>\n";
          }
          o << "   <string>" << CI->second << "</string>\n";
        }
        o << "  </array>\n";
      }
    }

    // Close up the entry.
    o << "  </dict>\n";
  }

  o << " </array>\n";

  // Finish.
  o << "</dict>\n</plist>";
}
/// createInvocationFromCommandLine - Construct a compiler invocation object for
/// a command line argument vector.
///
/// \return A CompilerInvocation, or 0 if none was built for the given
/// argument vector.
std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
    ArrayRef<const char *> ArgList, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
    IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
  if (!Diags.get()) {
    // No diagnostics engine was provided, so create our own diagnostics object
    // with the default options.
    Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions);
  }

  SmallVector<const char *, 16> Args(ArgList.begin(), ArgList.end());

  // FIXME: Find a cleaner way to force the driver into restricted modes.
  Args.push_back("-fsyntax-only");

  // FIXME: We shouldn't have to pass in the path info.
  driver::Driver TheDriver(Args[0], llvm::sys::getDefaultTargetTriple(),
                           *Diags, VFS);

  // Don't check that inputs exist, they may have been remapped.
  TheDriver.setCheckInputsExist(false);

  std::unique_ptr<driver::Compilation> C(TheDriver.BuildCompilation(Args));
  if (!C)
    return nullptr;

  // Just print the cc1 options if -### was present.
  if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) {
    C->getJobs().Print(llvm::errs(), "\n", true);
    return nullptr;
  }

  // We expect to get back exactly one command job, if we didn't something
  // failed. Offload compilation is an exception as it creates multiple jobs. If
  // that's the case, we proceed with the first job. If caller needs a
  // particular job, it should be controlled via options (e.g.
  // --cuda-{host|device}-only for CUDA) passed to the driver.
  const driver::JobList &Jobs = C->getJobs();
  bool OffloadCompilation = false;
  if (Jobs.size() > 1) {
    for (auto &A : C->getActions()){
      // On MacOSX real actions may end up being wrapped in BindArchAction
      if (isa<driver::BindArchAction>(A))
        A = *A->input_begin();
      if (isa<driver::OffloadAction>(A)) {
        OffloadCompilation = true;
        break;
      }
    }
  }
  if (Jobs.size() == 0 || !isa<driver::Command>(*Jobs.begin()) ||
      (Jobs.size() > 1 && !OffloadCompilation)) {
    SmallString<256> Msg;
    llvm::raw_svector_ostream OS(Msg);
    Jobs.Print(OS, "; ", true);
    Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
    return nullptr;
  }

  const driver::Command &Cmd = cast<driver::Command>(*Jobs.begin());
  if (StringRef(Cmd.getCreator().getName()) != "clang") {
    Diags->Report(diag::err_fe_expected_clang_command);
    return nullptr;
  }

  const ArgStringList &CCArgs = Cmd.getArguments();
  auto CI = llvm::make_unique<CompilerInvocation>();
  if (!CompilerInvocation::CreateFromArgs(*CI,
                                     const_cast<const char **>(CCArgs.data()),
                                     const_cast<const char **>(CCArgs.data()) +
                                     CCArgs.size(),
                                     *Diags))
    return nullptr;
  return CI;
}