Please use GitHub pull requests for new patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
clang-tools-extra/clangd/ConfigYAML.cpp
Show First 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | for (const auto &AllowedValue : AllowedValues) { | ||||
} else if (EditDistance < MaxEdit) { | } else if (EditDistance < MaxEdit) { | ||||
Result = AllowedValue; | Result = AllowedValue; | ||||
MaxEdit = EditDistance; | MaxEdit = EditDistance; | ||||
} | } | ||||
} | } | ||||
return Result; | return Result; | ||||
} | } | ||||
// Copied from OpDefinitionsGen | |||||
// Replaces all occurrences of `match` in `str` with `substitute`. | |||||
static std::string replaceAllSubstrs(std::string str, const std::string &match, | |||||
const std::string &substitute) { | |||||
std::string::size_type scanLoc = 0, matchLoc = std::string::npos; | |||||
while ((matchLoc = str.find(match, scanLoc)) != std::string::npos) { | |||||
str = str.replace(matchLoc, match.size(), substitute); | |||||
scanLoc = matchLoc + substitute.size(); | |||||
} | |||||
return str; | |||||
} | |||||
class Parser { | class Parser { | ||||
llvm::SourceMgr &SM; | llvm::SourceMgr &SM; | ||||
bool HadError = false; | bool HadError = false; | ||||
std::optional<llvm::StringRef> ConfigFilePath; | |||||
public: | public: | ||||
Parser(llvm::SourceMgr &SM) : SM(SM) {} | Parser(llvm::SourceMgr &SM, std::optional<llvm::StringRef> configFilePath) | ||||
: SM(SM), ConfigFilePath(configFilePath) {} | |||||
// Tries to parse N into F, returning false if it failed and we couldn't | // Tries to parse N into F, returning false if it failed and we couldn't | ||||
// meaningfully recover (YAML syntax error, or hard semantic error). | // meaningfully recover (YAML syntax error, or hard semantic error). | ||||
bool parse(Fragment &F, Node &N) { | bool parse(Fragment &F, Node &N) { | ||||
DictParser Dict("Config", this); | DictParser Dict("Config", this); | ||||
Dict.handle("If", [&](Node &N) { parse(F.If, N); }); | Dict.handle("If", [&](Node &N) { parse(F.If, N); }); | ||||
Dict.handle("CompileFlags", [&](Node &N) { parse(F.CompileFlags, N); }); | Dict.handle("CompileFlags", [&](Node &N) { parse(F.CompileFlags, N); }); | ||||
Dict.handle("Index", [&](Node &N) { parse(F.Index, N); }); | Dict.handle("Index", [&](Node &N) { parse(F.Index, N); }); | ||||
▲ Show 20 Lines • Show All 277 Lines • ▼ Show 20 Lines | void warnUnknownKeys(llvm::ArrayRef<Located<std::string>> UnknownKeys, | ||||
UnknownKey.Range); | UnknownKey.Range); | ||||
else | else | ||||
Outer->warning("Unknown " + Description + " key '" + *UnknownKey + | Outer->warning("Unknown " + Description + " key '" + *UnknownKey + | ||||
"'", | "'", | ||||
UnknownKey.Range); | UnknownKey.Range); | ||||
} | } | ||||
}; | }; | ||||
std::string keywordReplace(std::string value) { | |||||
return replaceAllSubstrs( | |||||
value, "${CURRENT_FILE_PATH}", | |||||
this->ConfigFilePath.value_or(llvm::StringRef()).str()); | |||||
} | |||||
// Try to parse a single scalar value from the node, warn on failure. | // Try to parse a single scalar value from the node, warn on failure. | ||||
std::optional<Located<std::string>> scalarValue(Node &N, | std::optional<Located<std::string>> scalarValue(Node &N, | ||||
llvm::StringRef Desc) { | llvm::StringRef Desc) { | ||||
llvm::SmallString<256> Buf; | llvm::SmallString<256> Buf; | ||||
if (auto *S = llvm::dyn_cast<ScalarNode>(&N)) | if (auto *S = llvm::dyn_cast<ScalarNode>(&N)) { | ||||
return Located<std::string>(S->getValue(Buf).str(), N.getSourceRange()); | return Located<std::string>(keywordReplace(S->getValue(Buf).str()), | ||||
if (auto *BS = llvm::dyn_cast<BlockScalarNode>(&N)) | N.getSourceRange()); | ||||
return Located<std::string>(BS->getValue().str(), N.getSourceRange()); | } | ||||
if (auto *BS = llvm::dyn_cast<BlockScalarNode>(&N)) { | |||||
return Located<std::string>(keywordReplace(BS->getValue().str()), | |||||
N.getSourceRange()); | |||||
} | |||||
warning(Desc + " should be scalar", N); | warning(Desc + " should be scalar", N); | ||||
return std::nullopt; | return std::nullopt; | ||||
} | } | ||||
std::optional<Located<bool>> boolValue(Node &N, llvm::StringRef Desc) { | std::optional<Located<bool>> boolValue(Node &N, llvm::StringRef Desc) { | ||||
if (auto Scalar = scalarValue(N, Desc)) { | if (auto Scalar = scalarValue(N, Desc)) { | ||||
if (auto Bool = llvm::yaml::parseBool(**Scalar)) | if (auto Bool = llvm::yaml::parseBool(**Scalar)) | ||||
return Located<bool>(*Bool, Scalar->Range); | return Located<bool>(*Bool, Scalar->Range); | ||||
Show All 38 Lines | private: | ||||
} | } | ||||
void warning(const llvm::Twine &Msg, const Node &N) { | void warning(const llvm::Twine &Msg, const Node &N) { | ||||
return warning(Msg, N.getSourceRange()); | return warning(Msg, N.getSourceRange()); | ||||
} | } | ||||
}; | }; | ||||
} // namespace | } // namespace | ||||
std::vector<Fragment> Fragment::parseYAML(llvm::StringRef YAML, | std::vector<Fragment> | ||||
llvm::StringRef BufferName, | Fragment::parseYAML(llvm::StringRef YAML, llvm::StringRef BufferName, | ||||
std::optional<llvm::StringRef> configFilePath, | |||||
DiagnosticCallback Diags) { | DiagnosticCallback Diags) { | ||||
// The YAML document may contain multiple conditional fragments. | // The YAML document may contain multiple conditional fragments. | ||||
// The SourceManager is shared for all of them. | // The SourceManager is shared for all of them. | ||||
auto SM = std::make_shared<llvm::SourceMgr>(); | auto SM = std::make_shared<llvm::SourceMgr>(); | ||||
auto Buf = llvm::MemoryBuffer::getMemBufferCopy(YAML, BufferName); | auto Buf = llvm::MemoryBuffer::getMemBufferCopy(YAML, BufferName); | ||||
// Adapt DiagnosticCallback to function-pointer interface. | // Adapt DiagnosticCallback to function-pointer interface. | ||||
// Callback receives both errors we emit and those from the YAML parser. | // Callback receives both errors we emit and those from the YAML parser. | ||||
SM->setDiagHandler( | SM->setDiagHandler( | ||||
[](const llvm::SMDiagnostic &Diag, void *Ctx) { | [](const llvm::SMDiagnostic &Diag, void *Ctx) { | ||||
(*reinterpret_cast<DiagnosticCallback *>(Ctx))(Diag); | (*reinterpret_cast<DiagnosticCallback *>(Ctx))(Diag); | ||||
}, | }, | ||||
&Diags); | &Diags); | ||||
std::vector<Fragment> Result; | std::vector<Fragment> Result; | ||||
for (auto &Doc : llvm::yaml::Stream(*Buf, *SM)) { | for (auto &Doc : llvm::yaml::Stream(*Buf, *SM)) { | ||||
if (Node *N = Doc.getRoot()) { | if (Node *N = Doc.getRoot()) { | ||||
Fragment Fragment; | Fragment Fragment; | ||||
Fragment.Source.Manager = SM; | Fragment.Source.Manager = SM; | ||||
Fragment.Source.Location = N->getSourceRange().Start; | Fragment.Source.Location = N->getSourceRange().Start; | ||||
SM->PrintMessage(Fragment.Source.Location, llvm::SourceMgr::DK_Note, | SM->PrintMessage(Fragment.Source.Location, llvm::SourceMgr::DK_Note, | ||||
"Parsing config fragment"); | "Parsing config fragment"); | ||||
if (Parser(*SM).parse(Fragment, *N)) | if (Parser(*SM, configFilePath).parse(Fragment, *N)) | ||||
Result.push_back(std::move(Fragment)); | Result.push_back(std::move(Fragment)); | ||||
} | } | ||||
} | } | ||||
SM->PrintMessage(SM->FindLocForLineAndColumn(SM->getMainFileID(), 0, 0), | SM->PrintMessage(SM->FindLocForLineAndColumn(SM->getMainFileID(), 0, 0), | ||||
llvm::SourceMgr::DK_Note, | llvm::SourceMgr::DK_Note, | ||||
"Parsed " + llvm::Twine(Result.size()) + | "Parsed " + llvm::Twine(Result.size()) + | ||||
" fragments from file"); | " fragments from file"); | ||||
// Hack: stash the buffer in the SourceMgr to keep it alive. | // Hack: stash the buffer in the SourceMgr to keep it alive. | ||||
// SM has two entries: "main" non-owning buffer, and ignored owning buffer. | // SM has two entries: "main" non-owning buffer, and ignored owning buffer. | ||||
SM->AddNewSourceBuffer(std::move(Buf), llvm::SMLoc()); | SM->AddNewSourceBuffer(std::move(Buf), llvm::SMLoc()); | ||||
return Result; | return Result; | ||||
} | } | ||||
} // namespace config | } // namespace config | ||||
} // namespace clangd | } // namespace clangd | ||||
} // namespace clang | } // namespace clang |