1 //===--- extra/modularize/ModularizeUtilities.cpp -------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements a class for loading and validating a module map or
11 // header list by checking that all headers in the corresponding directories
12 // are accounted for.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "ModularizeUtilities.h"
17 #include "llvm/ADT/SmallString.h"
18 #include "llvm/Support/FileUtilities.h"
19 #include "llvm/Support/MemoryBuffer.h"
20 #include "llvm/Support/Path.h"
21 #include "llvm/Support/raw_ostream.h"
22 
23 using namespace llvm;
24 using namespace Modularize;
25 
26 // ModularizeUtilities class implementation.
27 
28 // Constructor.
29 ModularizeUtilities::ModularizeUtilities(std::vector<std::string> &InputPaths,
30                                          llvm::StringRef Prefix)
31     : InputFilePaths(InputPaths),
32       HeaderPrefix(Prefix) {}
33 
34 // Create instance of ModularizeUtilities, to simplify setting up
35 // subordinate objects.
36 ModularizeUtilities *ModularizeUtilities::createModularizeUtilities(
37     std::vector<std::string> &InputPaths, llvm::StringRef Prefix) {
38 
39   return new ModularizeUtilities(InputPaths, Prefix);
40 }
41 
42 // Load all header lists and dependencies.
43 std::error_code ModularizeUtilities::loadAllHeaderListsAndDependencies() {
44   typedef std::vector<std::string>::iterator Iter;
45   for (Iter I = InputFilePaths.begin(), E = InputFilePaths.end(); I != E; ++I) {
46     if (std::error_code EC = loadSingleHeaderListsAndDependencies(*I)) {
47       errs() << "modularize: error: Unable to get header list '" << *I
48         << "': " << EC.message() << '\n';
49       return EC;
50     }
51   }
52   return std::error_code();
53 }
54 
55 // Load single header list and dependencies.
56 std::error_code ModularizeUtilities::loadSingleHeaderListsAndDependencies(
57     llvm::StringRef InputPath) {
58 
59   // By default, use the path component of the list file name.
60   SmallString<256> HeaderDirectory(InputPath);
61   llvm::sys::path::remove_filename(HeaderDirectory);
62   SmallString<256> CurrentDirectory;
63   llvm::sys::fs::current_path(CurrentDirectory);
64 
65   // Get the prefix if we have one.
66   if (HeaderPrefix.size() != 0)
67     HeaderDirectory = HeaderPrefix;
68 
69   // Read the header list file into a buffer.
70   ErrorOr<std::unique_ptr<MemoryBuffer>> listBuffer =
71     MemoryBuffer::getFile(InputPath);
72   if (std::error_code EC = listBuffer.getError())
73     return EC;
74 
75   // Parse the header list into strings.
76   SmallVector<StringRef, 32> Strings;
77   listBuffer.get()->getBuffer().split(Strings, "\n", -1, false);
78 
79   // Collect the header file names from the string list.
80   for (SmallVectorImpl<StringRef>::iterator I = Strings.begin(),
81     E = Strings.end();
82     I != E; ++I) {
83     StringRef Line = I->trim();
84     // Ignore comments and empty lines.
85     if (Line.empty() || (Line[0] == '#'))
86       continue;
87     std::pair<StringRef, StringRef> TargetAndDependents = Line.split(':');
88     SmallString<256> HeaderFileName;
89     // Prepend header file name prefix if it's not absolute.
90     if (llvm::sys::path::is_absolute(TargetAndDependents.first))
91       llvm::sys::path::native(TargetAndDependents.first, HeaderFileName);
92     else {
93       if (HeaderDirectory.size() != 0)
94         HeaderFileName = HeaderDirectory;
95       else
96         HeaderFileName = CurrentDirectory;
97       llvm::sys::path::append(HeaderFileName, TargetAndDependents.first);
98       llvm::sys::path::native(HeaderFileName);
99     }
100     // Handle optional dependencies.
101     DependentsVector Dependents;
102     SmallVector<StringRef, 4> DependentsList;
103     TargetAndDependents.second.split(DependentsList, " ", -1, false);
104     int Count = DependentsList.size();
105     for (int Index = 0; Index < Count; ++Index) {
106       SmallString<256> Dependent;
107       if (llvm::sys::path::is_absolute(DependentsList[Index]))
108         Dependent = DependentsList[Index];
109       else {
110         if (HeaderDirectory.size() != 0)
111           Dependent = HeaderDirectory;
112         else
113           Dependent = CurrentDirectory;
114         llvm::sys::path::append(Dependent, DependentsList[Index]);
115       }
116       llvm::sys::path::native(Dependent);
117       Dependents.push_back(Dependent.str());
118     }
119     // Save the resulting header file path and dependencies.
120     HeaderFileNames.push_back(HeaderFileName.str());
121     Dependencies[HeaderFileName.str()] = Dependents;
122   }
123   return std::error_code();
124 }
125