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