36
36
#include < llvm/Support/Error.h>
37
37
#include < llvm/Support/Path.h>
38
38
#include < llvm/Support/SHA1.h>
39
+ #include < llvm/Support/Process.h>
39
40
#include < memory>
40
41
#include < optional>
41
42
#include < ranges>
42
43
#include < unordered_set>
43
44
44
45
namespace clang ::mrdocs {
45
46
46
- auto
47
+ ASTVisitor::FileInfo
47
48
ASTVisitor::FileInfo::build (
48
- std::span<std::pair<std:: string, FileKind > const > /* search_dirs */ ,
49
+ std::span<std::string> const search_dirs,
49
50
std::string_view const file_path,
50
- std::string_view const sourceRoot) -> ASTVisitor::FileInfo {
51
+ std::string_view const sourceRoot) {
51
52
FileInfo file_info;
52
53
file_info.full_path = std::string (file_path);
53
- file_info.short_path = file_info. full_path ;
54
+ file_info.short_path = std::string (file_path) ;
54
55
55
- std::ptrdiff_t best_length = 0 ;
56
- auto check_dir = [&](
57
- std::string_view const dir_path,
58
- FileKind const kind)
56
+ // Find the best match for the file path
57
+ for (auto const & search_dir : search_dirs)
59
58
{
60
- auto NI = llvm::sys::path::begin (file_path);
61
- auto const NE = llvm::sys::path::end (file_path);
62
- auto DI = llvm::sys::path::begin (dir_path);
63
- auto const DE = llvm::sys::path::end (dir_path);
64
-
65
- for (; NI != NE; ++NI, ++DI)
59
+ if (files::startsWith (file_path, search_dir))
66
60
{
67
- // reached the end of the directory path
68
- if (DI == DE )
61
+ file_info. short_path . erase ( 0 , search_dir. size ());
62
+ if (file_info. short_path . starts_with ( ' / ' ) )
69
63
{
70
- // update the best prefix length
71
- if (std::ptrdiff_t length =
72
- NI - llvm::sys::path::begin (file_path);
73
- length > best_length)
74
- {
75
- best_length = length;
76
- file_info.kind = kind;
77
- return true ;
78
- }
79
- break ;
64
+ file_info.short_path .erase (0 , 1 );
80
65
}
81
- // separators always match
82
- if (NI->size () == 1 && DI->size () == 1 &&
83
- llvm::sys::path::is_separator (NI->front ()) &&
84
- llvm::sys::path::is_separator (DI->front ()))
85
- continue ;
86
- // components don't match
87
- if (*NI != *DI)
88
- break ;
66
+ return file_info;
89
67
}
90
- return false ;
91
- };
92
-
93
- bool const in_sourceRoot = check_dir (
94
- sourceRoot, FileKind::Source);
95
-
96
- // only use a sourceRoot relative path if we
97
- // don't find anything in the include search directories
98
- // bool any_match = false;
99
- // for (auto const& [dir_path, kind]: search_dirs)
100
- // {
101
- // any_match |= check_dir(dir_path, kind);
102
- // }
103
-
104
- // KRYSTIAN TODO: if we don't find any matches,
105
- // make the path relative to sourceRoot and return it
68
+ }
106
69
107
- // override the file kind if
108
- // the file was found in sourceRoot
109
- if (in_sourceRoot)
70
+ // Fallback to sourceRoot
71
+ if (files::startsWith (file_path, sourceRoot))
110
72
{
111
- file_info.kind = FileKind::Source;
73
+ file_info.short_path .erase (0 , sourceRoot.size ());
74
+ if (file_info.short_path .starts_with (' /' ))
75
+ {
76
+ file_info.short_path .erase (0 , 1 );
77
+ }
78
+ return file_info;
112
79
}
113
80
114
- file_info.short_path .erase (0 , best_length);
81
+ // Fallback to system search paths in PATH
82
+ std::optional<std::string> const optEnvPathsStr = llvm::sys::Process::GetEnv (" PATH" );
83
+ MRDOCS_CHECK_OR (optEnvPathsStr, file_info);
84
+ std::string const & envPathsStr = *optEnvPathsStr;
85
+ for (auto const envPaths = llvm::split (envPathsStr, llvm::sys::EnvPathSeparator);
86
+ auto envPath: envPaths)
87
+ {
88
+ auto normEnvPath = files::makePosixStyle (envPath);
89
+ if (files::startsWith (file_path, normEnvPath))
90
+ {
91
+ file_info.short_path .erase (0 , normEnvPath.size ());
92
+ if (file_info.short_path .starts_with (' /' ))
93
+ {
94
+ file_info.short_path .erase (0 , 1 );
95
+ }
96
+ return file_info;
97
+ }
98
+ }
115
99
return file_info;
116
100
}
117
101
@@ -140,63 +124,37 @@ ASTVisitor(
140
124
MRDOCS_ASSERT (context_.getTraversalScope () ==
141
125
std::vector<Decl*>{context_.getTranslationUnitDecl ()});
142
126
143
- auto make_posix_absolute = [&](std::string_view const old_path)
144
- {
145
- llvm::SmallString<128 > new_path (old_path);
146
- if (! llvm::sys::path::is_absolute (new_path))
147
- {
148
- // KRYSTIAN FIXME: use FileManager::makeAbsolutePath?
149
- auto const & cwd = source_.getFileManager ().
150
- getFileSystemOpts ().WorkingDir ;
151
- // we can't normalize a relative path
152
- // without a base directory
153
- // MRDOCS_ASSERT(! cwd.empty());
154
- llvm::sys::fs::make_absolute (cwd, new_path);
155
- }
156
- // remove ./ and ../
157
- llvm::sys::path::remove_dots (new_path, true , llvm::sys::path::Style::posix);
158
- // convert to posix style
159
- llvm::sys::path::native (new_path, llvm::sys::path::Style::posix);
160
- return std::string (new_path);
161
- };
162
-
127
+ // Store the search directories
128
+ auto const & cwd = source_.getFileManager ().getFileSystemOpts ().WorkingDir ;
163
129
Preprocessor& PP = sema_.getPreprocessor ();
164
130
HeaderSearch& HS = PP.getHeaderSearchInfo ();
165
- std::vector<std::pair<std::string, FileKind>> search_dirs;
166
- search_dirs.reserve (HS.search_dir_size ());
131
+ search_dirs_.reserve (HS.search_dir_size ());
167
132
// first, convert all the include search directories into POSIX style
168
133
for (const DirectoryLookup& DL : HS.search_dir_range ())
169
134
{
170
135
OptionalDirectoryEntryRef DR = DL.getDirRef ();
171
136
// only consider normal directories
172
- if (! DL.isNormalDir () || ! DR)
137
+ if (!DL.isNormalDir () || !DR)
138
+ {
173
139
continue ;
140
+ }
174
141
// store the normalized path
175
- search_dirs.emplace_back (
176
- make_posix_absolute (DR->getName ()),
177
- DL.isSystemHeaderDirectory () ?
178
- FileKind::System : FileKind::Other);
179
- }
180
-
181
- std::string const sourceRoot = make_posix_absolute (config_->sourceRoot );
182
- auto cacheFileInfo = [&](const FileEntry* entry)
183
- {
184
- // "try" implies this may fail, so fallback to getName
185
- // if an empty string is returned
186
- std::string_view file_path =
187
- entry->tryGetRealPathName ();
188
- files_.emplace (
189
- entry,
190
- FileInfo::build (
191
- search_dirs,
192
- make_posix_absolute (file_path),
193
- sourceRoot));
142
+ auto normPath = files::makePosixStyle (files::makeAbsolute (DR->getName (), cwd));
143
+ search_dirs_.push_back (std::move (normPath));
144
+ }
145
+
146
+ // Store preprocessed information about all file entries
147
+ std::string const sourceRoot = files::makePosixStyle (files::makeAbsolute (config_->sourceRoot , cwd));
148
+ auto cacheFileInfo = [&](FileEntry const * entry) {
149
+ std::string_view const file_path = entry->tryGetRealPathName ();
150
+ MRDOCS_CHECK_OR (!file_path.empty ());
151
+ auto const normPath = files::makePosixStyle (
152
+ files::makeAbsolute (file_path, cwd));
153
+ auto FI = FileInfo::build (search_dirs_, normPath, sourceRoot);
154
+ files_.emplace (entry, FI);
194
155
};
195
-
196
- // build the file info for the main file
197
- cacheFileInfo (source_.getFileEntryForID (source_.getMainFileID ()));
198
-
199
- // build the file info for all included files
156
+ FileEntry const * mainFileEntry = source_.getFileEntryForID (source_.getMainFileID ());
157
+ cacheFileInfo (mainFileEntry);
200
158
for (const FileEntry* file : PP.getIncludedFiles ())
201
159
{
202
160
cacheFileInfo (file);
@@ -829,9 +787,7 @@ populate(
829
787
{
830
788
return ;
831
789
}
832
- I.DefLoc .emplace (file->full_path ,
833
- file->short_path , line, file->kind ,
834
- documented);
790
+ I.DefLoc .emplace (file->full_path , file->short_path , line, documented);
835
791
}
836
792
else
837
793
{
@@ -846,9 +802,7 @@ populate(
846
802
{
847
803
return ;
848
804
}
849
- I.Loc .emplace_back (file->full_path ,
850
- file->short_path , line, file->kind ,
851
- documented);
805
+ I.Loc .emplace_back (file->full_path , file->short_path , line, documented);
852
806
}
853
807
}
854
808
0 commit comments