[clang] 791fe26 - [clang][ExtractAPI] Allow users to specify a list of symbols to ignore

Daniel Grumberg via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 25 03:46:22 PDT 2022


Author: Daniel Grumberg
Date: 2022-10-25T11:46:04+01:00
New Revision: 791fe26d758173e569d26d831b36ee8527e1a766

URL: https://github.com/llvm/llvm-project/commit/791fe26d758173e569d26d831b36ee8527e1a766
DIFF: https://github.com/llvm/llvm-project/commit/791fe26d758173e569d26d831b36ee8527e1a766.diff

LOG: [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

Added: 
    clang/include/clang/ExtractAPI/APIIgnoresList.h
    clang/lib/ExtractAPI/APIIgnoresList.cpp
    clang/test/Driver/extract-api-unknown-ignore-diag.h
    clang/test/ExtractAPI/ignored-symbols.c

Modified: 
    clang/include/clang/Basic/DiagnosticFrontendKinds.td
    clang/include/clang/Driver/Options.td
    clang/include/clang/ExtractAPI/FrontendActions.h
    clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
    clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
    clang/include/clang/Frontend/FrontendOptions.h
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/lib/ExtractAPI/CMakeLists.txt
    clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
    clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 3e87f6256e0aa..07ecbe332f8b3 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -331,4 +331,7 @@ def warn_profile_data_misexpect : Warning<
   InGroup<MisExpect>;
 } // end of instrumentation issue category
 
+def err_extract_api_ignores_file_not_found :
+  Error<"file '%0' specified by '--extract-api-ignores=' not found">, DefaultFatal;
+
 }

diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 2ab40ac6c9639..0f5b6d83330e1 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1121,6 +1121,9 @@ def extract_api : Flag<["-"], "extract-api">, Flags<[CC1Option]>, Group<Action_G
   HelpText<"Extract API information">;
 def product_name_EQ: Joined<["--"], "product-name=">, Flags<[CC1Option]>,
   MarshallingInfoString<FrontendOpts<"ProductName">>;
+def extract_api_ignores_EQ: Joined<["--"], "extract-api-ignores=">, Flags<[CC1Option]>,
+    HelpText<"File containing a new line separated list of API symbols to ignore when extracting API information.">,
+    MarshallingInfoString<FrontendOpts<"ExtractAPIIgnoresFile">>;
 def e : JoinedOrSeparate<["-"], "e">, Flags<[LinkerInput]>, Group<Link_Group>;
 def fmax_tokens_EQ : Joined<["-"], "fmax-tokens=">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Max total number of preprocessed tokens for -Wmax-tokens.">,

diff  --git a/clang/include/clang/ExtractAPI/APIIgnoresList.h b/clang/include/clang/ExtractAPI/APIIgnoresList.h
new file mode 100644
index 0000000000000..43c546102a2d6
--- /dev/null
+++ b/clang/include/clang/ExtractAPI/APIIgnoresList.h
@@ -0,0 +1,74 @@
+//===- ExtractAPI/APIIgnoresList.h ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file defines APIIgnoresList which is a type that allows querying
+/// a file containing symbols to ignore when extracting API information.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_API_IGNORES_LIST_H
+#define LLVM_CLANG_API_IGNORES_LIST_H
+
+#include "clang/Basic/FileManager.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <memory>
+#include <system_error>
+
+namespace llvm {
+class MemoryBuffer;
+} // namespace llvm
+
+namespace clang {
+namespace extractapi {
+
+struct IgnoresFileNotFound : public llvm::ErrorInfo<IgnoresFileNotFound> {
+  std::string Path;
+  static char ID;
+
+  explicit IgnoresFileNotFound(StringRef Path) : Path(Path) {}
+
+  virtual void log(llvm::raw_ostream &os) const override;
+
+  virtual std::error_code convertToErrorCode() const override;
+};
+
+/// A type that provides access to a new line separated list of symbol names to
+/// ignore when extracting API information.
+struct APIIgnoresList {
+  /// The API to use for generating from the file at \p IgnoresFilePath.
+  ///
+  /// \returns an initialized APIIgnoresList or an Error.
+  static llvm::Expected<APIIgnoresList> create(llvm::StringRef IgnoresFilePath,
+                                               FileManager &FM);
+
+  APIIgnoresList() = default;
+
+  /// Check if \p SymbolName is specified in the APIIgnoresList and if it should
+  /// therefore be ignored.
+  bool shouldIgnore(llvm::StringRef SymbolName) const;
+
+private:
+  using SymbolNameList = llvm::SmallVector<llvm::StringRef, 32>;
+
+  APIIgnoresList(SymbolNameList SymbolsToIgnore,
+                 std::unique_ptr<llvm::MemoryBuffer> Buffer)
+      : SymbolsToIgnore(std::move(SymbolsToIgnore)), Buffer(std::move(Buffer)) {
+  }
+
+  SymbolNameList SymbolsToIgnore;
+  std::unique_ptr<llvm::MemoryBuffer> Buffer;
+};
+
+} // namespace extractapi
+} // namespace clang
+
+#endif // LLVM_CLANG_API_IGNORES_LIST_H

diff  --git a/clang/include/clang/ExtractAPI/FrontendActions.h b/clang/include/clang/ExtractAPI/FrontendActions.h
index 2cb8ef130fdd7..e946b33abbd98 100644
--- a/clang/include/clang/ExtractAPI/FrontendActions.h
+++ b/clang/include/clang/ExtractAPI/FrontendActions.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_EXTRACTAPI_FRONTEND_ACTIONS_H
 
 #include "clang/ExtractAPI/API.h"
+#include "clang/ExtractAPI/APIIgnoresList.h"
 #include "clang/Frontend/FrontendAction.h"
 
 namespace clang {
@@ -39,6 +40,9 @@ class ExtractAPIAction : public ASTFrontendAction {
   /// files.
   std::unique_ptr<llvm::MemoryBuffer> Buffer;
 
+  /// The list of symbols to ignore during serialization
+  extractapi::APIIgnoresList IgnoresList;
+
   /// The input file originally provided on the command line.
   ///
   /// This captures the spelling used to include the file and whether the

diff  --git a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
index 2bcf81a804b39..0510dacb06495 100644
--- a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
+++ b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H
 
 #include "clang/ExtractAPI/API.h"
+#include "clang/ExtractAPI/APIIgnoresList.h"
 #include "llvm/Support/raw_ostream.h"
 
 namespace clang {
@@ -40,6 +41,11 @@ class APISerializer {
   /// Note: This should be used for populating metadata about the API.
   StringRef ProductName;
 
+  /// The list of symbols to ignore.
+  ///
+  /// Note: This should be consulted before emitting a symbol.
+  const APIIgnoresList &IgnoresList;
+
   APISerializerOption Options;
 
 public:
@@ -51,8 +57,10 @@ class APISerializer {
 
 protected:
   APISerializer(const APISet &API, StringRef ProductName,
+                const APIIgnoresList &IgnoresList,
                 APISerializerOption Options = {})
-      : API(API), ProductName(ProductName), Options(Options) {}
+      : API(API), ProductName(ProductName), IgnoresList(IgnoresList),
+        Options(Options) {}
 
   virtual ~APISerializer() = default;
 };

diff  --git a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
index f5ec2ea3ea771..7c82c8fa53b95 100644
--- a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
+++ b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
@@ -18,6 +18,7 @@
 #define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H
 
 #include "clang/ExtractAPI/API.h"
+#include "clang/ExtractAPI/APIIgnoresList.h"
 #include "clang/ExtractAPI/Serialization/SerializerBase.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/JSON.h"
@@ -168,8 +169,9 @@ class SymbolGraphSerializer : public APISerializer {
 
 public:
   SymbolGraphSerializer(const APISet &API, StringRef ProductName,
+                        const APIIgnoresList &IgnoresList,
                         APISerializerOption Options = {})
-      : APISerializer(API, ProductName, Options) {}
+      : APISerializer(API, ProductName, IgnoresList, Options) {}
 };
 
 } // namespace extractapi

diff  --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index 4f9aa1a749c96..3905ce7ef80e4 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -454,6 +454,10 @@ class FrontendOptions {
   /// The name of the product the input files belong too.
   std::string ProductName;
 
+  // Currently this is only used as part of the `-extract-api` action.
+  /// The file providing a list of APIs to ignore when extracting documentation
+  std::string ExtractAPIIgnoresFile;
+
   /// Args to pass to the plugins
   std::map<std::string, std::vector<std::string>> PluginArgs;
 

diff  --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 9d21975751af5..25b766be3ad9f 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -4813,6 +4813,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     CmdArgs.push_back("-extract-api");
     if (Arg *ProductNameArg = Args.getLastArg(options::OPT_product_name_EQ))
       ProductNameArg->render(Args, CmdArgs);
+    if (Arg *ExtractAPIIgnoresFileArg =
+            Args.getLastArg(options::OPT_extract_api_ignores_EQ))
+      ExtractAPIIgnoresFileArg->render(Args, CmdArgs);
   } else {
     assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) &&
            "Invalid action for clang tool.");

diff  --git a/clang/lib/ExtractAPI/APIIgnoresList.cpp b/clang/lib/ExtractAPI/APIIgnoresList.cpp
new file mode 100644
index 0000000000000..1d65ae2b8e31b
--- /dev/null
+++ b/clang/lib/ExtractAPI/APIIgnoresList.cpp
@@ -0,0 +1,53 @@
+//===- ExtractAPI/APIIgnoresList.cpp -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements APIIgnoresList that allows users to specifiy a file
+/// containing symbols to ignore during API extraction.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/ExtractAPI/APIIgnoresList.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
+
+using namespace clang;
+using namespace clang::extractapi;
+using namespace llvm;
+
+char IgnoresFileNotFound::ID;
+
+void IgnoresFileNotFound::log(llvm::raw_ostream &os) const {
+  os << "Could not find API ignores file " << Path;
+}
+
+std::error_code IgnoresFileNotFound::convertToErrorCode() const {
+  return llvm::inconvertibleErrorCode();
+}
+
+Expected<APIIgnoresList> APIIgnoresList::create(StringRef IgnoresFilePath,
+                                                FileManager &FM) {
+  auto BufferOrErr = FM.getBufferForFile(IgnoresFilePath);
+  if (!BufferOrErr)
+    return make_error<IgnoresFileNotFound>(IgnoresFilePath);
+
+  auto Buffer = std::move(BufferOrErr.get());
+  SmallVector<StringRef, 32> Lines;
+  Buffer->getBuffer().split(Lines, '\n', /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+  // Symbol names don't have spaces in them, let's just remove these in case the
+  // input is slighlty malformed.
+  transform(Lines, Lines.begin(), [](StringRef Line) { return Line.trim(); });
+  sort(Lines);
+  return APIIgnoresList(std::move(Lines), std::move(Buffer));
+}
+
+bool APIIgnoresList::shouldIgnore(StringRef SymbolName) const {
+  auto It = lower_bound(SymbolsToIgnore, SymbolName);
+  return (It != SymbolsToIgnore.end()) && (*It == SymbolName);
+}

diff  --git a/clang/lib/ExtractAPI/CMakeLists.txt b/clang/lib/ExtractAPI/CMakeLists.txt
index 904321ba33a58..e7de57d2984cc 100644
--- a/clang/lib/ExtractAPI/CMakeLists.txt
+++ b/clang/lib/ExtractAPI/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_clang_library(clangExtractAPI
   API.cpp
+  APIIgnoresList.cpp
   AvailabilityInfo.cpp
   ExtractAPIConsumer.cpp
   DeclarationFragments.cpp

diff  --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
index 2333f81fd3a36..2ab1828583a07 100644
--- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -20,10 +20,12 @@
 #include "clang/AST/ParentMapContext.h"
 #include "clang/AST/RawCommentList.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/ExtractAPI/API.h"
+#include "clang/ExtractAPI/APIIgnoresList.h"
 #include "clang/ExtractAPI/AvailabilityInfo.h"
 #include "clang/ExtractAPI/DeclarationFragments.h"
 #include "clang/ExtractAPI/FrontendActions.h"
@@ -38,6 +40,7 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
@@ -858,6 +861,18 @@ ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
   Policy.AnonymousTagLocations = false;
   CI.getASTContext().setPrintingPolicy(Policy);
 
+  if (!CI.getFrontendOpts().ExtractAPIIgnoresFile.empty()) {
+    llvm::handleAllErrors(
+        APIIgnoresList::create(CI.getFrontendOpts().ExtractAPIIgnoresFile,
+                               CI.getFileManager())
+            .moveInto(IgnoresList),
+        [&CI](const IgnoresFileNotFound &Err) {
+          CI.getDiagnostics().Report(
+              diag::err_extract_api_ignores_file_not_found)
+              << Err.Path;
+        });
+  }
+
   return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(),
                                               std::move(LCF), *API);
 }
@@ -926,7 +941,7 @@ void ExtractAPIAction::EndSourceFileAction() {
   // Setup a SymbolGraphSerializer to write out collected API information in
   // the Symbol Graph format.
   // FIXME: Make the kind of APISerializer configurable.
-  SymbolGraphSerializer SGSerializer(*API, ProductName);
+  SymbolGraphSerializer SGSerializer(*API, ProductName, IgnoresList);
   SGSerializer.serialize(*OS);
   OS.reset();
 }

diff  --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
index 0810dec91b49b..988ecd2defa9c 100644
--- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -14,6 +14,7 @@
 #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
 #include "clang/Basic/Version.h"
 #include "clang/ExtractAPI/API.h"
+#include "clang/ExtractAPI/APIIgnoresList.h"
 #include "clang/ExtractAPI/DeclarationFragments.h"
 #include "llvm/Support/JSON.h"
 #include "llvm/Support/Path.h"
@@ -480,6 +481,10 @@ Object SymbolGraphSerializer::serializeModule() const {
 }
 
 bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
+  // Skip explicitly ignored symbols.
+  if (IgnoresList.shouldIgnore(Record.Name))
+    return true;
+
   // Skip unconditionally unavailable symbols
   if (Record.Availabilities.isUnconditionallyUnavailable())
     return true;

diff  --git a/clang/test/Driver/extract-api-unknown-ignore-diag.h b/clang/test/Driver/extract-api-unknown-ignore-diag.h
new file mode 100644
index 0000000000000..9389c34ffefa2
--- /dev/null
+++ b/clang/test/Driver/extract-api-unknown-ignore-diag.h
@@ -0,0 +1,6 @@
+// RUN: rm -rf %t
+// RUN: not %clang -target x86_64-unknown-unknown -extract-api --extract-api-ignores=does-not-exist %s 2>&1 | FileCheck %s
+
+// CHECK: fatal error: file 'does-not-exist' specified by '--extract-api-ignores=' not found
+
+void dummy_function(void);

diff  --git a/clang/test/ExtractAPI/ignored-symbols.c b/clang/test/ExtractAPI/ignored-symbols.c
new file mode 100644
index 0000000000000..2a24430f11c32
--- /dev/null
+++ b/clang/test/ExtractAPI/ignored-symbols.c
@@ -0,0 +1,27 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -extract-api -triple arm64-apple-macosx \
+// RUN:   --extract-api-ignores=%t/ignores-list            \
+// RUN:   -x c-header %t/input.h -verify -o - | FileCheck %t/input.h
+
+//--- input.h
+#define IGNORED_1 1
+#define IGNORED_2 2
+#define IGNORED_3 3
+#define IGNORED_4 4
+typedef int Ignored;
+typedef float NonIgnored;
+
+// CHECK-NOT: IGNORED_1
+// CHECK-NOT: IGNORED_2
+// CHECK-NOT: IGNORED_3
+// CHECK: NonIgnored
+
+// expected-no-diagnostics
+
+//--- ignores-list
+Ignored
+IGNORED_4
+IGNORED_3   
+IGNORED_2
+IGNORED_1


        


More information about the cfe-commits mailing list