Skip to content

Commit feed66f

Browse files
authored
[InstallAPI] Pick up input headers by directory traversal (#94508)
Match TAPI behavior and allow input headers to be resolved via a passed directory, which is expected to be a library sitting in a build directory.
1 parent 445fc51 commit feed66f

19 files changed

+703
-24
lines changed

clang/include/clang/Basic/DiagnosticInstallAPIKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ def err_unsupported_environment : Error<"environment '%0' is not supported: '%1'
2626
def err_unsupported_os : Error<"os '%0' is not supported: '%1'">;
2727
def err_cannot_read_input_list : Error<"could not read %0 input list '%1': %2">;
2828
def err_invalid_label: Error<"label '%0' is reserved: use a different label name for -X<label>">;
29+
def err_directory_scanning: Error<"could not read directory '%0': %1">;
30+
def err_more_than_one_library: Error<"more than one framework/dynamic library found">;
2931
} // end of command line category.
3032

3133
let CategoryName = "Verification" in {
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//===- InstallAPI/DirectoryScanner.h ----------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
///
9+
/// The DirectoryScanner for collecting library files on the file system.
10+
///
11+
//===----------------------------------------------------------------------===//
12+
#ifndef LLVM_CLANG_INSTALLAPI_DIRECTORYSCANNER_H
13+
#define LLVM_CLANG_INSTALLAPI_DIRECTORYSCANNER_H
14+
15+
#include "clang/Basic/FileManager.h"
16+
#include "clang/InstallAPI/Library.h"
17+
18+
namespace clang::installapi {
19+
20+
enum ScanMode {
21+
/// Scanning Framework directory.
22+
ScanFrameworks,
23+
/// Scanning Dylib directory.
24+
ScanDylibs,
25+
};
26+
27+
class DirectoryScanner {
28+
public:
29+
DirectoryScanner(FileManager &FM, ScanMode Mode = ScanMode::ScanFrameworks)
30+
: FM(FM), Mode(Mode) {}
31+
32+
/// Scan for all input files throughout directory.
33+
///
34+
/// \param Directory Path of input directory.
35+
llvm::Error scan(StringRef Directory);
36+
37+
/// Take over ownership of stored libraries.
38+
std::vector<Library> takeLibraries() { return std::move(Libraries); };
39+
40+
/// Get all the header files in libraries.
41+
///
42+
/// \param Libraries Reference of collection of libraries.
43+
static HeaderSeq getHeaders(ArrayRef<Library> Libraries);
44+
45+
private:
46+
/// Collect files for dylibs in usr/(local)/lib within directory.
47+
llvm::Error scanForUnwrappedLibraries(StringRef Directory);
48+
49+
/// Collect files for any frameworks within directory.
50+
llvm::Error scanForFrameworks(StringRef Directory);
51+
52+
/// Get a library from the libraries collection.
53+
Library &getOrCreateLibrary(StringRef Path, std::vector<Library> &Libs) const;
54+
55+
/// Collect multiple frameworks from directory.
56+
llvm::Error scanMultipleFrameworks(StringRef Directory,
57+
std::vector<Library> &Libs) const;
58+
/// Collect files from nested frameworks.
59+
llvm::Error scanSubFrameworksDirectory(StringRef Directory,
60+
std::vector<Library> &Libs) const;
61+
62+
/// Collect files from framework path.
63+
llvm::Error scanFrameworkDirectory(StringRef Path, Library &Framework) const;
64+
65+
/// Collect header files from path.
66+
llvm::Error scanHeaders(StringRef Path, Library &Lib, HeaderType Type,
67+
StringRef BasePath,
68+
StringRef ParentPath = StringRef()) const;
69+
70+
/// Collect files from Version directories inside Framework directories.
71+
llvm::Error scanFrameworkVersionsDirectory(StringRef Path,
72+
Library &Lib) const;
73+
FileManager &FM;
74+
ScanMode Mode;
75+
StringRef RootPath;
76+
std::vector<Library> Libraries;
77+
};
78+
79+
} // namespace clang::installapi
80+
81+
#endif // LLVM_CLANG_INSTALLAPI_DIRECTORYSCANNER_H

clang/include/clang/InstallAPI/HeaderFile.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,19 @@ class HeaderFile {
9797
Other.Excluded, Other.Extra,
9898
Other.Umbrella);
9999
}
100+
101+
bool operator<(const HeaderFile &Other) const {
102+
/// For parsing of headers based on ordering,
103+
/// group by type, then whether its an umbrella.
104+
/// Capture 'extra' headers last.
105+
/// This optimizes the chance of a sucessful parse for
106+
/// headers that violate IWYU.
107+
if (isExtra() && Other.isExtra())
108+
return std::tie(Type, Umbrella) < std::tie(Other.Type, Other.Umbrella);
109+
110+
return std::tie(Type, Umbrella, Extra, FullPath) <
111+
std::tie(Other.Type, Other.Umbrella, Other.Extra, Other.FullPath);
112+
}
100113
};
101114

102115
/// Glob that represents a pattern of header files to retreive.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//===- InstallAPI/Library.h -------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
///
9+
/// Defines the content of a library, such as public and private
10+
/// header files, and whether it is a framework.
11+
///
12+
//===----------------------------------------------------------------------===//
13+
#ifndef LLVM_CLANG_INSTALLAPI_LIBRARY_H
14+
#define LLVM_CLANG_INSTALLAPI_LIBRARY_H
15+
16+
#include "clang/InstallAPI/HeaderFile.h"
17+
#include "clang/InstallAPI/MachO.h"
18+
19+
namespace clang::installapi {
20+
21+
class Library {
22+
public:
23+
Library(StringRef Directory) : BaseDirectory(Directory) {}
24+
25+
/// Capture the name of the framework by the install name.
26+
///
27+
/// \param InstallName The install name of the library encoded in a dynamic
28+
/// library.
29+
static StringRef getFrameworkNameFromInstallName(StringRef InstallName);
30+
31+
/// Get name of library by the discovered file path.
32+
StringRef getName() const;
33+
34+
/// Get discovered path of library.
35+
StringRef getPath() const { return BaseDirectory; }
36+
37+
/// Add a header file that belongs to the library.
38+
///
39+
/// \param FullPath Path to header file.
40+
/// \param Type Access level of header.
41+
/// \param IncludePath The way the header should be included.
42+
void addHeaderFile(StringRef FullPath, HeaderType Type,
43+
StringRef IncludePath = StringRef()) {
44+
Headers.emplace_back(FullPath, Type, IncludePath);
45+
}
46+
47+
/// Determine if library is empty.
48+
bool empty() {
49+
return SubFrameworks.empty() && Headers.empty() &&
50+
FrameworkVersions.empty();
51+
}
52+
53+
private:
54+
std::string BaseDirectory;
55+
HeaderSeq Headers;
56+
std::vector<Library> SubFrameworks;
57+
std::vector<Library> FrameworkVersions;
58+
bool IsUnwrappedDylib{false};
59+
60+
friend class DirectoryScanner;
61+
};
62+
63+
} // namespace clang::installapi
64+
65+
#endif // LLVM_CLANG_INSTALLAPI_LIBRARY_H

clang/include/clang/InstallAPI/MachO.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ using RecordLinkage = llvm::MachO::RecordLinkage;
3131
using Record = llvm::MachO::Record;
3232
using EncodeKind = llvm::MachO::EncodeKind;
3333
using GlobalRecord = llvm::MachO::GlobalRecord;
34+
using InterfaceFile = llvm::MachO::InterfaceFile;
3435
using ObjCContainerRecord = llvm::MachO::ObjCContainerRecord;
3536
using ObjCInterfaceRecord = llvm::MachO::ObjCInterfaceRecord;
3637
using ObjCCategoryRecord = llvm::MachO::ObjCCategoryRecord;

clang/lib/InstallAPI/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ set(LLVM_LINK_COMPONENTS
88

99
add_clang_library(clangInstallAPI
1010
DiagnosticBuilderWrappers.cpp
11+
DirectoryScanner.cpp
1112
DylibVerifier.cpp
1213
FileList.cpp
1314
Frontend.cpp
1415
HeaderFile.cpp
16+
Library.cpp
1517
Visitor.cpp
1618

1719
LINK_LIBS

0 commit comments

Comments
 (0)