[clang][extract-api] Use correct language info from inputs

The current way of getting the `clang::Language` from `LangOptions` does
not handle Objective-C correctly because `clang::Language::ObjC` does
not correspond to any `LangStandard`. This patch passes the correct
`Language` from the frontend input information.

Differential Revision: https://reviews.llvm.org/D122495
This commit is contained in:
Zixu Wang 2022-03-25 11:43:44 -07:00
parent ef6f7c4a60
commit 15bf0e5673
4 changed files with 186 additions and 24 deletions

View File

@ -309,8 +309,8 @@ public:
/// Get the target triple for the ExtractAPI invocation.
const llvm::Triple &getTarget() const { return Target; }
/// Get the language options used to parse the APIs.
const LangOptions &getLangOpts() const { return LangOpts; }
/// Get the language used by the APIs.
Language getLanguage() const { return Lang; }
const GlobalRecordMap &getGlobals() const { return Globals; }
const EnumRecordMap &getEnums() const { return Enums; }
@ -328,8 +328,8 @@ public:
/// \returns a StringRef of the copied string in APISet::Allocator.
StringRef copyString(StringRef String);
APISet(const llvm::Triple &Target, const LangOptions &LangOpts)
: Target(Target), LangOpts(LangOpts) {}
APISet(const llvm::Triple &Target, Language Lang)
: Target(Target), Lang(Lang) {}
private:
/// BumpPtrAllocator to store generated/copied strings.
@ -338,7 +338,7 @@ private:
llvm::BumpPtrAllocator StringAllocator;
const llvm::Triple Target;
const LangOptions LangOpts;
const Language Lang;
GlobalRecordMap Globals;
EnumRecordMap Enums;

View File

@ -41,9 +41,8 @@ namespace {
/// information.
class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
public:
explicit ExtractAPIVisitor(ASTContext &Context)
: Context(Context),
API(Context.getTargetInfo().getTriple(), Context.getLangOpts()) {}
ExtractAPIVisitor(ASTContext &Context, Language Lang)
: Context(Context), API(Context.getTargetInfo().getTriple(), Lang) {}
const APISet &getAPI() const { return API; }
@ -309,9 +308,9 @@ private:
class ExtractAPIConsumer : public ASTConsumer {
public:
ExtractAPIConsumer(ASTContext &Context, StringRef ProductName,
ExtractAPIConsumer(ASTContext &Context, StringRef ProductName, Language Lang,
std::unique_ptr<raw_pwrite_stream> OS)
: Visitor(Context), ProductName(ProductName), OS(std::move(OS)) {}
: Visitor(Context, Lang), ProductName(ProductName), OS(std::move(OS)) {}
void HandleTranslationUnit(ASTContext &Context) override {
// Use ExtractAPIVisitor to traverse symbol declarations in the context.
@ -339,6 +338,7 @@ ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return nullptr;
return std::make_unique<ExtractAPIConsumer>(
CI.getASTContext(), CI.getInvocation().getFrontendOpts().ProductName,
CI.getFrontendOpts().Inputs.back().getKind().getLanguage(),
std::move(OS));
}

View File

@ -151,11 +151,9 @@ Optional<Object> serializeAvailability(const AvailabilityInfo &Avail) {
return Availbility;
}
/// Get the short language name string for interface language references.
StringRef getLanguageName(const LangOptions &LangOpts) {
auto LanguageKind =
LangStandard::getLangStandardForKind(LangOpts.LangStd).getLanguage();
switch (LanguageKind) {
/// Get the language name string for interface language references.
StringRef getLanguageName(Language Lang) {
switch (Lang) {
case Language::C:
return "c";
case Language::ObjC:
@ -185,11 +183,10 @@ StringRef getLanguageName(const LangOptions &LangOpts) {
///
/// The identifier property of a symbol contains the USR for precise and unique
/// references, and the interface language name.
Object serializeIdentifier(const APIRecord &Record,
const LangOptions &LangOpts) {
Object serializeIdentifier(const APIRecord &Record, Language Lang) {
Object Identifier;
Identifier["precise"] = Record.USR;
Identifier["interfaceLanguage"] = getLanguageName(LangOpts);
Identifier["interfaceLanguage"] = getLanguageName(Lang);
return Identifier;
}
@ -335,10 +332,9 @@ Object serializeNames(const APIRecord &Record) {
/// The Symbol Graph symbol kind property contains a shorthand \c identifier
/// which is prefixed by the source language name, useful for tooling to parse
/// the kind, and a \c displayName for rendering human-readable names.
Object serializeSymbolKind(const APIRecord &Record,
const LangOptions &LangOpts) {
auto AddLangPrefix = [&LangOpts](StringRef S) -> std::string {
return (getLanguageName(LangOpts) + "." + S).str();
Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
return (getLanguageName(Lang) + "." + S).str();
};
Object Kind;
@ -420,8 +416,8 @@ SymbolGraphSerializer::serializeAPIRecord(const APIRecord &Record) const {
Object Obj;
serializeObject(Obj, "identifier",
serializeIdentifier(Record, API.getLangOpts()));
serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLangOpts()));
serializeIdentifier(Record, API.getLanguage()));
serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage()));
serializeObject(Obj, "names", serializeNames(Record));
serializeObject(
Obj, "location",

View File

@ -0,0 +1,166 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: sed -e "s@INPUT_DIR@%/t@g" %t/c.reference.output.json.in >> \
// RUN: %t/c.reference.output.json
// RUN: sed -e "s@INPUT_DIR@%/t@g" %t/objc.reference.output.json.in >> \
// RUN: %t/objc.reference.output.json
// RUN: %clang -extract-api -x c-header -target arm64-apple-macosx \
// RUN: %t/c.h -o %t/c.output.json | FileCheck -allow-empty %s
// RUN: %clang -extract-api -x objective-c-header -target arm64-apple-macosx \
// RUN: %t/objc.h -o %t/objc.output.json | FileCheck -allow-empty %s
// Generator version is not consistent across test runs, normalize it.
// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \
// RUN: %t/c.output.json >> %t/c.output-normalized.json
// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \
// RUN: %t/objc.output.json >> %t/objc.output-normalized.json
// RUN: diff %t/c.reference.output.json %t/c.output-normalized.json
// RUN: diff %t/objc.reference.output.json %t/objc.output-normalized.json
// CHECK-NOT: error:
// CHECK-NOT: warning:
//--- c.h
char c;
//--- objc.h
char objc;
//--- c.reference.output.json.in
{
"metadata": {
"formatVersion": {
"major": 0,
"minor": 5,
"patch": 3
},
"generator": "?"
},
"module": {
"name": "",
"platform": {
"architecture": "arm64",
"operatingSystem": {
"minimumVersion": {
"major": 11,
"minor": 0,
"patch": 0
},
"name": "macosx"
},
"vendor": "apple"
}
},
"relationhips": [],
"symbols": [
{
"declarationFragments": [
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:C",
"spelling": "char"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "c"
}
],
"identifier": {
"interfaceLanguage": "c",
"precise": "c:@c"
},
"kind": {
"displayName": "Global Variable",
"identifier": "c.var"
},
"location": {
"character": 6,
"line": 1,
"uri": "file://INPUT_DIR/c.h"
},
"names": {
"subHeading": [
{
"kind": "identifier",
"spelling": "c"
}
],
"title": "c"
}
}
]
}
//--- objc.reference.output.json.in
{
"metadata": {
"formatVersion": {
"major": 0,
"minor": 5,
"patch": 3
},
"generator": "?"
},
"module": {
"name": "",
"platform": {
"architecture": "arm64",
"operatingSystem": {
"minimumVersion": {
"major": 11,
"minor": 0,
"patch": 0
},
"name": "macosx"
},
"vendor": "apple"
}
},
"relationhips": [],
"symbols": [
{
"declarationFragments": [
{
"kind": "typeIdentifier",
"preciseIdentifier": "c:C",
"spelling": "char"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "objc"
}
],
"identifier": {
"interfaceLanguage": "objective-c",
"precise": "c:@objc"
},
"kind": {
"displayName": "Global Variable",
"identifier": "objective-c.var"
},
"location": {
"character": 6,
"line": 1,
"uri": "file://INPUT_DIR/objc.h"
},
"names": {
"subHeading": [
{
"kind": "identifier",
"spelling": "objc"
}
],
"title": "objc"
}
}
]
}