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 }