head	1.1;
branch	1.1.1;
access;
symbols
	netbsd-11-0-RC4:1.1.1.9
	netbsd-11-0-RC3:1.1.1.9
	netbsd-11-0-RC2:1.1.1.9
	netbsd-11-0-RC1:1.1.1.9
	perseant-exfatfs-base-20250801:1.1.1.9
	netbsd-11:1.1.1.9.0.10
	netbsd-11-base:1.1.1.9
	netbsd-10-1-RELEASE:1.1.1.9
	perseant-exfatfs-base-20240630:1.1.1.9
	perseant-exfatfs:1.1.1.9.0.8
	perseant-exfatfs-base:1.1.1.9
	netbsd-8-3-RELEASE:1.1.1.6
	netbsd-9-4-RELEASE:1.1.1.8
	netbsd-10-0-RELEASE:1.1.1.9
	netbsd-10-0-RC6:1.1.1.9
	netbsd-10-0-RC5:1.1.1.9
	netbsd-10-0-RC4:1.1.1.9
	netbsd-10-0-RC3:1.1.1.9
	netbsd-10-0-RC2:1.1.1.9
	netbsd-10-0-RC1:1.1.1.9
	netbsd-10:1.1.1.9.0.6
	netbsd-10-base:1.1.1.9
	netbsd-9-3-RELEASE:1.1.1.8
	cjep_sun2x:1.1.1.9.0.4
	cjep_sun2x-base:1.1.1.9
	cjep_staticlib_x-base1:1.1.1.9
	netbsd-9-2-RELEASE:1.1.1.8
	cjep_staticlib_x:1.1.1.9.0.2
	cjep_staticlib_x-base:1.1.1.9
	netbsd-9-1-RELEASE:1.1.1.8
	phil-wifi-20200421:1.1.1.9
	phil-wifi-20200411:1.1.1.9
	phil-wifi-20200406:1.1.1.9
	netbsd-8-2-RELEASE:1.1.1.6
	netbsd-9-0-RELEASE:1.1.1.8
	netbsd-9-0-RC2:1.1.1.8
	netbsd-9-0-RC1:1.1.1.8
	netbsd-9:1.1.1.8.0.2
	netbsd-9-base:1.1.1.8
	phil-wifi-20190609:1.1.1.8
	netbsd-8-1-RELEASE:1.1.1.6
	netbsd-8-1-RC1:1.1.1.6
	pgoyette-compat-merge-20190127:1.1.1.7.2.1
	pgoyette-compat-20190127:1.1.1.8
	pgoyette-compat-20190118:1.1.1.8
	pgoyette-compat-1226:1.1.1.8
	pgoyette-compat-1126:1.1.1.8
	pgoyette-compat-1020:1.1.1.8
	pgoyette-compat-0930:1.1.1.8
	pgoyette-compat-0906:1.1.1.8
	netbsd-7-2-RELEASE:1.1.1.4
	pgoyette-compat-0728:1.1.1.8
	clang-337282:1.1.1.8
	netbsd-8-0-RELEASE:1.1.1.6
	phil-wifi:1.1.1.7.0.4
	phil-wifi-base:1.1.1.7
	pgoyette-compat-0625:1.1.1.7
	netbsd-8-0-RC2:1.1.1.6
	pgoyette-compat-0521:1.1.1.7
	pgoyette-compat-0502:1.1.1.7
	pgoyette-compat-0422:1.1.1.7
	netbsd-8-0-RC1:1.1.1.6
	pgoyette-compat-0415:1.1.1.7
	pgoyette-compat-0407:1.1.1.7
	pgoyette-compat-0330:1.1.1.7
	pgoyette-compat-0322:1.1.1.7
	pgoyette-compat-0315:1.1.1.7
	netbsd-7-1-2-RELEASE:1.1.1.4
	pgoyette-compat:1.1.1.7.0.2
	pgoyette-compat-base:1.1.1.7
	netbsd-7-1-1-RELEASE:1.1.1.4
	clang-319952:1.1.1.7
	matt-nb8-mediatek:1.1.1.6.0.10
	matt-nb8-mediatek-base:1.1.1.6
	clang-309604:1.1.1.7
	perseant-stdc-iso10646:1.1.1.6.0.8
	perseant-stdc-iso10646-base:1.1.1.6
	netbsd-8:1.1.1.6.0.6
	netbsd-8-base:1.1.1.6
	prg-localcount2-base3:1.1.1.6
	prg-localcount2-base2:1.1.1.6
	prg-localcount2-base1:1.1.1.6
	prg-localcount2:1.1.1.6.0.4
	prg-localcount2-base:1.1.1.6
	pgoyette-localcount-20170426:1.1.1.6
	bouyer-socketcan-base1:1.1.1.6
	pgoyette-localcount-20170320:1.1.1.6
	netbsd-7-1:1.1.1.4.0.10
	netbsd-7-1-RELEASE:1.1.1.4
	netbsd-7-1-RC2:1.1.1.4
	clang-294123:1.1.1.6
	netbsd-7-nhusb-base-20170116:1.1.1.4
	bouyer-socketcan:1.1.1.6.0.2
	bouyer-socketcan-base:1.1.1.6
	clang-291444:1.1.1.6
	pgoyette-localcount-20170107:1.1.1.5
	netbsd-7-1-RC1:1.1.1.4
	pgoyette-localcount-20161104:1.1.1.5
	netbsd-7-0-2-RELEASE:1.1.1.4
	localcount-20160914:1.1.1.5
	netbsd-7-nhusb:1.1.1.4.0.8
	netbsd-7-nhusb-base:1.1.1.4
	clang-280599:1.1.1.5
	pgoyette-localcount-20160806:1.1.1.5
	pgoyette-localcount-20160726:1.1.1.5
	pgoyette-localcount:1.1.1.5.0.2
	pgoyette-localcount-base:1.1.1.5
	netbsd-7-0-1-RELEASE:1.1.1.4
	clang-261930:1.1.1.5
	netbsd-7-0:1.1.1.4.0.6
	netbsd-7-0-RELEASE:1.1.1.4
	netbsd-7-0-RC3:1.1.1.4
	netbsd-7-0-RC2:1.1.1.4
	netbsd-7-0-RC1:1.1.1.4
	clang-237755:1.1.1.4
	clang-232565:1.1.1.4
	clang-227398:1.1.1.4
	tls-maxphys-base:1.1.1.4
	tls-maxphys:1.1.1.4.0.4
	netbsd-7:1.1.1.4.0.2
	netbsd-7-base:1.1.1.4
	clang-215315:1.1.1.4
	clang-209886:1.1.1.3
	yamt-pagecache:1.1.1.2.0.4
	yamt-pagecache-base9:1.1.1.2
	tls-earlyentropy:1.1.1.2.0.2
	tls-earlyentropy-base:1.1.1.3
	riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.1.1.2
	riastradh-drm2-base3:1.1.1.2
	clang-202566:1.1.1.2
	clang-201163:1.1.1.2
	clang-199312:1.1.1.2
	clang-198450:1.1.1.2
	clang-196603:1.1.1.1
	clang-195771:1.1.1.1
	LLVM:1.1.1;
locks; strict;
comment	@// @;


1.1
date	2013.11.28.14.14.54;	author joerg;	state Exp;
branches
	1.1.1.1;
next	;
commitid	ow8OybrawrB1f3fx;

1.1.1.1
date	2013.11.28.14.14.54;	author joerg;	state Exp;
branches;
next	1.1.1.2;
commitid	ow8OybrawrB1f3fx;

1.1.1.2
date	2014.01.05.15.38.21;	author joerg;	state Exp;
branches
	1.1.1.2.2.1
	1.1.1.2.4.1;
next	1.1.1.3;
commitid	wh3aCSIWykURqWjx;

1.1.1.3
date	2014.05.30.18.14.45;	author joerg;	state Exp;
branches;
next	1.1.1.4;
commitid	8q0kdlBlCn09GACx;

1.1.1.4
date	2014.08.10.17.08.25;	author joerg;	state Exp;
branches
	1.1.1.4.4.1;
next	1.1.1.5;
commitid	N85tXAN6Ex9VZPLx;

1.1.1.5
date	2016.02.27.22.11.49;	author joerg;	state Exp;
branches
	1.1.1.5.2.1;
next	1.1.1.6;
commitid	tIimz3oDlh1NpBWy;

1.1.1.6
date	2017.01.11.10.35.43;	author joerg;	state Exp;
branches;
next	1.1.1.7;
commitid	CNnUNfII1jgNmxBz;

1.1.1.7
date	2017.08.01.19.35.18;	author joerg;	state Exp;
branches
	1.1.1.7.2.1
	1.1.1.7.4.1;
next	1.1.1.8;
commitid	pMuDy65V0VicSx1A;

1.1.1.8
date	2018.07.17.18.31.14;	author joerg;	state Exp;
branches;
next	1.1.1.9;
commitid	wDzL46ALjrCZgwKA;

1.1.1.9
date	2019.11.13.22.19.29;	author joerg;	state dead;
branches;
next	;
commitid	QD8YATxuNG34YJKB;

1.1.1.2.2.1
date	2014.08.10.07.08.10;	author tls;	state Exp;
branches;
next	;
commitid	t01A1TLTYxkpGMLx;

1.1.1.2.4.1
date	2014.01.05.15.38.21;	author yamt;	state dead;
branches;
next	1.1.1.2.4.2;
commitid	WSrDtL5nYAUyiyBx;

1.1.1.2.4.2
date	2014.05.22.16.18.31;	author yamt;	state Exp;
branches;
next	;
commitid	WSrDtL5nYAUyiyBx;

1.1.1.4.4.1
date	2014.08.10.17.08.25;	author tls;	state dead;
branches;
next	1.1.1.4.4.2;
commitid	jTnpym9Qu0o4R1Nx;

1.1.1.4.4.2
date	2014.08.19.23.47.32;	author tls;	state Exp;
branches;
next	;
commitid	jTnpym9Qu0o4R1Nx;

1.1.1.5.2.1
date	2017.03.20.06.52.42;	author pgoyette;	state Exp;
branches;
next	;
commitid	jjw7cAwgyKq7RfKz;

1.1.1.7.2.1
date	2018.07.28.04.33.24;	author pgoyette;	state Exp;
branches;
next	;
commitid	1UP1xAIUxv1ZgRLA;

1.1.1.7.4.1
date	2019.06.10.21.45.29;	author christos;	state Exp;
branches;
next	1.1.1.7.4.2;
commitid	jtc8rnCzWiEEHGqB;

1.1.1.7.4.2
date	2020.04.13.07.46.39;	author martin;	state dead;
branches;
next	;
commitid	X01YhRUPVUDaec4C;


desc
@@


1.1
log
@Initial revision
@
text
@//===--- JSONCompilationDatabase.cpp - ------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file contains the implementation of the JSONCompilationDatabase.
//
//===----------------------------------------------------------------------===//

#include "clang/Tooling/JSONCompilationDatabase.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/system_error.h"

namespace clang {
namespace tooling {

namespace {

/// \brief A parser for escaped strings of command line arguments.
///
/// Assumes \-escaping for quoted arguments (see the documentation of
/// unescapeCommandLine(...)).
class CommandLineArgumentParser {
 public:
  CommandLineArgumentParser(StringRef CommandLine)
      : Input(CommandLine), Position(Input.begin()-1) {}

  std::vector<std::string> parse() {
    bool HasMoreInput = true;
    while (HasMoreInput && nextNonWhitespace()) {
      std::string Argument;
      HasMoreInput = parseStringInto(Argument);
      CommandLine.push_back(Argument);
    }
    return CommandLine;
  }

 private:
  // All private methods return true if there is more input available.

  bool parseStringInto(std::string &String) {
    do {
      if (*Position == '"') {
        if (!parseDoubleQuotedStringInto(String)) return false;
      } else if (*Position == '\'') {
        if (!parseSingleQuotedStringInto(String)) return false;
      } else {
        if (!parseFreeStringInto(String)) return false;
      }
    } while (*Position != ' ');
    return true;
  }

  bool parseDoubleQuotedStringInto(std::string &String) {
    if (!next()) return false;
    while (*Position != '"') {
      if (!skipEscapeCharacter()) return false;
      String.push_back(*Position);
      if (!next()) return false;
    }
    return next();
  }

  bool parseSingleQuotedStringInto(std::string &String) {
    if (!next()) return false;
    while (*Position != '\'') {
      String.push_back(*Position);
      if (!next()) return false;
    }
    return next();
  }

  bool parseFreeStringInto(std::string &String) {
    do {
      if (!skipEscapeCharacter()) return false;
      String.push_back(*Position);
      if (!next()) return false;
    } while (*Position != ' ' && *Position != '"' && *Position != '\'');
    return true;
  }

  bool skipEscapeCharacter() {
    if (*Position == '\\') {
      return next();
    }
    return true;
  }

  bool nextNonWhitespace() {
    do {
      if (!next()) return false;
    } while (*Position == ' ');
    return true;
  }

  bool next() {
    ++Position;
    return Position != Input.end();
  }

  const StringRef Input;
  StringRef::iterator Position;
  std::vector<std::string> CommandLine;
};

std::vector<std::string> unescapeCommandLine(
    StringRef EscapedCommandLine) {
  CommandLineArgumentParser parser(EscapedCommandLine);
  return parser.parse();
}

class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
  virtual CompilationDatabase *loadFromDirectory(
      StringRef Directory, std::string &ErrorMessage) {
    SmallString<1024> JSONDatabasePath(Directory);
    llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
    OwningPtr<CompilationDatabase> Database(
        JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
    if (!Database)
      return NULL;
    return Database.take();
  }
};

} // end namespace

// Register the JSONCompilationDatabasePlugin with the
// CompilationDatabasePluginRegistry using this statically initialized variable.
static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin>
X("json-compilation-database", "Reads JSON formatted compilation databases");

// This anchor is used to force the linker to link in the generated object file
// and thus register the JSONCompilationDatabasePlugin.
volatile int JSONAnchorSource = 0;

JSONCompilationDatabase *
JSONCompilationDatabase::loadFromFile(StringRef FilePath,
                                      std::string &ErrorMessage) {
  OwningPtr<llvm::MemoryBuffer> DatabaseBuffer;
  llvm::error_code Result =
    llvm::MemoryBuffer::getFile(FilePath, DatabaseBuffer);
  if (Result != 0) {
    ErrorMessage = "Error while opening JSON database: " + Result.message();
    return NULL;
  }
  OwningPtr<JSONCompilationDatabase> Database(
    new JSONCompilationDatabase(DatabaseBuffer.take()));
  if (!Database->parse(ErrorMessage))
    return NULL;
  return Database.take();
}

JSONCompilationDatabase *
JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
                                        std::string &ErrorMessage) {
  OwningPtr<llvm::MemoryBuffer> DatabaseBuffer(
      llvm::MemoryBuffer::getMemBuffer(DatabaseString));
  OwningPtr<JSONCompilationDatabase> Database(
      new JSONCompilationDatabase(DatabaseBuffer.take()));
  if (!Database->parse(ErrorMessage))
    return NULL;
  return Database.take();
}

std::vector<CompileCommand>
JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
  SmallString<128> NativeFilePath;
  llvm::sys::path::native(FilePath, NativeFilePath);
  std::vector<StringRef> PossibleMatches;
  std::string Error;
  llvm::raw_string_ostream ES(Error);
  StringRef Match = MatchTrie.findEquivalent(NativeFilePath.str(), ES);
  if (Match.empty())
    return std::vector<CompileCommand>();
  llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
    CommandsRefI = IndexByFile.find(Match);
  if (CommandsRefI == IndexByFile.end())
    return std::vector<CompileCommand>();
  std::vector<CompileCommand> Commands;
  getCommands(CommandsRefI->getValue(), Commands);
  return Commands;
}

std::vector<std::string>
JSONCompilationDatabase::getAllFiles() const {
  std::vector<std::string> Result;

  llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
    CommandsRefI = IndexByFile.begin();
  const llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
    CommandsRefEnd = IndexByFile.end();
  for (; CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
    Result.push_back(CommandsRefI->first().str());
  }

  return Result;
}

std::vector<CompileCommand>
JSONCompilationDatabase::getAllCompileCommands() const {
  std::vector<CompileCommand> Commands;
  for (llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
        CommandsRefI = IndexByFile.begin(), CommandsRefEnd = IndexByFile.end();
      CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
    getCommands(CommandsRefI->getValue(), Commands);
  }
  return Commands;
}

void JSONCompilationDatabase::getCommands(
                                  ArrayRef<CompileCommandRef> CommandsRef,
                                  std::vector<CompileCommand> &Commands) const {
  for (int I = 0, E = CommandsRef.size(); I != E; ++I) {
    SmallString<8> DirectoryStorage;
    SmallString<1024> CommandStorage;
    Commands.push_back(CompileCommand(
      // FIXME: Escape correctly:
      CommandsRef[I].first->getValue(DirectoryStorage),
      unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage))));
  }
}

bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
  llvm::yaml::document_iterator I = YAMLStream.begin();
  if (I == YAMLStream.end()) {
    ErrorMessage = "Error while parsing YAML.";
    return false;
  }
  llvm::yaml::Node *Root = I->getRoot();
  if (Root == NULL) {
    ErrorMessage = "Error while parsing YAML.";
    return false;
  }
  llvm::yaml::SequenceNode *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
  if (Array == NULL) {
    ErrorMessage = "Expected array.";
    return false;
  }
  for (llvm::yaml::SequenceNode::iterator AI = Array->begin(),
                                          AE = Array->end();
       AI != AE; ++AI) {
    llvm::yaml::MappingNode *Object = dyn_cast<llvm::yaml::MappingNode>(&*AI);
    if (Object == NULL) {
      ErrorMessage = "Expected object.";
      return false;
    }
    llvm::yaml::ScalarNode *Directory = NULL;
    llvm::yaml::ScalarNode *Command = NULL;
    llvm::yaml::ScalarNode *File = NULL;
    for (llvm::yaml::MappingNode::iterator KVI = Object->begin(),
                                           KVE = Object->end();
         KVI != KVE; ++KVI) {
      llvm::yaml::Node *Value = (*KVI).getValue();
      if (Value == NULL) {
        ErrorMessage = "Expected value.";
        return false;
      }
      llvm::yaml::ScalarNode *ValueString =
          dyn_cast<llvm::yaml::ScalarNode>(Value);
      if (ValueString == NULL) {
        ErrorMessage = "Expected string as value.";
        return false;
      }
      llvm::yaml::ScalarNode *KeyString =
          dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey());
      if (KeyString == NULL) {
        ErrorMessage = "Expected strings as key.";
        return false;
      }
      SmallString<8> KeyStorage;
      if (KeyString->getValue(KeyStorage) == "directory") {
        Directory = ValueString;
      } else if (KeyString->getValue(KeyStorage) == "command") {
        Command = ValueString;
      } else if (KeyString->getValue(KeyStorage) == "file") {
        File = ValueString;
      } else {
        ErrorMessage = ("Unknown key: \"" +
                        KeyString->getRawValue() + "\"").str();
        return false;
      }
    }
    if (!File) {
      ErrorMessage = "Missing key: \"file\".";
      return false;
    }
    if (!Command) {
      ErrorMessage = "Missing key: \"command\".";
      return false;
    }
    if (!Directory) {
      ErrorMessage = "Missing key: \"directory\".";
      return false;
    }
    SmallString<8> FileStorage;
    StringRef FileName = File->getValue(FileStorage);
    SmallString<128> NativeFilePath;
    if (llvm::sys::path::is_relative(FileName)) {
      SmallString<8> DirectoryStorage;
      SmallString<128> AbsolutePath(
          Directory->getValue(DirectoryStorage));
      llvm::sys::path::append(AbsolutePath, FileName);
      llvm::sys::path::native(AbsolutePath.str(), NativeFilePath);
    } else {
      llvm::sys::path::native(FileName, NativeFilePath);
    }
    IndexByFile[NativeFilePath].push_back(
        CompileCommandRef(Directory, Command));
    MatchTrie.insert(NativeFilePath.str());
  }
  return true;
}

} // end namespace tooling
} // end namespace clang
@


1.1.1.1
log
@Import Clang 3.4rc1 r195771.
@
text
@@


1.1.1.2
log
@Import clang 3.5svn r198450.
@
text
@d177 1
a177 1

@


1.1.1.2.2.1
log
@Rebase.
@
text
@d121 2
a122 2
  CompilationDatabase *loadFromDirectory(StringRef Directory,
                                         std::string &ErrorMessage) override {
d125 1
a125 1
    std::unique_ptr<CompilationDatabase> Database(
d128 2
a129 2
      return nullptr;
    return Database.release();
d147 1
a147 1
  std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer;
d150 1
a150 1
  if (Result != nullptr) {
d152 1
a152 1
    return nullptr;
d154 2
a155 2
  std::unique_ptr<JSONCompilationDatabase> Database(
      new JSONCompilationDatabase(DatabaseBuffer.release()));
d157 2
a158 2
    return nullptr;
  return Database.release();
d164 1
a164 1
  std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer(
d166 2
a167 2
  std::unique_ptr<JSONCompilationDatabase> Database(
      new JSONCompilationDatabase(DatabaseBuffer.release()));
d169 2
a170 2
    return nullptr;
  return Database.release();
d238 1
a238 1
  if (!Root) {
d243 1
a243 1
  if (!Array) {
d251 1
a251 1
    if (!Object) {
d255 3
a257 3
    llvm::yaml::ScalarNode *Directory = nullptr;
    llvm::yaml::ScalarNode *Command = nullptr;
    llvm::yaml::ScalarNode *File = nullptr;
d262 1
a262 1
      if (!Value) {
d268 1
a268 1
      if (!ValueString) {
d274 1
a274 1
      if (!KeyString) {
@


1.1.1.3
log
@Import Clang 3.5svn r209886.
@
text
@d121 2
a122 2
  CompilationDatabase *loadFromDirectory(StringRef Directory,
                                         std::string &ErrorMessage) override {
d125 1
a125 1
    std::unique_ptr<CompilationDatabase> Database(
d128 2
a129 2
      return nullptr;
    return Database.release();
d147 1
a147 1
  std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer;
d150 1
a150 1
  if (Result != nullptr) {
d152 1
a152 1
    return nullptr;
d154 2
a155 2
  std::unique_ptr<JSONCompilationDatabase> Database(
      new JSONCompilationDatabase(DatabaseBuffer.release()));
d157 2
a158 2
    return nullptr;
  return Database.release();
d164 1
a164 1
  std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer(
d166 2
a167 2
  std::unique_ptr<JSONCompilationDatabase> Database(
      new JSONCompilationDatabase(DatabaseBuffer.release()));
d169 2
a170 2
    return nullptr;
  return Database.release();
d238 1
a238 1
  if (!Root) {
d243 1
a243 1
  if (!Array) {
d251 1
a251 1
    if (!Object) {
d255 3
a257 3
    llvm::yaml::ScalarNode *Directory = nullptr;
    llvm::yaml::ScalarNode *Command = nullptr;
    llvm::yaml::ScalarNode *File = nullptr;
d262 1
a262 1
      if (!Value) {
d268 1
a268 1
      if (!ValueString) {
d274 1
a274 1
      if (!KeyString) {
@


1.1.1.4
log
@Import clang 3.6svn r215315.
@
text
@d20 1
a20 1
#include <system_error>
d121 2
a122 2
  std::unique_ptr<CompilationDatabase>
  loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
d129 1
a129 1
    return Database;
d144 1
a144 1
std::unique_ptr<JSONCompilationDatabase>
d147 4
a150 3
  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> DatabaseBuffer =
      llvm::MemoryBuffer::getFile(FilePath);
  if (std::error_code Result = DatabaseBuffer.getError()) {
d155 1
a155 1
      new JSONCompilationDatabase(std::move(*DatabaseBuffer)));
d158 1
a158 1
  return Database;
d161 1
a161 1
std::unique_ptr<JSONCompilationDatabase>
d167 1
a167 1
      new JSONCompilationDatabase(std::move(DatabaseBuffer)));
d170 1
a170 1
  return Database;
@


1.1.1.5
log
@Import Clang 3.8.0rc3 r261930.
@
text
@d179 1
a179 1
  StringRef Match = MatchTrie.findEquivalent(NativeFilePath, ES);
d209 5
a213 1
  getCommands(AllCommands, Commands);
a216 13
static std::vector<std::string>
nodeToCommandLine(const std::vector<llvm::yaml::ScalarNode *> &Nodes) {
  SmallString<1024> Storage;
  if (Nodes.size() == 1) {
    return unescapeCommandLine(Nodes[0]->getValue(Storage));
  }
  std::vector<std::string> Arguments;
  for (auto *Node : Nodes) {
    Arguments.push_back(Node->getValue(Storage));
  }
  return Arguments;
}

d218 2
a219 2
    ArrayRef<CompileCommandRef> CommandsRef,
    std::vector<CompileCommand> &Commands) const {
d222 5
a226 5
    SmallString<32> FilenameStorage;
    Commands.emplace_back(
      std::get<0>(CommandsRef[I])->getValue(DirectoryStorage),
      std::get<1>(CommandsRef[I])->getValue(FilenameStorage),
      nodeToCommandLine(std::get<2>(CommandsRef[I])));
d246 4
a249 2
  for (auto& NextObject : *Array) {
    llvm::yaml::MappingNode *Object = dyn_cast<llvm::yaml::MappingNode>(&NextObject);
d255 1
a255 1
    llvm::Optional<std::vector<llvm::yaml::ScalarNode *>> Command;
d257 4
a260 10
    for (auto& NextKeyValue : *Object) {
      llvm::yaml::ScalarNode *KeyString =
          dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
      if (!KeyString) {
        ErrorMessage = "Expected strings as key.";
        return false;
      }
      SmallString<10> KeyStorage;
      StringRef KeyValue = KeyString->getValue(KeyStorage);
      llvm::yaml::Node *Value = NextKeyValue.getValue();
d267 2
a268 4
      llvm::yaml::SequenceNode *SequenceString =
          dyn_cast<llvm::yaml::SequenceNode>(Value);
      if (KeyValue == "arguments" && !SequenceString) {
        ErrorMessage = "Expected sequence as value.";
d270 5
a274 2
      } else if (KeyValue != "arguments" && !ValueString) {
        ErrorMessage = "Expected string as value.";
d277 2
a278 1
      if (KeyValue == "directory") {
d280 3
a282 14
      } else if (KeyValue == "arguments") {
        Command = std::vector<llvm::yaml::ScalarNode *>();
        for (auto &Argument : *SequenceString) {
          auto Scalar = dyn_cast<llvm::yaml::ScalarNode>(&Argument);
          if (!Scalar) {
            ErrorMessage = "Only strings are allowed in 'arguments'.";
            return false;
          }
          Command->push_back(Scalar);
        }
      } else if (KeyValue == "command") {
        if (!Command)
          Command = std::vector<llvm::yaml::ScalarNode *>(1, ValueString);
      } else if (KeyValue == "file") {
d295 1
a295 1
      ErrorMessage = "Missing key: \"command\" or \"arguments\".";
d310 1
a310 1
      llvm::sys::path::native(AbsolutePath, NativeFilePath);
d314 3
a316 4
    auto Cmd = CompileCommandRef(Directory, File, *Command);
    IndexByFile[NativeFilePath].push_back(Cmd);
    AllCommands.push_back(Cmd);
    MatchTrie.insert(NativeFilePath);
@


1.1.1.5.2.1
log
@Sync with HEAD
@
text
@a18 2
#include "llvm/Support/Allocator.h"
#include "llvm/Support/CommandLine.h"
a19 1
#include "llvm/Support/StringSaver.h"
d114 2
a115 23
std::vector<std::string> unescapeCommandLine(JSONCommandLineSyntax Syntax,
                                             StringRef EscapedCommandLine) {
  if (Syntax == JSONCommandLineSyntax::AutoDetect) {
    Syntax = JSONCommandLineSyntax::Gnu;
    llvm::Triple Triple(llvm::sys::getProcessTriple());
    if (Triple.getOS() == llvm::Triple::OSType::Win32) {
      // Assume Windows command line parsing on Win32 unless the triple
      // explicitly tells us otherwise.
      if (!Triple.hasEnvironment() ||
          Triple.getEnvironment() == llvm::Triple::EnvironmentType::MSVC)
        Syntax = JSONCommandLineSyntax::Windows;
    }
  }

  if (Syntax == JSONCommandLineSyntax::Windows) {
    llvm::BumpPtrAllocator Alloc;
    llvm::StringSaver Saver(Alloc);
    llvm::SmallVector<const char *, 64> T;
    llvm::cl::TokenizeWindowsCommandLine(EscapedCommandLine, Saver, T);
    std::vector<std::string> Result(T.begin(), T.end());
    return Result;
  }
  assert(Syntax == JSONCommandLineSyntax::Gnu);
d126 1
a126 2
        JSONCompilationDatabase::loadFromFile(
            JSONDatabasePath, ErrorMessage, JSONCommandLineSyntax::AutoDetect));
d146 1
a146 2
                                      std::string &ErrorMessage,
                                      JSONCommandLineSyntax Syntax) {
d154 1
a154 1
      new JSONCompilationDatabase(std::move(*DatabaseBuffer), Syntax));
d162 1
a162 2
                                        std::string &ErrorMessage,
                                        JSONCommandLineSyntax Syntax) {
d166 1
a166 1
      new JSONCompilationDatabase(std::move(DatabaseBuffer), Syntax));
d214 1
a214 2
nodeToCommandLine(JSONCommandLineSyntax Syntax,
                  const std::vector<llvm::yaml::ScalarNode *> &Nodes) {
d217 1
a217 1
    return unescapeCommandLine(Syntax, Nodes[0]->getValue(Storage));
a231 2
    SmallString<32> OutputStorage;
    auto Output = std::get<3>(CommandsRef[I]);
d233 3
a235 4
        std::get<0>(CommandsRef[I])->getValue(DirectoryStorage),
        std::get<1>(CommandsRef[I])->getValue(FilenameStorage),
        nodeToCommandLine(Syntax, std::get<2>(CommandsRef[I])),
        Output ? Output->getValue(OutputStorage) : "");
a263 1
    llvm::yaml::ScalarNode *Output = nullptr;
a305 2
      } else if (KeyValue == "output") {
        Output = ValueString;
d336 1
a336 1
    auto Cmd = CompileCommandRef(Directory, File, *Command, Output);
@


1.1.1.6
log
@Import Clang pre-4.0.0 r291444.
@
text
@a18 2
#include "llvm/Support/Allocator.h"
#include "llvm/Support/CommandLine.h"
a19 1
#include "llvm/Support/StringSaver.h"
d114 2
a115 23
std::vector<std::string> unescapeCommandLine(JSONCommandLineSyntax Syntax,
                                             StringRef EscapedCommandLine) {
  if (Syntax == JSONCommandLineSyntax::AutoDetect) {
    Syntax = JSONCommandLineSyntax::Gnu;
    llvm::Triple Triple(llvm::sys::getProcessTriple());
    if (Triple.getOS() == llvm::Triple::OSType::Win32) {
      // Assume Windows command line parsing on Win32 unless the triple
      // explicitly tells us otherwise.
      if (!Triple.hasEnvironment() ||
          Triple.getEnvironment() == llvm::Triple::EnvironmentType::MSVC)
        Syntax = JSONCommandLineSyntax::Windows;
    }
  }

  if (Syntax == JSONCommandLineSyntax::Windows) {
    llvm::BumpPtrAllocator Alloc;
    llvm::StringSaver Saver(Alloc);
    llvm::SmallVector<const char *, 64> T;
    llvm::cl::TokenizeWindowsCommandLine(EscapedCommandLine, Saver, T);
    std::vector<std::string> Result(T.begin(), T.end());
    return Result;
  }
  assert(Syntax == JSONCommandLineSyntax::Gnu);
d126 1
a126 2
        JSONCompilationDatabase::loadFromFile(
            JSONDatabasePath, ErrorMessage, JSONCommandLineSyntax::AutoDetect));
d146 1
a146 2
                                      std::string &ErrorMessage,
                                      JSONCommandLineSyntax Syntax) {
d154 1
a154 1
      new JSONCompilationDatabase(std::move(*DatabaseBuffer), Syntax));
d162 1
a162 2
                                        std::string &ErrorMessage,
                                        JSONCommandLineSyntax Syntax) {
d166 1
a166 1
      new JSONCompilationDatabase(std::move(DatabaseBuffer), Syntax));
d214 1
a214 2
nodeToCommandLine(JSONCommandLineSyntax Syntax,
                  const std::vector<llvm::yaml::ScalarNode *> &Nodes) {
d217 1
a217 1
    return unescapeCommandLine(Syntax, Nodes[0]->getValue(Storage));
a231 2
    SmallString<32> OutputStorage;
    auto Output = std::get<3>(CommandsRef[I]);
d233 3
a235 4
        std::get<0>(CommandsRef[I])->getValue(DirectoryStorage),
        std::get<1>(CommandsRef[I])->getValue(FilenameStorage),
        nodeToCommandLine(Syntax, std::get<2>(CommandsRef[I])),
        Output ? Output->getValue(OutputStorage) : "");
a263 1
    llvm::yaml::ScalarNode *Output = nullptr;
a305 2
      } else if (KeyValue == "output") {
        Output = ValueString;
d336 1
a336 1
    auto Cmd = CompileCommandRef(Directory, File, *Command, Output);
@


1.1.1.7
log
@Import clang r309604 from branches/release_50
@
text
@d149 6
a154 2
    return JSONCompilationDatabase::loadFromFile(
        JSONDatabasePath, ErrorMessage, JSONCommandLineSyntax::AutoDetect);
@


1.1.1.7.4.1
log
@Sync with HEAD
@
text
@d1 1
a1 1
//===- JSONCompilationDatabase.cpp ----------------------------------------===//
a14 1
#include "clang/Basic/LLVM.h"
d17 1
a17 1
#include "llvm/ADT/Optional.h"
a18 3
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
a19 1
#include "llvm/Support/Casting.h"
a20 3
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
a22 5
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <memory>
#include <string>
a23 3
#include <tuple>
#include <utility>
#include <vector>
d25 2
a26 2
using namespace clang;
using namespace tooling;
d30 1
a30 1
/// A parser for escaped strings of command line arguments.
d154 1
a154 1
} // namespace
a160 3
namespace clang {
namespace tooling {

a164 3
} // namespace tooling
} // namespace clang

d204 3
a206 2
    return {};
  const auto CommandsRefI = IndexByFile.find(Match);
d208 1
a208 1
    return {};
d217 9
a225 2
  for (const auto &CommandRef : IndexByFile)
    Result.push_back(CommandRef.first().str());
d240 1
a240 1
  if (Nodes.size() == 1)
d242 1
d244 1
a244 1
  for (const auto *Node : Nodes)
d246 1
d253 1
a253 1
  for (const auto &CommandRef : CommandsRef) {
d257 1
a257 1
    auto Output = std::get<3>(CommandRef);
d259 3
a261 3
        std::get<0>(CommandRef)->getValue(DirectoryStorage),
        std::get<1>(CommandRef)->getValue(FilenameStorage),
        nodeToCommandLine(Syntax, std::get<2>(CommandRef)),
d277 1
a277 1
  auto *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
d282 2
a283 2
  for (auto &NextObject : *Array) {
    auto *Object = dyn_cast<llvm::yaml::MappingNode>(&NextObject);
d293 2
a294 1
      auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
d306 4
a309 2
      auto *ValueString = dyn_cast<llvm::yaml::ScalarNode>(Value);
      auto *SequenceString = dyn_cast<llvm::yaml::SequenceNode>(Value);
d322 1
a322 1
          auto *Scalar = dyn_cast<llvm::yaml::ScalarNode>(&Argument);
d373 3
@


1.1.1.7.4.2
log
@Mostly merge changes from HEAD upto 20200411
@
text
@@


1.1.1.7.2.1
log
@Sync with HEAD
@
text
@d1 1
a1 1
//===- JSONCompilationDatabase.cpp ----------------------------------------===//
a14 1
#include "clang/Basic/LLVM.h"
d17 1
a17 1
#include "llvm/ADT/Optional.h"
a18 3
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
a19 1
#include "llvm/Support/Casting.h"
a20 3
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
a22 5
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <memory>
#include <string>
a23 3
#include <tuple>
#include <utility>
#include <vector>
d25 2
a26 2
using namespace clang;
using namespace tooling;
d30 1
a30 1
/// A parser for escaped strings of command line arguments.
d154 1
a154 1
} // namespace
a160 3
namespace clang {
namespace tooling {

a164 3
} // namespace tooling
} // namespace clang

d204 3
a206 2
    return {};
  const auto CommandsRefI = IndexByFile.find(Match);
d208 1
a208 1
    return {};
d217 9
a225 2
  for (const auto &CommandRef : IndexByFile)
    Result.push_back(CommandRef.first().str());
d240 1
a240 1
  if (Nodes.size() == 1)
d242 1
d244 1
a244 1
  for (const auto *Node : Nodes)
d246 1
d253 1
a253 1
  for (const auto &CommandRef : CommandsRef) {
d257 1
a257 1
    auto Output = std::get<3>(CommandRef);
d259 3
a261 3
        std::get<0>(CommandRef)->getValue(DirectoryStorage),
        std::get<1>(CommandRef)->getValue(FilenameStorage),
        nodeToCommandLine(Syntax, std::get<2>(CommandRef)),
d277 1
a277 1
  auto *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
d282 2
a283 2
  for (auto &NextObject : *Array) {
    auto *Object = dyn_cast<llvm::yaml::MappingNode>(&NextObject);
d293 2
a294 1
      auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
d306 4
a309 2
      auto *ValueString = dyn_cast<llvm::yaml::ScalarNode>(Value);
      auto *SequenceString = dyn_cast<llvm::yaml::SequenceNode>(Value);
d322 1
a322 1
          auto *Scalar = dyn_cast<llvm::yaml::ScalarNode>(&Argument);
d373 3
@


1.1.1.8
log
@Import clang r337282 from trunk
@
text
@d1 1
a1 1
//===- JSONCompilationDatabase.cpp ----------------------------------------===//
a14 1
#include "clang/Basic/LLVM.h"
d17 1
a17 1
#include "llvm/ADT/Optional.h"
a18 3
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
a19 1
#include "llvm/Support/Casting.h"
a20 3
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
a22 5
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <memory>
#include <string>
a23 3
#include <tuple>
#include <utility>
#include <vector>
d25 2
a26 2
using namespace clang;
using namespace tooling;
d30 1
a30 1
/// A parser for escaped strings of command line arguments.
d154 1
a154 1
} // namespace
a160 3
namespace clang {
namespace tooling {

a164 3
} // namespace tooling
} // namespace clang

d204 3
a206 2
    return {};
  const auto CommandsRefI = IndexByFile.find(Match);
d208 1
a208 1
    return {};
d217 9
a225 2
  for (const auto &CommandRef : IndexByFile)
    Result.push_back(CommandRef.first().str());
d240 1
a240 1
  if (Nodes.size() == 1)
d242 1
d244 1
a244 1
  for (const auto *Node : Nodes)
d246 1
d253 1
a253 1
  for (const auto &CommandRef : CommandsRef) {
d257 1
a257 1
    auto Output = std::get<3>(CommandRef);
d259 3
a261 3
        std::get<0>(CommandRef)->getValue(DirectoryStorage),
        std::get<1>(CommandRef)->getValue(FilenameStorage),
        nodeToCommandLine(Syntax, std::get<2>(CommandRef)),
d277 1
a277 1
  auto *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
d282 2
a283 2
  for (auto &NextObject : *Array) {
    auto *Object = dyn_cast<llvm::yaml::MappingNode>(&NextObject);
d293 2
a294 1
      auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
d306 4
a309 2
      auto *ValueString = dyn_cast<llvm::yaml::ScalarNode>(Value);
      auto *SequenceString = dyn_cast<llvm::yaml::SequenceNode>(Value);
d322 1
a322 1
          auto *Scalar = dyn_cast<llvm::yaml::ScalarNode>(&Argument);
d373 3
@


1.1.1.9
log
@Mark old LLVM instance as dead.
@
text
@@


1.1.1.4.4.1
log
@file JSONCompilationDatabase.cpp was added on branch tls-maxphys on 2014-08-19 23:47:32 +0000
@
text
@d1 322
@


1.1.1.4.4.2
log
@Rebase to HEAD as of a few days ago.
@
text
@a0 322
//===--- JSONCompilationDatabase.cpp - ------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file contains the implementation of the JSONCompilationDatabase.
//
//===----------------------------------------------------------------------===//

#include "clang/Tooling/JSONCompilationDatabase.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
#include <system_error>

namespace clang {
namespace tooling {

namespace {

/// \brief A parser for escaped strings of command line arguments.
///
/// Assumes \-escaping for quoted arguments (see the documentation of
/// unescapeCommandLine(...)).
class CommandLineArgumentParser {
 public:
  CommandLineArgumentParser(StringRef CommandLine)
      : Input(CommandLine), Position(Input.begin()-1) {}

  std::vector<std::string> parse() {
    bool HasMoreInput = true;
    while (HasMoreInput && nextNonWhitespace()) {
      std::string Argument;
      HasMoreInput = parseStringInto(Argument);
      CommandLine.push_back(Argument);
    }
    return CommandLine;
  }

 private:
  // All private methods return true if there is more input available.

  bool parseStringInto(std::string &String) {
    do {
      if (*Position == '"') {
        if (!parseDoubleQuotedStringInto(String)) return false;
      } else if (*Position == '\'') {
        if (!parseSingleQuotedStringInto(String)) return false;
      } else {
        if (!parseFreeStringInto(String)) return false;
      }
    } while (*Position != ' ');
    return true;
  }

  bool parseDoubleQuotedStringInto(std::string &String) {
    if (!next()) return false;
    while (*Position != '"') {
      if (!skipEscapeCharacter()) return false;
      String.push_back(*Position);
      if (!next()) return false;
    }
    return next();
  }

  bool parseSingleQuotedStringInto(std::string &String) {
    if (!next()) return false;
    while (*Position != '\'') {
      String.push_back(*Position);
      if (!next()) return false;
    }
    return next();
  }

  bool parseFreeStringInto(std::string &String) {
    do {
      if (!skipEscapeCharacter()) return false;
      String.push_back(*Position);
      if (!next()) return false;
    } while (*Position != ' ' && *Position != '"' && *Position != '\'');
    return true;
  }

  bool skipEscapeCharacter() {
    if (*Position == '\\') {
      return next();
    }
    return true;
  }

  bool nextNonWhitespace() {
    do {
      if (!next()) return false;
    } while (*Position == ' ');
    return true;
  }

  bool next() {
    ++Position;
    return Position != Input.end();
  }

  const StringRef Input;
  StringRef::iterator Position;
  std::vector<std::string> CommandLine;
};

std::vector<std::string> unescapeCommandLine(
    StringRef EscapedCommandLine) {
  CommandLineArgumentParser parser(EscapedCommandLine);
  return parser.parse();
}

class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
  std::unique_ptr<CompilationDatabase>
  loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
    SmallString<1024> JSONDatabasePath(Directory);
    llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
    std::unique_ptr<CompilationDatabase> Database(
        JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
    if (!Database)
      return nullptr;
    return Database;
  }
};

} // end namespace

// Register the JSONCompilationDatabasePlugin with the
// CompilationDatabasePluginRegistry using this statically initialized variable.
static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin>
X("json-compilation-database", "Reads JSON formatted compilation databases");

// This anchor is used to force the linker to link in the generated object file
// and thus register the JSONCompilationDatabasePlugin.
volatile int JSONAnchorSource = 0;

std::unique_ptr<JSONCompilationDatabase>
JSONCompilationDatabase::loadFromFile(StringRef FilePath,
                                      std::string &ErrorMessage) {
  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> DatabaseBuffer =
      llvm::MemoryBuffer::getFile(FilePath);
  if (std::error_code Result = DatabaseBuffer.getError()) {
    ErrorMessage = "Error while opening JSON database: " + Result.message();
    return nullptr;
  }
  std::unique_ptr<JSONCompilationDatabase> Database(
      new JSONCompilationDatabase(std::move(*DatabaseBuffer)));
  if (!Database->parse(ErrorMessage))
    return nullptr;
  return Database;
}

std::unique_ptr<JSONCompilationDatabase>
JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
                                        std::string &ErrorMessage) {
  std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer(
      llvm::MemoryBuffer::getMemBuffer(DatabaseString));
  std::unique_ptr<JSONCompilationDatabase> Database(
      new JSONCompilationDatabase(std::move(DatabaseBuffer)));
  if (!Database->parse(ErrorMessage))
    return nullptr;
  return Database;
}

std::vector<CompileCommand>
JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
  SmallString<128> NativeFilePath;
  llvm::sys::path::native(FilePath, NativeFilePath);

  std::string Error;
  llvm::raw_string_ostream ES(Error);
  StringRef Match = MatchTrie.findEquivalent(NativeFilePath.str(), ES);
  if (Match.empty())
    return std::vector<CompileCommand>();
  llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
    CommandsRefI = IndexByFile.find(Match);
  if (CommandsRefI == IndexByFile.end())
    return std::vector<CompileCommand>();
  std::vector<CompileCommand> Commands;
  getCommands(CommandsRefI->getValue(), Commands);
  return Commands;
}

std::vector<std::string>
JSONCompilationDatabase::getAllFiles() const {
  std::vector<std::string> Result;

  llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
    CommandsRefI = IndexByFile.begin();
  const llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
    CommandsRefEnd = IndexByFile.end();
  for (; CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
    Result.push_back(CommandsRefI->first().str());
  }

  return Result;
}

std::vector<CompileCommand>
JSONCompilationDatabase::getAllCompileCommands() const {
  std::vector<CompileCommand> Commands;
  for (llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
        CommandsRefI = IndexByFile.begin(), CommandsRefEnd = IndexByFile.end();
      CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
    getCommands(CommandsRefI->getValue(), Commands);
  }
  return Commands;
}

void JSONCompilationDatabase::getCommands(
                                  ArrayRef<CompileCommandRef> CommandsRef,
                                  std::vector<CompileCommand> &Commands) const {
  for (int I = 0, E = CommandsRef.size(); I != E; ++I) {
    SmallString<8> DirectoryStorage;
    SmallString<1024> CommandStorage;
    Commands.push_back(CompileCommand(
      // FIXME: Escape correctly:
      CommandsRef[I].first->getValue(DirectoryStorage),
      unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage))));
  }
}

bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
  llvm::yaml::document_iterator I = YAMLStream.begin();
  if (I == YAMLStream.end()) {
    ErrorMessage = "Error while parsing YAML.";
    return false;
  }
  llvm::yaml::Node *Root = I->getRoot();
  if (!Root) {
    ErrorMessage = "Error while parsing YAML.";
    return false;
  }
  llvm::yaml::SequenceNode *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
  if (!Array) {
    ErrorMessage = "Expected array.";
    return false;
  }
  for (llvm::yaml::SequenceNode::iterator AI = Array->begin(),
                                          AE = Array->end();
       AI != AE; ++AI) {
    llvm::yaml::MappingNode *Object = dyn_cast<llvm::yaml::MappingNode>(&*AI);
    if (!Object) {
      ErrorMessage = "Expected object.";
      return false;
    }
    llvm::yaml::ScalarNode *Directory = nullptr;
    llvm::yaml::ScalarNode *Command = nullptr;
    llvm::yaml::ScalarNode *File = nullptr;
    for (llvm::yaml::MappingNode::iterator KVI = Object->begin(),
                                           KVE = Object->end();
         KVI != KVE; ++KVI) {
      llvm::yaml::Node *Value = (*KVI).getValue();
      if (!Value) {
        ErrorMessage = "Expected value.";
        return false;
      }
      llvm::yaml::ScalarNode *ValueString =
          dyn_cast<llvm::yaml::ScalarNode>(Value);
      if (!ValueString) {
        ErrorMessage = "Expected string as value.";
        return false;
      }
      llvm::yaml::ScalarNode *KeyString =
          dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey());
      if (!KeyString) {
        ErrorMessage = "Expected strings as key.";
        return false;
      }
      SmallString<8> KeyStorage;
      if (KeyString->getValue(KeyStorage) == "directory") {
        Directory = ValueString;
      } else if (KeyString->getValue(KeyStorage) == "command") {
        Command = ValueString;
      } else if (KeyString->getValue(KeyStorage) == "file") {
        File = ValueString;
      } else {
        ErrorMessage = ("Unknown key: \"" +
                        KeyString->getRawValue() + "\"").str();
        return false;
      }
    }
    if (!File) {
      ErrorMessage = "Missing key: \"file\".";
      return false;
    }
    if (!Command) {
      ErrorMessage = "Missing key: \"command\".";
      return false;
    }
    if (!Directory) {
      ErrorMessage = "Missing key: \"directory\".";
      return false;
    }
    SmallString<8> FileStorage;
    StringRef FileName = File->getValue(FileStorage);
    SmallString<128> NativeFilePath;
    if (llvm::sys::path::is_relative(FileName)) {
      SmallString<8> DirectoryStorage;
      SmallString<128> AbsolutePath(
          Directory->getValue(DirectoryStorage));
      llvm::sys::path::append(AbsolutePath, FileName);
      llvm::sys::path::native(AbsolutePath.str(), NativeFilePath);
    } else {
      llvm::sys::path::native(FileName, NativeFilePath);
    }
    IndexByFile[NativeFilePath].push_back(
        CompileCommandRef(Directory, Command));
    MatchTrie.insert(NativeFilePath.str());
  }
  return true;
}

} // end namespace tooling
} // end namespace clang
@


1.1.1.2.4.1
log
@file JSONCompilationDatabase.cpp was added on branch yamt-pagecache on 2014-05-22 16:18:31 +0000
@
text
@d1 323
@


1.1.1.2.4.2
log
@sync with head.

for a reference, the tree before this commit was tagged
as yamt-pagecache-tag8.

this commit was splitted into small chunks to avoid
a limitation of cvs.  ("Protocol error: too many arguments")
@
text
@a0 323
//===--- JSONCompilationDatabase.cpp - ------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file contains the implementation of the JSONCompilationDatabase.
//
//===----------------------------------------------------------------------===//

#include "clang/Tooling/JSONCompilationDatabase.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/system_error.h"

namespace clang {
namespace tooling {

namespace {

/// \brief A parser for escaped strings of command line arguments.
///
/// Assumes \-escaping for quoted arguments (see the documentation of
/// unescapeCommandLine(...)).
class CommandLineArgumentParser {
 public:
  CommandLineArgumentParser(StringRef CommandLine)
      : Input(CommandLine), Position(Input.begin()-1) {}

  std::vector<std::string> parse() {
    bool HasMoreInput = true;
    while (HasMoreInput && nextNonWhitespace()) {
      std::string Argument;
      HasMoreInput = parseStringInto(Argument);
      CommandLine.push_back(Argument);
    }
    return CommandLine;
  }

 private:
  // All private methods return true if there is more input available.

  bool parseStringInto(std::string &String) {
    do {
      if (*Position == '"') {
        if (!parseDoubleQuotedStringInto(String)) return false;
      } else if (*Position == '\'') {
        if (!parseSingleQuotedStringInto(String)) return false;
      } else {
        if (!parseFreeStringInto(String)) return false;
      }
    } while (*Position != ' ');
    return true;
  }

  bool parseDoubleQuotedStringInto(std::string &String) {
    if (!next()) return false;
    while (*Position != '"') {
      if (!skipEscapeCharacter()) return false;
      String.push_back(*Position);
      if (!next()) return false;
    }
    return next();
  }

  bool parseSingleQuotedStringInto(std::string &String) {
    if (!next()) return false;
    while (*Position != '\'') {
      String.push_back(*Position);
      if (!next()) return false;
    }
    return next();
  }

  bool parseFreeStringInto(std::string &String) {
    do {
      if (!skipEscapeCharacter()) return false;
      String.push_back(*Position);
      if (!next()) return false;
    } while (*Position != ' ' && *Position != '"' && *Position != '\'');
    return true;
  }

  bool skipEscapeCharacter() {
    if (*Position == '\\') {
      return next();
    }
    return true;
  }

  bool nextNonWhitespace() {
    do {
      if (!next()) return false;
    } while (*Position == ' ');
    return true;
  }

  bool next() {
    ++Position;
    return Position != Input.end();
  }

  const StringRef Input;
  StringRef::iterator Position;
  std::vector<std::string> CommandLine;
};

std::vector<std::string> unescapeCommandLine(
    StringRef EscapedCommandLine) {
  CommandLineArgumentParser parser(EscapedCommandLine);
  return parser.parse();
}

class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
  virtual CompilationDatabase *loadFromDirectory(
      StringRef Directory, std::string &ErrorMessage) {
    SmallString<1024> JSONDatabasePath(Directory);
    llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
    OwningPtr<CompilationDatabase> Database(
        JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
    if (!Database)
      return NULL;
    return Database.take();
  }
};

} // end namespace

// Register the JSONCompilationDatabasePlugin with the
// CompilationDatabasePluginRegistry using this statically initialized variable.
static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin>
X("json-compilation-database", "Reads JSON formatted compilation databases");

// This anchor is used to force the linker to link in the generated object file
// and thus register the JSONCompilationDatabasePlugin.
volatile int JSONAnchorSource = 0;

JSONCompilationDatabase *
JSONCompilationDatabase::loadFromFile(StringRef FilePath,
                                      std::string &ErrorMessage) {
  OwningPtr<llvm::MemoryBuffer> DatabaseBuffer;
  llvm::error_code Result =
    llvm::MemoryBuffer::getFile(FilePath, DatabaseBuffer);
  if (Result != 0) {
    ErrorMessage = "Error while opening JSON database: " + Result.message();
    return NULL;
  }
  OwningPtr<JSONCompilationDatabase> Database(
    new JSONCompilationDatabase(DatabaseBuffer.take()));
  if (!Database->parse(ErrorMessage))
    return NULL;
  return Database.take();
}

JSONCompilationDatabase *
JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
                                        std::string &ErrorMessage) {
  OwningPtr<llvm::MemoryBuffer> DatabaseBuffer(
      llvm::MemoryBuffer::getMemBuffer(DatabaseString));
  OwningPtr<JSONCompilationDatabase> Database(
      new JSONCompilationDatabase(DatabaseBuffer.take()));
  if (!Database->parse(ErrorMessage))
    return NULL;
  return Database.take();
}

std::vector<CompileCommand>
JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
  SmallString<128> NativeFilePath;
  llvm::sys::path::native(FilePath, NativeFilePath);

  std::string Error;
  llvm::raw_string_ostream ES(Error);
  StringRef Match = MatchTrie.findEquivalent(NativeFilePath.str(), ES);
  if (Match.empty())
    return std::vector<CompileCommand>();
  llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
    CommandsRefI = IndexByFile.find(Match);
  if (CommandsRefI == IndexByFile.end())
    return std::vector<CompileCommand>();
  std::vector<CompileCommand> Commands;
  getCommands(CommandsRefI->getValue(), Commands);
  return Commands;
}

std::vector<std::string>
JSONCompilationDatabase::getAllFiles() const {
  std::vector<std::string> Result;

  llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
    CommandsRefI = IndexByFile.begin();
  const llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
    CommandsRefEnd = IndexByFile.end();
  for (; CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
    Result.push_back(CommandsRefI->first().str());
  }

  return Result;
}

std::vector<CompileCommand>
JSONCompilationDatabase::getAllCompileCommands() const {
  std::vector<CompileCommand> Commands;
  for (llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
        CommandsRefI = IndexByFile.begin(), CommandsRefEnd = IndexByFile.end();
      CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
    getCommands(CommandsRefI->getValue(), Commands);
  }
  return Commands;
}

void JSONCompilationDatabase::getCommands(
                                  ArrayRef<CompileCommandRef> CommandsRef,
                                  std::vector<CompileCommand> &Commands) const {
  for (int I = 0, E = CommandsRef.size(); I != E; ++I) {
    SmallString<8> DirectoryStorage;
    SmallString<1024> CommandStorage;
    Commands.push_back(CompileCommand(
      // FIXME: Escape correctly:
      CommandsRef[I].first->getValue(DirectoryStorage),
      unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage))));
  }
}

bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
  llvm::yaml::document_iterator I = YAMLStream.begin();
  if (I == YAMLStream.end()) {
    ErrorMessage = "Error while parsing YAML.";
    return false;
  }
  llvm::yaml::Node *Root = I->getRoot();
  if (Root == NULL) {
    ErrorMessage = "Error while parsing YAML.";
    return false;
  }
  llvm::yaml::SequenceNode *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
  if (Array == NULL) {
    ErrorMessage = "Expected array.";
    return false;
  }
  for (llvm::yaml::SequenceNode::iterator AI = Array->begin(),
                                          AE = Array->end();
       AI != AE; ++AI) {
    llvm::yaml::MappingNode *Object = dyn_cast<llvm::yaml::MappingNode>(&*AI);
    if (Object == NULL) {
      ErrorMessage = "Expected object.";
      return false;
    }
    llvm::yaml::ScalarNode *Directory = NULL;
    llvm::yaml::ScalarNode *Command = NULL;
    llvm::yaml::ScalarNode *File = NULL;
    for (llvm::yaml::MappingNode::iterator KVI = Object->begin(),
                                           KVE = Object->end();
         KVI != KVE; ++KVI) {
      llvm::yaml::Node *Value = (*KVI).getValue();
      if (Value == NULL) {
        ErrorMessage = "Expected value.";
        return false;
      }
      llvm::yaml::ScalarNode *ValueString =
          dyn_cast<llvm::yaml::ScalarNode>(Value);
      if (ValueString == NULL) {
        ErrorMessage = "Expected string as value.";
        return false;
      }
      llvm::yaml::ScalarNode *KeyString =
          dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey());
      if (KeyString == NULL) {
        ErrorMessage = "Expected strings as key.";
        return false;
      }
      SmallString<8> KeyStorage;
      if (KeyString->getValue(KeyStorage) == "directory") {
        Directory = ValueString;
      } else if (KeyString->getValue(KeyStorage) == "command") {
        Command = ValueString;
      } else if (KeyString->getValue(KeyStorage) == "file") {
        File = ValueString;
      } else {
        ErrorMessage = ("Unknown key: \"" +
                        KeyString->getRawValue() + "\"").str();
        return false;
      }
    }
    if (!File) {
      ErrorMessage = "Missing key: \"file\".";
      return false;
    }
    if (!Command) {
      ErrorMessage = "Missing key: \"command\".";
      return false;
    }
    if (!Directory) {
      ErrorMessage = "Missing key: \"directory\".";
      return false;
    }
    SmallString<8> FileStorage;
    StringRef FileName = File->getValue(FileStorage);
    SmallString<128> NativeFilePath;
    if (llvm::sys::path::is_relative(FileName)) {
      SmallString<8> DirectoryStorage;
      SmallString<128> AbsolutePath(
          Directory->getValue(DirectoryStorage));
      llvm::sys::path::append(AbsolutePath, FileName);
      llvm::sys::path::native(AbsolutePath.str(), NativeFilePath);
    } else {
      llvm::sys::path::native(FileName, NativeFilePath);
    }
    IndexByFile[NativeFilePath].push_back(
        CompileCommandRef(Directory, Command));
    MatchTrie.insert(NativeFilePath.str());
  }
  return true;
}

} // end namespace tooling
} // end namespace clang
@


