Skip to content

Commit 791fe26

Browse files
[clang][ExtractAPI] Allow users to specify a list of symbols to ignore
Adds a `--extract-api-ignores=` command line option that allows users to provide a file containing a new line separated list of symbols to unconditionally ignore when extracting API information. Differential Revision: https://reviews.llvm.org/D136450
1 parent 1fe096e commit 791fe26

File tree

14 files changed

+211
-3
lines changed

14 files changed

+211
-3
lines changed

clang/include/clang/Basic/DiagnosticFrontendKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,4 +331,7 @@ def warn_profile_data_misexpect : Warning<
331331
InGroup<MisExpect>;
332332
} // end of instrumentation issue category
333333

334+
def err_extract_api_ignores_file_not_found :
335+
Error<"file '%0' specified by '--extract-api-ignores=' not found">, DefaultFatal;
336+
334337
}

clang/include/clang/Driver/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,9 @@ def extract_api : Flag<["-"], "extract-api">, Flags<[CC1Option]>, Group<Action_G
11211121
HelpText<"Extract API information">;
11221122
def product_name_EQ: Joined<["--"], "product-name=">, Flags<[CC1Option]>,
11231123
MarshallingInfoString<FrontendOpts<"ProductName">>;
1124+
def extract_api_ignores_EQ: Joined<["--"], "extract-api-ignores=">, Flags<[CC1Option]>,
1125+
HelpText<"File containing a new line separated list of API symbols to ignore when extracting API information.">,
1126+
MarshallingInfoString<FrontendOpts<"ExtractAPIIgnoresFile">>;
11241127
def e : JoinedOrSeparate<["-"], "e">, Flags<[LinkerInput]>, Group<Link_Group>;
11251128
def fmax_tokens_EQ : Joined<["-"], "fmax-tokens=">, Group<f_Group>, Flags<[CC1Option]>,
11261129
HelpText<"Max total number of preprocessed tokens for -Wmax-tokens.">,
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//===- ExtractAPI/APIIgnoresList.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+
/// \file This file defines APIIgnoresList which is a type that allows querying
10+
/// a file containing symbols to ignore when extracting API information.
11+
///
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_CLANG_API_IGNORES_LIST_H
15+
#define LLVM_CLANG_API_IGNORES_LIST_H
16+
17+
#include "clang/Basic/FileManager.h"
18+
#include "llvm/ADT/SmallVector.h"
19+
#include "llvm/ADT/StringRef.h"
20+
#include "llvm/Support/Error.h"
21+
#include "llvm/Support/raw_ostream.h"
22+
23+
#include <memory>
24+
#include <system_error>
25+
26+
namespace llvm {
27+
class MemoryBuffer;
28+
} // namespace llvm
29+
30+
namespace clang {
31+
namespace extractapi {
32+
33+
struct IgnoresFileNotFound : public llvm::ErrorInfo<IgnoresFileNotFound> {
34+
std::string Path;
35+
static char ID;
36+
37+
explicit IgnoresFileNotFound(StringRef Path) : Path(Path) {}
38+
39+
virtual void log(llvm::raw_ostream &os) const override;
40+
41+
virtual std::error_code convertToErrorCode() const override;
42+
};
43+
44+
/// A type that provides access to a new line separated list of symbol names to
45+
/// ignore when extracting API information.
46+
struct APIIgnoresList {
47+
/// The API to use for generating from the file at \p IgnoresFilePath.
48+
///
49+
/// \returns an initialized APIIgnoresList or an Error.
50+
static llvm::Expected<APIIgnoresList> create(llvm::StringRef IgnoresFilePath,
51+
FileManager &FM);
52+
53+
APIIgnoresList() = default;
54+
55+
/// Check if \p SymbolName is specified in the APIIgnoresList and if it should
56+
/// therefore be ignored.
57+
bool shouldIgnore(llvm::StringRef SymbolName) const;
58+
59+
private:
60+
using SymbolNameList = llvm::SmallVector<llvm::StringRef, 32>;
61+
62+
APIIgnoresList(SymbolNameList SymbolsToIgnore,
63+
std::unique_ptr<llvm::MemoryBuffer> Buffer)
64+
: SymbolsToIgnore(std::move(SymbolsToIgnore)), Buffer(std::move(Buffer)) {
65+
}
66+
67+
SymbolNameList SymbolsToIgnore;
68+
std::unique_ptr<llvm::MemoryBuffer> Buffer;
69+
};
70+
71+
} // namespace extractapi
72+
} // namespace clang
73+
74+
#endif // LLVM_CLANG_API_IGNORES_LIST_H

clang/include/clang/ExtractAPI/FrontendActions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define LLVM_CLANG_EXTRACTAPI_FRONTEND_ACTIONS_H
1616

1717
#include "clang/ExtractAPI/API.h"
18+
#include "clang/ExtractAPI/APIIgnoresList.h"
1819
#include "clang/Frontend/FrontendAction.h"
1920

2021
namespace clang {
@@ -39,6 +40,9 @@ class ExtractAPIAction : public ASTFrontendAction {
3940
/// files.
4041
std::unique_ptr<llvm::MemoryBuffer> Buffer;
4142

43+
/// The list of symbols to ignore during serialization
44+
extractapi::APIIgnoresList IgnoresList;
45+
4246
/// The input file originally provided on the command line.
4347
///
4448
/// This captures the spelling used to include the file and whether the

clang/include/clang/ExtractAPI/Serialization/SerializerBase.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H
1616

1717
#include "clang/ExtractAPI/API.h"
18+
#include "clang/ExtractAPI/APIIgnoresList.h"
1819
#include "llvm/Support/raw_ostream.h"
1920

2021
namespace clang {
@@ -40,6 +41,11 @@ class APISerializer {
4041
/// Note: This should be used for populating metadata about the API.
4142
StringRef ProductName;
4243

44+
/// The list of symbols to ignore.
45+
///
46+
/// Note: This should be consulted before emitting a symbol.
47+
const APIIgnoresList &IgnoresList;
48+
4349
APISerializerOption Options;
4450

4551
public:
@@ -51,8 +57,10 @@ class APISerializer {
5157

5258
protected:
5359
APISerializer(const APISet &API, StringRef ProductName,
60+
const APIIgnoresList &IgnoresList,
5461
APISerializerOption Options = {})
55-
: API(API), ProductName(ProductName), Options(Options) {}
62+
: API(API), ProductName(ProductName), IgnoresList(IgnoresList),
63+
Options(Options) {}
5664

5765
virtual ~APISerializer() = default;
5866
};

clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H
1919

2020
#include "clang/ExtractAPI/API.h"
21+
#include "clang/ExtractAPI/APIIgnoresList.h"
2122
#include "clang/ExtractAPI/Serialization/SerializerBase.h"
2223
#include "llvm/ADT/SmallVector.h"
2324
#include "llvm/Support/JSON.h"
@@ -168,8 +169,9 @@ class SymbolGraphSerializer : public APISerializer {
168169

169170
public:
170171
SymbolGraphSerializer(const APISet &API, StringRef ProductName,
172+
const APIIgnoresList &IgnoresList,
171173
APISerializerOption Options = {})
172-
: APISerializer(API, ProductName, Options) {}
174+
: APISerializer(API, ProductName, IgnoresList, Options) {}
173175
};
174176

175177
} // namespace extractapi

clang/include/clang/Frontend/FrontendOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,10 @@ class FrontendOptions {
454454
/// The name of the product the input files belong too.
455455
std::string ProductName;
456456

457+
// Currently this is only used as part of the `-extract-api` action.
458+
/// The file providing a list of APIs to ignore when extracting documentation
459+
std::string ExtractAPIIgnoresFile;
460+
457461
/// Args to pass to the plugins
458462
std::map<std::string, std::vector<std::string>> PluginArgs;
459463

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4813,6 +4813,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
48134813
CmdArgs.push_back("-extract-api");
48144814
if (Arg *ProductNameArg = Args.getLastArg(options::OPT_product_name_EQ))
48154815
ProductNameArg->render(Args, CmdArgs);
4816+
if (Arg *ExtractAPIIgnoresFileArg =
4817+
Args.getLastArg(options::OPT_extract_api_ignores_EQ))
4818+
ExtractAPIIgnoresFileArg->render(Args, CmdArgs);
48164819
} else {
48174820
assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) &&
48184821
"Invalid action for clang tool.");
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===- ExtractAPI/APIIgnoresList.cpp -------*- 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+
/// \file
10+
/// This file implements APIIgnoresList that allows users to specifiy a file
11+
/// containing symbols to ignore during API extraction.
12+
///
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "clang/ExtractAPI/APIIgnoresList.h"
16+
#include "clang/Basic/FileManager.h"
17+
#include "llvm/ADT/STLExtras.h"
18+
#include "llvm/Support/Error.h"
19+
20+
using namespace clang;
21+
using namespace clang::extractapi;
22+
using namespace llvm;
23+
24+
char IgnoresFileNotFound::ID;
25+
26+
void IgnoresFileNotFound::log(llvm::raw_ostream &os) const {
27+
os << "Could not find API ignores file " << Path;
28+
}
29+
30+
std::error_code IgnoresFileNotFound::convertToErrorCode() const {
31+
return llvm::inconvertibleErrorCode();
32+
}
33+
34+
Expected<APIIgnoresList> APIIgnoresList::create(StringRef IgnoresFilePath,
35+
FileManager &FM) {
36+
auto BufferOrErr = FM.getBufferForFile(IgnoresFilePath);
37+
if (!BufferOrErr)
38+
return make_error<IgnoresFileNotFound>(IgnoresFilePath);
39+
40+
auto Buffer = std::move(BufferOrErr.get());
41+
SmallVector<StringRef, 32> Lines;
42+
Buffer->getBuffer().split(Lines, '\n', /*MaxSplit*/ -1, /*KeepEmpty*/ false);
43+
// Symbol names don't have spaces in them, let's just remove these in case the
44+
// input is slighlty malformed.
45+
transform(Lines, Lines.begin(), [](StringRef Line) { return Line.trim(); });
46+
sort(Lines);
47+
return APIIgnoresList(std::move(Lines), std::move(Buffer));
48+
}
49+
50+
bool APIIgnoresList::shouldIgnore(StringRef SymbolName) const {
51+
auto It = lower_bound(SymbolsToIgnore, SymbolName);
52+
return (It != SymbolsToIgnore.end()) && (*It == SymbolName);
53+
}

clang/lib/ExtractAPI/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
44

55
add_clang_library(clangExtractAPI
66
API.cpp
7+
APIIgnoresList.cpp
78
AvailabilityInfo.cpp
89
ExtractAPIConsumer.cpp
910
DeclarationFragments.cpp

clang/lib/ExtractAPI/ExtractAPIConsumer.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@
2020
#include "clang/AST/ParentMapContext.h"
2121
#include "clang/AST/RawCommentList.h"
2222
#include "clang/AST/RecursiveASTVisitor.h"
23+
#include "clang/Basic/DiagnosticFrontend.h"
2324
#include "clang/Basic/SourceLocation.h"
2425
#include "clang/Basic/SourceManager.h"
2526
#include "clang/Basic/TargetInfo.h"
2627
#include "clang/ExtractAPI/API.h"
28+
#include "clang/ExtractAPI/APIIgnoresList.h"
2729
#include "clang/ExtractAPI/AvailabilityInfo.h"
2830
#include "clang/ExtractAPI/DeclarationFragments.h"
2931
#include "clang/ExtractAPI/FrontendActions.h"
@@ -38,6 +40,7 @@
3840
#include "llvm/ADT/DenseSet.h"
3941
#include "llvm/ADT/STLExtras.h"
4042
#include "llvm/ADT/SmallVector.h"
43+
#include "llvm/Support/Error.h"
4144
#include "llvm/Support/FileSystem.h"
4245
#include "llvm/Support/MemoryBuffer.h"
4346
#include "llvm/Support/Path.h"
@@ -858,6 +861,18 @@ ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
858861
Policy.AnonymousTagLocations = false;
859862
CI.getASTContext().setPrintingPolicy(Policy);
860863

864+
if (!CI.getFrontendOpts().ExtractAPIIgnoresFile.empty()) {
865+
llvm::handleAllErrors(
866+
APIIgnoresList::create(CI.getFrontendOpts().ExtractAPIIgnoresFile,
867+
CI.getFileManager())
868+
.moveInto(IgnoresList),
869+
[&CI](const IgnoresFileNotFound &Err) {
870+
CI.getDiagnostics().Report(
871+
diag::err_extract_api_ignores_file_not_found)
872+
<< Err.Path;
873+
});
874+
}
875+
861876
return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(),
862877
std::move(LCF), *API);
863878
}
@@ -926,7 +941,7 @@ void ExtractAPIAction::EndSourceFileAction() {
926941
// Setup a SymbolGraphSerializer to write out collected API information in
927942
// the Symbol Graph format.
928943
// FIXME: Make the kind of APISerializer configurable.
929-
SymbolGraphSerializer SGSerializer(*API, ProductName);
944+
SymbolGraphSerializer SGSerializer(*API, ProductName, IgnoresList);
930945
SGSerializer.serialize(*OS);
931946
OS.reset();
932947
}

clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
1515
#include "clang/Basic/Version.h"
1616
#include "clang/ExtractAPI/API.h"
17+
#include "clang/ExtractAPI/APIIgnoresList.h"
1718
#include "clang/ExtractAPI/DeclarationFragments.h"
1819
#include "llvm/Support/JSON.h"
1920
#include "llvm/Support/Path.h"
@@ -480,6 +481,10 @@ Object SymbolGraphSerializer::serializeModule() const {
480481
}
481482

482483
bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
484+
// Skip explicitly ignored symbols.
485+
if (IgnoresList.shouldIgnore(Record.Name))
486+
return true;
487+
483488
// Skip unconditionally unavailable symbols
484489
if (Record.Availabilities.isUnconditionallyUnavailable())
485490
return true;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: rm -rf %t
2+
// RUN: not %clang -target x86_64-unknown-unknown -extract-api --extract-api-ignores=does-not-exist %s 2>&1 | FileCheck %s
3+
4+
// CHECK: fatal error: file 'does-not-exist' specified by '--extract-api-ignores=' not found
5+
6+
void dummy_function(void);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \
4+
// RUN: --extract-api-ignores=%t/ignores-list \
5+
// RUN: -x c-header %t/input.h -verify -o - | FileCheck %t/input.h
6+
7+
//--- input.h
8+
#define IGNORED_1 1
9+
#define IGNORED_2 2
10+
#define IGNORED_3 3
11+
#define IGNORED_4 4
12+
typedef int Ignored;
13+
typedef float NonIgnored;
14+
15+
// CHECK-NOT: IGNORED_1
16+
// CHECK-NOT: IGNORED_2
17+
// CHECK-NOT: IGNORED_3
18+
// CHECK: NonIgnored
19+
20+
// expected-no-diagnostics
21+
22+
//--- ignores-list
23+
Ignored
24+
IGNORED_4
25+
IGNORED_3
26+
IGNORED_2
27+
IGNORED_1

0 commit comments

Comments
 (0)