forked from OSchip/llvm-project
[clang][extract-api] Add enum support
Add support for enum records - Add `EnumConstantRecord` and `EnumRecord` to store API information for enums - Implement `VisitEnumDecl` in `ExtractAPIVisitor` - Implement serializatin for enum records and `MemberOf` relationship - Add test case for enum records - Few other improvements Depends on D122160 Differential Revision: https://reviews.llvm.org/D121873
This commit is contained in:
parent
5a2e56b70e
commit
71b4c22612
|
@ -30,6 +30,25 @@
|
|||
#include "llvm/Support/Casting.h"
|
||||
#include <memory>
|
||||
|
||||
namespace {
|
||||
|
||||
/// \brief A custom deleter used for ``std::unique_ptr`` to APIRecords stored
|
||||
/// in the BumpPtrAllocator.
|
||||
///
|
||||
/// \tparam T the exact type of the APIRecord subclass.
|
||||
template <typename T> struct UniquePtrBumpPtrAllocatorDeleter {
|
||||
void operator()(T *Instance) { Instance->~T(); }
|
||||
};
|
||||
|
||||
/// A unique pointer to an APIRecord stored in the BumpPtrAllocator.
|
||||
///
|
||||
/// \tparam T the exact type of the APIRecord subclass.
|
||||
template <typename T>
|
||||
using APIRecordUniquePtr =
|
||||
std::unique_ptr<T, UniquePtrBumpPtrAllocatorDeleter<T>>;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace clang {
|
||||
namespace extractapi {
|
||||
|
||||
|
@ -73,6 +92,8 @@ struct APIRecord {
|
|||
/// Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
|
||||
enum RecordKind {
|
||||
RK_Global,
|
||||
RK_EnumConstant,
|
||||
RK_Enum,
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -125,6 +146,36 @@ private:
|
|||
virtual void anchor();
|
||||
};
|
||||
|
||||
/// This holds information associated with enum constants.
|
||||
struct EnumConstantRecord : APIRecord {
|
||||
EnumConstantRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading)
|
||||
: APIRecord(RK_EnumConstant, Name, USR, Loc, Availability,
|
||||
LinkageInfo::none(), Comment, Declaration, SubHeading) {}
|
||||
|
||||
static bool classof(const APIRecord *Record) {
|
||||
return Record->getKind() == RK_EnumConstant;
|
||||
}
|
||||
};
|
||||
|
||||
/// This holds information associated with enums.
|
||||
struct EnumRecord : APIRecord {
|
||||
SmallVector<APIRecordUniquePtr<EnumConstantRecord>> Constants;
|
||||
|
||||
EnumRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability, const DocComment &Comment,
|
||||
DeclarationFragments Declaration, DeclarationFragments SubHeading)
|
||||
: APIRecord(RK_Enum, Name, USR, Loc, Availability, LinkageInfo::none(),
|
||||
Comment, Declaration, SubHeading) {}
|
||||
|
||||
static bool classof(const APIRecord *Record) {
|
||||
return Record->getKind() == RK_Enum;
|
||||
}
|
||||
};
|
||||
|
||||
/// APISet holds the set of API records collected from given inputs.
|
||||
class APISet {
|
||||
public:
|
||||
|
@ -166,28 +217,41 @@ public:
|
|||
DeclarationFragments SubHeading,
|
||||
FunctionSignature Signature);
|
||||
|
||||
private:
|
||||
/// \brief A custom deleter used for ``std::unique_ptr`` to APIRecords stored
|
||||
/// in the BumpPtrAllocator.
|
||||
/// Create and add an enum constant record into the API set.
|
||||
///
|
||||
/// \tparam T the exact type of the APIRecord subclass.
|
||||
template <typename T> struct UniquePtrBumpPtrAllocatorDeleter {
|
||||
void operator()(T *Instance) { Instance->~T(); }
|
||||
};
|
||||
/// Note: the caller is responsible for keeping the StringRef \p Name and
|
||||
/// \p USR alive. APISet::copyString provides a way to copy strings into
|
||||
/// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method
|
||||
/// to generate the USR for \c D and keep it alive in APISet.
|
||||
EnumConstantRecord *addEnumConstant(EnumRecord *Enum, StringRef Name,
|
||||
StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading);
|
||||
|
||||
public:
|
||||
/// A unique pointer to an APIRecord stored in the BumpPtrAllocator.
|
||||
/// Create and add an enum record into the API set.
|
||||
///
|
||||
/// \tparam T the exact type of the APIRecord subclass.
|
||||
template <typename T>
|
||||
using APIRecordUniquePtr =
|
||||
std::unique_ptr<T, UniquePtrBumpPtrAllocatorDeleter<T>>;
|
||||
/// Note: the caller is responsible for keeping the StringRef \p Name and
|
||||
/// \p USR alive. APISet::copyString provides a way to copy strings into
|
||||
/// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method
|
||||
/// to generate the USR for \c D and keep it alive in APISet.
|
||||
EnumRecord *addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading);
|
||||
|
||||
/// A map to store the set of GlobalRecord%s with the declaration name as the
|
||||
/// key.
|
||||
using GlobalRecordMap =
|
||||
llvm::MapVector<StringRef, APIRecordUniquePtr<GlobalRecord>>;
|
||||
|
||||
/// A map to store the set of EnumRecord%s with the declaration name as the
|
||||
/// key.
|
||||
using EnumRecordMap =
|
||||
llvm::MapVector<StringRef, APIRecordUniquePtr<EnumRecord>>;
|
||||
|
||||
/// Get the target triple for the ExtractAPI invocation.
|
||||
const llvm::Triple &getTarget() const { return Target; }
|
||||
|
||||
|
@ -195,6 +259,7 @@ public:
|
|||
const LangOptions &getLangOpts() const { return LangOpts; }
|
||||
|
||||
const GlobalRecordMap &getGlobals() const { return Globals; }
|
||||
const EnumRecordMap &getEnums() const { return Enums; }
|
||||
|
||||
/// Generate and store the USR of declaration \p D.
|
||||
///
|
||||
|
@ -219,6 +284,7 @@ private:
|
|||
const LangOptions LangOpts;
|
||||
|
||||
GlobalRecordMap Globals;
|
||||
EnumRecordMap Enums;
|
||||
};
|
||||
|
||||
} // namespace extractapi
|
||||
|
|
|
@ -188,6 +188,14 @@ public:
|
|||
/// Build DeclarationFragments for a function declaration FunctionDecl.
|
||||
static DeclarationFragments getFragmentsForFunction(const FunctionDecl *);
|
||||
|
||||
/// Build DeclarationFragments for an enum constant declaration
|
||||
/// EnumConstantDecl.
|
||||
static DeclarationFragments
|
||||
getFragmentsForEnumConstant(const EnumConstantDecl *);
|
||||
|
||||
/// Build DeclarationFragments for an enum declaration EnumDecl.
|
||||
static DeclarationFragments getFragmentsForEnum(const EnumDecl *);
|
||||
|
||||
/// Build sub-heading fragments for a NamedDecl.
|
||||
static DeclarationFragments getSubHeading(const NamedDecl *);
|
||||
|
||||
|
|
|
@ -56,6 +56,17 @@ public:
|
|||
/// write out the serialized JSON object to \p os.
|
||||
void serialize(raw_ostream &os) override;
|
||||
|
||||
/// The kind of a relationship between two symbols.
|
||||
enum RelationshipKind {
|
||||
/// The source symbol is a member of the target symbol.
|
||||
/// For example enum constants are members of the enum, class/instance
|
||||
/// methods are members of the class, etc.
|
||||
MemberOf,
|
||||
};
|
||||
|
||||
/// Get the string representation of the relationship kind.
|
||||
static StringRef getRelationshipString(RelationshipKind Kind);
|
||||
|
||||
private:
|
||||
/// Synthesize the metadata section of the Symbol Graph format.
|
||||
///
|
||||
|
@ -86,9 +97,19 @@ private:
|
|||
/// containing common symbol information of \p Record.
|
||||
Optional<Object> serializeAPIRecord(const APIRecord &Record) const;
|
||||
|
||||
/// Serialize the \p Kind relationship between \p Source and \p Target.
|
||||
///
|
||||
/// Record the relationship between the two symbols in
|
||||
/// SymbolGraphSerializer::Relationships.
|
||||
void serializeRelationship(RelationshipKind Kind, const APIRecord &Source,
|
||||
const APIRecord &Target);
|
||||
|
||||
/// Serialize a global record.
|
||||
void serializeGlobalRecord(const GlobalRecord &Record);
|
||||
|
||||
/// Serialize an enum record.
|
||||
void serializeEnumRecord(const EnumRecord &Record);
|
||||
|
||||
public:
|
||||
SymbolGraphSerializer(const APISet &API, StringRef ProductName,
|
||||
APISerializerOption Options = {})
|
||||
|
|
|
@ -59,6 +59,31 @@ APISet::addFunction(StringRef Name, StringRef USR, PresumedLoc Loc,
|
|||
Comment, Fragments, SubHeading, Signature);
|
||||
}
|
||||
|
||||
EnumConstantRecord *APISet::addEnumConstant(
|
||||
EnumRecord *Enum, StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability, const DocComment &Comment,
|
||||
DeclarationFragments Declaration, DeclarationFragments SubHeading) {
|
||||
auto Record =
|
||||
APIRecordUniquePtr<EnumConstantRecord>(new (Allocator) EnumConstantRecord{
|
||||
Name, USR, Loc, Availability, Comment, Declaration, SubHeading});
|
||||
return Enum->Constants.emplace_back(std::move(Record)).get();
|
||||
}
|
||||
|
||||
EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
|
||||
const AvailabilityInfo &Availability,
|
||||
const DocComment &Comment,
|
||||
DeclarationFragments Declaration,
|
||||
DeclarationFragments SubHeading) {
|
||||
auto Result = Enums.insert({Name, nullptr});
|
||||
if (Result.second) {
|
||||
// Create the record if it does not already exist.
|
||||
auto Record = APIRecordUniquePtr<EnumRecord>(new (Allocator) EnumRecord{
|
||||
Name, USR, Loc, Availability, Comment, Declaration, SubHeading});
|
||||
Result.first->second = std::move(Record);
|
||||
}
|
||||
return Result.first->second.get();
|
||||
}
|
||||
|
||||
StringRef APISet::recordUSR(const Decl *D) {
|
||||
SmallString<128> USR;
|
||||
index::generateUSRForDecl(D, USR);
|
||||
|
|
|
@ -401,6 +401,35 @@ DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) {
|
|||
return Fragments;
|
||||
}
|
||||
|
||||
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForEnumConstant(
|
||||
const EnumConstantDecl *EnumConstDecl) {
|
||||
DeclarationFragments Fragments;
|
||||
return Fragments.append(EnumConstDecl->getName(),
|
||||
DeclarationFragments::FragmentKind::Identifier);
|
||||
}
|
||||
|
||||
DeclarationFragments
|
||||
DeclarationFragmentsBuilder::getFragmentsForEnum(const EnumDecl *EnumDecl) {
|
||||
// TODO: After we support typedef records, if there's a typedef for this enum
|
||||
// just use the declaration fragments of the typedef decl.
|
||||
|
||||
DeclarationFragments Fragments, After;
|
||||
Fragments.append("enum", DeclarationFragments::FragmentKind::Keyword);
|
||||
|
||||
if (!EnumDecl->getName().empty())
|
||||
Fragments.appendSpace().append(
|
||||
EnumDecl->getName(), DeclarationFragments::FragmentKind::Identifier);
|
||||
|
||||
QualType IntegerType = EnumDecl->getIntegerType();
|
||||
if (!IntegerType.isNull())
|
||||
Fragments.append(": ", DeclarationFragments::FragmentKind::Text)
|
||||
.append(
|
||||
getFragmentsForType(IntegerType, EnumDecl->getASTContext(), After))
|
||||
.append(std::move(After));
|
||||
|
||||
return Fragments;
|
||||
}
|
||||
|
||||
FunctionSignature
|
||||
DeclarationFragmentsBuilder::getFunctionSignature(const FunctionDecl *Func) {
|
||||
FunctionSignature Signature;
|
||||
|
|
|
@ -145,6 +145,40 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool VisitEnumDecl(const EnumDecl *Decl) {
|
||||
if (!Decl->isComplete())
|
||||
return true;
|
||||
|
||||
// Skip forward declaration.
|
||||
if (!Decl->isThisDeclarationADefinition())
|
||||
return true;
|
||||
|
||||
// Collect symbol information.
|
||||
StringRef Name = Decl->getName();
|
||||
StringRef USR = API.recordUSR(Decl);
|
||||
PresumedLoc Loc =
|
||||
Context.getSourceManager().getPresumedLoc(Decl->getLocation());
|
||||
AvailabilityInfo Availability = getAvailability(Decl);
|
||||
DocComment Comment;
|
||||
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
|
||||
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
|
||||
Context.getDiagnostics());
|
||||
|
||||
// Build declaration fragments and sub-heading for the enum.
|
||||
DeclarationFragments Declaration =
|
||||
DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
|
||||
DeclarationFragments SubHeading =
|
||||
DeclarationFragmentsBuilder::getSubHeading(Decl);
|
||||
|
||||
EnumRecord *EnumRecord = API.addEnum(Name, USR, Loc, Availability, Comment,
|
||||
Declaration, SubHeading);
|
||||
|
||||
// Now collect information about the enumerators in this enum.
|
||||
recordEnumConstants(EnumRecord, Decl->enumerators());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Get availability information of the declaration \p D.
|
||||
AvailabilityInfo getAvailability(const Decl *D) const {
|
||||
|
@ -177,6 +211,33 @@ private:
|
|||
return Availability;
|
||||
}
|
||||
|
||||
/// Collect API information for the enum constants and associate with the
|
||||
/// parent enum.
|
||||
void recordEnumConstants(EnumRecord *EnumRecord,
|
||||
const EnumDecl::enumerator_range Constants) {
|
||||
for (const auto *Constant : Constants) {
|
||||
// Collect symbol information.
|
||||
StringRef Name = Constant->getName();
|
||||
StringRef USR = API.recordUSR(Constant);
|
||||
PresumedLoc Loc =
|
||||
Context.getSourceManager().getPresumedLoc(Constant->getLocation());
|
||||
AvailabilityInfo Availability = getAvailability(Constant);
|
||||
DocComment Comment;
|
||||
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
|
||||
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
|
||||
Context.getDiagnostics());
|
||||
|
||||
// Build declaration fragments and sub-heading for the enum constant.
|
||||
DeclarationFragments Declaration =
|
||||
DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
|
||||
DeclarationFragments SubHeading =
|
||||
DeclarationFragmentsBuilder::getSubHeading(Constant);
|
||||
|
||||
API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment,
|
||||
Declaration, SubHeading);
|
||||
}
|
||||
}
|
||||
|
||||
ASTContext &Context;
|
||||
APISet API;
|
||||
};
|
||||
|
|
|
@ -336,17 +336,21 @@ Object serializeNames(const APIRecord &Record) {
|
|||
/// 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 Kind;
|
||||
switch (Record.getKind()) {
|
||||
case APIRecord::RK_Global:
|
||||
case APIRecord::RK_Global: {
|
||||
auto *GR = dyn_cast<GlobalRecord>(&Record);
|
||||
switch (GR->GlobalKind) {
|
||||
case GVKind::Function:
|
||||
Kind["identifier"] = (getLanguageName(LangOpts) + ".func").str();
|
||||
Kind["identifier"] = AddLangPrefix("func");
|
||||
Kind["displayName"] = "Function";
|
||||
break;
|
||||
case GVKind::Variable:
|
||||
Kind["identifier"] = (getLanguageName(LangOpts) + ".var").str();
|
||||
Kind["identifier"] = AddLangPrefix("var");
|
||||
Kind["displayName"] = "Global Variable";
|
||||
break;
|
||||
case GVKind::Unknown:
|
||||
|
@ -355,6 +359,15 @@ Object serializeSymbolKind(const APIRecord &Record,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case APIRecord::RK_EnumConstant:
|
||||
Kind["identifier"] = AddLangPrefix("enum.case");
|
||||
Kind["displayName"] = "Enumeration Case";
|
||||
break;
|
||||
case APIRecord::RK_Enum:
|
||||
Kind["identifier"] = AddLangPrefix("enum");
|
||||
Kind["displayName"] = "Enumeration";
|
||||
break;
|
||||
}
|
||||
|
||||
return Kind;
|
||||
}
|
||||
|
@ -413,6 +426,25 @@ SymbolGraphSerializer::serializeAPIRecord(const APIRecord &Record) const {
|
|||
return Obj;
|
||||
}
|
||||
|
||||
StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
|
||||
switch (Kind) {
|
||||
case RelationshipKind::MemberOf:
|
||||
return "memberOf";
|
||||
}
|
||||
llvm_unreachable("Unhandled relationship kind");
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
|
||||
const APIRecord &Source,
|
||||
const APIRecord &Target) {
|
||||
Object Relationship;
|
||||
Relationship["source"] = Source.USR;
|
||||
Relationship["target"] = Target.USR;
|
||||
Relationship["kind"] = getRelationshipString(Kind);
|
||||
|
||||
Relationships.emplace_back(std::move(Relationship));
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::serializeGlobalRecord(const GlobalRecord &Record) {
|
||||
auto Obj = serializeAPIRecord(Record);
|
||||
if (!Obj)
|
||||
|
@ -425,6 +457,23 @@ void SymbolGraphSerializer::serializeGlobalRecord(const GlobalRecord &Record) {
|
|||
Symbols.emplace_back(std::move(*Obj));
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::serializeEnumRecord(const EnumRecord &Record) {
|
||||
auto Enum = serializeAPIRecord(Record);
|
||||
if (!Enum)
|
||||
return;
|
||||
|
||||
Symbols.emplace_back(std::move(*Enum));
|
||||
|
||||
for (const auto &Constant : Record.Constants) {
|
||||
auto EnumConstant = serializeAPIRecord(*Constant);
|
||||
if (!EnumConstant)
|
||||
continue;
|
||||
|
||||
Symbols.emplace_back(std::move(*EnumConstant));
|
||||
serializeRelationship(RelationshipKind::MemberOf, *Constant, Record);
|
||||
}
|
||||
}
|
||||
|
||||
Object SymbolGraphSerializer::serialize() {
|
||||
Object Root;
|
||||
serializeObject(Root, "metadata", serializeMetadata());
|
||||
|
@ -434,6 +483,10 @@ Object SymbolGraphSerializer::serialize() {
|
|||
for (const auto &Global : API.getGlobals())
|
||||
serializeGlobalRecord(*Global.second);
|
||||
|
||||
// Serialize enum records in the API set.
|
||||
for (const auto &Enum : API.getEnums())
|
||||
serializeEnumRecord(*Enum.second);
|
||||
|
||||
Root["symbols"] = std::move(Symbols);
|
||||
Root["relationhips"] = std::move(Relationships);
|
||||
|
||||
|
|
|
@ -0,0 +1,505 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: split-file %s %t
|
||||
// RUN: sed -e "s@INPUT_DIR@%/t@g" %t/reference.output.json.in >> \
|
||||
// RUN: %t/reference.output.json
|
||||
// RUN: %clang -extract-api -target arm64-apple-macosx \
|
||||
// RUN: %t/input.h -o %t/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/output.json >> %t/output-normalized.json
|
||||
// RUN: diff %t/reference.output.json %t/output-normalized.json
|
||||
|
||||
// CHECK-NOT: error:
|
||||
// CHECK-NOT: warning:
|
||||
|
||||
//--- input.h
|
||||
/// Kinds of vehicles
|
||||
enum Vehicle {
|
||||
Bicycle,
|
||||
Car,
|
||||
Train, ///< Move this to the top! -Sheldon
|
||||
Ship,
|
||||
Airplane,
|
||||
};
|
||||
|
||||
enum Direction : unsigned char {
|
||||
North = 0,
|
||||
East,
|
||||
South,
|
||||
West
|
||||
};
|
||||
|
||||
//--- 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": [
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:@E@Vehicle@Bicycle",
|
||||
"target": "c:@E@Vehicle"
|
||||
},
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:@E@Vehicle@Car",
|
||||
"target": "c:@E@Vehicle"
|
||||
},
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:@E@Vehicle@Train",
|
||||
"target": "c:@E@Vehicle"
|
||||
},
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:@E@Vehicle@Ship",
|
||||
"target": "c:@E@Vehicle"
|
||||
},
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:@E@Vehicle@Airplane",
|
||||
"target": "c:@E@Vehicle"
|
||||
},
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:@E@Direction@North",
|
||||
"target": "c:@E@Direction"
|
||||
},
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:@E@Direction@East",
|
||||
"target": "c:@E@Direction"
|
||||
},
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:@E@Direction@South",
|
||||
"target": "c:@E@Direction"
|
||||
},
|
||||
{
|
||||
"kind": "memberOf",
|
||||
"source": "c:@E@Direction@West",
|
||||
"target": "c:@E@Direction"
|
||||
}
|
||||
],
|
||||
"symbols": [
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "enum"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Vehicle"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ": "
|
||||
},
|
||||
{
|
||||
"kind": "typeIdentifier",
|
||||
"preciseIdentifier": "c:i",
|
||||
"spelling": "unsigned int"
|
||||
}
|
||||
],
|
||||
"docComment": {
|
||||
"lines": [
|
||||
{
|
||||
"range": {
|
||||
"end": {
|
||||
"character": 22,
|
||||
"line": 1
|
||||
},
|
||||
"start": {
|
||||
"character": 5,
|
||||
"line": 1
|
||||
}
|
||||
},
|
||||
"text": "Kinds of vehicles"
|
||||
}
|
||||
]
|
||||
},
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c",
|
||||
"precise": "c:@E@Vehicle"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Enumeration",
|
||||
"identifier": "c.enum"
|
||||
},
|
||||
"location": {
|
||||
"character": 6,
|
||||
"line": 2,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Vehicle"
|
||||
}
|
||||
],
|
||||
"title": "Vehicle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Bicycle"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c",
|
||||
"precise": "c:@E@Vehicle@Bicycle"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Enumeration Case",
|
||||
"identifier": "c.enum.case"
|
||||
},
|
||||
"location": {
|
||||
"character": 3,
|
||||
"line": 3,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Bicycle"
|
||||
}
|
||||
],
|
||||
"title": "Bicycle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Car"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c",
|
||||
"precise": "c:@E@Vehicle@Car"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Enumeration Case",
|
||||
"identifier": "c.enum.case"
|
||||
},
|
||||
"location": {
|
||||
"character": 3,
|
||||
"line": 4,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Car"
|
||||
}
|
||||
],
|
||||
"title": "Car"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Train"
|
||||
}
|
||||
],
|
||||
"docComment": {
|
||||
"lines": [
|
||||
{
|
||||
"range": {
|
||||
"end": {
|
||||
"character": 45,
|
||||
"line": 5
|
||||
},
|
||||
"start": {
|
||||
"character": 15,
|
||||
"line": 5
|
||||
}
|
||||
},
|
||||
"text": "Move this to the top! -Sheldon"
|
||||
}
|
||||
]
|
||||
},
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c",
|
||||
"precise": "c:@E@Vehicle@Train"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Enumeration Case",
|
||||
"identifier": "c.enum.case"
|
||||
},
|
||||
"location": {
|
||||
"character": 3,
|
||||
"line": 5,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Train"
|
||||
}
|
||||
],
|
||||
"title": "Train"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Ship"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c",
|
||||
"precise": "c:@E@Vehicle@Ship"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Enumeration Case",
|
||||
"identifier": "c.enum.case"
|
||||
},
|
||||
"location": {
|
||||
"character": 3,
|
||||
"line": 6,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Ship"
|
||||
}
|
||||
],
|
||||
"title": "Ship"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Airplane"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c",
|
||||
"precise": "c:@E@Vehicle@Airplane"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Enumeration Case",
|
||||
"identifier": "c.enum.case"
|
||||
},
|
||||
"location": {
|
||||
"character": 3,
|
||||
"line": 7,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Airplane"
|
||||
}
|
||||
],
|
||||
"title": "Airplane"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "keyword",
|
||||
"spelling": "enum"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": " "
|
||||
},
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Direction"
|
||||
},
|
||||
{
|
||||
"kind": "text",
|
||||
"spelling": ": "
|
||||
},
|
||||
{
|
||||
"kind": "typeIdentifier",
|
||||
"preciseIdentifier": "c:c",
|
||||
"spelling": "unsigned char"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c",
|
||||
"precise": "c:@E@Direction"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Enumeration",
|
||||
"identifier": "c.enum"
|
||||
},
|
||||
"location": {
|
||||
"character": 6,
|
||||
"line": 10,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "Direction"
|
||||
}
|
||||
],
|
||||
"title": "Direction"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "North"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c",
|
||||
"precise": "c:@E@Direction@North"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Enumeration Case",
|
||||
"identifier": "c.enum.case"
|
||||
},
|
||||
"location": {
|
||||
"character": 3,
|
||||
"line": 11,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "North"
|
||||
}
|
||||
],
|
||||
"title": "North"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "East"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c",
|
||||
"precise": "c:@E@Direction@East"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Enumeration Case",
|
||||
"identifier": "c.enum.case"
|
||||
},
|
||||
"location": {
|
||||
"character": 3,
|
||||
"line": 12,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "East"
|
||||
}
|
||||
],
|
||||
"title": "East"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "South"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c",
|
||||
"precise": "c:@E@Direction@South"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Enumeration Case",
|
||||
"identifier": "c.enum.case"
|
||||
},
|
||||
"location": {
|
||||
"character": 3,
|
||||
"line": 13,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "South"
|
||||
}
|
||||
],
|
||||
"title": "South"
|
||||
}
|
||||
},
|
||||
{
|
||||
"declarationFragments": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "West"
|
||||
}
|
||||
],
|
||||
"identifier": {
|
||||
"interfaceLanguage": "c",
|
||||
"precise": "c:@E@Direction@West"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Enumeration Case",
|
||||
"identifier": "c.enum.case"
|
||||
},
|
||||
"location": {
|
||||
"character": 3,
|
||||
"line": 14,
|
||||
"uri": "file://INPUT_DIR/input.h"
|
||||
},
|
||||
"names": {
|
||||
"subHeading": [
|
||||
{
|
||||
"kind": "identifier",
|
||||
"spelling": "West"
|
||||
}
|
||||
],
|
||||
"title": "West"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue