1*9379d19fSRaphael Isemann //===-- CppModuleConfiguration.cpp ----------------------------------------===//
2*9379d19fSRaphael Isemann //
3*9379d19fSRaphael Isemann // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*9379d19fSRaphael Isemann // See https://llvm.org/LICENSE.txt for license information.
5*9379d19fSRaphael Isemann // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*9379d19fSRaphael Isemann //
7*9379d19fSRaphael Isemann //===----------------------------------------------------------------------===//
8*9379d19fSRaphael Isemann 
9*9379d19fSRaphael Isemann #include "CppModuleConfiguration.h"
10*9379d19fSRaphael Isemann 
11*9379d19fSRaphael Isemann #include "ClangHost.h"
12*9379d19fSRaphael Isemann #include "lldb/Host/FileSystem.h"
13*9379d19fSRaphael Isemann 
14*9379d19fSRaphael Isemann using namespace lldb_private;
15*9379d19fSRaphael Isemann 
16*9379d19fSRaphael Isemann bool CppModuleConfiguration::SetOncePath::TrySet(llvm::StringRef path) {
17*9379d19fSRaphael Isemann   // Setting for the first time always works.
18*9379d19fSRaphael Isemann   if (m_first) {
19*9379d19fSRaphael Isemann     m_path = path.str();
20*9379d19fSRaphael Isemann     m_valid = true;
21*9379d19fSRaphael Isemann     m_first = false;
22*9379d19fSRaphael Isemann     return true;
23*9379d19fSRaphael Isemann   }
24*9379d19fSRaphael Isemann   // Changing the path to the same value is fine.
25*9379d19fSRaphael Isemann   if (m_path == path)
26*9379d19fSRaphael Isemann     return true;
27*9379d19fSRaphael Isemann 
28*9379d19fSRaphael Isemann   // Changing the path after it was already set is not allowed.
29*9379d19fSRaphael Isemann   m_valid = false;
30*9379d19fSRaphael Isemann   return false;
31*9379d19fSRaphael Isemann }
32*9379d19fSRaphael Isemann 
33*9379d19fSRaphael Isemann bool CppModuleConfiguration::analyzeFile(const FileSpec &f) {
34*9379d19fSRaphael Isemann   llvm::SmallString<256> dir_buffer = f.GetDirectory().GetStringRef();
35*9379d19fSRaphael Isemann   // Convert to posix style so that we can use '/'.
36*9379d19fSRaphael Isemann   llvm::sys::path::native(dir_buffer, llvm::sys::path::Style::posix);
37*9379d19fSRaphael Isemann   llvm::StringRef posix_dir(dir_buffer);
38*9379d19fSRaphael Isemann 
39*9379d19fSRaphael Isemann   // Check for /c++/vX/ that is used by libc++.
40*9379d19fSRaphael Isemann   static llvm::Regex libcpp_regex(R"regex(/c[+][+]/v[0-9]/)regex");
41*9379d19fSRaphael Isemann   if (libcpp_regex.match(f.GetPath())) {
42*9379d19fSRaphael Isemann     // Strip away libc++'s /experimental directory if there is one.
43*9379d19fSRaphael Isemann     posix_dir.consume_back("/experimental");
44*9379d19fSRaphael Isemann     return m_std_inc.TrySet(posix_dir);
45*9379d19fSRaphael Isemann   }
46*9379d19fSRaphael Isemann 
47*9379d19fSRaphael Isemann   // Check for /usr/include. On Linux this might be /usr/include/bits, so
48*9379d19fSRaphael Isemann   // we should remove that '/bits' suffix to get the actual include directory.
49*9379d19fSRaphael Isemann   if (posix_dir.endswith("/usr/include/bits"))
50*9379d19fSRaphael Isemann     posix_dir.consume_back("/bits");
51*9379d19fSRaphael Isemann   if (posix_dir.endswith("/usr/include"))
52*9379d19fSRaphael Isemann     return m_c_inc.TrySet(posix_dir);
53*9379d19fSRaphael Isemann 
54*9379d19fSRaphael Isemann   // File wasn't interesting, continue analyzing.
55*9379d19fSRaphael Isemann   return true;
56*9379d19fSRaphael Isemann }
57*9379d19fSRaphael Isemann 
58*9379d19fSRaphael Isemann bool CppModuleConfiguration::hasValidConfig() {
59*9379d19fSRaphael Isemann   // We all these include directories to have a valid usable configuration.
60*9379d19fSRaphael Isemann   return m_c_inc.Valid() && m_std_inc.Valid();
61*9379d19fSRaphael Isemann }
62*9379d19fSRaphael Isemann 
63*9379d19fSRaphael Isemann CppModuleConfiguration::CppModuleConfiguration(
64*9379d19fSRaphael Isemann     const FileSpecList &support_files) {
65*9379d19fSRaphael Isemann   // Analyze all files we were given to build the configuration.
66*9379d19fSRaphael Isemann   bool error = !std::all_of(support_files.begin(), support_files.end(),
67*9379d19fSRaphael Isemann                             std::bind(&CppModuleConfiguration::analyzeFile,
68*9379d19fSRaphael Isemann                                       this, std::placeholders::_1));
69*9379d19fSRaphael Isemann   // If we have a valid configuration at this point, set the
70*9379d19fSRaphael Isemann   // include directories and module list that should be used.
71*9379d19fSRaphael Isemann   if (!error && hasValidConfig()) {
72*9379d19fSRaphael Isemann     // Calculate the resource directory for LLDB.
73*9379d19fSRaphael Isemann     llvm::SmallString<256> resource_dir;
74*9379d19fSRaphael Isemann     llvm::sys::path::append(resource_dir, GetClangResourceDir().GetPath(),
75*9379d19fSRaphael Isemann                             "include");
76*9379d19fSRaphael Isemann     m_resource_inc = resource_dir.str();
77*9379d19fSRaphael Isemann 
78*9379d19fSRaphael Isemann     // This order matches the way Clang orders these directories.
79*9379d19fSRaphael Isemann     m_include_dirs = {m_std_inc.Get(), m_resource_inc, m_c_inc.Get()};
80*9379d19fSRaphael Isemann     m_imported_modules = {"std"};
81*9379d19fSRaphael Isemann   }
82*9379d19fSRaphael Isemann }
83