1 #include "file_consumer.h"
2
3 #include "clang_utils.h"
4 #include "indexer.h"
5 #include "platform.h"
6 #include "utils.h"
7
8 #include <loguru.hpp>
9
10 namespace {
11
GetFileContents(const std::string & path,FileContentsMap * file_contents)12 optional<std::string> GetFileContents(const std::string& path,
13 FileContentsMap* file_contents) {
14 auto it = file_contents->find(path);
15 if (it == file_contents->end()) {
16 optional<std::string> content = ReadContent(path);
17 if (content)
18 (*file_contents)[path] = FileContents(path, *content);
19 return content;
20 }
21 return it->second.content;
22 }
23
24 } // namespace
25
operator ==(const CXFileUniqueID & a,const CXFileUniqueID & b)26 bool operator==(const CXFileUniqueID& a, const CXFileUniqueID& b) {
27 return a.data[0] == b.data[0] && a.data[1] == b.data[1] &&
28 a.data[2] == b.data[2];
29 }
30
Mark(const std::string & file)31 bool FileConsumerSharedState::Mark(const std::string& file) {
32 std::lock_guard<std::mutex> lock(mutex);
33 return used_files.insert(file).second;
34 }
35
Reset(const std::string & file)36 void FileConsumerSharedState::Reset(const std::string& file) {
37 std::lock_guard<std::mutex> lock(mutex);
38 auto it = used_files.find(file);
39 if (it != used_files.end())
40 used_files.erase(it);
41 }
42
FileConsumer(FileConsumerSharedState * shared_state,const AbsolutePath & parse_file)43 FileConsumer::FileConsumer(FileConsumerSharedState* shared_state,
44 const AbsolutePath& parse_file)
45 : shared_(shared_state), parse_file_(parse_file) {}
46
TryConsumeFile(CXFile file,bool * is_first_ownership,FileContentsMap * file_contents_map)47 IndexFile* FileConsumer::TryConsumeFile(CXFile file,
48 bool* is_first_ownership,
49 FileContentsMap* file_contents_map) {
50 assert(is_first_ownership);
51
52 CXFileUniqueID file_id;
53 if (clang_getFileUniqueID(file, &file_id) != 0) {
54 EmitError(file);
55 return nullptr;
56 }
57
58 // Try to find cached local result.
59 auto it = local_.find(file_id);
60 if (it != local_.end()) {
61 *is_first_ownership = false;
62 return it->second.get();
63 }
64
65 optional<AbsolutePath> file_name = FileName(file);
66 if (!file_name) {
67 LOG_S(ERROR) << "Could not normalize path "
68 << ToString(clang_getFileName(file));
69 return nullptr;
70 }
71
72 // No result in local; we need to query global.
73 bool did_insert = shared_->Mark(file_name->path);
74
75 // We did not take the file from global. Cache that we failed so we don't try
76 // again and return nullptr.
77 if (!did_insert) {
78 local_[file_id] = nullptr;
79 return nullptr;
80 }
81
82 // Read the file contents, if we fail then we cannot index the file.
83 optional<std::string> contents =
84 GetFileContents(file_name->path, file_contents_map);
85 if (!contents) {
86 *is_first_ownership = false;
87 return nullptr;
88 }
89
90 // Build IndexFile instance.
91 *is_first_ownership = true;
92 local_[file_id] = std::make_unique<IndexFile>(file_name->path, *contents);
93 return local_[file_id].get();
94 }
95
TakeLocalState()96 std::vector<std::unique_ptr<IndexFile>> FileConsumer::TakeLocalState() {
97 std::vector<std::unique_ptr<IndexFile>> result;
98 for (auto& entry : local_) {
99 if (entry.second)
100 result.push_back(std::move(entry.second));
101 }
102 return result;
103 }
104
EmitError(CXFile file) const105 void FileConsumer::EmitError(CXFile file) const {
106 std::string file_name = ToString(clang_getFileName(file));
107 // TODO: Investigate this more, why can we get an empty file name?
108 if (!file_name.empty()) {
109 LOG_S(ERROR) << "Could not get unique file id for " << file_name
110 << " when parsing " << parse_file_;
111 }
112 }