Skip to content

Commit 487720f

Browse files
authored
Reapply "[InstallAPI] Add --extra* and --exclude* cli options for header input (#86522)" (#86574)
1 parent 7c8f754 commit 487720f

File tree

23 files changed

+3931
-2
lines changed

23 files changed

+3931
-2
lines changed

clang/include/clang/Basic/DiagnosticInstallAPIKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ let CategoryName = "Command line" in {
1515
def err_cannot_write_file : Error<"cannot write file '%0': %1">;
1616
def err_no_install_name : Error<"no install name specified: add -install_name <path>">;
1717
def err_no_output_file: Error<"no output file specified">;
18+
def err_no_such_header_file : Error<"no such %select{public|private|project}1 header file: '%0'">;
19+
def warn_no_such_excluded_header_file : Warning<"no such excluded %select{public|private}0 header file: '%1'">, InGroup<InstallAPIViolation>;
20+
def warn_glob_did_not_match: Warning<"glob '%0' did not match any header file">, InGroup<InstallAPIViolation>;
1821
} // end of command line category.
1922

2023
let CategoryName = "Verification" in {

clang/include/clang/InstallAPI/HeaderFile.h

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
#ifndef LLVM_CLANG_INSTALLAPI_HEADERFILE_H
1414
#define LLVM_CLANG_INSTALLAPI_HEADERFILE_H
1515

16+
#include "clang/Basic/FileManager.h"
1617
#include "clang/Basic/LangStandard.h"
18+
#include "clang/InstallAPI/MachO.h"
1719
#include "llvm/ADT/StringRef.h"
1820
#include "llvm/Support/ErrorHandling.h"
1921
#include "llvm/Support/Regex.h"
@@ -56,6 +58,10 @@ class HeaderFile {
5658
std::string IncludeName;
5759
/// Supported language mode for header.
5860
std::optional<clang::Language> Language;
61+
/// Exclude header file from processing.
62+
bool Excluded{false};
63+
/// Add header file to processing.
64+
bool Extra{false};
5965

6066
public:
6167
HeaderFile() = delete;
@@ -71,17 +77,48 @@ class HeaderFile {
7177
StringRef getIncludeName() const { return IncludeName; }
7278
StringRef getPath() const { return FullPath; }
7379

80+
void setExtra(bool V = true) { Extra = V; }
81+
void setExcluded(bool V = true) { Excluded = V; }
82+
bool isExtra() const { return Extra; }
83+
bool isExcluded() const { return Excluded; }
84+
7485
bool useIncludeName() const {
7586
return Type != HeaderType::Project && !IncludeName.empty();
7687
}
7788

7889
bool operator==(const HeaderFile &Other) const {
79-
return std::tie(Type, FullPath, IncludeName, Language) ==
90+
return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra) ==
8091
std::tie(Other.Type, Other.FullPath, Other.IncludeName,
81-
Other.Language);
92+
Other.Language, Other.Excluded, Other.Extra);
8293
}
8394
};
8495

96+
/// Glob that represents a pattern of header files to retreive.
97+
class HeaderGlob {
98+
private:
99+
std::string GlobString;
100+
llvm::Regex Rule;
101+
HeaderType Type;
102+
bool FoundMatch{false};
103+
104+
public:
105+
HeaderGlob(StringRef GlobString, llvm::Regex &&, HeaderType Type);
106+
107+
/// Create a header glob from string for the header access level.
108+
static llvm::Expected<std::unique_ptr<HeaderGlob>>
109+
create(StringRef GlobString, HeaderType Type);
110+
111+
/// Query if provided header matches glob.
112+
bool match(const HeaderFile &Header);
113+
114+
/// Query if a header was matched in the glob, used primarily for error
115+
/// reporting.
116+
bool didMatch() { return FoundMatch; }
117+
118+
/// Provide back input glob string.
119+
StringRef str() { return GlobString; }
120+
};
121+
85122
/// Assemble expected way header will be included by clients.
86123
/// As in what maps inside the brackets of `#include <IncludeName.h>`
87124
/// For example,
@@ -93,6 +130,19 @@ class HeaderFile {
93130
std::optional<std::string> createIncludeHeaderName(const StringRef FullPath);
94131
using HeaderSeq = std::vector<HeaderFile>;
95132

133+
/// Determine if Path is a header file.
134+
/// It does not touch the file system.
135+
///
136+
/// \param Path File path to file.
137+
bool isHeaderFile(StringRef Path);
138+
139+
/// Given input directory, collect all header files.
140+
///
141+
/// \param FM FileManager for finding input files.
142+
/// \param Directory Path to directory file.
143+
llvm::Expected<PathSeq> enumerateFiles(clang::FileManager &FM,
144+
StringRef Directory);
145+
96146
} // namespace clang::installapi
97147

98148
#endif // LLVM_CLANG_INSTALLAPI_HEADERFILE_H

clang/include/clang/InstallAPI/MachO.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ using SymbolSet = llvm::MachO::SymbolSet;
4040
using SimpleSymbol = llvm::MachO::SimpleSymbol;
4141
using FileType = llvm::MachO::FileType;
4242
using PackedVersion = llvm::MachO::PackedVersion;
43+
using PathSeq = llvm::MachO::PathSeq;
4344
using Target = llvm::MachO::Target;
4445
using TargetList = llvm::MachO::TargetList;
4546

clang/lib/InstallAPI/Frontend.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ std::unique_ptr<MemoryBuffer> createInputBuffer(InstallAPIContext &Ctx) {
138138
SmallString<4096> Contents;
139139
raw_svector_ostream OS(Contents);
140140
for (const HeaderFile &H : Ctx.InputHeaders) {
141+
if (H.isExcluded())
142+
continue;
141143
if (H.getType() != Ctx.Type)
142144
continue;
143145
if (Ctx.LangMode == Language::C || Ctx.LangMode == Language::CXX)

clang/lib/InstallAPI/HeaderFile.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "clang/InstallAPI/HeaderFile.h"
10+
#include "llvm/TextAPI/Utils.h"
1011

1112
using namespace llvm;
1213
namespace clang::installapi {
@@ -34,4 +35,54 @@ std::optional<std::string> createIncludeHeaderName(const StringRef FullPath) {
3435
return Matches[1].drop_front(Matches[1].rfind('/') + 1).str() + "/" +
3536
Matches[3].str();
3637
}
38+
39+
bool isHeaderFile(StringRef Path) {
40+
return StringSwitch<bool>(sys::path::extension(Path))
41+
.Cases(".h", ".H", ".hh", ".hpp", ".hxx", true)
42+
.Default(false);
43+
}
44+
45+
llvm::Expected<PathSeq> enumerateFiles(FileManager &FM, StringRef Directory) {
46+
PathSeq Files;
47+
std::error_code EC;
48+
auto &FS = FM.getVirtualFileSystem();
49+
for (llvm::vfs::recursive_directory_iterator i(FS, Directory, EC), ie;
50+
i != ie; i.increment(EC)) {
51+
if (EC)
52+
return errorCodeToError(EC);
53+
54+
// Skip files that do not exist. This usually happens for broken symlinks.
55+
if (FS.status(i->path()) == std::errc::no_such_file_or_directory)
56+
continue;
57+
58+
StringRef Path = i->path();
59+
if (isHeaderFile(Path))
60+
Files.emplace_back(Path);
61+
}
62+
63+
return Files;
64+
}
65+
66+
HeaderGlob::HeaderGlob(StringRef GlobString, Regex &&Rule, HeaderType Type)
67+
: GlobString(GlobString), Rule(std::move(Rule)), Type(Type) {}
68+
69+
bool HeaderGlob::match(const HeaderFile &Header) {
70+
if (Header.getType() != Type)
71+
return false;
72+
73+
bool Match = Rule.match(Header.getPath());
74+
if (Match)
75+
FoundMatch = true;
76+
return Match;
77+
}
78+
79+
Expected<std::unique_ptr<HeaderGlob>> HeaderGlob::create(StringRef GlobString,
80+
HeaderType Type) {
81+
auto Rule = MachO::createRegexFromGlob(GlobString);
82+
if (!Rule)
83+
return Rule.takeError();
84+
85+
return std::make_unique<HeaderGlob>(GlobString, std::move(*Rule), Type);
86+
}
87+
3788
} // namespace clang::installapi
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extern int extraGlobalAPI1;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extern int extraGlobalAPI2;
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#import <Foundation/Foundation.h>
2+
3+
// Basic class with no super class
4+
@interface Basic1
5+
@end
6+
7+
@interface Basic2 : NSObject
8+
@end
9+
10+
@interface Basic3 : NSObject
11+
@property BOOL property1;
12+
@property(readonly) BOOL property2;
13+
@property(getter=isProperty3) BOOL property3;
14+
@property BOOL dynamicProp;
15+
@end
16+
17+
@interface Basic4 : NSObject {
18+
@public
19+
BOOL ivar1;
20+
@protected
21+
BOOL ivar2;
22+
@package
23+
BOOL ivar3;
24+
@private
25+
BOOL ivar4;
26+
}
27+
@end
28+
29+
__attribute__((visibility("hidden"))) @interface Basic4_1 : NSObject {
30+
@public
31+
BOOL ivar1;
32+
@protected
33+
BOOL ivar2;
34+
@package
35+
BOOL ivar3;
36+
@private
37+
BOOL ivar4;
38+
}
39+
@end
40+
41+
@interface Basic4_2 : NSObject {
42+
@private
43+
BOOL ivar4;
44+
@package
45+
BOOL ivar3;
46+
@protected
47+
BOOL ivar2;
48+
@public
49+
BOOL ivar1;
50+
}
51+
@end
52+
53+
@interface Basic5 : NSObject
54+
+ (void)aClassMethod;
55+
- (void)anInstanceMethod;
56+
@end
57+
58+
@interface Basic6 : NSObject
59+
@end
60+
61+
@interface Basic6 () {
62+
@public
63+
BOOL ivar1;
64+
}
65+
@property BOOL property1;
66+
- (void)anInstanceMethodFromAnExtension;
67+
@end
68+
69+
@interface Basic6 (Foo)
70+
@property BOOL property2;
71+
- (void)anInstanceMethodFromACategory;
72+
@end
73+
74+
__attribute__((visibility("hidden")))
75+
@interface Basic7 : NSObject
76+
@end
77+
78+
@interface Basic7 ()
79+
- (void) anInstanceMethodFromAnHiddenExtension;
80+
@end
81+
82+
@interface Basic8 : NSObject
83+
+ (void)useSameName;
84+
@end
85+
86+
// Classes and protocols can have the same name. For now they would only clash
87+
// in the selector map if the protocl starts with '_'.
88+
@protocol _A
89+
- (void)aMethod;
90+
@end
91+
92+
@interface A : NSObject
93+
- (void)aMethod NS_AVAILABLE(10_11, 9_0);
94+
- (void)bMethod NS_UNAVAILABLE;
95+
@end
96+
97+
@interface Basic9 : NSObject
98+
@property(readonly) BOOL aProperty NS_AVAILABLE(10_10, 8_0);
99+
@end
100+
101+
@interface Basic9 (deprecated)
102+
@property(readwrite) BOOL aProperty NS_DEPRECATED_MAC(10_8, 10_10);
103+
@end
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#import <Foundation/Foundation.h>
2+
3+
// Sub-class an external defined ObjC Class.
4+
@interface ExternalManagedObject : NSManagedObject
5+
- (void)foo;
6+
@end
7+
8+
// Add category to external defined ObjC Class.
9+
@interface NSManagedObject (Simple)
10+
- (int)supportsSimple;
11+
@end
12+
13+
// CoreData Accessors are dynamically generated and have no implementation.
14+
@interface ExternalManagedObject (CoreDataGeneratedAccessors)
15+
- (void)addChildObject:(ExternalManagedObject *)value;
16+
- (void)removeChildObject:(ExternalManagedObject *)value;
17+
- (void)addChild:(NSSet *)values;
18+
- (void)removeChild:(NSSet *)values;
19+
@end
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#import <Foundation/Foundation.h>
2+
3+
// Useless forward declaration. This is used for testing.
4+
@class FooBar;
5+
@protocol FooProtocol;
6+
7+
@protocol ForwardProcotol;
8+
9+
// Test public global.
10+
extern int publicGlobalVariable;
11+
12+
// Test weak public global.
13+
extern int weakPublicGlobalVariable __attribute__((weak));
14+
15+
// Test public ObjC class
16+
@interface Simple : NSObject
17+
@end
18+
19+
__attribute__((objc_exception))
20+
@interface Base : NSObject
21+
@end
22+
23+
@interface SubClass : Base
24+
@end
25+
26+
@protocol BaseProtocol
27+
- (void) baseMethod;
28+
@end
29+
30+
NS_AVAILABLE(10_11, 9_0)
31+
@protocol FooProtocol <BaseProtocol>
32+
- (void) protocolMethod;
33+
@end
34+
35+
@protocol BarProtocol
36+
- (void) barMethod;
37+
@end
38+
39+
@interface FooClass <FooProtocol, BarProtocol>
40+
@end
41+
42+
// Create an empty category conforms to a forward declared protocol.
43+
// <rdar://problem/35605892>
44+
@interface FooClass (Test) <ForwardProcotol>
45+
@end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extern int otherFrameworkAPI;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Test private global variable.
2+
extern int privateGlobalVariable;
3+
4+
// Test weak private global.
5+
extern int weakPrivateGlobalVariable __attribute__((weak));
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Test private global variable.
2+
extern int otherFrameworkSPI;

0 commit comments

Comments
 (0)