blob: 6b39dfd21164ccc8fcf9825b4286bc2b66bea69f [file] [log] [blame]
/*
* Copyright 2014 The Kythe Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "IndexerFrontendAction.h"
#include <memory>
#include <string>
#include <utility>
#include "KytheGraphObserver.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_format.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h"
#include "kythe/cxx/common/indexing/KytheGraphRecorder.h"
#include "kythe/cxx/common/json_proto.h"
#include "kythe/cxx/indexer/cxx/KytheClaimClient.h"
#include "kythe/cxx/indexer/cxx/KytheVFS.h"
#include "kythe/cxx/indexer/cxx/proto_conversions.h"
#include "kythe/proto/analysis.pb.h"
#include "kythe/proto/buildinfo.pb.h"
#include "kythe/proto/cxx.pb.h"
#include "kythe/proto/filecontext.pb.h"
#include "llvm/ADT/Twine.h"
#include "third_party/llvm/src/clang_builtin_headers.h"
namespace kythe {
bool RunToolOnCode(std::unique_ptr<clang::FrontendAction> tool_action,
llvm::Twine code, const std::string& filename) {
if (tool_action == nullptr) return false;
return clang::tooling::runToolOnCode(tool_action.release(), code, filename);
}
namespace {
// Message type URI for the build details message.
constexpr absl::string_view kBuildDetailsURI =
"kythe.io/proto/kythe.proto.BuildDetails";
/// \brief Range wrapper around unpacked ContextDependentVersion rows.
class FileContextRows {
public:
using iterator = decltype(
std::declval<kythe::proto::ContextDependentVersion>().row().begin());
explicit FileContextRows(
const kythe::proto::CompilationUnit::FileInput& file_input) {
for (const google::protobuf::Any& detail : file_input.details()) {
if (detail.UnpackTo(&context_)) break;
}
}
iterator begin() const { return context_.row().begin(); }
iterator end() const { return context_.row().end(); }
bool empty() const { return context_.row().empty(); }
private:
kythe::proto::ContextDependentVersion context_;
};
bool DecodeDetails(const proto::CompilationUnit& Unit,
proto::CxxCompilationUnitDetails& Details) {
for (const auto& Any : Unit.details()) {
if (Any.type_url() == kCxxCompilationUnitDetailsURI) {
if (UnpackAny(Any, &Details)) {
return true;
}
}
}
return false;
}
std::string ExtractBuildConfig(const proto::CompilationUnit& Unit) {
proto::BuildDetails details;
for (const auto& Any : Unit.details()) {
if (Any.type_url() == kBuildDetailsURI) {
if (UnpackAny(Any, &details)) {
return details.build_config();
}
}
}
return "";
}
bool DecodeHeaderSearchInfo(const proto::CxxCompilationUnitDetails& Details,
HeaderSearchInfo& Info) {
if (!Details.has_header_search_info()) {
return false;
}
if (!Info.CopyFrom(Details)) {
absl::FPrintF(
stderr,
"Warning: unit has header search info, but it is ill-formed.\n");
return false;
}
return true;
}
std::string ConfigureSystemHeaders(const proto::CompilationUnit& Unit,
std::vector<proto::FileData>& Files) {
std::vector<proto::FileData> OldFiles;
OldFiles.swap(Files);
const std::string HeaderPath = "/kythe_builtins/include/";
std::unordered_set<std::string> NewHeaders;
for (const auto* Header = builtin_headers_create(); Header->name != nullptr;
++Header) {
auto Path = HeaderPath + Header->name;
auto Data = Header->data;
proto::FileData NewFile;
NewFile.mutable_info()->set_path(Path);
NewFile.mutable_info()->set_digest("");
*NewFile.mutable_content() = Data;
Files.push_back(NewFile);
NewHeaders.insert(Path);
}
for (const auto& File : OldFiles) {
if (NewHeaders.find(File.info().path()) == NewHeaders.end()) {
Files.push_back(File);
}
}
return "-resource-dir=/kythe_builtins";
}
} // anonymous namespace
std::string IndexCompilationUnit(
const proto::CompilationUnit& Unit, std::vector<proto::FileData>& Files,
KytheClaimClient& Client, HashCache* Cache, KytheCachingOutput& Output,
const IndexerOptions& Options, const MetadataSupports* MetaSupports,
const LibrarySupports* LibrarySupports,
std::function<std::unique_ptr<IndexerWorklist>(IndexerASTVisitor*)>
CreateWorklist) {
HeaderSearchInfo HSI;
proto::CxxCompilationUnitDetails Details;
bool HSIValid = false;
std::vector<llvm::StringRef> Dirs;
if (DecodeDetails(Unit, Details)) {
HSIValid = DecodeHeaderSearchInfo(Details, HSI);
for (const auto& stat_path : Details.stat_path()) {
Dirs.push_back(ToStringRef(stat_path.path()));
}
}
std::string FixupArgument = ConfigureSystemHeaders(Unit, Files);
if (HSIValid) {
FixupArgument.clear();
}
clang::FileSystemOptions FSO;
FSO.WorkingDir = Options.EffectiveWorkingDirectory;
for (auto& Path : HSI.paths) {
Dirs.push_back(ToStringRef(Path.path));
}
llvm::IntrusiveRefCntPtr<IndexVFS> VFS(
new IndexVFS(FSO.WorkingDir, Files, Dirs));
KytheGraphRecorder Recorder(&Output);
KytheGraphObserver Observer(&Recorder, &Client, MetaSupports, VFS,
Options.ReportProfileEvent,
ExtractBuildConfig(Unit));
if (Cache != nullptr) {
Output.UseHashCache(Cache);
Observer.StopDeferringNodes();
}
if (Options.DropInstantiationIndependentData) {
Observer.DropRedundantWraiths();
}
Observer.set_claimant(Unit.v_name());
Observer.set_starting_context(Unit.entry_context());
for (const auto& Input : Unit.required_input()) {
if (Input.has_info() && !Input.info().path().empty() &&
Input.has_v_name()) {
VFS->SetVName(Input.info().path(), Input.v_name());
}
const std::string& FilePath = Input.info().path();
for (const auto& Row : FileContextRows(Input)) {
if (Row.always_process()) {
auto ClaimableVname = Input.v_name();
ClaimableVname.set_signature(Row.source_context() +
ClaimableVname.signature());
Client.AssignClaim(ClaimableVname, Unit.v_name());
}
for (const auto& Col : Row.column()) {
Observer.AddContextInformation(FilePath, Row.source_context(),
Col.offset(), Col.linked_context());
}
}
}
if (MetaSupports != nullptr) {
MetaSupports->UseVNameLookup(
[VFS](const std::string& path, proto::VName* out) {
return VFS->get_vname(path, out);
});
}
std::unique_ptr<IndexerFrontendAction> Action =
absl::make_unique<IndexerFrontendAction>(
&Observer, HSIValid ? &HSI : nullptr, Options.ShouldStopIndexing,
std::move(CreateWorklist), LibrarySupports);
Action->setIgnoreUnimplemented(Options.UnimplementedBehavior);
Action->setTemplateMode(Options.TemplateBehavior);
Action->setVerbosity(Options.Verbosity);
Action->setObjCFwdDeclEmitDocs(Options.ObjCFwdDocs);
Action->setCppFwdDeclEmitDocs(Options.CppFwdDocs);
Action->setUsrByteSize(Options.UsrByteSize);
llvm::IntrusiveRefCntPtr<clang::FileManager> FileManager(
new clang::FileManager(FSO, Options.AllowFSAccess ? nullptr : VFS));
std::vector<std::string> Args(Unit.argument().begin(), Unit.argument().end());
Args.insert(Args.begin() + 1, "-fsyntax-only");
Args.insert(Args.begin() + 1, "-w");
Args.insert(Args.begin() + 1, "-nocudalib");
if (!FixupArgument.empty()) {
Args.insert(Args.begin() + 1, FixupArgument);
}
// StdinAdjustSingleFrontendActionFactory takes ownership of its action.
std::unique_ptr<StdinAdjustSingleFrontendActionFactory> Tool =
absl::make_unique<StdinAdjustSingleFrontendActionFactory>(
std::move(Action));
// ToolInvocation doesn't take ownership of ToolActions.
clang::tooling::ToolInvocation Invocation(
Args, Tool.get(), FileManager.get(),
std::make_shared<clang::PCHContainerOperations>());
ProfileBlock block(Observer.getProfilingCallback(), "run_invocation");
if (!Invocation.run()) {
return "Errors during indexing.";
}
return "";
}
} // namespace kythe