189f6b26fSZixu Wang //===- ExtractAPI/ExtractAPIConsumer.cpp ------------------------*- C++ -*-===// 289f6b26fSZixu Wang // 389f6b26fSZixu Wang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 489f6b26fSZixu Wang // See https://llvm.org/LICENSE.txt for license information. 589f6b26fSZixu Wang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 689f6b26fSZixu Wang // 789f6b26fSZixu Wang //===----------------------------------------------------------------------===// 889f6b26fSZixu Wang /// 989f6b26fSZixu Wang /// \file 1089f6b26fSZixu Wang /// This file implements the ExtractAPIAction, and ASTVisitor/Consumer to 1189f6b26fSZixu Wang /// collect API information. 1289f6b26fSZixu Wang /// 1389f6b26fSZixu Wang //===----------------------------------------------------------------------===// 1489f6b26fSZixu Wang 159fc45ca0SDaniel Grumberg #include "TypedefUnderlyingTypeResolver.h" 1689f6b26fSZixu Wang #include "clang/AST/ASTConsumer.h" 1789f6b26fSZixu Wang #include "clang/AST/ASTContext.h" 1889f6b26fSZixu Wang #include "clang/AST/Decl.h" 1989f6b26fSZixu Wang #include "clang/AST/DeclCXX.h" 2089f6b26fSZixu Wang #include "clang/AST/ParentMapContext.h" 2189f6b26fSZixu Wang #include "clang/AST/RawCommentList.h" 2289f6b26fSZixu Wang #include "clang/AST/RecursiveASTVisitor.h" 23aebe5fc6SDaniel Grumberg #include "clang/Basic/SourceLocation.h" 24aebe5fc6SDaniel Grumberg #include "clang/Basic/SourceManager.h" 2589f6b26fSZixu Wang #include "clang/Basic/TargetInfo.h" 2689f6b26fSZixu Wang #include "clang/ExtractAPI/API.h" 2789f6b26fSZixu Wang #include "clang/ExtractAPI/AvailabilityInfo.h" 2889f6b26fSZixu Wang #include "clang/ExtractAPI/DeclarationFragments.h" 2989f6b26fSZixu Wang #include "clang/ExtractAPI/FrontendActions.h" 3089f6b26fSZixu Wang #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" 3189f6b26fSZixu Wang #include "clang/Frontend/ASTConsumers.h" 3289f6b26fSZixu Wang #include "clang/Frontend/CompilerInstance.h" 33f833aab0SDaniel Grumberg #include "clang/Frontend/FrontendOptions.h" 34529a0570SDaniel Grumberg #include "clang/Lex/MacroInfo.h" 35529a0570SDaniel Grumberg #include "clang/Lex/PPCallbacks.h" 36aebe5fc6SDaniel Grumberg #include "clang/Lex/Preprocessor.h" 37529a0570SDaniel Grumberg #include "clang/Lex/PreprocessorOptions.h" 38aebe5fc6SDaniel Grumberg #include "llvm/ADT/DenseSet.h" 39529a0570SDaniel Grumberg #include "llvm/ADT/STLExtras.h" 40f833aab0SDaniel Grumberg #include "llvm/ADT/SmallVector.h" 41*cb5bb285SZixu Wang #include "llvm/Support/FileSystem.h" 42f833aab0SDaniel Grumberg #include "llvm/Support/MemoryBuffer.h" 43*cb5bb285SZixu Wang #include "llvm/Support/Path.h" 44*cb5bb285SZixu Wang #include "llvm/Support/Regex.h" 4589f6b26fSZixu Wang #include "llvm/Support/raw_ostream.h" 46aebe5fc6SDaniel Grumberg #include <memory> 47aebe5fc6SDaniel Grumberg #include <utility> 4889f6b26fSZixu Wang 4989f6b26fSZixu Wang using namespace clang; 5089f6b26fSZixu Wang using namespace extractapi; 5189f6b26fSZixu Wang 5289f6b26fSZixu Wang namespace { 5389f6b26fSZixu Wang 549fc45ca0SDaniel Grumberg StringRef getTypedefName(const TagDecl *Decl) { 559fc45ca0SDaniel Grumberg if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl()) 569fc45ca0SDaniel Grumberg return TypedefDecl->getName(); 579fc45ca0SDaniel Grumberg 589fc45ca0SDaniel Grumberg return {}; 599fc45ca0SDaniel Grumberg } 609fc45ca0SDaniel Grumberg 61*cb5bb285SZixu Wang Optional<std::string> getRelativeIncludeName(const CompilerInstance &CI, 62*cb5bb285SZixu Wang StringRef File, 63*cb5bb285SZixu Wang bool *IsQuoted = nullptr) { 64*cb5bb285SZixu Wang assert(CI.hasFileManager() && 65*cb5bb285SZixu Wang "CompilerInstance does not have a FileNamager!"); 66*cb5bb285SZixu Wang 67*cb5bb285SZixu Wang using namespace llvm::sys; 68*cb5bb285SZixu Wang // Matches framework include patterns 69*cb5bb285SZixu Wang const llvm::Regex Rule("/(.+)\\.framework/(.+)?Headers/(.+)"); 70*cb5bb285SZixu Wang 71*cb5bb285SZixu Wang const auto &FS = CI.getVirtualFileSystem(); 72*cb5bb285SZixu Wang 73*cb5bb285SZixu Wang SmallString<128> FilePath(File.begin(), File.end()); 74*cb5bb285SZixu Wang FS.makeAbsolute(FilePath); 75*cb5bb285SZixu Wang path::remove_dots(FilePath, true); 76*cb5bb285SZixu Wang FilePath = path::convert_to_slash(FilePath); 77*cb5bb285SZixu Wang File = FilePath; 78*cb5bb285SZixu Wang 79*cb5bb285SZixu Wang // Checks whether `Dir` is a strict path prefix of `File`. If so returns 80*cb5bb285SZixu Wang // the prefix length. Otherwise return 0. 81*cb5bb285SZixu Wang auto CheckDir = [&](llvm::StringRef Dir) -> unsigned { 82*cb5bb285SZixu Wang llvm::SmallString<32> DirPath(Dir.begin(), Dir.end()); 83*cb5bb285SZixu Wang FS.makeAbsolute(DirPath); 84*cb5bb285SZixu Wang path::remove_dots(DirPath, true); 85*cb5bb285SZixu Wang Dir = DirPath; 86*cb5bb285SZixu Wang for (auto NI = path::begin(File), NE = path::end(File), 87*cb5bb285SZixu Wang DI = path::begin(Dir), DE = path::end(Dir); 88*cb5bb285SZixu Wang /*termination condition in loop*/; ++NI, ++DI) { 89*cb5bb285SZixu Wang // '.' components in File are ignored. 90*cb5bb285SZixu Wang while (NI != NE && *NI == ".") 91*cb5bb285SZixu Wang ++NI; 92*cb5bb285SZixu Wang if (NI == NE) 93*cb5bb285SZixu Wang break; 94*cb5bb285SZixu Wang 95*cb5bb285SZixu Wang // '.' components in Dir are ignored. 96*cb5bb285SZixu Wang while (DI != DE && *DI == ".") 97*cb5bb285SZixu Wang ++DI; 98*cb5bb285SZixu Wang 99*cb5bb285SZixu Wang // Dir is a prefix of File, up to '.' components and choice of path 100*cb5bb285SZixu Wang // separators. 101*cb5bb285SZixu Wang if (DI == DE) 102*cb5bb285SZixu Wang return NI - path::begin(File); 103*cb5bb285SZixu Wang 104*cb5bb285SZixu Wang // Consider all path separators equal. 105*cb5bb285SZixu Wang if (NI->size() == 1 && DI->size() == 1 && 106*cb5bb285SZixu Wang path::is_separator(NI->front()) && path::is_separator(DI->front())) 107*cb5bb285SZixu Wang continue; 108*cb5bb285SZixu Wang 109*cb5bb285SZixu Wang // Special case Apple .sdk folders since the search path is typically a 110*cb5bb285SZixu Wang // symlink like `iPhoneSimulator14.5.sdk` while the file is instead 111*cb5bb285SZixu Wang // located in `iPhoneSimulator.sdk` (the real folder). 112*cb5bb285SZixu Wang if (NI->endswith(".sdk") && DI->endswith(".sdk")) { 113*cb5bb285SZixu Wang StringRef NBasename = path::stem(*NI); 114*cb5bb285SZixu Wang StringRef DBasename = path::stem(*DI); 115*cb5bb285SZixu Wang if (DBasename.startswith(NBasename)) 116*cb5bb285SZixu Wang continue; 117*cb5bb285SZixu Wang } 118*cb5bb285SZixu Wang 119*cb5bb285SZixu Wang if (*NI != *DI) 120*cb5bb285SZixu Wang break; 121*cb5bb285SZixu Wang } 122*cb5bb285SZixu Wang return 0; 123*cb5bb285SZixu Wang }; 124*cb5bb285SZixu Wang 125*cb5bb285SZixu Wang unsigned PrefixLength = 0; 126*cb5bb285SZixu Wang 127*cb5bb285SZixu Wang // Go through the search paths and find the first one that is a prefix of 128*cb5bb285SZixu Wang // the header. 129*cb5bb285SZixu Wang for (const auto &Entry : CI.getHeaderSearchOpts().UserEntries) { 130*cb5bb285SZixu Wang // Note whether the match is found in a quoted entry. 131*cb5bb285SZixu Wang if (IsQuoted) 132*cb5bb285SZixu Wang *IsQuoted = Entry.Group == frontend::Quoted; 133*cb5bb285SZixu Wang 134*cb5bb285SZixu Wang if (auto EntryFile = CI.getFileManager().getOptionalFileRef(Entry.Path)) { 135*cb5bb285SZixu Wang if (auto HMap = HeaderMap::Create(*EntryFile, CI.getFileManager())) { 136*cb5bb285SZixu Wang // If this is a headermap entry, try to reverse lookup the full path 137*cb5bb285SZixu Wang // for a spelled name before mapping. 138*cb5bb285SZixu Wang StringRef SpelledFilename = HMap->reverseLookupFilename(File); 139*cb5bb285SZixu Wang if (!SpelledFilename.empty()) 140*cb5bb285SZixu Wang return SpelledFilename.str(); 141*cb5bb285SZixu Wang 142*cb5bb285SZixu Wang // No matching mapping in this headermap, try next search entry. 143*cb5bb285SZixu Wang continue; 144*cb5bb285SZixu Wang } 145*cb5bb285SZixu Wang } 146*cb5bb285SZixu Wang 147*cb5bb285SZixu Wang // Entry is a directory search entry, try to check if it's a prefix of File. 148*cb5bb285SZixu Wang PrefixLength = CheckDir(Entry.Path); 149*cb5bb285SZixu Wang if (PrefixLength > 0) { 150*cb5bb285SZixu Wang // The header is found in a framework path, construct the framework-style 151*cb5bb285SZixu Wang // include name `<Framework/Header.h>` 152*cb5bb285SZixu Wang if (Entry.IsFramework) { 153*cb5bb285SZixu Wang SmallVector<StringRef, 4> Matches; 154*cb5bb285SZixu Wang Rule.match(File, &Matches); 155*cb5bb285SZixu Wang // Returned matches are always in stable order. 156*cb5bb285SZixu Wang if (Matches.size() != 4) 157*cb5bb285SZixu Wang return None; 158*cb5bb285SZixu Wang 159*cb5bb285SZixu Wang return path::convert_to_slash( 160*cb5bb285SZixu Wang (Matches[1].drop_front(Matches[1].rfind('/') + 1) + "/" + 161*cb5bb285SZixu Wang Matches[3]) 162*cb5bb285SZixu Wang .str()); 163*cb5bb285SZixu Wang } 164*cb5bb285SZixu Wang 165*cb5bb285SZixu Wang // The header is found in a normal search path, strip the search path 166*cb5bb285SZixu Wang // prefix to get an include name. 167*cb5bb285SZixu Wang return path::convert_to_slash(File.drop_front(PrefixLength)); 168*cb5bb285SZixu Wang } 169*cb5bb285SZixu Wang } 170*cb5bb285SZixu Wang 171*cb5bb285SZixu Wang // Couldn't determine a include name, use full path instead. 172*cb5bb285SZixu Wang return None; 173*cb5bb285SZixu Wang } 174*cb5bb285SZixu Wang 175aebe5fc6SDaniel Grumberg struct LocationFileChecker { 176aebe5fc6SDaniel Grumberg bool isLocationInKnownFile(SourceLocation Loc) { 177aebe5fc6SDaniel Grumberg // If the loc refers to a macro expansion we need to first get the file 178aebe5fc6SDaniel Grumberg // location of the expansion. 179*cb5bb285SZixu Wang auto &SM = CI.getSourceManager(); 180aebe5fc6SDaniel Grumberg auto FileLoc = SM.getFileLoc(Loc); 181aebe5fc6SDaniel Grumberg FileID FID = SM.getFileID(FileLoc); 182aebe5fc6SDaniel Grumberg if (FID.isInvalid()) 183aebe5fc6SDaniel Grumberg return false; 184aebe5fc6SDaniel Grumberg 185aebe5fc6SDaniel Grumberg const auto *File = SM.getFileEntryForID(FID); 186aebe5fc6SDaniel Grumberg if (!File) 187aebe5fc6SDaniel Grumberg return false; 188aebe5fc6SDaniel Grumberg 189aebe5fc6SDaniel Grumberg if (KnownFileEntries.count(File)) 190aebe5fc6SDaniel Grumberg return true; 191aebe5fc6SDaniel Grumberg 192*cb5bb285SZixu Wang if (ExternalFileEntries.count(File)) 193*cb5bb285SZixu Wang return false; 194*cb5bb285SZixu Wang 195*cb5bb285SZixu Wang StringRef FileName = File->tryGetRealPathName().empty() 196*cb5bb285SZixu Wang ? File->getName() 197*cb5bb285SZixu Wang : File->tryGetRealPathName(); 198*cb5bb285SZixu Wang 199*cb5bb285SZixu Wang // Try to reduce the include name the same way we tried to include it. 200*cb5bb285SZixu Wang bool IsQuoted = false; 201*cb5bb285SZixu Wang if (auto IncludeName = getRelativeIncludeName(CI, FileName, &IsQuoted)) 202*cb5bb285SZixu Wang if (llvm::find_if(KnownFiles, 203*cb5bb285SZixu Wang [&IsQuoted, &IncludeName](const auto &KnownFile) { 204*cb5bb285SZixu Wang return KnownFile.first.equals(*IncludeName) && 205*cb5bb285SZixu Wang KnownFile.second == IsQuoted; 206*cb5bb285SZixu Wang }) != KnownFiles.end()) { 207*cb5bb285SZixu Wang KnownFileEntries.insert(File); 208*cb5bb285SZixu Wang return true; 209*cb5bb285SZixu Wang } 210*cb5bb285SZixu Wang 211*cb5bb285SZixu Wang // Record that the file was not found to avoid future reverse lookup for 212*cb5bb285SZixu Wang // the same file. 213*cb5bb285SZixu Wang ExternalFileEntries.insert(File); 214aebe5fc6SDaniel Grumberg return false; 215aebe5fc6SDaniel Grumberg } 216aebe5fc6SDaniel Grumberg 217*cb5bb285SZixu Wang LocationFileChecker(const CompilerInstance &CI, 218*cb5bb285SZixu Wang SmallVector<std::pair<SmallString<32>, bool>> &KnownFiles) 219*cb5bb285SZixu Wang : CI(CI), KnownFiles(KnownFiles), ExternalFileEntries() { 220*cb5bb285SZixu Wang for (const auto &KnownFile : KnownFiles) 221*cb5bb285SZixu Wang if (auto FileEntry = CI.getFileManager().getFile(KnownFile.first)) 222aebe5fc6SDaniel Grumberg KnownFileEntries.insert(*FileEntry); 223aebe5fc6SDaniel Grumberg } 224aebe5fc6SDaniel Grumberg 225aebe5fc6SDaniel Grumberg private: 226*cb5bb285SZixu Wang const CompilerInstance &CI; 227*cb5bb285SZixu Wang SmallVector<std::pair<SmallString<32>, bool>> &KnownFiles; 228aebe5fc6SDaniel Grumberg llvm::DenseSet<const FileEntry *> KnownFileEntries; 229*cb5bb285SZixu Wang llvm::DenseSet<const FileEntry *> ExternalFileEntries; 230aebe5fc6SDaniel Grumberg }; 231aebe5fc6SDaniel Grumberg 23289f6b26fSZixu Wang /// The RecursiveASTVisitor to traverse symbol declarations and collect API 23389f6b26fSZixu Wang /// information. 23489f6b26fSZixu Wang class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> { 23589f6b26fSZixu Wang public: 236aebe5fc6SDaniel Grumberg ExtractAPIVisitor(ASTContext &Context, LocationFileChecker &LCF, APISet &API) 237aebe5fc6SDaniel Grumberg : Context(Context), API(API), LCF(LCF) {} 23889f6b26fSZixu Wang 23989f6b26fSZixu Wang const APISet &getAPI() const { return API; } 24089f6b26fSZixu Wang 24189f6b26fSZixu Wang bool VisitVarDecl(const VarDecl *Decl) { 24289f6b26fSZixu Wang // Skip function parameters. 24389f6b26fSZixu Wang if (isa<ParmVarDecl>(Decl)) 24489f6b26fSZixu Wang return true; 24589f6b26fSZixu Wang 24689f6b26fSZixu Wang // Skip non-global variables in records (struct/union/class). 24789f6b26fSZixu Wang if (Decl->getDeclContext()->isRecord()) 24889f6b26fSZixu Wang return true; 24989f6b26fSZixu Wang 25089f6b26fSZixu Wang // Skip local variables inside function or method. 25189f6b26fSZixu Wang if (!Decl->isDefinedOutsideFunctionOrMethod()) 25289f6b26fSZixu Wang return true; 25389f6b26fSZixu Wang 25489f6b26fSZixu Wang // If this is a template but not specialization or instantiation, skip. 25589f6b26fSZixu Wang if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) && 25689f6b26fSZixu Wang Decl->getTemplateSpecializationKind() == TSK_Undeclared) 25789f6b26fSZixu Wang return true; 25889f6b26fSZixu Wang 259aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(Decl->getLocation())) 260aebe5fc6SDaniel Grumberg return true; 261aebe5fc6SDaniel Grumberg 26289f6b26fSZixu Wang // Collect symbol information. 26389f6b26fSZixu Wang StringRef Name = Decl->getName(); 26489f6b26fSZixu Wang StringRef USR = API.recordUSR(Decl); 26589f6b26fSZixu Wang PresumedLoc Loc = 26689f6b26fSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 26789f6b26fSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 26889f6b26fSZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 26989f6b26fSZixu Wang DocComment Comment; 27089f6b26fSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 27189f6b26fSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 27289f6b26fSZixu Wang Context.getDiagnostics()); 27389f6b26fSZixu Wang 27489f6b26fSZixu Wang // Build declaration fragments and sub-heading for the variable. 27589f6b26fSZixu Wang DeclarationFragments Declaration = 27689f6b26fSZixu Wang DeclarationFragmentsBuilder::getFragmentsForVar(Decl); 27789f6b26fSZixu Wang DeclarationFragments SubHeading = 27889f6b26fSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 27989f6b26fSZixu Wang 28089f6b26fSZixu Wang // Add the global variable record to the API set. 28189f6b26fSZixu Wang API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment, 28289f6b26fSZixu Wang Declaration, SubHeading); 28389f6b26fSZixu Wang return true; 28489f6b26fSZixu Wang } 28589f6b26fSZixu Wang 28689f6b26fSZixu Wang bool VisitFunctionDecl(const FunctionDecl *Decl) { 28789f6b26fSZixu Wang if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) { 28889f6b26fSZixu Wang // Skip member function in class templates. 28989f6b26fSZixu Wang if (Method->getParent()->getDescribedClassTemplate() != nullptr) 29089f6b26fSZixu Wang return true; 29189f6b26fSZixu Wang 29289f6b26fSZixu Wang // Skip methods in records. 29389f6b26fSZixu Wang for (auto P : Context.getParents(*Method)) { 29489f6b26fSZixu Wang if (P.get<CXXRecordDecl>()) 29589f6b26fSZixu Wang return true; 29689f6b26fSZixu Wang } 29789f6b26fSZixu Wang 29889f6b26fSZixu Wang // Skip ConstructorDecl and DestructorDecl. 29989f6b26fSZixu Wang if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method)) 30089f6b26fSZixu Wang return true; 30189f6b26fSZixu Wang } 30289f6b26fSZixu Wang 30389f6b26fSZixu Wang // Skip templated functions. 30489f6b26fSZixu Wang switch (Decl->getTemplatedKind()) { 30589f6b26fSZixu Wang case FunctionDecl::TK_NonTemplate: 30689f6b26fSZixu Wang break; 30789f6b26fSZixu Wang case FunctionDecl::TK_MemberSpecialization: 30889f6b26fSZixu Wang case FunctionDecl::TK_FunctionTemplateSpecialization: 30989f6b26fSZixu Wang if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) { 31089f6b26fSZixu Wang if (!TemplateInfo->isExplicitInstantiationOrSpecialization()) 31189f6b26fSZixu Wang return true; 31289f6b26fSZixu Wang } 31389f6b26fSZixu Wang break; 31489f6b26fSZixu Wang case FunctionDecl::TK_FunctionTemplate: 31589f6b26fSZixu Wang case FunctionDecl::TK_DependentFunctionTemplateSpecialization: 31689f6b26fSZixu Wang return true; 31789f6b26fSZixu Wang } 31889f6b26fSZixu Wang 319aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(Decl->getLocation())) 320aebe5fc6SDaniel Grumberg return true; 321aebe5fc6SDaniel Grumberg 32289f6b26fSZixu Wang // Collect symbol information. 32389f6b26fSZixu Wang StringRef Name = Decl->getName(); 32489f6b26fSZixu Wang StringRef USR = API.recordUSR(Decl); 32589f6b26fSZixu Wang PresumedLoc Loc = 32689f6b26fSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 32789f6b26fSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 32889f6b26fSZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 32989f6b26fSZixu Wang DocComment Comment; 33089f6b26fSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 33189f6b26fSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 33289f6b26fSZixu Wang Context.getDiagnostics()); 33389f6b26fSZixu Wang 33489f6b26fSZixu Wang // Build declaration fragments, sub-heading, and signature of the function. 33589f6b26fSZixu Wang DeclarationFragments Declaration = 33689f6b26fSZixu Wang DeclarationFragmentsBuilder::getFragmentsForFunction(Decl); 33789f6b26fSZixu Wang DeclarationFragments SubHeading = 33889f6b26fSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 33989f6b26fSZixu Wang FunctionSignature Signature = 34089f6b26fSZixu Wang DeclarationFragmentsBuilder::getFunctionSignature(Decl); 34189f6b26fSZixu Wang 34289f6b26fSZixu Wang // Add the function record to the API set. 343236b6a0eSDaniel Grumberg API.addGlobalFunction(Name, USR, Loc, Availability, Linkage, Comment, 344236b6a0eSDaniel Grumberg Declaration, SubHeading, Signature); 34589f6b26fSZixu Wang return true; 34689f6b26fSZixu Wang } 34789f6b26fSZixu Wang 34871b4c226SZixu Wang bool VisitEnumDecl(const EnumDecl *Decl) { 34971b4c226SZixu Wang if (!Decl->isComplete()) 35071b4c226SZixu Wang return true; 35171b4c226SZixu Wang 35271b4c226SZixu Wang // Skip forward declaration. 35371b4c226SZixu Wang if (!Decl->isThisDeclarationADefinition()) 35471b4c226SZixu Wang return true; 35571b4c226SZixu Wang 356aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(Decl->getLocation())) 357aebe5fc6SDaniel Grumberg return true; 358aebe5fc6SDaniel Grumberg 35971b4c226SZixu Wang // Collect symbol information. 3607443a504SDaniel Grumberg std::string NameString = Decl->getQualifiedNameAsString(); 3617443a504SDaniel Grumberg StringRef Name(NameString); 3629fc45ca0SDaniel Grumberg if (Name.empty()) 3639fc45ca0SDaniel Grumberg Name = getTypedefName(Decl); 3647443a504SDaniel Grumberg 36571b4c226SZixu Wang StringRef USR = API.recordUSR(Decl); 36671b4c226SZixu Wang PresumedLoc Loc = 36771b4c226SZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 36871b4c226SZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 36971b4c226SZixu Wang DocComment Comment; 37071b4c226SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 37171b4c226SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 37271b4c226SZixu Wang Context.getDiagnostics()); 37371b4c226SZixu Wang 37471b4c226SZixu Wang // Build declaration fragments and sub-heading for the enum. 37571b4c226SZixu Wang DeclarationFragments Declaration = 37671b4c226SZixu Wang DeclarationFragmentsBuilder::getFragmentsForEnum(Decl); 37771b4c226SZixu Wang DeclarationFragments SubHeading = 37871b4c226SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 37971b4c226SZixu Wang 3807443a504SDaniel Grumberg EnumRecord *EnumRecord = 3817443a504SDaniel Grumberg API.addEnum(API.copyString(Name), USR, Loc, Availability, Comment, 38271b4c226SZixu Wang Declaration, SubHeading); 38371b4c226SZixu Wang 38471b4c226SZixu Wang // Now collect information about the enumerators in this enum. 38571b4c226SZixu Wang recordEnumConstants(EnumRecord, Decl->enumerators()); 38671b4c226SZixu Wang 38771b4c226SZixu Wang return true; 38871b4c226SZixu Wang } 38971b4c226SZixu Wang 3905bb5704cSZixu Wang bool VisitRecordDecl(const RecordDecl *Decl) { 3915bb5704cSZixu Wang if (!Decl->isCompleteDefinition()) 3925bb5704cSZixu Wang return true; 3935bb5704cSZixu Wang 3945bb5704cSZixu Wang // Skip C++ structs/classes/unions 3955bb5704cSZixu Wang // TODO: support C++ records 3965bb5704cSZixu Wang if (isa<CXXRecordDecl>(Decl)) 3975bb5704cSZixu Wang return true; 3985bb5704cSZixu Wang 399aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(Decl->getLocation())) 400aebe5fc6SDaniel Grumberg return true; 401aebe5fc6SDaniel Grumberg 4025bb5704cSZixu Wang // Collect symbol information. 4035bb5704cSZixu Wang StringRef Name = Decl->getName(); 4049fc45ca0SDaniel Grumberg if (Name.empty()) 4059fc45ca0SDaniel Grumberg Name = getTypedefName(Decl); 4065bb5704cSZixu Wang StringRef USR = API.recordUSR(Decl); 4075bb5704cSZixu Wang PresumedLoc Loc = 4085bb5704cSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 4095bb5704cSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 4105bb5704cSZixu Wang DocComment Comment; 4115bb5704cSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 4125bb5704cSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 4135bb5704cSZixu Wang Context.getDiagnostics()); 4145bb5704cSZixu Wang 4155bb5704cSZixu Wang // Build declaration fragments and sub-heading for the struct. 4165bb5704cSZixu Wang DeclarationFragments Declaration = 4175bb5704cSZixu Wang DeclarationFragmentsBuilder::getFragmentsForStruct(Decl); 4185bb5704cSZixu Wang DeclarationFragments SubHeading = 4195bb5704cSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 4205bb5704cSZixu Wang 4215bb5704cSZixu Wang StructRecord *StructRecord = API.addStruct( 4225bb5704cSZixu Wang Name, USR, Loc, Availability, Comment, Declaration, SubHeading); 4235bb5704cSZixu Wang 4245bb5704cSZixu Wang // Now collect information about the fields in this struct. 4255bb5704cSZixu Wang recordStructFields(StructRecord, Decl->fields()); 4265bb5704cSZixu Wang 4275bb5704cSZixu Wang return true; 4285bb5704cSZixu Wang } 4295bb5704cSZixu Wang 4309b36e126SZixu Wang bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) { 4319b36e126SZixu Wang // Skip forward declaration for classes (@class) 4329b36e126SZixu Wang if (!Decl->isThisDeclarationADefinition()) 4339b36e126SZixu Wang return true; 4349b36e126SZixu Wang 435aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(Decl->getLocation())) 436aebe5fc6SDaniel Grumberg return true; 437aebe5fc6SDaniel Grumberg 4389b36e126SZixu Wang // Collect symbol information. 4399b36e126SZixu Wang StringRef Name = Decl->getName(); 4409b36e126SZixu Wang StringRef USR = API.recordUSR(Decl); 4419b36e126SZixu Wang PresumedLoc Loc = 4429b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 4439b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 4449b36e126SZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 4459b36e126SZixu Wang DocComment Comment; 4469b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 4479b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 4489b36e126SZixu Wang Context.getDiagnostics()); 4499b36e126SZixu Wang 4509b36e126SZixu Wang // Build declaration fragments and sub-heading for the interface. 4519b36e126SZixu Wang DeclarationFragments Declaration = 4529b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl); 4539b36e126SZixu Wang DeclarationFragments SubHeading = 4549b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 4559b36e126SZixu Wang 4569b36e126SZixu Wang // Collect super class information. 4579b36e126SZixu Wang SymbolReference SuperClass; 4589b36e126SZixu Wang if (const auto *SuperClassDecl = Decl->getSuperClass()) { 4599b36e126SZixu Wang SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString(); 4609b36e126SZixu Wang SuperClass.USR = API.recordUSR(SuperClassDecl); 4619b36e126SZixu Wang } 4629b36e126SZixu Wang 4639b36e126SZixu Wang ObjCInterfaceRecord *ObjCInterfaceRecord = 4649b36e126SZixu Wang API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment, 4659b36e126SZixu Wang Declaration, SubHeading, SuperClass); 4669b36e126SZixu Wang 4679b36e126SZixu Wang // Record all methods (selectors). This doesn't include automatically 4689b36e126SZixu Wang // synthesized property methods. 4699b36e126SZixu Wang recordObjCMethods(ObjCInterfaceRecord, Decl->methods()); 4709b36e126SZixu Wang recordObjCProperties(ObjCInterfaceRecord, Decl->properties()); 4719b36e126SZixu Wang recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars()); 4729b36e126SZixu Wang recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols()); 4739b36e126SZixu Wang 4749b36e126SZixu Wang return true; 4759b36e126SZixu Wang } 4769b36e126SZixu Wang 477d1d34bafSZixu Wang bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) { 478d1d34bafSZixu Wang // Skip forward declaration for protocols (@protocol). 479d1d34bafSZixu Wang if (!Decl->isThisDeclarationADefinition()) 480d1d34bafSZixu Wang return true; 481d1d34bafSZixu Wang 482aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(Decl->getLocation())) 483aebe5fc6SDaniel Grumberg return true; 484aebe5fc6SDaniel Grumberg 485d1d34bafSZixu Wang // Collect symbol information. 486d1d34bafSZixu Wang StringRef Name = Decl->getName(); 487d1d34bafSZixu Wang StringRef USR = API.recordUSR(Decl); 488d1d34bafSZixu Wang PresumedLoc Loc = 489d1d34bafSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 490d1d34bafSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 491d1d34bafSZixu Wang DocComment Comment; 492d1d34bafSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 493d1d34bafSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 494d1d34bafSZixu Wang Context.getDiagnostics()); 495d1d34bafSZixu Wang 496d1d34bafSZixu Wang // Build declaration fragments and sub-heading for the protocol. 497d1d34bafSZixu Wang DeclarationFragments Declaration = 498d1d34bafSZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl); 499d1d34bafSZixu Wang DeclarationFragments SubHeading = 500d1d34bafSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 501d1d34bafSZixu Wang 502d1d34bafSZixu Wang ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol( 503d1d34bafSZixu Wang Name, USR, Loc, Availability, Comment, Declaration, SubHeading); 504d1d34bafSZixu Wang 505d1d34bafSZixu Wang recordObjCMethods(ObjCProtocolRecord, Decl->methods()); 506d1d34bafSZixu Wang recordObjCProperties(ObjCProtocolRecord, Decl->properties()); 507d1d34bafSZixu Wang recordObjCProtocols(ObjCProtocolRecord, Decl->protocols()); 508d1d34bafSZixu Wang 509d1d34bafSZixu Wang return true; 510d1d34bafSZixu Wang } 511d1d34bafSZixu Wang 5129fc45ca0SDaniel Grumberg bool VisitTypedefNameDecl(const TypedefNameDecl *Decl) { 5139fc45ca0SDaniel Grumberg // Skip ObjC Type Parameter for now. 5149fc45ca0SDaniel Grumberg if (isa<ObjCTypeParamDecl>(Decl)) 5159fc45ca0SDaniel Grumberg return true; 5169fc45ca0SDaniel Grumberg 5179fc45ca0SDaniel Grumberg if (!Decl->isDefinedOutsideFunctionOrMethod()) 5189fc45ca0SDaniel Grumberg return true; 5199fc45ca0SDaniel Grumberg 520aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(Decl->getLocation())) 521aebe5fc6SDaniel Grumberg return true; 522aebe5fc6SDaniel Grumberg 5239fc45ca0SDaniel Grumberg PresumedLoc Loc = 5249fc45ca0SDaniel Grumberg Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 5259fc45ca0SDaniel Grumberg StringRef Name = Decl->getName(); 5269fc45ca0SDaniel Grumberg AvailabilityInfo Availability = getAvailability(Decl); 5279fc45ca0SDaniel Grumberg StringRef USR = API.recordUSR(Decl); 5289fc45ca0SDaniel Grumberg DocComment Comment; 5299fc45ca0SDaniel Grumberg if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 5309fc45ca0SDaniel Grumberg Comment = RawComment->getFormattedLines(Context.getSourceManager(), 5319fc45ca0SDaniel Grumberg Context.getDiagnostics()); 5329fc45ca0SDaniel Grumberg 5339fc45ca0SDaniel Grumberg QualType Type = Decl->getUnderlyingType(); 5349fc45ca0SDaniel Grumberg SymbolReference SymRef = 5359fc45ca0SDaniel Grumberg TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type, 5369fc45ca0SDaniel Grumberg API); 5379fc45ca0SDaniel Grumberg 5389fc45ca0SDaniel Grumberg API.addTypedef(Name, USR, Loc, Availability, Comment, 5399fc45ca0SDaniel Grumberg DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl), 5409fc45ca0SDaniel Grumberg DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef); 5419fc45ca0SDaniel Grumberg 5429fc45ca0SDaniel Grumberg return true; 5439fc45ca0SDaniel Grumberg } 5449fc45ca0SDaniel Grumberg 545178aad9bSZixu Wang bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl) { 546178aad9bSZixu Wang // Collect symbol information. 547178aad9bSZixu Wang StringRef Name = Decl->getName(); 548178aad9bSZixu Wang StringRef USR = API.recordUSR(Decl); 549178aad9bSZixu Wang PresumedLoc Loc = 550178aad9bSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 551178aad9bSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 552178aad9bSZixu Wang DocComment Comment; 553178aad9bSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 554178aad9bSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 555178aad9bSZixu Wang Context.getDiagnostics()); 556178aad9bSZixu Wang // Build declaration fragments and sub-heading for the category. 557178aad9bSZixu Wang DeclarationFragments Declaration = 558178aad9bSZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl); 559178aad9bSZixu Wang DeclarationFragments SubHeading = 560178aad9bSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 561178aad9bSZixu Wang 562178aad9bSZixu Wang const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface(); 563178aad9bSZixu Wang SymbolReference Interface(InterfaceDecl->getName(), 564178aad9bSZixu Wang API.recordUSR(InterfaceDecl)); 565178aad9bSZixu Wang 566178aad9bSZixu Wang ObjCCategoryRecord *ObjCCategoryRecord = 567178aad9bSZixu Wang API.addObjCCategory(Name, USR, Loc, Availability, Comment, Declaration, 568178aad9bSZixu Wang SubHeading, Interface); 569178aad9bSZixu Wang 570178aad9bSZixu Wang recordObjCMethods(ObjCCategoryRecord, Decl->methods()); 571178aad9bSZixu Wang recordObjCProperties(ObjCCategoryRecord, Decl->properties()); 572178aad9bSZixu Wang recordObjCInstanceVariables(ObjCCategoryRecord, Decl->ivars()); 573178aad9bSZixu Wang recordObjCProtocols(ObjCCategoryRecord, Decl->protocols()); 574178aad9bSZixu Wang 575178aad9bSZixu Wang return true; 576178aad9bSZixu Wang } 577178aad9bSZixu Wang 57889f6b26fSZixu Wang private: 57989f6b26fSZixu Wang /// Get availability information of the declaration \p D. 58089f6b26fSZixu Wang AvailabilityInfo getAvailability(const Decl *D) const { 58189f6b26fSZixu Wang StringRef PlatformName = Context.getTargetInfo().getPlatformName(); 58289f6b26fSZixu Wang 58389f6b26fSZixu Wang AvailabilityInfo Availability; 58489f6b26fSZixu Wang // Collect availability attributes from all redeclarations. 58589f6b26fSZixu Wang for (const auto *RD : D->redecls()) { 58689f6b26fSZixu Wang for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) { 58789f6b26fSZixu Wang if (A->getPlatform()->getName() != PlatformName) 58889f6b26fSZixu Wang continue; 58989f6b26fSZixu Wang Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(), 59089f6b26fSZixu Wang A->getObsoleted(), A->getUnavailable(), 59189f6b26fSZixu Wang /* UnconditionallyDeprecated */ false, 59289f6b26fSZixu Wang /* UnconditionallyUnavailable */ false); 59389f6b26fSZixu Wang break; 59489f6b26fSZixu Wang } 59589f6b26fSZixu Wang 59689f6b26fSZixu Wang if (const auto *A = RD->getAttr<UnavailableAttr>()) 59789f6b26fSZixu Wang if (!A->isImplicit()) { 59889f6b26fSZixu Wang Availability.Unavailable = true; 59989f6b26fSZixu Wang Availability.UnconditionallyUnavailable = true; 60089f6b26fSZixu Wang } 60189f6b26fSZixu Wang 60289f6b26fSZixu Wang if (const auto *A = RD->getAttr<DeprecatedAttr>()) 60389f6b26fSZixu Wang if (!A->isImplicit()) 60489f6b26fSZixu Wang Availability.UnconditionallyDeprecated = true; 60589f6b26fSZixu Wang } 60689f6b26fSZixu Wang 60789f6b26fSZixu Wang return Availability; 60889f6b26fSZixu Wang } 60989f6b26fSZixu Wang 61071b4c226SZixu Wang /// Collect API information for the enum constants and associate with the 61171b4c226SZixu Wang /// parent enum. 61271b4c226SZixu Wang void recordEnumConstants(EnumRecord *EnumRecord, 61371b4c226SZixu Wang const EnumDecl::enumerator_range Constants) { 61471b4c226SZixu Wang for (const auto *Constant : Constants) { 61571b4c226SZixu Wang // Collect symbol information. 61671b4c226SZixu Wang StringRef Name = Constant->getName(); 61771b4c226SZixu Wang StringRef USR = API.recordUSR(Constant); 61871b4c226SZixu Wang PresumedLoc Loc = 61971b4c226SZixu Wang Context.getSourceManager().getPresumedLoc(Constant->getLocation()); 62071b4c226SZixu Wang AvailabilityInfo Availability = getAvailability(Constant); 62171b4c226SZixu Wang DocComment Comment; 62271b4c226SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant)) 62371b4c226SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 62471b4c226SZixu Wang Context.getDiagnostics()); 62571b4c226SZixu Wang 62671b4c226SZixu Wang // Build declaration fragments and sub-heading for the enum constant. 62771b4c226SZixu Wang DeclarationFragments Declaration = 62871b4c226SZixu Wang DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant); 62971b4c226SZixu Wang DeclarationFragments SubHeading = 63071b4c226SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Constant); 63171b4c226SZixu Wang 63271b4c226SZixu Wang API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment, 63371b4c226SZixu Wang Declaration, SubHeading); 63471b4c226SZixu Wang } 63571b4c226SZixu Wang } 63671b4c226SZixu Wang 6375bb5704cSZixu Wang /// Collect API information for the struct fields and associate with the 6385bb5704cSZixu Wang /// parent struct. 6395bb5704cSZixu Wang void recordStructFields(StructRecord *StructRecord, 6405bb5704cSZixu Wang const RecordDecl::field_range Fields) { 6415bb5704cSZixu Wang for (const auto *Field : Fields) { 6425bb5704cSZixu Wang // Collect symbol information. 6435bb5704cSZixu Wang StringRef Name = Field->getName(); 6445bb5704cSZixu Wang StringRef USR = API.recordUSR(Field); 6455bb5704cSZixu Wang PresumedLoc Loc = 6465bb5704cSZixu Wang Context.getSourceManager().getPresumedLoc(Field->getLocation()); 6475bb5704cSZixu Wang AvailabilityInfo Availability = getAvailability(Field); 6485bb5704cSZixu Wang DocComment Comment; 6495bb5704cSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field)) 6505bb5704cSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 6515bb5704cSZixu Wang Context.getDiagnostics()); 6525bb5704cSZixu Wang 6535bb5704cSZixu Wang // Build declaration fragments and sub-heading for the struct field. 6545bb5704cSZixu Wang DeclarationFragments Declaration = 6555bb5704cSZixu Wang DeclarationFragmentsBuilder::getFragmentsForField(Field); 6565bb5704cSZixu Wang DeclarationFragments SubHeading = 6575bb5704cSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Field); 6585bb5704cSZixu Wang 6595bb5704cSZixu Wang API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment, 6605bb5704cSZixu Wang Declaration, SubHeading); 6615bb5704cSZixu Wang } 6625bb5704cSZixu Wang } 6635bb5704cSZixu Wang 6649b36e126SZixu Wang /// Collect API information for the Objective-C methods and associate with the 6659b36e126SZixu Wang /// parent container. 6669b36e126SZixu Wang void recordObjCMethods(ObjCContainerRecord *Container, 6679b36e126SZixu Wang const ObjCContainerDecl::method_range Methods) { 6689b36e126SZixu Wang for (const auto *Method : Methods) { 6699b36e126SZixu Wang // Don't record selectors for properties. 6709b36e126SZixu Wang if (Method->isPropertyAccessor()) 6719b36e126SZixu Wang continue; 6729b36e126SZixu Wang 6739b36e126SZixu Wang StringRef Name = API.copyString(Method->getSelector().getAsString()); 6749b36e126SZixu Wang StringRef USR = API.recordUSR(Method); 6759b36e126SZixu Wang PresumedLoc Loc = 6769b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Method->getLocation()); 6779b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Method); 6789b36e126SZixu Wang DocComment Comment; 6799b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method)) 6809b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 6819b36e126SZixu Wang Context.getDiagnostics()); 6829b36e126SZixu Wang 6839b36e126SZixu Wang // Build declaration fragments, sub-heading, and signature for the method. 6849b36e126SZixu Wang DeclarationFragments Declaration = 6859b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method); 6869b36e126SZixu Wang DeclarationFragments SubHeading = 6879b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Method); 6889b36e126SZixu Wang FunctionSignature Signature = 6899b36e126SZixu Wang DeclarationFragmentsBuilder::getFunctionSignature(Method); 6909b36e126SZixu Wang 6919b36e126SZixu Wang API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment, 6929b36e126SZixu Wang Declaration, SubHeading, Signature, 6939b36e126SZixu Wang Method->isInstanceMethod()); 6949b36e126SZixu Wang } 6959b36e126SZixu Wang } 6969b36e126SZixu Wang 6979b36e126SZixu Wang void recordObjCProperties(ObjCContainerRecord *Container, 6989b36e126SZixu Wang const ObjCContainerDecl::prop_range Properties) { 6999b36e126SZixu Wang for (const auto *Property : Properties) { 7009b36e126SZixu Wang StringRef Name = Property->getName(); 7019b36e126SZixu Wang StringRef USR = API.recordUSR(Property); 7029b36e126SZixu Wang PresumedLoc Loc = 7039b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Property->getLocation()); 7049b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Property); 7059b36e126SZixu Wang DocComment Comment; 7069b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property)) 7079b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 7089b36e126SZixu Wang Context.getDiagnostics()); 7099b36e126SZixu Wang 7109b36e126SZixu Wang // Build declaration fragments and sub-heading for the property. 7119b36e126SZixu Wang DeclarationFragments Declaration = 7129b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property); 7139b36e126SZixu Wang DeclarationFragments SubHeading = 7149b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Property); 7159b36e126SZixu Wang 7169b36e126SZixu Wang StringRef GetterName = 7179b36e126SZixu Wang API.copyString(Property->getGetterName().getAsString()); 7189b36e126SZixu Wang StringRef SetterName = 7199b36e126SZixu Wang API.copyString(Property->getSetterName().getAsString()); 7209b36e126SZixu Wang 7219b36e126SZixu Wang // Get the attributes for property. 7229b36e126SZixu Wang unsigned Attributes = ObjCPropertyRecord::NoAttr; 7239b36e126SZixu Wang if (Property->getPropertyAttributes() & 7249b36e126SZixu Wang ObjCPropertyAttribute::kind_readonly) 7259b36e126SZixu Wang Attributes |= ObjCPropertyRecord::ReadOnly; 7269b36e126SZixu Wang if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class) 7279b36e126SZixu Wang Attributes |= ObjCPropertyRecord::Class; 7289b36e126SZixu Wang 7299b36e126SZixu Wang API.addObjCProperty( 7309b36e126SZixu Wang Container, Name, USR, Loc, Availability, Comment, Declaration, 7319b36e126SZixu Wang SubHeading, 7329b36e126SZixu Wang static_cast<ObjCPropertyRecord::AttributeKind>(Attributes), 7339b36e126SZixu Wang GetterName, SetterName, Property->isOptional()); 7349b36e126SZixu Wang } 7359b36e126SZixu Wang } 7369b36e126SZixu Wang 7379b36e126SZixu Wang void recordObjCInstanceVariables( 7389b36e126SZixu Wang ObjCContainerRecord *Container, 7399b36e126SZixu Wang const llvm::iterator_range< 7409b36e126SZixu Wang DeclContext::specific_decl_iterator<ObjCIvarDecl>> 7419b36e126SZixu Wang Ivars) { 7429b36e126SZixu Wang for (const auto *Ivar : Ivars) { 7439b36e126SZixu Wang StringRef Name = Ivar->getName(); 7449b36e126SZixu Wang StringRef USR = API.recordUSR(Ivar); 7459b36e126SZixu Wang PresumedLoc Loc = 7469b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Ivar->getLocation()); 7479b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Ivar); 7489b36e126SZixu Wang DocComment Comment; 7499b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar)) 7509b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 7519b36e126SZixu Wang Context.getDiagnostics()); 7529b36e126SZixu Wang 7539b36e126SZixu Wang // Build declaration fragments and sub-heading for the instance variable. 7549b36e126SZixu Wang DeclarationFragments Declaration = 7559b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForField(Ivar); 7569b36e126SZixu Wang DeclarationFragments SubHeading = 7579b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Ivar); 7589b36e126SZixu Wang 7599b36e126SZixu Wang ObjCInstanceVariableRecord::AccessControl Access = 7609b36e126SZixu Wang Ivar->getCanonicalAccessControl(); 7619b36e126SZixu Wang 7629b36e126SZixu Wang API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability, 7639b36e126SZixu Wang Comment, Declaration, SubHeading, Access); 7649b36e126SZixu Wang } 7659b36e126SZixu Wang } 7669b36e126SZixu Wang 7679b36e126SZixu Wang void recordObjCProtocols(ObjCContainerRecord *Container, 7689b36e126SZixu Wang ObjCInterfaceDecl::protocol_range Protocols) { 7699b36e126SZixu Wang for (const auto *Protocol : Protocols) 7709b36e126SZixu Wang Container->Protocols.emplace_back(Protocol->getName(), 7719b36e126SZixu Wang API.recordUSR(Protocol)); 7729b36e126SZixu Wang } 7739b36e126SZixu Wang 77489f6b26fSZixu Wang ASTContext &Context; 775a9909d23SDaniel Grumberg APISet &API; 776aebe5fc6SDaniel Grumberg LocationFileChecker &LCF; 77789f6b26fSZixu Wang }; 77889f6b26fSZixu Wang 77989f6b26fSZixu Wang class ExtractAPIConsumer : public ASTConsumer { 78089f6b26fSZixu Wang public: 781aebe5fc6SDaniel Grumberg ExtractAPIConsumer(ASTContext &Context, 782aebe5fc6SDaniel Grumberg std::unique_ptr<LocationFileChecker> LCF, APISet &API) 783aebe5fc6SDaniel Grumberg : Visitor(Context, *LCF, API), LCF(std::move(LCF)) {} 78489f6b26fSZixu Wang 78589f6b26fSZixu Wang void HandleTranslationUnit(ASTContext &Context) override { 78689f6b26fSZixu Wang // Use ExtractAPIVisitor to traverse symbol declarations in the context. 78789f6b26fSZixu Wang Visitor.TraverseDecl(Context.getTranslationUnitDecl()); 78889f6b26fSZixu Wang } 78989f6b26fSZixu Wang 79089f6b26fSZixu Wang private: 79189f6b26fSZixu Wang ExtractAPIVisitor Visitor; 792aebe5fc6SDaniel Grumberg std::unique_ptr<LocationFileChecker> LCF; 79389f6b26fSZixu Wang }; 79489f6b26fSZixu Wang 795529a0570SDaniel Grumberg class MacroCallback : public PPCallbacks { 796529a0570SDaniel Grumberg public: 79710155922SDaniel Grumberg MacroCallback(const SourceManager &SM, LocationFileChecker &LCF, APISet &API, 79810155922SDaniel Grumberg Preprocessor &PP) 79910155922SDaniel Grumberg : SM(SM), LCF(LCF), API(API), PP(PP) {} 800529a0570SDaniel Grumberg 801529a0570SDaniel Grumberg void MacroDefined(const Token &MacroNameToken, 802529a0570SDaniel Grumberg const MacroDirective *MD) override { 803529a0570SDaniel Grumberg auto *MacroInfo = MD->getMacroInfo(); 804529a0570SDaniel Grumberg 805529a0570SDaniel Grumberg if (MacroInfo->isBuiltinMacro()) 806529a0570SDaniel Grumberg return; 807529a0570SDaniel Grumberg 808529a0570SDaniel Grumberg auto SourceLoc = MacroNameToken.getLocation(); 809529a0570SDaniel Grumberg if (SM.isWrittenInBuiltinFile(SourceLoc) || 810529a0570SDaniel Grumberg SM.isWrittenInCommandLineFile(SourceLoc)) 811529a0570SDaniel Grumberg return; 812529a0570SDaniel Grumberg 813529a0570SDaniel Grumberg PendingMacros.emplace_back(MacroNameToken, MD); 814529a0570SDaniel Grumberg } 815529a0570SDaniel Grumberg 816529a0570SDaniel Grumberg // If a macro gets undefined at some point during preprocessing of the inputs 817529a0570SDaniel Grumberg // it means that it isn't an exposed API and we should therefore not add a 818529a0570SDaniel Grumberg // macro definition for it. 819529a0570SDaniel Grumberg void MacroUndefined(const Token &MacroNameToken, const MacroDefinition &MD, 820529a0570SDaniel Grumberg const MacroDirective *Undef) override { 8218b63622bSDaniel Grumberg // If this macro wasn't previously defined we don't need to do anything 8228b63622bSDaniel Grumberg // here. 8238b63622bSDaniel Grumberg if (!Undef) 8248b63622bSDaniel Grumberg return; 8258b63622bSDaniel Grumberg 82610155922SDaniel Grumberg llvm::erase_if(PendingMacros, [&MD, this](const PendingMacro &PM) { 82710155922SDaniel Grumberg return MD.getMacroInfo()->isIdenticalTo(*PM.MD->getMacroInfo(), PP, 82810155922SDaniel Grumberg /*Syntactically*/ false); 829529a0570SDaniel Grumberg }); 830529a0570SDaniel Grumberg } 831529a0570SDaniel Grumberg 832529a0570SDaniel Grumberg void EndOfMainFile() override { 833529a0570SDaniel Grumberg for (auto &PM : PendingMacros) { 834529a0570SDaniel Grumberg // `isUsedForHeaderGuard` is only set when the preprocessor leaves the 835529a0570SDaniel Grumberg // file so check for it here. 836529a0570SDaniel Grumberg if (PM.MD->getMacroInfo()->isUsedForHeaderGuard()) 837529a0570SDaniel Grumberg continue; 838529a0570SDaniel Grumberg 839aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(PM.MacroNameToken.getLocation())) 840aebe5fc6SDaniel Grumberg continue; 841aebe5fc6SDaniel Grumberg 842529a0570SDaniel Grumberg StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName(); 843529a0570SDaniel Grumberg PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation()); 844529a0570SDaniel Grumberg StringRef USR = 845529a0570SDaniel Grumberg API.recordUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM); 846529a0570SDaniel Grumberg 847529a0570SDaniel Grumberg API.addMacroDefinition( 848529a0570SDaniel Grumberg Name, USR, Loc, 849529a0570SDaniel Grumberg DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD), 850529a0570SDaniel Grumberg DeclarationFragmentsBuilder::getSubHeadingForMacro(Name)); 851529a0570SDaniel Grumberg } 852529a0570SDaniel Grumberg 853529a0570SDaniel Grumberg PendingMacros.clear(); 854529a0570SDaniel Grumberg } 855529a0570SDaniel Grumberg 856529a0570SDaniel Grumberg private: 857529a0570SDaniel Grumberg struct PendingMacro { 858529a0570SDaniel Grumberg Token MacroNameToken; 859529a0570SDaniel Grumberg const MacroDirective *MD; 860529a0570SDaniel Grumberg 861529a0570SDaniel Grumberg PendingMacro(const Token &MacroNameToken, const MacroDirective *MD) 862529a0570SDaniel Grumberg : MacroNameToken(MacroNameToken), MD(MD) {} 863529a0570SDaniel Grumberg }; 864529a0570SDaniel Grumberg 865529a0570SDaniel Grumberg const SourceManager &SM; 866aebe5fc6SDaniel Grumberg LocationFileChecker &LCF; 867529a0570SDaniel Grumberg APISet &API; 86810155922SDaniel Grumberg Preprocessor &PP; 869529a0570SDaniel Grumberg llvm::SmallVector<PendingMacro> PendingMacros; 870529a0570SDaniel Grumberg }; 871529a0570SDaniel Grumberg 87289f6b26fSZixu Wang } // namespace 87389f6b26fSZixu Wang 87489f6b26fSZixu Wang std::unique_ptr<ASTConsumer> 87589f6b26fSZixu Wang ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { 876a9909d23SDaniel Grumberg OS = CreateOutputFile(CI, InFile); 87789f6b26fSZixu Wang if (!OS) 87889f6b26fSZixu Wang return nullptr; 879a9909d23SDaniel Grumberg 880a9909d23SDaniel Grumberg ProductName = CI.getFrontendOpts().ProductName; 881a9909d23SDaniel Grumberg 882a9909d23SDaniel Grumberg // Now that we have enough information about the language options and the 883a9909d23SDaniel Grumberg // target triple, let's create the APISet before anyone uses it. 884a9909d23SDaniel Grumberg API = std::make_unique<APISet>( 885a9909d23SDaniel Grumberg CI.getTarget().getTriple(), 886a9909d23SDaniel Grumberg CI.getFrontendOpts().Inputs.back().getKind().getLanguage()); 887a9909d23SDaniel Grumberg 888*cb5bb285SZixu Wang auto LCF = std::make_unique<LocationFileChecker>(CI, KnownInputFiles); 889aebe5fc6SDaniel Grumberg 89010155922SDaniel Grumberg CI.getPreprocessor().addPPCallbacks(std::make_unique<MacroCallback>( 89110155922SDaniel Grumberg CI.getSourceManager(), *LCF, *API, CI.getPreprocessor())); 892529a0570SDaniel Grumberg 893aebe5fc6SDaniel Grumberg return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(), 894aebe5fc6SDaniel Grumberg std::move(LCF), *API); 89589f6b26fSZixu Wang } 89689f6b26fSZixu Wang 897f833aab0SDaniel Grumberg bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) { 898f833aab0SDaniel Grumberg auto &Inputs = CI.getFrontendOpts().Inputs; 899f833aab0SDaniel Grumberg if (Inputs.empty()) 900f833aab0SDaniel Grumberg return true; 901f833aab0SDaniel Grumberg 902*cb5bb285SZixu Wang if (!CI.hasFileManager()) 903*cb5bb285SZixu Wang if (!CI.createFileManager()) 904*cb5bb285SZixu Wang return false; 905*cb5bb285SZixu Wang 906f833aab0SDaniel Grumberg auto Kind = Inputs[0].getKind(); 907f833aab0SDaniel Grumberg 908f833aab0SDaniel Grumberg // Convert the header file inputs into a single input buffer. 909f833aab0SDaniel Grumberg SmallString<256> HeaderContents; 910*cb5bb285SZixu Wang bool IsQuoted = false; 911f833aab0SDaniel Grumberg for (const FrontendInputFile &FIF : Inputs) { 912f833aab0SDaniel Grumberg if (Kind.isObjectiveC()) 913f833aab0SDaniel Grumberg HeaderContents += "#import"; 914f833aab0SDaniel Grumberg else 915f833aab0SDaniel Grumberg HeaderContents += "#include"; 9164c262feeSZixu Wang 917*cb5bb285SZixu Wang StringRef FilePath = FIF.getFile(); 918*cb5bb285SZixu Wang if (auto RelativeName = getRelativeIncludeName(CI, FilePath, &IsQuoted)) { 919*cb5bb285SZixu Wang if (IsQuoted) 920*cb5bb285SZixu Wang HeaderContents += " \""; 921*cb5bb285SZixu Wang else 922*cb5bb285SZixu Wang HeaderContents += " <"; 923*cb5bb285SZixu Wang 924*cb5bb285SZixu Wang HeaderContents += *RelativeName; 925*cb5bb285SZixu Wang 926*cb5bb285SZixu Wang if (IsQuoted) 927*cb5bb285SZixu Wang HeaderContents += "\"\n"; 928*cb5bb285SZixu Wang else 929*cb5bb285SZixu Wang HeaderContents += ">\n"; 930*cb5bb285SZixu Wang KnownInputFiles.emplace_back(*RelativeName, IsQuoted); 931*cb5bb285SZixu Wang } else { 932*cb5bb285SZixu Wang HeaderContents += " \""; 933*cb5bb285SZixu Wang HeaderContents += FilePath; 934*cb5bb285SZixu Wang HeaderContents += "\"\n"; 935*cb5bb285SZixu Wang KnownInputFiles.emplace_back(FilePath, true); 9362966f0faSZixu Wang } 937*cb5bb285SZixu Wang } 938*cb5bb285SZixu Wang 939*cb5bb285SZixu Wang if (CI.getHeaderSearchOpts().Verbose) 940*cb5bb285SZixu Wang CI.getVerboseOutputStream() << getInputBufferName() << ":\n" 941*cb5bb285SZixu Wang << HeaderContents << "\n"; 942f833aab0SDaniel Grumberg 943985eaa1aSDaniel Grumberg Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents, 944f833aab0SDaniel Grumberg getInputBufferName()); 945f833aab0SDaniel Grumberg 946f833aab0SDaniel Grumberg // Set that buffer up as our "real" input in the CompilerInstance. 947f833aab0SDaniel Grumberg Inputs.clear(); 948f833aab0SDaniel Grumberg Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false); 949f833aab0SDaniel Grumberg 950f833aab0SDaniel Grumberg return true; 951f833aab0SDaniel Grumberg } 952f833aab0SDaniel Grumberg 953a9909d23SDaniel Grumberg void ExtractAPIAction::EndSourceFileAction() { 954a9909d23SDaniel Grumberg if (!OS) 955a9909d23SDaniel Grumberg return; 956a9909d23SDaniel Grumberg 957a9909d23SDaniel Grumberg // Setup a SymbolGraphSerializer to write out collected API information in 958a9909d23SDaniel Grumberg // the Symbol Graph format. 959a9909d23SDaniel Grumberg // FIXME: Make the kind of APISerializer configurable. 960a9909d23SDaniel Grumberg SymbolGraphSerializer SGSerializer(*API, ProductName); 961a9909d23SDaniel Grumberg SGSerializer.serialize(*OS); 9622d133867SDuncan P. N. Exon Smith OS.reset(); 963a9909d23SDaniel Grumberg } 964a9909d23SDaniel Grumberg 96589f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> 96689f6b26fSZixu Wang ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) { 96789f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> OS = 96889f6b26fSZixu Wang CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json", 96989f6b26fSZixu Wang /*RemoveFileOnSignal=*/false); 97089f6b26fSZixu Wang if (!OS) 97189f6b26fSZixu Wang return nullptr; 97289f6b26fSZixu Wang return OS; 97389f6b26fSZixu Wang } 974