3636#include < llvm/Support/Error.h>
3737#include < llvm/Support/Path.h>
3838#include < llvm/Support/SHA1.h>
39+ #include < llvm/Support/Process.h>
3940#include < memory>
4041#include < optional>
4142#include < ranges>
4243#include < unordered_set>
4344
4445namespace clang ::mrdocs {
4546
46- auto
47+ ASTVisitor::FileInfo
4748ASTVisitor::FileInfo::build (
48- std::span<std::pair<std:: string, FileKind > const > /* search_dirs */ ,
49+ std::span<std::string> const search_dirs,
4950 std::string_view const file_path,
50- std::string_view const sourceRoot) -> ASTVisitor::FileInfo {
51+ std::string_view const sourceRoot) {
5152 FileInfo file_info;
5253 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) ;
5455
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)
5958 {
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))
6660 {
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 ( ' / ' ) )
6963 {
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 );
8065 }
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;
8967 }
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+ }
10669
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))
11072 {
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;
11279 }
11380
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+ }
11599 return file_info;
116100}
117101
@@ -140,63 +124,37 @@ ASTVisitor(
140124 MRDOCS_ASSERT (context_.getTraversalScope () ==
141125 std::vector<Decl*>{context_.getTranslationUnitDecl ()});
142126
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 ;
163129 Preprocessor& PP = sema_.getPreprocessor ();
164130 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 ());
167132 // first, convert all the include search directories into POSIX style
168133 for (const DirectoryLookup& DL : HS.search_dir_range ())
169134 {
170135 OptionalDirectoryEntryRef DR = DL.getDirRef ();
171136 // only consider normal directories
172- if (! DL.isNormalDir () || ! DR)
137+ if (!DL.isNormalDir () || !DR)
138+ {
173139 continue ;
140+ }
174141 // 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);
194155 };
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);
200158 for (const FileEntry* file : PP.getIncludedFiles ())
201159 {
202160 cacheFileInfo (file);
@@ -829,9 +787,7 @@ populate(
829787 {
830788 return ;
831789 }
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);
835791 }
836792 else
837793 {
@@ -846,9 +802,7 @@ populate(
846802 {
847803 return ;
848804 }
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);
852806 }
853807}
854808
0 commit comments