diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Index')
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Index/CodegenNameGenerator.cpp | 195 | ||||
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Index/CommentToXML.cpp | 1143 | ||||
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Index/IndexBody.cpp | 348 | ||||
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp | 482 | ||||
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Index/IndexSymbol.cpp | 425 | ||||
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Index/IndexTypeSourceInfo.cpp | 202 | ||||
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Index/IndexingAction.cpp | 176 | ||||
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Index/IndexingContext.cpp | 326 | ||||
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Index/IndexingContext.h | 121 | ||||
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Index/SimpleFormatContext.h | 75 | ||||
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp | 931 |
11 files changed, 4424 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Index/CodegenNameGenerator.cpp b/contrib/llvm/tools/clang/lib/Index/CodegenNameGenerator.cpp new file mode 100644 index 000000000000..92740b05703b --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/CodegenNameGenerator.cpp @@ -0,0 +1,195 @@ +//===- CodegenNameGenerator.cpp - Codegen name generation -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Determines the name that the symbol will get for code generation. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/CodegenNameGenerator.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Mangle.h" +#include "clang/AST/VTableBuilder.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Mangler.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace clang::index; + +struct CodegenNameGenerator::Implementation { + std::unique_ptr<MangleContext> MC; + llvm::DataLayout DL; + + Implementation(ASTContext &Ctx) + : MC(Ctx.createMangleContext()), + DL(Ctx.getTargetInfo().getDataLayout()) {} + + bool writeName(const Decl *D, raw_ostream &OS) { + // First apply frontend mangling. + SmallString<128> FrontendBuf; + llvm::raw_svector_ostream FrontendBufOS(FrontendBuf); + if (auto *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isDependentContext()) + return true; + if (writeFuncOrVarName(FD, FrontendBufOS)) + return true; + } else if (auto *VD = dyn_cast<VarDecl>(D)) { + if (writeFuncOrVarName(VD, FrontendBufOS)) + return true; + } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) { + MC->mangleObjCMethodNameWithoutSize(MD, OS); + return false; + } else if (auto *ID = dyn_cast<ObjCInterfaceDecl>(D)) { + writeObjCClassName(ID, FrontendBufOS); + } else { + return true; + } + + // Now apply backend mangling. + llvm::Mangler::getNameWithPrefix(OS, FrontendBufOS.str(), DL); + return false; + } + + std::string getName(const Decl *D) { + std::string Name; + { + llvm::raw_string_ostream OS(Name); + writeName(D, OS); + } + return Name; + } + + std::vector<std::string> getAllManglings(const Decl *D) { + if (!(isa<CXXRecordDecl>(D) || isa<CXXMethodDecl>(D))) + return {}; + + const NamedDecl *ND = cast<NamedDecl>(D); + + ASTContext &Ctx = ND->getASTContext(); + std::unique_ptr<MangleContext> M(Ctx.createMangleContext()); + + std::vector<std::string> Manglings; + + auto hasDefaultCXXMethodCC = [](ASTContext &C, const CXXMethodDecl *MD) { + auto DefaultCC = C.getDefaultCallingConvention(/*IsVariadic=*/false, + /*IsCSSMethod=*/true); + auto CC = MD->getType()->getAs<FunctionProtoType>()->getCallConv(); + return CC == DefaultCC; + }; + + if (const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(ND)) { + Manglings.emplace_back(getMangledStructor(CD, Ctor_Base)); + + if (Ctx.getTargetInfo().getCXXABI().isItaniumFamily()) + if (!CD->getParent()->isAbstract()) + Manglings.emplace_back(getMangledStructor(CD, Ctor_Complete)); + + if (Ctx.getTargetInfo().getCXXABI().isMicrosoft()) + if (CD->hasAttr<DLLExportAttr>() && CD->isDefaultConstructor()) + if (!(hasDefaultCXXMethodCC(Ctx, CD) && CD->getNumParams() == 0)) + Manglings.emplace_back(getMangledStructor(CD, Ctor_DefaultClosure)); + } else if (const auto *DD = dyn_cast_or_null<CXXDestructorDecl>(ND)) { + Manglings.emplace_back(getMangledStructor(DD, Dtor_Base)); + if (Ctx.getTargetInfo().getCXXABI().isItaniumFamily()) { + Manglings.emplace_back(getMangledStructor(DD, Dtor_Complete)); + if (DD->isVirtual()) + Manglings.emplace_back(getMangledStructor(DD, Dtor_Deleting)); + } + } else if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(ND)) { + Manglings.emplace_back(getName(ND)); + if (MD->isVirtual()) + if (const auto *TIV = Ctx.getVTableContext()->getThunkInfo(MD)) + for (const auto &T : *TIV) + Manglings.emplace_back(getMangledThunk(MD, T)); + } + + return Manglings; + } + +private: + bool writeFuncOrVarName(const NamedDecl *D, raw_ostream &OS) { + if (MC->shouldMangleDeclName(D)) { + if (const auto *CtorD = dyn_cast<CXXConstructorDecl>(D)) + MC->mangleCXXCtor(CtorD, Ctor_Complete, OS); + else if (const auto *DtorD = dyn_cast<CXXDestructorDecl>(D)) + MC->mangleCXXDtor(DtorD, Dtor_Complete, OS); + else + MC->mangleName(D, OS); + return false; + } else { + IdentifierInfo *II = D->getIdentifier(); + if (!II) + return true; + OS << II->getName(); + return false; + } + } + + void writeObjCClassName(const ObjCInterfaceDecl *D, raw_ostream &OS) { + OS << getClassSymbolPrefix(); + OS << D->getObjCRuntimeNameAsString(); + } + + static StringRef getClassSymbolPrefix() { + return "OBJC_CLASS_$_"; + } + + std::string getMangledStructor(const NamedDecl *ND, unsigned StructorType) { + std::string FrontendBuf; + llvm::raw_string_ostream FOS(FrontendBuf); + + if (const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(ND)) + MC->mangleCXXCtor(CD, static_cast<CXXCtorType>(StructorType), FOS); + else if (const auto *DD = dyn_cast_or_null<CXXDestructorDecl>(ND)) + MC->mangleCXXDtor(DD, static_cast<CXXDtorType>(StructorType), FOS); + + std::string BackendBuf; + llvm::raw_string_ostream BOS(BackendBuf); + + llvm::Mangler::getNameWithPrefix(BOS, FOS.str(), DL); + + return BOS.str(); + } + + std::string getMangledThunk(const CXXMethodDecl *MD, const ThunkInfo &T) { + std::string FrontendBuf; + llvm::raw_string_ostream FOS(FrontendBuf); + + MC->mangleThunk(MD, T, FOS); + + std::string BackendBuf; + llvm::raw_string_ostream BOS(BackendBuf); + + llvm::Mangler::getNameWithPrefix(BOS, FOS.str(), DL); + + return BOS.str(); + } +}; + +CodegenNameGenerator::CodegenNameGenerator(ASTContext &Ctx) + : Impl(new Implementation(Ctx)) { +} + +CodegenNameGenerator::~CodegenNameGenerator() { +} + +bool CodegenNameGenerator::writeName(const Decl *D, raw_ostream &OS) { + return Impl->writeName(D, OS); +} + +std::string CodegenNameGenerator::getName(const Decl *D) { + return Impl->getName(D); +} + +std::vector<std::string> CodegenNameGenerator::getAllManglings(const Decl *D) { + return Impl->getAllManglings(D); +} diff --git a/contrib/llvm/tools/clang/lib/Index/CommentToXML.cpp b/contrib/llvm/tools/clang/lib/Index/CommentToXML.cpp new file mode 100644 index 000000000000..ee066cc6d985 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/CommentToXML.cpp @@ -0,0 +1,1143 @@ +//===--- CommentToXML.cpp - Convert comments to XML representation --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/CommentToXML.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Comment.h" +#include "clang/AST/CommentVisitor.h" +#include "clang/Format/Format.h" +#include "clang/Index/USRGeneration.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace clang::comments; +using namespace clang::index; + +namespace { + +/// This comparison will sort parameters with valid index by index, then vararg +/// parameters, and invalid (unresolved) parameters last. +class ParamCommandCommentCompareIndex { +public: + bool operator()(const ParamCommandComment *LHS, + const ParamCommandComment *RHS) const { + unsigned LHSIndex = UINT_MAX; + unsigned RHSIndex = UINT_MAX; + + if (LHS->isParamIndexValid()) { + if (LHS->isVarArgParam()) + LHSIndex = UINT_MAX - 1; + else + LHSIndex = LHS->getParamIndex(); + } + if (RHS->isParamIndexValid()) { + if (RHS->isVarArgParam()) + RHSIndex = UINT_MAX - 1; + else + RHSIndex = RHS->getParamIndex(); + } + return LHSIndex < RHSIndex; + } +}; + +/// This comparison will sort template parameters in the following order: +/// \li real template parameters (depth = 1) in index order; +/// \li all other names (depth > 1); +/// \li unresolved names. +class TParamCommandCommentComparePosition { +public: + bool operator()(const TParamCommandComment *LHS, + const TParamCommandComment *RHS) const { + // Sort unresolved names last. + if (!LHS->isPositionValid()) + return false; + if (!RHS->isPositionValid()) + return true; + + if (LHS->getDepth() > 1) + return false; + if (RHS->getDepth() > 1) + return true; + + // Sort template parameters in index order. + if (LHS->getDepth() == 1 && RHS->getDepth() == 1) + return LHS->getIndex(0) < RHS->getIndex(0); + + // Leave all other names in source order. + return true; + } +}; + +/// Separate parts of a FullComment. +struct FullCommentParts { + /// Take a full comment apart and initialize members accordingly. + FullCommentParts(const FullComment *C, + const CommandTraits &Traits); + + const BlockContentComment *Brief; + const BlockContentComment *Headerfile; + const ParagraphComment *FirstParagraph; + SmallVector<const BlockCommandComment *, 4> Returns; + SmallVector<const ParamCommandComment *, 8> Params; + SmallVector<const TParamCommandComment *, 4> TParams; + llvm::TinyPtrVector<const BlockCommandComment *> Exceptions; + SmallVector<const BlockContentComment *, 8> MiscBlocks; +}; + +FullCommentParts::FullCommentParts(const FullComment *C, + const CommandTraits &Traits) : + Brief(nullptr), Headerfile(nullptr), FirstParagraph(nullptr) { + for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); + I != E; ++I) { + const Comment *Child = *I; + if (!Child) + continue; + switch (Child->getCommentKind()) { + case Comment::NoCommentKind: + continue; + + case Comment::ParagraphCommentKind: { + const ParagraphComment *PC = cast<ParagraphComment>(Child); + if (PC->isWhitespace()) + break; + if (!FirstParagraph) + FirstParagraph = PC; + + MiscBlocks.push_back(PC); + break; + } + + case Comment::BlockCommandCommentKind: { + const BlockCommandComment *BCC = cast<BlockCommandComment>(Child); + const CommandInfo *Info = Traits.getCommandInfo(BCC->getCommandID()); + if (!Brief && Info->IsBriefCommand) { + Brief = BCC; + break; + } + if (!Headerfile && Info->IsHeaderfileCommand) { + Headerfile = BCC; + break; + } + if (Info->IsReturnsCommand) { + Returns.push_back(BCC); + break; + } + if (Info->IsThrowsCommand) { + Exceptions.push_back(BCC); + break; + } + MiscBlocks.push_back(BCC); + break; + } + + case Comment::ParamCommandCommentKind: { + const ParamCommandComment *PCC = cast<ParamCommandComment>(Child); + if (!PCC->hasParamName()) + break; + + if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph()) + break; + + Params.push_back(PCC); + break; + } + + case Comment::TParamCommandCommentKind: { + const TParamCommandComment *TPCC = cast<TParamCommandComment>(Child); + if (!TPCC->hasParamName()) + break; + + if (!TPCC->hasNonWhitespaceParagraph()) + break; + + TParams.push_back(TPCC); + break; + } + + case Comment::VerbatimBlockCommentKind: + MiscBlocks.push_back(cast<BlockCommandComment>(Child)); + break; + + case Comment::VerbatimLineCommentKind: { + const VerbatimLineComment *VLC = cast<VerbatimLineComment>(Child); + const CommandInfo *Info = Traits.getCommandInfo(VLC->getCommandID()); + if (!Info->IsDeclarationCommand) + MiscBlocks.push_back(VLC); + break; + } + + case Comment::TextCommentKind: + case Comment::InlineCommandCommentKind: + case Comment::HTMLStartTagCommentKind: + case Comment::HTMLEndTagCommentKind: + case Comment::VerbatimBlockLineCommentKind: + case Comment::FullCommentKind: + llvm_unreachable("AST node of this kind can't be a child of " + "a FullComment"); + } + } + + // Sort params in order they are declared in the function prototype. + // Unresolved parameters are put at the end of the list in the same order + // they were seen in the comment. + std::stable_sort(Params.begin(), Params.end(), + ParamCommandCommentCompareIndex()); + + std::stable_sort(TParams.begin(), TParams.end(), + TParamCommandCommentComparePosition()); +} + +void printHTMLStartTagComment(const HTMLStartTagComment *C, + llvm::raw_svector_ostream &Result) { + Result << "<" << C->getTagName(); + + if (C->getNumAttrs() != 0) { + for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) { + Result << " "; + const HTMLStartTagComment::Attribute &Attr = C->getAttr(i); + Result << Attr.Name; + if (!Attr.Value.empty()) + Result << "=\"" << Attr.Value << "\""; + } + } + + if (!C->isSelfClosing()) + Result << ">"; + else + Result << "/>"; +} + +class CommentASTToHTMLConverter : + public ConstCommentVisitor<CommentASTToHTMLConverter> { +public: + /// \param Str accumulator for HTML. + CommentASTToHTMLConverter(const FullComment *FC, + SmallVectorImpl<char> &Str, + const CommandTraits &Traits) : + FC(FC), Result(Str), Traits(Traits) + { } + + // Inline content. + void visitTextComment(const TextComment *C); + void visitInlineCommandComment(const InlineCommandComment *C); + void visitHTMLStartTagComment(const HTMLStartTagComment *C); + void visitHTMLEndTagComment(const HTMLEndTagComment *C); + + // Block content. + void visitParagraphComment(const ParagraphComment *C); + void visitBlockCommandComment(const BlockCommandComment *C); + void visitParamCommandComment(const ParamCommandComment *C); + void visitTParamCommandComment(const TParamCommandComment *C); + void visitVerbatimBlockComment(const VerbatimBlockComment *C); + void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); + void visitVerbatimLineComment(const VerbatimLineComment *C); + + void visitFullComment(const FullComment *C); + + // Helpers. + + /// Convert a paragraph that is not a block by itself (an argument to some + /// command). + void visitNonStandaloneParagraphComment(const ParagraphComment *C); + + void appendToResultWithHTMLEscaping(StringRef S); + +private: + const FullComment *FC; + /// Output stream for HTML. + llvm::raw_svector_ostream Result; + + const CommandTraits &Traits; +}; +} // end unnamed namespace + +void CommentASTToHTMLConverter::visitTextComment(const TextComment *C) { + appendToResultWithHTMLEscaping(C->getText()); +} + +void CommentASTToHTMLConverter::visitInlineCommandComment( + const InlineCommandComment *C) { + // Nothing to render if no arguments supplied. + if (C->getNumArgs() == 0) + return; + + // Nothing to render if argument is empty. + StringRef Arg0 = C->getArgText(0); + if (Arg0.empty()) + return; + + switch (C->getRenderKind()) { + case InlineCommandComment::RenderNormal: + for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) { + appendToResultWithHTMLEscaping(C->getArgText(i)); + Result << " "; + } + return; + + case InlineCommandComment::RenderBold: + assert(C->getNumArgs() == 1); + Result << "<b>"; + appendToResultWithHTMLEscaping(Arg0); + Result << "</b>"; + return; + case InlineCommandComment::RenderMonospaced: + assert(C->getNumArgs() == 1); + Result << "<tt>"; + appendToResultWithHTMLEscaping(Arg0); + Result<< "</tt>"; + return; + case InlineCommandComment::RenderEmphasized: + assert(C->getNumArgs() == 1); + Result << "<em>"; + appendToResultWithHTMLEscaping(Arg0); + Result << "</em>"; + return; + } +} + +void CommentASTToHTMLConverter::visitHTMLStartTagComment( + const HTMLStartTagComment *C) { + printHTMLStartTagComment(C, Result); +} + +void CommentASTToHTMLConverter::visitHTMLEndTagComment( + const HTMLEndTagComment *C) { + Result << "</" << C->getTagName() << ">"; +} + +void CommentASTToHTMLConverter::visitParagraphComment( + const ParagraphComment *C) { + if (C->isWhitespace()) + return; + + Result << "<p>"; + for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); + I != E; ++I) { + visit(*I); + } + Result << "</p>"; +} + +void CommentASTToHTMLConverter::visitBlockCommandComment( + const BlockCommandComment *C) { + const CommandInfo *Info = Traits.getCommandInfo(C->getCommandID()); + if (Info->IsBriefCommand) { + Result << "<p class=\"para-brief\">"; + visitNonStandaloneParagraphComment(C->getParagraph()); + Result << "</p>"; + return; + } + if (Info->IsReturnsCommand) { + Result << "<p class=\"para-returns\">" + "<span class=\"word-returns\">Returns</span> "; + visitNonStandaloneParagraphComment(C->getParagraph()); + Result << "</p>"; + return; + } + // We don't know anything about this command. Just render the paragraph. + visit(C->getParagraph()); +} + +void CommentASTToHTMLConverter::visitParamCommandComment( + const ParamCommandComment *C) { + if (C->isParamIndexValid()) { + if (C->isVarArgParam()) { + Result << "<dt class=\"param-name-index-vararg\">"; + appendToResultWithHTMLEscaping(C->getParamNameAsWritten()); + } else { + Result << "<dt class=\"param-name-index-" + << C->getParamIndex() + << "\">"; + appendToResultWithHTMLEscaping(C->getParamName(FC)); + } + } else { + Result << "<dt class=\"param-name-index-invalid\">"; + appendToResultWithHTMLEscaping(C->getParamNameAsWritten()); + } + Result << "</dt>"; + + if (C->isParamIndexValid()) { + if (C->isVarArgParam()) + Result << "<dd class=\"param-descr-index-vararg\">"; + else + Result << "<dd class=\"param-descr-index-" + << C->getParamIndex() + << "\">"; + } else + Result << "<dd class=\"param-descr-index-invalid\">"; + + visitNonStandaloneParagraphComment(C->getParagraph()); + Result << "</dd>"; +} + +void CommentASTToHTMLConverter::visitTParamCommandComment( + const TParamCommandComment *C) { + if (C->isPositionValid()) { + if (C->getDepth() == 1) + Result << "<dt class=\"tparam-name-index-" + << C->getIndex(0) + << "\">"; + else + Result << "<dt class=\"tparam-name-index-other\">"; + appendToResultWithHTMLEscaping(C->getParamName(FC)); + } else { + Result << "<dt class=\"tparam-name-index-invalid\">"; + appendToResultWithHTMLEscaping(C->getParamNameAsWritten()); + } + + Result << "</dt>"; + + if (C->isPositionValid()) { + if (C->getDepth() == 1) + Result << "<dd class=\"tparam-descr-index-" + << C->getIndex(0) + << "\">"; + else + Result << "<dd class=\"tparam-descr-index-other\">"; + } else + Result << "<dd class=\"tparam-descr-index-invalid\">"; + + visitNonStandaloneParagraphComment(C->getParagraph()); + Result << "</dd>"; +} + +void CommentASTToHTMLConverter::visitVerbatimBlockComment( + const VerbatimBlockComment *C) { + unsigned NumLines = C->getNumLines(); + if (NumLines == 0) + return; + + Result << "<pre>"; + for (unsigned i = 0; i != NumLines; ++i) { + appendToResultWithHTMLEscaping(C->getText(i)); + if (i + 1 != NumLines) + Result << '\n'; + } + Result << "</pre>"; +} + +void CommentASTToHTMLConverter::visitVerbatimBlockLineComment( + const VerbatimBlockLineComment *C) { + llvm_unreachable("should not see this AST node"); +} + +void CommentASTToHTMLConverter::visitVerbatimLineComment( + const VerbatimLineComment *C) { + Result << "<pre>"; + appendToResultWithHTMLEscaping(C->getText()); + Result << "</pre>"; +} + +void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) { + FullCommentParts Parts(C, Traits); + + bool FirstParagraphIsBrief = false; + if (Parts.Headerfile) + visit(Parts.Headerfile); + if (Parts.Brief) + visit(Parts.Brief); + else if (Parts.FirstParagraph) { + Result << "<p class=\"para-brief\">"; + visitNonStandaloneParagraphComment(Parts.FirstParagraph); + Result << "</p>"; + FirstParagraphIsBrief = true; + } + + for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) { + const Comment *C = Parts.MiscBlocks[i]; + if (FirstParagraphIsBrief && C == Parts.FirstParagraph) + continue; + visit(C); + } + + if (Parts.TParams.size() != 0) { + Result << "<dl>"; + for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i) + visit(Parts.TParams[i]); + Result << "</dl>"; + } + + if (Parts.Params.size() != 0) { + Result << "<dl>"; + for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i) + visit(Parts.Params[i]); + Result << "</dl>"; + } + + if (Parts.Returns.size() != 0) { + Result << "<div class=\"result-discussion\">"; + for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i) + visit(Parts.Returns[i]); + Result << "</div>"; + } + +} + +void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment( + const ParagraphComment *C) { + if (!C) + return; + + for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); + I != E; ++I) { + visit(*I); + } +} + +void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) { + for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) { + const char C = *I; + switch (C) { + case '&': + Result << "&"; + break; + case '<': + Result << "<"; + break; + case '>': + Result << ">"; + break; + case '"': + Result << """; + break; + case '\'': + Result << "'"; + break; + case '/': + Result << "/"; + break; + default: + Result << C; + break; + } + } +} + +namespace { +class CommentASTToXMLConverter : + public ConstCommentVisitor<CommentASTToXMLConverter> { +public: + /// \param Str accumulator for XML. + CommentASTToXMLConverter(const FullComment *FC, + SmallVectorImpl<char> &Str, + const CommandTraits &Traits, + const SourceManager &SM) : + FC(FC), Result(Str), Traits(Traits), SM(SM) { } + + // Inline content. + void visitTextComment(const TextComment *C); + void visitInlineCommandComment(const InlineCommandComment *C); + void visitHTMLStartTagComment(const HTMLStartTagComment *C); + void visitHTMLEndTagComment(const HTMLEndTagComment *C); + + // Block content. + void visitParagraphComment(const ParagraphComment *C); + + void appendParagraphCommentWithKind(const ParagraphComment *C, + StringRef Kind); + + void visitBlockCommandComment(const BlockCommandComment *C); + void visitParamCommandComment(const ParamCommandComment *C); + void visitTParamCommandComment(const TParamCommandComment *C); + void visitVerbatimBlockComment(const VerbatimBlockComment *C); + void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); + void visitVerbatimLineComment(const VerbatimLineComment *C); + + void visitFullComment(const FullComment *C); + + // Helpers. + void appendToResultWithXMLEscaping(StringRef S); + void appendToResultWithCDATAEscaping(StringRef S); + + void formatTextOfDeclaration(const DeclInfo *DI, + SmallString<128> &Declaration); + +private: + const FullComment *FC; + + /// Output stream for XML. + llvm::raw_svector_ostream Result; + + const CommandTraits &Traits; + const SourceManager &SM; +}; + +void getSourceTextOfDeclaration(const DeclInfo *ThisDecl, + SmallVectorImpl<char> &Str) { + ASTContext &Context = ThisDecl->CurrentDecl->getASTContext(); + const LangOptions &LangOpts = Context.getLangOpts(); + llvm::raw_svector_ostream OS(Str); + PrintingPolicy PPolicy(LangOpts); + PPolicy.PolishForDeclaration = true; + PPolicy.TerseOutput = true; + ThisDecl->CurrentDecl->print(OS, PPolicy, + /*Indentation*/0, /*PrintInstantiation*/false); +} + +void CommentASTToXMLConverter::formatTextOfDeclaration( + const DeclInfo *DI, SmallString<128> &Declaration) { + // Formatting API expects null terminated input string. + StringRef StringDecl(Declaration.c_str(), Declaration.size()); + + // Formatter specific code. + unsigned Offset = 0; + unsigned Length = Declaration.size(); + + bool IncompleteFormat = false; + tooling::Replacements Replaces = + reformat(format::getLLVMStyle(), StringDecl, + tooling::Range(Offset, Length), "xmldecl.xd", &IncompleteFormat); + auto FormattedStringDecl = applyAllReplacements(StringDecl, Replaces); + if (static_cast<bool>(FormattedStringDecl)) { + Declaration = *FormattedStringDecl; + } +} + +} // end unnamed namespace + +void CommentASTToXMLConverter::visitTextComment(const TextComment *C) { + appendToResultWithXMLEscaping(C->getText()); +} + +void CommentASTToXMLConverter::visitInlineCommandComment( + const InlineCommandComment *C) { + // Nothing to render if no arguments supplied. + if (C->getNumArgs() == 0) + return; + + // Nothing to render if argument is empty. + StringRef Arg0 = C->getArgText(0); + if (Arg0.empty()) + return; + + switch (C->getRenderKind()) { + case InlineCommandComment::RenderNormal: + for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) { + appendToResultWithXMLEscaping(C->getArgText(i)); + Result << " "; + } + return; + case InlineCommandComment::RenderBold: + assert(C->getNumArgs() == 1); + Result << "<bold>"; + appendToResultWithXMLEscaping(Arg0); + Result << "</bold>"; + return; + case InlineCommandComment::RenderMonospaced: + assert(C->getNumArgs() == 1); + Result << "<monospaced>"; + appendToResultWithXMLEscaping(Arg0); + Result << "</monospaced>"; + return; + case InlineCommandComment::RenderEmphasized: + assert(C->getNumArgs() == 1); + Result << "<emphasized>"; + appendToResultWithXMLEscaping(Arg0); + Result << "</emphasized>"; + return; + } +} + +void CommentASTToXMLConverter::visitHTMLStartTagComment( + const HTMLStartTagComment *C) { + Result << "<rawHTML"; + if (C->isMalformed()) + Result << " isMalformed=\"1\""; + Result << ">"; + { + SmallString<32> Tag; + { + llvm::raw_svector_ostream TagOS(Tag); + printHTMLStartTagComment(C, TagOS); + } + appendToResultWithCDATAEscaping(Tag); + } + Result << "</rawHTML>"; +} + +void +CommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) { + Result << "<rawHTML"; + if (C->isMalformed()) + Result << " isMalformed=\"1\""; + Result << "></" << C->getTagName() << "></rawHTML>"; +} + +void +CommentASTToXMLConverter::visitParagraphComment(const ParagraphComment *C) { + appendParagraphCommentWithKind(C, StringRef()); +} + +void CommentASTToXMLConverter::appendParagraphCommentWithKind( + const ParagraphComment *C, + StringRef ParagraphKind) { + if (C->isWhitespace()) + return; + + if (ParagraphKind.empty()) + Result << "<Para>"; + else + Result << "<Para kind=\"" << ParagraphKind << "\">"; + + for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); + I != E; ++I) { + visit(*I); + } + Result << "</Para>"; +} + +void CommentASTToXMLConverter::visitBlockCommandComment( + const BlockCommandComment *C) { + StringRef ParagraphKind; + + switch (C->getCommandID()) { + case CommandTraits::KCI_attention: + case CommandTraits::KCI_author: + case CommandTraits::KCI_authors: + case CommandTraits::KCI_bug: + case CommandTraits::KCI_copyright: + case CommandTraits::KCI_date: + case CommandTraits::KCI_invariant: + case CommandTraits::KCI_note: + case CommandTraits::KCI_post: + case CommandTraits::KCI_pre: + case CommandTraits::KCI_remark: + case CommandTraits::KCI_remarks: + case CommandTraits::KCI_sa: + case CommandTraits::KCI_see: + case CommandTraits::KCI_since: + case CommandTraits::KCI_todo: + case CommandTraits::KCI_version: + case CommandTraits::KCI_warning: + ParagraphKind = C->getCommandName(Traits); + default: + break; + } + + appendParagraphCommentWithKind(C->getParagraph(), ParagraphKind); +} + +void CommentASTToXMLConverter::visitParamCommandComment( + const ParamCommandComment *C) { + Result << "<Parameter><Name>"; + appendToResultWithXMLEscaping(C->isParamIndexValid() + ? C->getParamName(FC) + : C->getParamNameAsWritten()); + Result << "</Name>"; + + if (C->isParamIndexValid()) { + if (C->isVarArgParam()) + Result << "<IsVarArg />"; + else + Result << "<Index>" << C->getParamIndex() << "</Index>"; + } + + Result << "<Direction isExplicit=\"" << C->isDirectionExplicit() << "\">"; + switch (C->getDirection()) { + case ParamCommandComment::In: + Result << "in"; + break; + case ParamCommandComment::Out: + Result << "out"; + break; + case ParamCommandComment::InOut: + Result << "in,out"; + break; + } + Result << "</Direction><Discussion>"; + visit(C->getParagraph()); + Result << "</Discussion></Parameter>"; +} + +void CommentASTToXMLConverter::visitTParamCommandComment( + const TParamCommandComment *C) { + Result << "<Parameter><Name>"; + appendToResultWithXMLEscaping(C->isPositionValid() ? C->getParamName(FC) + : C->getParamNameAsWritten()); + Result << "</Name>"; + + if (C->isPositionValid() && C->getDepth() == 1) { + Result << "<Index>" << C->getIndex(0) << "</Index>"; + } + + Result << "<Discussion>"; + visit(C->getParagraph()); + Result << "</Discussion></Parameter>"; +} + +void CommentASTToXMLConverter::visitVerbatimBlockComment( + const VerbatimBlockComment *C) { + unsigned NumLines = C->getNumLines(); + if (NumLines == 0) + return; + + switch (C->getCommandID()) { + case CommandTraits::KCI_code: + Result << "<Verbatim xml:space=\"preserve\" kind=\"code\">"; + break; + default: + Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">"; + break; + } + for (unsigned i = 0; i != NumLines; ++i) { + appendToResultWithXMLEscaping(C->getText(i)); + if (i + 1 != NumLines) + Result << '\n'; + } + Result << "</Verbatim>"; +} + +void CommentASTToXMLConverter::visitVerbatimBlockLineComment( + const VerbatimBlockLineComment *C) { + llvm_unreachable("should not see this AST node"); +} + +void CommentASTToXMLConverter::visitVerbatimLineComment( + const VerbatimLineComment *C) { + Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">"; + appendToResultWithXMLEscaping(C->getText()); + Result << "</Verbatim>"; +} + +void CommentASTToXMLConverter::visitFullComment(const FullComment *C) { + FullCommentParts Parts(C, Traits); + + const DeclInfo *DI = C->getDeclInfo(); + StringRef RootEndTag; + if (DI) { + switch (DI->getKind()) { + case DeclInfo::OtherKind: + RootEndTag = "</Other>"; + Result << "<Other"; + break; + case DeclInfo::FunctionKind: + RootEndTag = "</Function>"; + Result << "<Function"; + switch (DI->TemplateKind) { + case DeclInfo::NotTemplate: + break; + case DeclInfo::Template: + Result << " templateKind=\"template\""; + break; + case DeclInfo::TemplateSpecialization: + Result << " templateKind=\"specialization\""; + break; + case DeclInfo::TemplatePartialSpecialization: + llvm_unreachable("partial specializations of functions " + "are not allowed in C++"); + } + if (DI->IsInstanceMethod) + Result << " isInstanceMethod=\"1\""; + if (DI->IsClassMethod) + Result << " isClassMethod=\"1\""; + break; + case DeclInfo::ClassKind: + RootEndTag = "</Class>"; + Result << "<Class"; + switch (DI->TemplateKind) { + case DeclInfo::NotTemplate: + break; + case DeclInfo::Template: + Result << " templateKind=\"template\""; + break; + case DeclInfo::TemplateSpecialization: + Result << " templateKind=\"specialization\""; + break; + case DeclInfo::TemplatePartialSpecialization: + Result << " templateKind=\"partialSpecialization\""; + break; + } + break; + case DeclInfo::VariableKind: + RootEndTag = "</Variable>"; + Result << "<Variable"; + break; + case DeclInfo::NamespaceKind: + RootEndTag = "</Namespace>"; + Result << "<Namespace"; + break; + case DeclInfo::TypedefKind: + RootEndTag = "</Typedef>"; + Result << "<Typedef"; + break; + case DeclInfo::EnumKind: + RootEndTag = "</Enum>"; + Result << "<Enum"; + break; + } + + { + // Print line and column number. + SourceLocation Loc = DI->CurrentDecl->getLocation(); + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + FileID FID = LocInfo.first; + unsigned FileOffset = LocInfo.second; + + if (FID.isValid()) { + if (const FileEntry *FE = SM.getFileEntryForID(FID)) { + Result << " file=\""; + appendToResultWithXMLEscaping(FE->getName()); + Result << "\""; + } + Result << " line=\"" << SM.getLineNumber(FID, FileOffset) + << "\" column=\"" << SM.getColumnNumber(FID, FileOffset) + << "\""; + } + } + + // Finish the root tag. + Result << ">"; + + bool FoundName = false; + if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) { + if (DeclarationName DeclName = ND->getDeclName()) { + Result << "<Name>"; + std::string Name = DeclName.getAsString(); + appendToResultWithXMLEscaping(Name); + FoundName = true; + Result << "</Name>"; + } + } + if (!FoundName) + Result << "<Name><anonymous></Name>"; + + { + // Print USR. + SmallString<128> USR; + generateUSRForDecl(DI->CommentDecl, USR); + if (!USR.empty()) { + Result << "<USR>"; + appendToResultWithXMLEscaping(USR); + Result << "</USR>"; + } + } + } else { + // No DeclInfo -- just emit some root tag and name tag. + RootEndTag = "</Other>"; + Result << "<Other><Name>unknown</Name>"; + } + + if (Parts.Headerfile) { + Result << "<Headerfile>"; + visit(Parts.Headerfile); + Result << "</Headerfile>"; + } + + { + // Pretty-print the declaration. + Result << "<Declaration>"; + SmallString<128> Declaration; + getSourceTextOfDeclaration(DI, Declaration); + formatTextOfDeclaration(DI, Declaration); + appendToResultWithXMLEscaping(Declaration); + Result << "</Declaration>"; + } + + bool FirstParagraphIsBrief = false; + if (Parts.Brief) { + Result << "<Abstract>"; + visit(Parts.Brief); + Result << "</Abstract>"; + } else if (Parts.FirstParagraph) { + Result << "<Abstract>"; + visit(Parts.FirstParagraph); + Result << "</Abstract>"; + FirstParagraphIsBrief = true; + } + + if (Parts.TParams.size() != 0) { + Result << "<TemplateParameters>"; + for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i) + visit(Parts.TParams[i]); + Result << "</TemplateParameters>"; + } + + if (Parts.Params.size() != 0) { + Result << "<Parameters>"; + for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i) + visit(Parts.Params[i]); + Result << "</Parameters>"; + } + + if (Parts.Exceptions.size() != 0) { + Result << "<Exceptions>"; + for (unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i) + visit(Parts.Exceptions[i]); + Result << "</Exceptions>"; + } + + if (Parts.Returns.size() != 0) { + Result << "<ResultDiscussion>"; + for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i) + visit(Parts.Returns[i]); + Result << "</ResultDiscussion>"; + } + + if (DI->CommentDecl->hasAttrs()) { + const AttrVec &Attrs = DI->CommentDecl->getAttrs(); + for (unsigned i = 0, e = Attrs.size(); i != e; i++) { + const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]); + if (!AA) { + if (const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) { + if (DA->getMessage().empty()) + Result << "<Deprecated/>"; + else { + Result << "<Deprecated>"; + appendToResultWithXMLEscaping(DA->getMessage()); + Result << "</Deprecated>"; + } + } + else if (const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) { + if (UA->getMessage().empty()) + Result << "<Unavailable/>"; + else { + Result << "<Unavailable>"; + appendToResultWithXMLEscaping(UA->getMessage()); + Result << "</Unavailable>"; + } + } + continue; + } + + // 'availability' attribute. + Result << "<Availability"; + StringRef Distribution; + if (AA->getPlatform()) { + Distribution = AvailabilityAttr::getPrettyPlatformName( + AA->getPlatform()->getName()); + if (Distribution.empty()) + Distribution = AA->getPlatform()->getName(); + } + Result << " distribution=\"" << Distribution << "\">"; + VersionTuple IntroducedInVersion = AA->getIntroduced(); + if (!IntroducedInVersion.empty()) { + Result << "<IntroducedInVersion>" + << IntroducedInVersion.getAsString() + << "</IntroducedInVersion>"; + } + VersionTuple DeprecatedInVersion = AA->getDeprecated(); + if (!DeprecatedInVersion.empty()) { + Result << "<DeprecatedInVersion>" + << DeprecatedInVersion.getAsString() + << "</DeprecatedInVersion>"; + } + VersionTuple RemovedAfterVersion = AA->getObsoleted(); + if (!RemovedAfterVersion.empty()) { + Result << "<RemovedAfterVersion>" + << RemovedAfterVersion.getAsString() + << "</RemovedAfterVersion>"; + } + StringRef DeprecationSummary = AA->getMessage(); + if (!DeprecationSummary.empty()) { + Result << "<DeprecationSummary>"; + appendToResultWithXMLEscaping(DeprecationSummary); + Result << "</DeprecationSummary>"; + } + if (AA->getUnavailable()) + Result << "<Unavailable/>"; + Result << "</Availability>"; + } + } + + { + bool StartTagEmitted = false; + for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) { + const Comment *C = Parts.MiscBlocks[i]; + if (FirstParagraphIsBrief && C == Parts.FirstParagraph) + continue; + if (!StartTagEmitted) { + Result << "<Discussion>"; + StartTagEmitted = true; + } + visit(C); + } + if (StartTagEmitted) + Result << "</Discussion>"; + } + + Result << RootEndTag; +} + +void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) { + for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) { + const char C = *I; + switch (C) { + case '&': + Result << "&"; + break; + case '<': + Result << "<"; + break; + case '>': + Result << ">"; + break; + case '"': + Result << """; + break; + case '\'': + Result << "'"; + break; + default: + Result << C; + break; + } + } +} + +void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) { + if (S.empty()) + return; + + Result << "<![CDATA["; + while (!S.empty()) { + size_t Pos = S.find("]]>"); + if (Pos == 0) { + Result << "]]]]><![CDATA[>"; + S = S.drop_front(3); + continue; + } + if (Pos == StringRef::npos) + Pos = S.size(); + + Result << S.substr(0, Pos); + + S = S.drop_front(Pos); + } + Result << "]]>"; +} + +CommentToXMLConverter::CommentToXMLConverter() {} +CommentToXMLConverter::~CommentToXMLConverter() {} + +void CommentToXMLConverter::convertCommentToHTML(const FullComment *FC, + SmallVectorImpl<char> &HTML, + const ASTContext &Context) { + CommentASTToHTMLConverter Converter(FC, HTML, + Context.getCommentCommandTraits()); + Converter.visit(FC); +} + +void CommentToXMLConverter::convertHTMLTagNodeToText( + const comments::HTMLTagComment *HTC, SmallVectorImpl<char> &Text, + const ASTContext &Context) { + CommentASTToHTMLConverter Converter(nullptr, Text, + Context.getCommentCommandTraits()); + Converter.visit(HTC); +} + +void CommentToXMLConverter::convertCommentToXML(const FullComment *FC, + SmallVectorImpl<char> &XML, + const ASTContext &Context) { + CommentASTToXMLConverter Converter(FC, XML, Context.getCommentCommandTraits(), + Context.getSourceManager()); + Converter.visit(FC); +} diff --git a/contrib/llvm/tools/clang/lib/Index/IndexBody.cpp b/contrib/llvm/tools/clang/lib/Index/IndexBody.cpp new file mode 100644 index 000000000000..3aa0152ec996 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/IndexBody.cpp @@ -0,0 +1,348 @@ +//===- IndexBody.cpp - Indexing statements --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "IndexingContext.h" +#include "clang/AST/RecursiveASTVisitor.h" + +using namespace clang; +using namespace clang::index; + +namespace { + +class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> { + IndexingContext &IndexCtx; + const NamedDecl *Parent; + const DeclContext *ParentDC; + SmallVector<Stmt*, 16> StmtStack; + + typedef RecursiveASTVisitor<BodyIndexer> base; +public: + BodyIndexer(IndexingContext &indexCtx, + const NamedDecl *Parent, const DeclContext *DC) + : IndexCtx(indexCtx), Parent(Parent), ParentDC(DC) { } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + + bool dataTraverseStmtPre(Stmt *S) { + StmtStack.push_back(S); + return true; + } + + bool dataTraverseStmtPost(Stmt *S) { + assert(StmtStack.back() == S); + StmtStack.pop_back(); + return true; + } + + bool TraverseTypeLoc(TypeLoc TL) { + IndexCtx.indexTypeLoc(TL, Parent, ParentDC); + return true; + } + + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { + IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC); + return true; + } + + SymbolRoleSet getRolesForRef(const Expr *E, + SmallVectorImpl<SymbolRelation> &Relations) { + SymbolRoleSet Roles{}; + assert(!StmtStack.empty() && E == StmtStack.back()); + if (StmtStack.size() == 1) + return Roles; + auto It = StmtStack.end()-2; + while (isa<CastExpr>(*It) || isa<ParenExpr>(*It)) { + if (auto ICE = dyn_cast<ImplicitCastExpr>(*It)) { + if (ICE->getCastKind() == CK_LValueToRValue) + Roles |= (unsigned)(unsigned)SymbolRole::Read; + } + if (It == StmtStack.begin()) + break; + --It; + } + const Stmt *Parent = *It; + + if (auto BO = dyn_cast<BinaryOperator>(Parent)) { + if (BO->getOpcode() == BO_Assign && BO->getLHS()->IgnoreParenCasts() == E) + Roles |= (unsigned)SymbolRole::Write; + + } else if (auto UO = dyn_cast<UnaryOperator>(Parent)) { + if (UO->isIncrementDecrementOp()) { + Roles |= (unsigned)SymbolRole::Read; + Roles |= (unsigned)SymbolRole::Write; + } else if (UO->getOpcode() == UO_AddrOf) { + Roles |= (unsigned)SymbolRole::AddressOf; + } + + } else if (auto CA = dyn_cast<CompoundAssignOperator>(Parent)) { + if (CA->getLHS()->IgnoreParenCasts() == E) { + Roles |= (unsigned)SymbolRole::Read; + Roles |= (unsigned)SymbolRole::Write; + } + + } else if (auto CE = dyn_cast<CallExpr>(Parent)) { + if (CE->getCallee()->IgnoreParenCasts() == E) { + addCallRole(Roles, Relations); + if (auto *ME = dyn_cast<MemberExpr>(E)) { + if (auto *CXXMD = dyn_cast_or_null<CXXMethodDecl>(ME->getMemberDecl())) + if (CXXMD->isVirtual() && !ME->hasQualifier()) { + Roles |= (unsigned)SymbolRole::Dynamic; + auto BaseTy = ME->getBase()->IgnoreImpCasts()->getType(); + if (!BaseTy.isNull()) + if (auto *CXXRD = BaseTy->getPointeeCXXRecordDecl()) + Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy, + CXXRD); + } + } + } else if (auto CXXOp = dyn_cast<CXXOperatorCallExpr>(CE)) { + if (CXXOp->getNumArgs() > 0 && CXXOp->getArg(0)->IgnoreParenCasts() == E) { + OverloadedOperatorKind Op = CXXOp->getOperator(); + if (Op == OO_Equal) { + Roles |= (unsigned)SymbolRole::Write; + } else if ((Op >= OO_PlusEqual && Op <= OO_PipeEqual) || + Op == OO_LessLessEqual || Op == OO_GreaterGreaterEqual || + Op == OO_PlusPlus || Op == OO_MinusMinus) { + Roles |= (unsigned)SymbolRole::Read; + Roles |= (unsigned)SymbolRole::Write; + } else if (Op == OO_Amp) { + Roles |= (unsigned)SymbolRole::AddressOf; + } + } + } + } + + return Roles; + } + + void addCallRole(SymbolRoleSet &Roles, + SmallVectorImpl<SymbolRelation> &Relations) { + Roles |= (unsigned)SymbolRole::Call; + if (auto *FD = dyn_cast<FunctionDecl>(ParentDC)) + Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, FD); + else if (auto *MD = dyn_cast<ObjCMethodDecl>(ParentDC)) + Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, MD); + } + + bool VisitDeclRefExpr(DeclRefExpr *E) { + SmallVector<SymbolRelation, 4> Relations; + SymbolRoleSet Roles = getRolesForRef(E, Relations); + return IndexCtx.handleReference(E->getDecl(), E->getLocation(), + Parent, ParentDC, Roles, Relations, E); + } + + bool VisitMemberExpr(MemberExpr *E) { + SourceLocation Loc = E->getMemberLoc(); + if (Loc.isInvalid()) + Loc = E->getLocStart(); + SmallVector<SymbolRelation, 4> Relations; + SymbolRoleSet Roles = getRolesForRef(E, Relations); + return IndexCtx.handleReference(E->getMemberDecl(), Loc, + Parent, ParentDC, Roles, Relations, E); + } + + bool VisitDesignatedInitExpr(DesignatedInitExpr *E) { + for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) { + if (D.isFieldDesignator() && D.getField()) + return IndexCtx.handleReference(D.getField(), D.getFieldLoc(), Parent, + ParentDC, SymbolRoleSet(), {}, E); + } + return true; + } + + bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { + SmallVector<SymbolRelation, 4> Relations; + SymbolRoleSet Roles = getRolesForRef(E, Relations); + return IndexCtx.handleReference(E->getDecl(), E->getLocation(), + Parent, ParentDC, Roles, Relations, E); + } + + bool VisitObjCMessageExpr(ObjCMessageExpr *E) { + auto isDynamic = [](const ObjCMessageExpr *MsgE)->bool { + if (MsgE->getReceiverKind() != ObjCMessageExpr::Instance) + return false; + if (auto *RecE = dyn_cast<ObjCMessageExpr>( + MsgE->getInstanceReceiver()->IgnoreParenCasts())) { + if (RecE->getMethodFamily() == OMF_alloc) + return false; + } + return true; + }; + + if (ObjCMethodDecl *MD = E->getMethodDecl()) { + SymbolRoleSet Roles{}; + SmallVector<SymbolRelation, 2> Relations; + addCallRole(Roles, Relations); + if (E->isImplicit()) + Roles |= (unsigned)SymbolRole::Implicit; + + if (isDynamic(E)) { + Roles |= (unsigned)SymbolRole::Dynamic; + if (auto *RecD = E->getReceiverInterface()) + Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy, RecD); + } + + return IndexCtx.handleReference(MD, E->getSelectorStartLoc(), + Parent, ParentDC, Roles, Relations, E); + } + return true; + } + + bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { + if (E->isExplicitProperty()) + return IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(), + Parent, ParentDC, SymbolRoleSet(), {}, E); + + // No need to do a handleReference for the objc method, because there will + // be a message expr as part of PseudoObjectExpr. + return true; + } + + bool VisitMSPropertyRefExpr(MSPropertyRefExpr *E) { + return IndexCtx.handleReference(E->getPropertyDecl(), E->getMemberLoc(), + Parent, ParentDC, SymbolRoleSet(), {}, E); + } + + bool VisitObjCProtocolExpr(ObjCProtocolExpr *E) { + return IndexCtx.handleReference(E->getProtocol(), E->getProtocolIdLoc(), + Parent, ParentDC, SymbolRoleSet(), {}, E); + } + + bool passObjCLiteralMethodCall(const ObjCMethodDecl *MD, const Expr *E) { + SymbolRoleSet Roles{}; + SmallVector<SymbolRelation, 2> Relations; + addCallRole(Roles, Relations); + Roles |= (unsigned)SymbolRole::Implicit; + return IndexCtx.handleReference(MD, E->getLocStart(), + Parent, ParentDC, Roles, Relations, E); + } + + bool VisitObjCBoxedExpr(ObjCBoxedExpr *E) { + if (ObjCMethodDecl *MD = E->getBoxingMethod()) { + return passObjCLiteralMethodCall(MD, E); + } + return true; + } + + bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) { + if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod()) { + return passObjCLiteralMethodCall(MD, E); + } + return true; + } + + bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) { + if (ObjCMethodDecl *MD = E->getArrayWithObjectsMethod()) { + return passObjCLiteralMethodCall(MD, E); + } + return true; + } + + bool VisitCXXConstructExpr(CXXConstructExpr *E) { + SymbolRoleSet Roles{}; + SmallVector<SymbolRelation, 2> Relations; + addCallRole(Roles, Relations); + return IndexCtx.handleReference(E->getConstructor(), E->getLocation(), + Parent, ParentDC, Roles, Relations, E); + } + + bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E, + DataRecursionQueue *Q = nullptr) { + if (E->getOperatorLoc().isInvalid()) + return true; // implicit. + return base::TraverseCXXOperatorCallExpr(E, Q); + } + + bool VisitDeclStmt(DeclStmt *S) { + if (IndexCtx.shouldIndexFunctionLocalSymbols()) { + IndexCtx.indexDeclGroupRef(S->getDeclGroup()); + return true; + } + + DeclGroupRef DG = S->getDeclGroup(); + for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) { + const Decl *D = *I; + if (!D) + continue; + if (!IndexCtx.isFunctionLocalDecl(D)) + IndexCtx.indexTopLevelDecl(D); + } + + return true; + } + + bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, + Expr *Init) { + if (C->capturesThis() || C->capturesVLAType()) + return true; + + if (C->capturesVariable() && IndexCtx.shouldIndexFunctionLocalSymbols()) + return IndexCtx.handleReference(C->getCapturedVar(), C->getLocation(), + Parent, ParentDC, SymbolRoleSet()); + + // FIXME: Lambda init-captures. + return true; + } + + // RecursiveASTVisitor visits both syntactic and semantic forms, duplicating + // the things that we visit. Make sure to only visit the semantic form. + // Also visit things that are in the syntactic form but not the semantic one, + // for example the indices in DesignatedInitExprs. + bool TraverseInitListExpr(InitListExpr *S, DataRecursionQueue *Q = nullptr) { + auto visitForm = [&](InitListExpr *Form) { + for (Stmt *SubStmt : Form->children()) { + if (!TraverseStmt(SubStmt, Q)) + return false; + } + return true; + }; + + auto visitSyntacticDesignatedInitExpr = [&](DesignatedInitExpr *E) -> bool { + for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) { + if (D.isFieldDesignator()) + return IndexCtx.handleReference(D.getField(), D.getFieldLoc(), + Parent, ParentDC, SymbolRoleSet(), + {}, E); + } + return true; + }; + + InitListExpr *SemaForm = S->isSemanticForm() ? S : S->getSemanticForm(); + InitListExpr *SyntaxForm = S->isSemanticForm() ? S->getSyntacticForm() : S; + + if (SemaForm) { + // Visit things present in syntactic form but not the semantic form. + if (SyntaxForm) { + for (Expr *init : SyntaxForm->inits()) { + if (auto *DIE = dyn_cast<DesignatedInitExpr>(init)) + visitSyntacticDesignatedInitExpr(DIE); + } + } + return visitForm(SemaForm); + } + + // No semantic, try the syntactic. + if (SyntaxForm) { + return visitForm(SyntaxForm); + } + + return true; + } +}; + +} // anonymous namespace + +void IndexingContext::indexBody(const Stmt *S, const NamedDecl *Parent, + const DeclContext *DC) { + if (!S) + return; + + if (!DC) + DC = Parent->getLexicalDeclContext(); + BodyIndexer(*this, Parent, DC).TraverseStmt(const_cast<Stmt*>(S)); +} diff --git a/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp b/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp new file mode 100644 index 000000000000..1225391dc2a6 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp @@ -0,0 +1,482 @@ +//===- IndexDecl.cpp - Indexing declarations ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "IndexingContext.h" +#include "clang/Index/IndexDataConsumer.h" +#include "clang/AST/DeclVisitor.h" + +using namespace clang; +using namespace index; + +#define TRY_TO(CALL_EXPR) \ + do { \ + if (!CALL_EXPR) \ + return false; \ + } while (0) + +namespace { + +class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> { + IndexingContext &IndexCtx; + +public: + explicit IndexingDeclVisitor(IndexingContext &indexCtx) + : IndexCtx(indexCtx) { } + + bool Handled = true; + + bool VisitDecl(const Decl *D) { + Handled = false; + return true; + } + + /// \brief Returns true if the given method has been defined explicitly by the + /// user. + static bool hasUserDefined(const ObjCMethodDecl *D, + const ObjCImplDecl *Container) { + const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(), + D->isInstanceMethod()); + return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition(); + } + + void handleDeclarator(const DeclaratorDecl *D, + const NamedDecl *Parent = nullptr) { + if (!Parent) Parent = D; + + IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent); + IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent); + if (IndexCtx.shouldIndexFunctionLocalSymbols()) { + // Only index parameters in definitions, parameters in declarations are + // not useful. + if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) { + auto *DC = Parm->getDeclContext(); + if (auto *FD = dyn_cast<FunctionDecl>(DC)) { + if (FD->isThisDeclarationADefinition()) + IndexCtx.handleDecl(Parm); + } else if (auto *MD = dyn_cast<ObjCMethodDecl>(DC)) { + if (MD->isThisDeclarationADefinition()) + IndexCtx.handleDecl(Parm); + } else { + IndexCtx.handleDecl(Parm); + } + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isThisDeclarationADefinition()) { + for (auto PI : FD->parameters()) { + IndexCtx.handleDecl(PI); + } + } + } + } + } + + bool handleObjCMethod(const ObjCMethodDecl *D, + const ObjCPropertyDecl *AssociatedProp = nullptr) { + SmallVector<SymbolRelation, 4> Relations; + SmallVector<const ObjCMethodDecl*, 4> Overriden; + + D->getOverriddenMethods(Overriden); + for(auto overridden: Overriden) { + Relations.emplace_back((unsigned) SymbolRole::RelationOverrideOf, + overridden); + } + if (AssociatedProp) + Relations.emplace_back((unsigned)SymbolRole::RelationAccessorOf, + AssociatedProp); + + if (!IndexCtx.handleDecl(D, (unsigned)SymbolRole::Dynamic, Relations)) + return false; + IndexCtx.indexTypeSourceInfo(D->getReturnTypeSourceInfo(), D); + for (const auto *I : D->parameters()) + handleDeclarator(I, D); + + if (D->isThisDeclarationADefinition()) { + const Stmt *Body = D->getBody(); + if (Body) { + IndexCtx.indexBody(Body, D, D); + } + } + return true; + } + + bool VisitFunctionDecl(const FunctionDecl *D) { + if (D->isDeleted()) + return true; + + SymbolRoleSet Roles{}; + SmallVector<SymbolRelation, 4> Relations; + if (auto *CXXMD = dyn_cast<CXXMethodDecl>(D)) { + if (CXXMD->isVirtual()) + Roles |= (unsigned)SymbolRole::Dynamic; + for (auto I = CXXMD->begin_overridden_methods(), + E = CXXMD->end_overridden_methods(); I != E; ++I) { + Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I); + } + } + + if (!IndexCtx.handleDecl(D, Roles, Relations)) + return false; + handleDeclarator(D); + + if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) { + // Constructor initializers. + for (const auto *Init : Ctor->inits()) { + if (Init->isWritten()) { + IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D); + if (const FieldDecl *Member = Init->getAnyMember()) + IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D, + (unsigned)SymbolRole::Write); + IndexCtx.indexBody(Init->getInit(), D, D); + } + } + } + + if (D->isThisDeclarationADefinition()) { + const Stmt *Body = D->getBody(); + if (Body) { + IndexCtx.indexBody(Body, D, D); + } + } + return true; + } + + bool VisitVarDecl(const VarDecl *D) { + if (!IndexCtx.handleDecl(D)) + return false; + handleDeclarator(D); + IndexCtx.indexBody(D->getInit(), D); + return true; + } + + bool VisitFieldDecl(const FieldDecl *D) { + if (!IndexCtx.handleDecl(D)) + return false; + handleDeclarator(D); + if (D->isBitField()) + IndexCtx.indexBody(D->getBitWidth(), D); + else if (D->hasInClassInitializer()) + IndexCtx.indexBody(D->getInClassInitializer(), D); + return true; + } + + bool VisitObjCIvarDecl(const ObjCIvarDecl *D) { + if (D->getSynthesize()) { + // For synthesized ivars, use the location of the ObjC implementation, + // not the location of the property. + // Otherwise the header file containing the @interface will have different + // indexing contents based on whether the @implementation was present or + // not in the translation unit. + return IndexCtx.handleDecl(D, + cast<Decl>(D->getDeclContext())->getLocation(), + (unsigned)SymbolRole::Implicit); + } + if (!IndexCtx.handleDecl(D)) + return false; + handleDeclarator(D); + return true; + } + + bool VisitMSPropertyDecl(const MSPropertyDecl *D) { + handleDeclarator(D); + return true; + } + + bool VisitEnumConstantDecl(const EnumConstantDecl *D) { + if (!IndexCtx.handleDecl(D)) + return false; + IndexCtx.indexBody(D->getInitExpr(), D); + return true; + } + + bool VisitTypedefNameDecl(const TypedefNameDecl *D) { + if (!IndexCtx.handleDecl(D)) + return false; + IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); + return true; + } + + bool VisitTagDecl(const TagDecl *D) { + // Non-free standing tags are handled in indexTypeSourceInfo. + if (D->isFreeStanding()) { + if (D->isThisDeclarationADefinition()) { + IndexCtx.indexTagDecl(D); + } else { + auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext()); + return IndexCtx.handleReference(D, D->getLocation(), Parent, + D->getLexicalDeclContext(), + SymbolRoleSet()); + } + } + return true; + } + + bool handleReferencedProtocols(const ObjCProtocolList &ProtList, + const ObjCContainerDecl *ContD) { + ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin(); + for (ObjCInterfaceDecl::protocol_iterator + I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) { + SourceLocation Loc = *LI; + ObjCProtocolDecl *PD = *I; + TRY_TO(IndexCtx.handleReference(PD, Loc, ContD, ContD, + SymbolRoleSet(), + SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, ContD})); + } + return true; + } + + bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { + if (D->isThisDeclarationADefinition()) { + TRY_TO(IndexCtx.handleDecl(D)); + if (auto *SuperD = D->getSuperClass()) { + TRY_TO(IndexCtx.handleReference(SuperD, D->getSuperClassLoc(), D, D, + SymbolRoleSet(), + SymbolRelation{(unsigned)SymbolRole::RelationBaseOf, D})); + } + TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D)); + TRY_TO(IndexCtx.indexDeclContext(D)); + } else { + return IndexCtx.handleReference(D, D->getLocation(), nullptr, + D->getDeclContext(), SymbolRoleSet()); + } + return true; + } + + bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { + if (D->isThisDeclarationADefinition()) { + TRY_TO(IndexCtx.handleDecl(D)); + TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D)); + TRY_TO(IndexCtx.indexDeclContext(D)); + } else { + return IndexCtx.handleReference(D, D->getLocation(), nullptr, + D->getDeclContext(), SymbolRoleSet()); + } + return true; + } + + bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { + const ObjCInterfaceDecl *Class = D->getClassInterface(); + if (!Class) + return true; + + if (Class->isImplicitInterfaceDecl()) + IndexCtx.handleDecl(Class); + + if (!IndexCtx.handleDecl(D)) + return false; + + // Index the ivars first to make sure the synthesized ivars are indexed + // before indexing the methods that can reference them. + for (const auto *IvarI : D->ivars()) + IndexCtx.indexDecl(IvarI); + for (const auto *I : D->decls()) { + if (!isa<ObjCIvarDecl>(I)) + IndexCtx.indexDecl(I); + } + + return true; + } + + bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { + const ObjCInterfaceDecl *C = D->getClassInterface(); + if (C) + TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, + SymbolRoleSet(), SymbolRelation{ + (unsigned)SymbolRole::RelationExtendedBy, D + })); + SourceLocation CategoryLoc = D->getCategoryNameLoc(); + if (!CategoryLoc.isValid()) + CategoryLoc = D->getLocation(); + TRY_TO(IndexCtx.handleDecl(D, CategoryLoc)); + TRY_TO(handleReferencedProtocols(D->getReferencedProtocols(), D)); + TRY_TO(IndexCtx.indexDeclContext(D)); + return true; + } + + bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { + const ObjCCategoryDecl *Cat = D->getCategoryDecl(); + if (!Cat) + return true; + const ObjCInterfaceDecl *C = D->getClassInterface(); + if (C) + TRY_TO(IndexCtx.handleReference(C, D->getLocation(), D, D, + SymbolRoleSet())); + SourceLocation CategoryLoc = D->getCategoryNameLoc(); + if (!CategoryLoc.isValid()) + CategoryLoc = D->getLocation(); + if (!IndexCtx.handleDecl(D, CategoryLoc)) + return false; + IndexCtx.indexDeclContext(D); + return true; + } + + bool VisitObjCMethodDecl(const ObjCMethodDecl *D) { + // Methods associated with a property, even user-declared ones, are + // handled when we handle the property. + if (D->isPropertyAccessor()) + return true; + + handleObjCMethod(D); + return true; + } + + bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { + if (ObjCMethodDecl *MD = D->getGetterMethodDecl()) + if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) + handleObjCMethod(MD, D); + if (ObjCMethodDecl *MD = D->getSetterMethodDecl()) + if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) + handleObjCMethod(MD, D); + if (!IndexCtx.handleDecl(D)) + return false; + IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); + return true; + } + + bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { + ObjCPropertyDecl *PD = D->getPropertyDecl(); + if (!IndexCtx.handleReference(PD, D->getLocation(), + /*Parent=*/cast<NamedDecl>(D->getDeclContext()), + D->getDeclContext(), SymbolRoleSet(), {}, + /*RefE=*/nullptr, D)) + return false; + + if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + return true; + assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); + + if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { + if (!IvarD->getSynthesize()) + IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), nullptr, + D->getDeclContext(), SymbolRoleSet()); + } + + auto *ImplD = cast<ObjCImplDecl>(D->getDeclContext()); + if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { + if (MD->isPropertyAccessor() && + !hasUserDefined(MD, ImplD)) + IndexCtx.handleDecl(MD, D->getLocation(), SymbolRoleSet(), {}, ImplD); + } + if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { + if (MD->isPropertyAccessor() && + !hasUserDefined(MD, ImplD)) + IndexCtx.handleDecl(MD, D->getLocation(), SymbolRoleSet(), {}, ImplD); + } + return true; + } + + bool VisitNamespaceDecl(const NamespaceDecl *D) { + if (!IndexCtx.handleDecl(D)) + return false; + IndexCtx.indexDeclContext(D); + return true; + } + + bool VisitUsingDecl(const UsingDecl *D) { + const DeclContext *DC = D->getDeclContext()->getRedeclContext(); + const NamedDecl *Parent = dyn_cast<NamedDecl>(DC); + + IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, + D->getLexicalDeclContext()); + for (const auto *I : D->shadows()) + IndexCtx.handleReference(I->getUnderlyingDecl(), D->getLocation(), Parent, + D->getLexicalDeclContext(), SymbolRoleSet()); + return true; + } + + bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { + const DeclContext *DC = D->getDeclContext()->getRedeclContext(); + const NamedDecl *Parent = dyn_cast<NamedDecl>(DC); + + IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent, + D->getLexicalDeclContext()); + return IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(), + D->getLocation(), Parent, + D->getLexicalDeclContext(), + SymbolRoleSet()); + } + + bool VisitClassTemplateSpecializationDecl(const + ClassTemplateSpecializationDecl *D) { + // FIXME: Notify subsequent callbacks if info comes from implicit + // instantiation. + if (D->isThisDeclarationADefinition()) + IndexCtx.indexTagDecl(D); + return true; + } + + bool VisitTemplateDecl(const TemplateDecl *D) { + // FIXME: Template parameters. + return Visit(D->getTemplatedDecl()); + } + + bool VisitFriendDecl(const FriendDecl *D) { + if (auto ND = D->getFriendDecl()) { + // FIXME: Ignore a class template in a dependent context, these are not + // linked properly with their redeclarations, ending up with duplicate + // USRs. + // See comment "Friend templates are visible in fairly strange ways." in + // SemaTemplate.cpp which precedes code that prevents the friend template + // from becoming visible from the enclosing context. + if (isa<ClassTemplateDecl>(ND) && D->getDeclContext()->isDependentContext()) + return true; + return Visit(ND); + } + if (auto Ty = D->getFriendType()) { + IndexCtx.indexTypeSourceInfo(Ty, cast<NamedDecl>(D->getDeclContext())); + } + return true; + } + + bool VisitImportDecl(const ImportDecl *D) { + return IndexCtx.importedModule(D); + } +}; + +} // anonymous namespace + +bool IndexingContext::indexDecl(const Decl *D) { + if (D->isImplicit() && shouldIgnoreIfImplicit(D)) + return true; + + if (isTemplateImplicitInstantiation(D)) + return true; + + IndexingDeclVisitor Visitor(*this); + bool ShouldContinue = Visitor.Visit(D); + if (!ShouldContinue) + return false; + + if (!Visitor.Handled && isa<DeclContext>(D)) + return indexDeclContext(cast<DeclContext>(D)); + + return true; +} + +bool IndexingContext::indexDeclContext(const DeclContext *DC) { + for (const auto *I : DC->decls()) + if (!indexDecl(I)) + return false; + return true; +} + +bool IndexingContext::indexTopLevelDecl(const Decl *D) { + if (D->getLocation().isInvalid()) + return true; + + if (isa<ObjCMethodDecl>(D)) + return true; // Wait for the objc container. + + return indexDecl(D); +} + +bool IndexingContext::indexDeclGroupRef(DeclGroupRef DG) { + for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) + if (!indexTopLevelDecl(*I)) + return false; + return true; +} diff --git a/contrib/llvm/tools/clang/lib/Index/IndexSymbol.cpp b/contrib/llvm/tools/clang/lib/Index/IndexSymbol.cpp new file mode 100644 index 000000000000..be847e762091 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/IndexSymbol.cpp @@ -0,0 +1,425 @@ +//===--- IndexSymbol.cpp - Types and functions for indexing symbols -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/IndexSymbol.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/PrettyPrinter.h" + +using namespace clang; +using namespace clang::index; + +/// \returns true if \c D is a subclass of 'XCTestCase'. +static bool isUnitTestCase(const ObjCInterfaceDecl *D) { + if (!D) + return false; + while (const ObjCInterfaceDecl *SuperD = D->getSuperClass()) { + if (SuperD->getName() == "XCTestCase") + return true; + D = SuperD; + } + return false; +} + +/// \returns true if \c D is in a subclass of 'XCTestCase', returns void, has +/// no parameters, and its name starts with 'test'. +static bool isUnitTest(const ObjCMethodDecl *D) { + if (!D->parameters().empty()) + return false; + if (!D->getReturnType()->isVoidType()) + return false; + if (!D->getSelector().getNameForSlot(0).startswith("test")) + return false; + return isUnitTestCase(D->getClassInterface()); +} + +static void checkForIBOutlets(const Decl *D, SymbolPropertySet &PropSet) { + if (D->hasAttr<IBOutletAttr>()) { + PropSet |= (unsigned)SymbolProperty::IBAnnotated; + } else if (D->hasAttr<IBOutletCollectionAttr>()) { + PropSet |= (unsigned)SymbolProperty::IBAnnotated; + PropSet |= (unsigned)SymbolProperty::IBOutletCollection; + } +} + +SymbolInfo index::getSymbolInfo(const Decl *D) { + assert(D); + SymbolInfo Info; + Info.Kind = SymbolKind::Unknown; + Info.SubKind = SymbolSubKind::None; + Info.Properties = SymbolPropertySet(); + Info.Lang = SymbolLanguage::C; + + if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { + switch (TD->getTagKind()) { + case TTK_Struct: + Info.Kind = SymbolKind::Struct; break; + case TTK_Union: + Info.Kind = SymbolKind::Union; break; + case TTK_Class: + Info.Kind = SymbolKind::Class; + Info.Lang = SymbolLanguage::CXX; + break; + case TTK_Interface: + Info.Kind = SymbolKind::Protocol; + Info.Lang = SymbolLanguage::CXX; + break; + case TTK_Enum: + Info.Kind = SymbolKind::Enum; break; + } + + if (const CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(D)) { + if (!CXXRec->isCLike()) { + Info.Lang = SymbolLanguage::CXX; + if (CXXRec->getDescribedClassTemplate()) { + Info.Properties |= (unsigned)SymbolProperty::Generic; + } + } + } + + if (isa<ClassTemplatePartialSpecializationDecl>(D)) { + Info.Properties |= (unsigned)SymbolProperty::Generic; + Info.Properties |= (unsigned)SymbolProperty::TemplatePartialSpecialization; + } else if (isa<ClassTemplateSpecializationDecl>(D)) { + Info.Properties |= (unsigned)SymbolProperty::Generic; + Info.Properties |= (unsigned)SymbolProperty::TemplateSpecialization; + } + + } else if (auto *VD = dyn_cast<VarDecl>(D)) { + Info.Kind = SymbolKind::Variable; + if (isa<CXXRecordDecl>(D->getDeclContext())) { + Info.Kind = SymbolKind::StaticProperty; + Info.Lang = SymbolLanguage::CXX; + } + if (isa<VarTemplatePartialSpecializationDecl>(D)) { + Info.Lang = SymbolLanguage::CXX; + Info.Properties |= (unsigned)SymbolProperty::Generic; + Info.Properties |= (unsigned)SymbolProperty::TemplatePartialSpecialization; + } else if (isa<VarTemplateSpecializationDecl>(D)) { + Info.Lang = SymbolLanguage::CXX; + Info.Properties |= (unsigned)SymbolProperty::Generic; + Info.Properties |= (unsigned)SymbolProperty::TemplateSpecialization; + } else if (VD->getDescribedVarTemplate()) { + Info.Lang = SymbolLanguage::CXX; + Info.Properties |= (unsigned)SymbolProperty::Generic; + } + + } else { + switch (D->getKind()) { + case Decl::Import: + Info.Kind = SymbolKind::Module; + break; + case Decl::Typedef: + Info.Kind = SymbolKind::TypeAlias; break; // Lang = C + case Decl::Function: + Info.Kind = SymbolKind::Function; + break; + case Decl::Field: + Info.Kind = SymbolKind::Field; + if (const CXXRecordDecl * + CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) { + if (!CXXRec->isCLike()) + Info.Lang = SymbolLanguage::CXX; + } + break; + case Decl::EnumConstant: + Info.Kind = SymbolKind::EnumConstant; break; + case Decl::ObjCInterface: + case Decl::ObjCImplementation: { + Info.Kind = SymbolKind::Class; + Info.Lang = SymbolLanguage::ObjC; + const ObjCInterfaceDecl *ClsD = dyn_cast<ObjCInterfaceDecl>(D); + if (!ClsD) + ClsD = cast<ObjCImplementationDecl>(D)->getClassInterface(); + if (isUnitTestCase(ClsD)) + Info.Properties |= (unsigned)SymbolProperty::UnitTest; + break; + } + case Decl::ObjCProtocol: + Info.Kind = SymbolKind::Protocol; + Info.Lang = SymbolLanguage::ObjC; + break; + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + Info.Kind = SymbolKind::Extension; + Info.Lang = SymbolLanguage::ObjC; + break; + case Decl::ObjCMethod: + if (cast<ObjCMethodDecl>(D)->isInstanceMethod()) + Info.Kind = SymbolKind::InstanceMethod; + else + Info.Kind = SymbolKind::ClassMethod; + Info.Lang = SymbolLanguage::ObjC; + if (isUnitTest(cast<ObjCMethodDecl>(D))) + Info.Properties |= (unsigned)SymbolProperty::UnitTest; + if (D->hasAttr<IBActionAttr>()) + Info.Properties |= (unsigned)SymbolProperty::IBAnnotated; + break; + case Decl::ObjCProperty: + Info.Kind = SymbolKind::InstanceProperty; + Info.Lang = SymbolLanguage::ObjC; + checkForIBOutlets(D, Info.Properties); + if (auto *Annot = D->getAttr<AnnotateAttr>()) { + if (Annot->getAnnotation() == "gk_inspectable") + Info.Properties |= (unsigned)SymbolProperty::GKInspectable; + } + break; + case Decl::ObjCIvar: + Info.Kind = SymbolKind::Field; + Info.Lang = SymbolLanguage::ObjC; + checkForIBOutlets(D, Info.Properties); + break; + case Decl::Namespace: + Info.Kind = SymbolKind::Namespace; + Info.Lang = SymbolLanguage::CXX; + break; + case Decl::NamespaceAlias: + Info.Kind = SymbolKind::NamespaceAlias; + Info.Lang = SymbolLanguage::CXX; + break; + case Decl::CXXConstructor: { + Info.Kind = SymbolKind::Constructor; + Info.Lang = SymbolLanguage::CXX; + auto *CD = cast<CXXConstructorDecl>(D); + if (CD->isCopyConstructor()) + Info.SubKind = SymbolSubKind::CXXCopyConstructor; + else if (CD->isMoveConstructor()) + Info.SubKind = SymbolSubKind::CXXMoveConstructor; + break; + } + case Decl::CXXDestructor: + Info.Kind = SymbolKind::Destructor; + Info.Lang = SymbolLanguage::CXX; + break; + case Decl::CXXConversion: + Info.Kind = SymbolKind::ConversionFunction; + Info.Lang = SymbolLanguage::CXX; + break; + case Decl::CXXMethod: { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(D); + if (MD->isStatic()) + Info.Kind = SymbolKind::StaticMethod; + else + Info.Kind = SymbolKind::InstanceMethod; + Info.Lang = SymbolLanguage::CXX; + break; + } + case Decl::ClassTemplate: + Info.Kind = SymbolKind::Class; + Info.Properties |= (unsigned)SymbolProperty::Generic; + Info.Lang = SymbolLanguage::CXX; + break; + case Decl::FunctionTemplate: + Info.Kind = SymbolKind::Function; + Info.Properties |= (unsigned)SymbolProperty::Generic; + Info.Lang = SymbolLanguage::CXX; + if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>( + cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) { + if (isa<CXXConstructorDecl>(MD)) + Info.Kind = SymbolKind::Constructor; + else if (isa<CXXDestructorDecl>(MD)) + Info.Kind = SymbolKind::Destructor; + else if (isa<CXXConversionDecl>(MD)) + Info.Kind = SymbolKind::ConversionFunction; + else { + if (MD->isStatic()) + Info.Kind = SymbolKind::StaticMethod; + else + Info.Kind = SymbolKind::InstanceMethod; + } + } + break; + case Decl::TypeAliasTemplate: + Info.Kind = SymbolKind::TypeAlias; + Info.Lang = SymbolLanguage::CXX; + Info.Properties |= (unsigned)SymbolProperty::Generic; + break; + case Decl::TypeAlias: + Info.Kind = SymbolKind::TypeAlias; + Info.Lang = SymbolLanguage::CXX; + break; + default: + break; + } + } + + if (Info.Kind == SymbolKind::Unknown) + return Info; + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->getTemplatedKind() == + FunctionDecl::TK_FunctionTemplateSpecialization) { + Info.Properties |= (unsigned)SymbolProperty::Generic; + Info.Properties |= (unsigned)SymbolProperty::TemplateSpecialization; + } + } + + if (Info.Properties & (unsigned)SymbolProperty::Generic) + Info.Lang = SymbolLanguage::CXX; + + return Info; +} + +void index::applyForEachSymbolRole(SymbolRoleSet Roles, + llvm::function_ref<void(SymbolRole)> Fn) { +#define APPLY_FOR_ROLE(Role) \ + if (Roles & (unsigned)SymbolRole::Role) \ + Fn(SymbolRole::Role) + + APPLY_FOR_ROLE(Declaration); + APPLY_FOR_ROLE(Definition); + APPLY_FOR_ROLE(Reference); + APPLY_FOR_ROLE(Read); + APPLY_FOR_ROLE(Write); + APPLY_FOR_ROLE(Call); + APPLY_FOR_ROLE(Dynamic); + APPLY_FOR_ROLE(AddressOf); + APPLY_FOR_ROLE(Implicit); + APPLY_FOR_ROLE(RelationChildOf); + APPLY_FOR_ROLE(RelationBaseOf); + APPLY_FOR_ROLE(RelationOverrideOf); + APPLY_FOR_ROLE(RelationReceivedBy); + APPLY_FOR_ROLE(RelationCalledBy); + APPLY_FOR_ROLE(RelationExtendedBy); + APPLY_FOR_ROLE(RelationAccessorOf); + +#undef APPLY_FOR_ROLE +} + +void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) { + bool VisitedOnce = false; + applyForEachSymbolRole(Roles, [&](SymbolRole Role) { + if (VisitedOnce) + OS << ','; + else + VisitedOnce = true; + switch (Role) { + case SymbolRole::Declaration: OS << "Decl"; break; + case SymbolRole::Definition: OS << "Def"; break; + case SymbolRole::Reference: OS << "Ref"; break; + case SymbolRole::Read: OS << "Read"; break; + case SymbolRole::Write: OS << "Writ"; break; + case SymbolRole::Call: OS << "Call"; break; + case SymbolRole::Dynamic: OS << "Dyn"; break; + case SymbolRole::AddressOf: OS << "Addr"; break; + case SymbolRole::Implicit: OS << "Impl"; break; + case SymbolRole::RelationChildOf: OS << "RelChild"; break; + case SymbolRole::RelationBaseOf: OS << "RelBase"; break; + case SymbolRole::RelationOverrideOf: OS << "RelOver"; break; + case SymbolRole::RelationReceivedBy: OS << "RelRec"; break; + case SymbolRole::RelationCalledBy: OS << "RelCall"; break; + case SymbolRole::RelationExtendedBy: OS << "RelExt"; break; + case SymbolRole::RelationAccessorOf: OS << "RelAcc"; break; + } + }); +} + +bool index::printSymbolName(const Decl *D, const LangOptions &LO, + raw_ostream &OS) { + if (auto *ND = dyn_cast<NamedDecl>(D)) { + PrintingPolicy Policy(LO); + // Forward references can have different template argument names. Suppress + // the template argument names in constructors to make their name more + // stable. + Policy.SuppressTemplateArgsInCXXConstructors = true; + DeclarationName DeclName = ND->getDeclName(); + if (DeclName.isEmpty()) + return true; + DeclName.print(OS, Policy); + return false; + } else { + return true; + } +} + +StringRef index::getSymbolKindString(SymbolKind K) { + switch (K) { + case SymbolKind::Unknown: return "<unknown>"; + case SymbolKind::Module: return "module"; + case SymbolKind::Namespace: return "namespace"; + case SymbolKind::NamespaceAlias: return "namespace-alias"; + case SymbolKind::Macro: return "macro"; + case SymbolKind::Enum: return "enum"; + case SymbolKind::Struct: return "struct"; + case SymbolKind::Class: return "class"; + case SymbolKind::Protocol: return "protocol"; + case SymbolKind::Extension: return "extension"; + case SymbolKind::Union: return "union"; + case SymbolKind::TypeAlias: return "type-alias"; + case SymbolKind::Function: return "function"; + case SymbolKind::Variable: return "variable"; + case SymbolKind::Field: return "field"; + case SymbolKind::EnumConstant: return "enumerator"; + case SymbolKind::InstanceMethod: return "instance-method"; + case SymbolKind::ClassMethod: return "class-method"; + case SymbolKind::StaticMethod: return "static-method"; + case SymbolKind::InstanceProperty: return "instance-property"; + case SymbolKind::ClassProperty: return "class-property"; + case SymbolKind::StaticProperty: return "static-property"; + case SymbolKind::Constructor: return "constructor"; + case SymbolKind::Destructor: return "destructor"; + case SymbolKind::ConversionFunction: return "coversion-func"; + } + llvm_unreachable("invalid symbol kind"); +} + +StringRef index::getSymbolSubKindString(SymbolSubKind K) { + switch (K) { + case SymbolSubKind::None: return "<none>"; + case SymbolSubKind::CXXCopyConstructor: return "cxx-copy-ctor"; + case SymbolSubKind::CXXMoveConstructor: return "cxx-move-ctor"; + } + llvm_unreachable("invalid symbol subkind"); +} + +StringRef index::getSymbolLanguageString(SymbolLanguage K) { + switch (K) { + case SymbolLanguage::C: return "C"; + case SymbolLanguage::ObjC: return "ObjC"; + case SymbolLanguage::CXX: return "C++"; + } + llvm_unreachable("invalid symbol language kind"); +} + +void index::applyForEachSymbolProperty(SymbolPropertySet Props, + llvm::function_ref<void(SymbolProperty)> Fn) { +#define APPLY_FOR_PROPERTY(K) \ + if (Props & (unsigned)SymbolProperty::K) \ + Fn(SymbolProperty::K) + + APPLY_FOR_PROPERTY(Generic); + APPLY_FOR_PROPERTY(TemplatePartialSpecialization); + APPLY_FOR_PROPERTY(TemplateSpecialization); + APPLY_FOR_PROPERTY(UnitTest); + APPLY_FOR_PROPERTY(IBAnnotated); + APPLY_FOR_PROPERTY(IBOutletCollection); + APPLY_FOR_PROPERTY(GKInspectable); + +#undef APPLY_FOR_PROPERTY +} + +void index::printSymbolProperties(SymbolPropertySet Props, raw_ostream &OS) { + bool VisitedOnce = false; + applyForEachSymbolProperty(Props, [&](SymbolProperty Prop) { + if (VisitedOnce) + OS << ','; + else + VisitedOnce = true; + switch (Prop) { + case SymbolProperty::Generic: OS << "Gen"; break; + case SymbolProperty::TemplatePartialSpecialization: OS << "TPS"; break; + case SymbolProperty::TemplateSpecialization: OS << "TS"; break; + case SymbolProperty::UnitTest: OS << "test"; break; + case SymbolProperty::IBAnnotated: OS << "IB"; break; + case SymbolProperty::IBOutletCollection: OS << "IBColl"; break; + case SymbolProperty::GKInspectable: OS << "GKI"; break; + } + }); +} diff --git a/contrib/llvm/tools/clang/lib/Index/IndexTypeSourceInfo.cpp b/contrib/llvm/tools/clang/lib/Index/IndexTypeSourceInfo.cpp new file mode 100644 index 000000000000..619a9a48befd --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/IndexTypeSourceInfo.cpp @@ -0,0 +1,202 @@ +//===- IndexTypeSourceInfo.cpp - Indexing types ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "IndexingContext.h" +#include "clang/AST/RecursiveASTVisitor.h" + +using namespace clang; +using namespace index; + +namespace { + +class TypeIndexer : public RecursiveASTVisitor<TypeIndexer> { + IndexingContext &IndexCtx; + const NamedDecl *Parent; + const DeclContext *ParentDC; + bool IsBase; + SmallVector<SymbolRelation, 3> Relations; + + typedef RecursiveASTVisitor<TypeIndexer> base; + +public: + TypeIndexer(IndexingContext &indexCtx, const NamedDecl *parent, + const DeclContext *DC, bool isBase) + : IndexCtx(indexCtx), Parent(parent), ParentDC(DC), IsBase(isBase) { + if (IsBase) { + assert(Parent); + Relations.emplace_back((unsigned)SymbolRole::RelationBaseOf, Parent); + } + } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + + bool VisitTypedefTypeLoc(TypedefTypeLoc TL) { + return IndexCtx.handleReference(TL.getTypedefNameDecl(), TL.getNameLoc(), + Parent, ParentDC, SymbolRoleSet(), + Relations); + } + +#define TRY_TO(CALL_EXPR) \ + do { \ + if (!CALL_EXPR) \ + return false; \ + } while (0) + + bool traverseParamVarHelper(ParmVarDecl *D) { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + if (D->getTypeSourceInfo()) + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + return true; + } + + bool TraverseParmVarDecl(ParmVarDecl *D) { + // Avoid visiting default arguments from the definition that were already + // visited in the declaration. + // FIXME: A free function definition can have default arguments. + // Avoiding double visitaiton of default arguments should be handled by the + // visitor probably with a bit in the AST to indicate if the attached + // default argument was 'inherited' or written in source. + if (auto FD = dyn_cast<FunctionDecl>(D->getDeclContext())) { + if (FD->isThisDeclarationADefinition()) { + return traverseParamVarHelper(D); + } + } + + return base::TraverseParmVarDecl(D); + } + + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { + IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC); + return true; + } + + bool VisitTagTypeLoc(TagTypeLoc TL) { + TagDecl *D = TL.getDecl(); + if (D->getParentFunctionOrMethod()) + return true; + + if (TL.isDefinition()) { + IndexCtx.indexTagDecl(D); + return true; + } + + return IndexCtx.handleReference(D, TL.getNameLoc(), + Parent, ParentDC, SymbolRoleSet(), + Relations); + } + + bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + return IndexCtx.handleReference(TL.getIFaceDecl(), TL.getNameLoc(), + Parent, ParentDC, SymbolRoleSet()); + } + + bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) { + IndexCtx.handleReference(TL.getProtocol(i), TL.getProtocolLoc(i), + Parent, ParentDC, SymbolRoleSet()); + } + return true; + } + + bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { + if (const TemplateSpecializationType *T = TL.getTypePtr()) { + if (IndexCtx.shouldIndexImplicitTemplateInsts()) { + if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + IndexCtx.handleReference(RD, TL.getTemplateNameLoc(), + Parent, ParentDC, SymbolRoleSet(), Relations); + } else { + if (const TemplateDecl *D = T->getTemplateName().getAsTemplateDecl()) + IndexCtx.handleReference(D, TL.getTemplateNameLoc(), + Parent, ParentDC, SymbolRoleSet(), Relations); + } + } + return true; + } + + bool TraverseStmt(Stmt *S) { + IndexCtx.indexBody(S, Parent, ParentDC); + return true; + } +}; + +} // anonymous namespace + +void IndexingContext::indexTypeSourceInfo(TypeSourceInfo *TInfo, + const NamedDecl *Parent, + const DeclContext *DC, + bool isBase) { + if (!TInfo || TInfo->getTypeLoc().isNull()) + return; + + indexTypeLoc(TInfo->getTypeLoc(), Parent, DC, isBase); +} + +void IndexingContext::indexTypeLoc(TypeLoc TL, + const NamedDecl *Parent, + const DeclContext *DC, + bool isBase) { + if (TL.isNull()) + return; + + if (!DC) + DC = Parent->getLexicalDeclContext(); + TypeIndexer(*this, Parent, DC, isBase).TraverseTypeLoc(TL); +} + +void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, + const NamedDecl *Parent, + const DeclContext *DC) { + if (!NNS) + return; + + if (NestedNameSpecifierLoc Prefix = NNS.getPrefix()) + indexNestedNameSpecifierLoc(Prefix, Parent, DC); + + if (!DC) + DC = Parent->getLexicalDeclContext(); + SourceLocation Loc = NNS.getSourceRange().getBegin(); + + switch (NNS.getNestedNameSpecifier()->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: + break; + + case NestedNameSpecifier::Namespace: + handleReference(NNS.getNestedNameSpecifier()->getAsNamespace(), + Loc, Parent, DC, SymbolRoleSet()); + break; + case NestedNameSpecifier::NamespaceAlias: + handleReference(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(), + Loc, Parent, DC, SymbolRoleSet()); + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + indexTypeLoc(NNS.getTypeLoc(), Parent, DC); + break; + } +} + +void IndexingContext::indexTagDecl(const TagDecl *D) { + if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D)) + return; + + if (handleDecl(D)) { + if (D->isThisDeclarationADefinition()) { + indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); + if (auto CXXRD = dyn_cast<CXXRecordDecl>(D)) { + for (const auto &I : CXXRD->bases()) { + indexTypeSourceInfo(I.getTypeSourceInfo(), CXXRD, CXXRD, /*isBase=*/true); + } + } + indexDeclContext(D); + } + } +} diff --git a/contrib/llvm/tools/clang/lib/Index/IndexingAction.cpp b/contrib/llvm/tools/clang/lib/Index/IndexingAction.cpp new file mode 100644 index 000000000000..d7442931523f --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/IndexingAction.cpp @@ -0,0 +1,176 @@ +//===- IndexingAction.cpp - Frontend index action -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/IndexingAction.h" +#include "clang/Index/IndexDataConsumer.h" +#include "IndexingContext.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/MultiplexConsumer.h" +#include "clang/Lex/Preprocessor.h" + +using namespace clang; +using namespace clang::index; + +void IndexDataConsumer::_anchor() {} + +bool IndexDataConsumer::handleDeclOccurence(const Decl *D, SymbolRoleSet Roles, + ArrayRef<SymbolRelation> Relations, + FileID FID, unsigned Offset, + ASTNodeInfo ASTNode) { + return true; +} + +bool IndexDataConsumer::handleMacroOccurence(const IdentifierInfo *Name, + const MacroInfo *MI, SymbolRoleSet Roles, + FileID FID, unsigned Offset) { + return true; +} + +bool IndexDataConsumer::handleModuleOccurence(const ImportDecl *ImportD, + SymbolRoleSet Roles, + FileID FID, unsigned Offset) { + return true; +} + +namespace { + +class IndexASTConsumer : public ASTConsumer { + IndexingContext &IndexCtx; + +public: + IndexASTConsumer(IndexingContext &IndexCtx) + : IndexCtx(IndexCtx) {} + +protected: + void Initialize(ASTContext &Context) override { + IndexCtx.setASTContext(Context); + IndexCtx.getDataConsumer().initialize(Context); + } + + bool HandleTopLevelDecl(DeclGroupRef DG) override { + return IndexCtx.indexDeclGroupRef(DG); + } + + void HandleInterestingDecl(DeclGroupRef DG) override { + // Ignore deserialized decls. + } + + void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override { + IndexCtx.indexDeclGroupRef(DG); + } + + void HandleTranslationUnit(ASTContext &Ctx) override { + } +}; + +class IndexActionBase { +protected: + std::shared_ptr<IndexDataConsumer> DataConsumer; + IndexingContext IndexCtx; + + IndexActionBase(std::shared_ptr<IndexDataConsumer> dataConsumer, + IndexingOptions Opts) + : DataConsumer(std::move(dataConsumer)), + IndexCtx(Opts, *DataConsumer) {} + + std::unique_ptr<IndexASTConsumer> createIndexASTConsumer() { + return llvm::make_unique<IndexASTConsumer>(IndexCtx); + } + + void finish() { + DataConsumer->finish(); + } +}; + +class IndexAction : public ASTFrontendAction, IndexActionBase { +public: + IndexAction(std::shared_ptr<IndexDataConsumer> DataConsumer, + IndexingOptions Opts) + : IndexActionBase(std::move(DataConsumer), Opts) {} + +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override { + return createIndexASTConsumer(); + } + + void EndSourceFileAction() override { + FrontendAction::EndSourceFileAction(); + finish(); + } +}; + +class WrappingIndexAction : public WrapperFrontendAction, IndexActionBase { + bool IndexActionFailed = false; + +public: + WrappingIndexAction(std::unique_ptr<FrontendAction> WrappedAction, + std::shared_ptr<IndexDataConsumer> DataConsumer, + IndexingOptions Opts) + : WrapperFrontendAction(std::move(WrappedAction)), + IndexActionBase(std::move(DataConsumer), Opts) {} + +protected: + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + void EndSourceFileAction() override; +}; + +} // anonymous namespace + +void WrappingIndexAction::EndSourceFileAction() { + // Invoke wrapped action's method. + WrapperFrontendAction::EndSourceFileAction(); + if (!IndexActionFailed) + finish(); +} + +std::unique_ptr<ASTConsumer> +WrappingIndexAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { + auto OtherConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile); + if (!OtherConsumer) { + IndexActionFailed = true; + return nullptr; + } + + std::vector<std::unique_ptr<ASTConsumer>> Consumers; + Consumers.push_back(std::move(OtherConsumer)); + Consumers.push_back(createIndexASTConsumer()); + return llvm::make_unique<MultiplexConsumer>(std::move(Consumers)); +} + +std::unique_ptr<FrontendAction> +index::createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer, + IndexingOptions Opts, + std::unique_ptr<FrontendAction> WrappedAction) { + if (WrappedAction) + return llvm::make_unique<WrappingIndexAction>(std::move(WrappedAction), + std::move(DataConsumer), + Opts); + return llvm::make_unique<IndexAction>(std::move(DataConsumer), Opts); +} + + +static bool topLevelDeclVisitor(void *context, const Decl *D) { + IndexingContext &IndexCtx = *static_cast<IndexingContext*>(context); + return IndexCtx.indexTopLevelDecl(D); +} + +static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IndexCtx) { + Unit.visitLocalTopLevelDecls(&IndexCtx, topLevelDeclVisitor); +} + +void index::indexASTUnit(ASTUnit &Unit, + std::shared_ptr<IndexDataConsumer> DataConsumer, + IndexingOptions Opts) { + IndexingContext IndexCtx(Opts, *DataConsumer); + IndexCtx.setASTContext(Unit.getASTContext()); + DataConsumer->initialize(Unit.getASTContext()); + indexTranslationUnit(Unit, IndexCtx); +} diff --git a/contrib/llvm/tools/clang/lib/Index/IndexingContext.cpp b/contrib/llvm/tools/clang/lib/Index/IndexingContext.cpp new file mode 100644 index 000000000000..e623a495b47b --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/IndexingContext.cpp @@ -0,0 +1,326 @@ +//===- IndexingContext.cpp - Indexing context data ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "IndexingContext.h" +#include "clang/Index/IndexDataConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceManager.h" + +using namespace clang; +using namespace index; + +bool IndexingContext::shouldIndexFunctionLocalSymbols() const { + return IndexOpts.IndexFunctionLocals; +} + +bool IndexingContext::handleDecl(const Decl *D, + SymbolRoleSet Roles, + ArrayRef<SymbolRelation> Relations) { + return handleDeclOccurrence(D, D->getLocation(), /*IsRef=*/false, + cast<Decl>(D->getDeclContext()), Roles, Relations, + nullptr, nullptr, D->getDeclContext()); +} + +bool IndexingContext::handleDecl(const Decl *D, SourceLocation Loc, + SymbolRoleSet Roles, + ArrayRef<SymbolRelation> Relations, + const DeclContext *DC) { + if (!DC) + DC = D->getDeclContext(); + return handleDeclOccurrence(D, Loc, /*IsRef=*/false, cast<Decl>(DC), + Roles, Relations, + nullptr, nullptr, DC); +} + +bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc, + const NamedDecl *Parent, + const DeclContext *DC, + SymbolRoleSet Roles, + ArrayRef<SymbolRelation> Relations, + const Expr *RefE, + const Decl *RefD) { + if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D)) + return true; + + if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D)) + return true; + + return handleDeclOccurrence(D, Loc, /*IsRef=*/true, Parent, Roles, Relations, + RefE, RefD, DC); +} + +bool IndexingContext::importedModule(const ImportDecl *ImportD) { + SourceLocation Loc; + auto IdLocs = ImportD->getIdentifierLocs(); + if (!IdLocs.empty()) + Loc = IdLocs.front(); + else + Loc = ImportD->getLocation(); + SourceManager &SM = Ctx->getSourceManager(); + Loc = SM.getFileLoc(Loc); + if (Loc.isInvalid()) + return true; + + FileID FID; + unsigned Offset; + std::tie(FID, Offset) = SM.getDecomposedLoc(Loc); + if (FID.isInvalid()) + return true; + + bool Invalid = false; + const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); + if (Invalid || !SEntry.isFile()) + return true; + + if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) { + switch (IndexOpts.SystemSymbolFilter) { + case IndexingOptions::SystemSymbolFilterKind::None: + return true; + case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly: + case IndexingOptions::SystemSymbolFilterKind::All: + break; + } + } + + SymbolRoleSet Roles = (unsigned)SymbolRole::Declaration; + if (ImportD->isImplicit()) + Roles |= (unsigned)SymbolRole::Implicit; + + return DataConsumer.handleModuleOccurence(ImportD, Roles, FID, Offset); +} + +bool IndexingContext::isFunctionLocalDecl(const Decl *D) { + assert(D); + + if (isa<TemplateTemplateParmDecl>(D)) + return true; + + if (isa<ObjCTypeParamDecl>(D)) + return true; + + if (!D->getParentFunctionOrMethod()) + return false; + + if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { + switch (ND->getFormalLinkage()) { + case NoLinkage: + case VisibleNoLinkage: + case InternalLinkage: + return true; + case UniqueExternalLinkage: + llvm_unreachable("Not a sema linkage"); + case ExternalLinkage: + return false; + } + } + + return true; +} + +bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) { + TemplateSpecializationKind TKind = TSK_Undeclared; + if (const ClassTemplateSpecializationDecl * + SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + TKind = SD->getSpecializationKind(); + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + TKind = FD->getTemplateSpecializationKind(); + } else if (auto *VD = dyn_cast<VarDecl>(D)) { + TKind = VD->getTemplateSpecializationKind(); + } + switch (TKind) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + return false; + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + return true; + } + llvm_unreachable("invalid TemplateSpecializationKind"); +} + +bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) { + if (isa<ObjCInterfaceDecl>(D)) + return false; + if (isa<ObjCCategoryDecl>(D)) + return false; + if (isa<ObjCIvarDecl>(D)) + return false; + if (isa<ObjCMethodDecl>(D)) + return false; + if (isa<ImportDecl>(D)) + return false; + return true; +} + +static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) { + if (const ClassTemplateSpecializationDecl * + SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + return SD->getTemplateInstantiationPattern(); + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + return FD->getTemplateInstantiationPattern(); + } else if (auto *VD = dyn_cast<VarDecl>(D)) { + return VD->getTemplateInstantiationPattern(); + } + return nullptr; +} + +static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, ASTContext &Ctx) { + if (auto VD = dyn_cast<VarDecl>(D)) + return VD->isThisDeclarationADefinition(Ctx); + + if (auto FD = dyn_cast<FunctionDecl>(D)) + return FD->isThisDeclarationADefinition(); + + if (auto TD = dyn_cast<TagDecl>(D)) + return TD->isThisDeclarationADefinition(); + + if (auto MD = dyn_cast<ObjCMethodDecl>(D)) + return MD->isThisDeclarationADefinition() || isa<ObjCImplDecl>(ContainerDC); + + if (isa<TypedefNameDecl>(D) || + isa<EnumConstantDecl>(D) || + isa<FieldDecl>(D) || + isa<MSPropertyDecl>(D) || + isa<ObjCImplDecl>(D) || + isa<ObjCPropertyImplDecl>(D)) + return true; + + return false; +} + +static const Decl *adjustParent(const Decl *Parent) { + if (!Parent) + return nullptr; + for (;; Parent = cast<Decl>(Parent->getDeclContext())) { + if (isa<TranslationUnitDecl>(Parent)) + return nullptr; + if (isa<LinkageSpecDecl>(Parent) || isa<BlockDecl>(Parent)) + continue; + if (auto NS = dyn_cast<NamespaceDecl>(Parent)) { + if (NS->isAnonymousNamespace()) + continue; + } else if (auto RD = dyn_cast<RecordDecl>(Parent)) { + if (RD->isAnonymousStructOrUnion()) + continue; + } else if (auto FD = dyn_cast<FieldDecl>(Parent)) { + if (FD->getDeclName().isEmpty()) + continue; + } + return Parent; + } +} + +static const Decl *getCanonicalDecl(const Decl *D) { + D = D->getCanonicalDecl(); + if (auto TD = dyn_cast<TemplateDecl>(D)) { + D = TD->getTemplatedDecl(); + assert(D->isCanonicalDecl()); + } + + return D; +} + +bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc, + bool IsRef, const Decl *Parent, + SymbolRoleSet Roles, + ArrayRef<SymbolRelation> Relations, + const Expr *OrigE, + const Decl *OrigD, + const DeclContext *ContainerDC) { + if (D->isImplicit() && !isa<ObjCMethodDecl>(D)) + return true; + if (!isa<NamedDecl>(D) || + (cast<NamedDecl>(D)->getDeclName().isEmpty() && + !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D))) + return true; + + SourceManager &SM = Ctx->getSourceManager(); + Loc = SM.getFileLoc(Loc); + if (Loc.isInvalid()) + return true; + + FileID FID; + unsigned Offset; + std::tie(FID, Offset) = SM.getDecomposedLoc(Loc); + if (FID.isInvalid()) + return true; + + bool Invalid = false; + const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); + if (Invalid || !SEntry.isFile()) + return true; + + if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) { + switch (IndexOpts.SystemSymbolFilter) { + case IndexingOptions::SystemSymbolFilterKind::None: + return true; + case IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly: + if (IsRef) + return true; + break; + case IndexingOptions::SystemSymbolFilterKind::All: + break; + } + } + + if (isTemplateImplicitInstantiation(D)) { + if (!IsRef) + return true; + D = adjustTemplateImplicitInstantiation(D); + if (!D) + return true; + assert(!isTemplateImplicitInstantiation(D)); + } + + if (!OrigD) + OrigD = D; + + if (IsRef) + Roles |= (unsigned)SymbolRole::Reference; + else if (isDeclADefinition(D, ContainerDC, *Ctx)) + Roles |= (unsigned)SymbolRole::Definition; + else + Roles |= (unsigned)SymbolRole::Declaration; + + D = getCanonicalDecl(D); + Parent = adjustParent(Parent); + if (Parent) + Parent = getCanonicalDecl(Parent); + + SmallVector<SymbolRelation, 6> FinalRelations; + FinalRelations.reserve(Relations.size()+1); + + auto addRelation = [&](SymbolRelation Rel) { + auto It = std::find_if(FinalRelations.begin(), FinalRelations.end(), + [&](SymbolRelation Elem)->bool { + return Elem.RelatedSymbol == Rel.RelatedSymbol; + }); + if (It != FinalRelations.end()) { + It->Roles |= Rel.Roles; + } else { + FinalRelations.push_back(Rel); + } + Roles |= Rel.Roles; + }; + + if (!IsRef && Parent && !cast<DeclContext>(Parent)->isFunctionOrMethod()) { + addRelation(SymbolRelation{(unsigned)SymbolRole::RelationChildOf, Parent}); + } + for (auto &Rel : Relations) { + addRelation(SymbolRelation(Rel.Roles, + Rel.RelatedSymbol->getCanonicalDecl())); + } + + IndexDataConsumer::ASTNodeInfo Node{ OrigE, OrigD, Parent, ContainerDC }; + return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, FID, Offset, + Node); +} diff --git a/contrib/llvm/tools/clang/lib/Index/IndexingContext.h b/contrib/llvm/tools/clang/lib/Index/IndexingContext.h new file mode 100644 index 000000000000..600fc433b58d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/IndexingContext.h @@ -0,0 +1,121 @@ +//===- IndexingContext.h - Indexing context data ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_INDEX_INDEXINGCONTEXT_H +#define LLVM_CLANG_LIB_INDEX_INDEXINGCONTEXT_H + +#include "clang/Basic/LLVM.h" +#include "clang/Index/IndexSymbol.h" +#include "clang/Index/IndexingAction.h" +#include "llvm/ADT/ArrayRef.h" + +namespace clang { + class ASTContext; + class Decl; + class DeclGroupRef; + class ImportDecl; + class TagDecl; + class TypeSourceInfo; + class NamedDecl; + class ObjCMethodDecl; + class DeclContext; + class NestedNameSpecifierLoc; + class Stmt; + class Expr; + class TypeLoc; + class SourceLocation; + +namespace index { + class IndexDataConsumer; + +class IndexingContext { + IndexingOptions IndexOpts; + IndexDataConsumer &DataConsumer; + ASTContext *Ctx = nullptr; + +public: + IndexingContext(IndexingOptions IndexOpts, IndexDataConsumer &DataConsumer) + : IndexOpts(IndexOpts), DataConsumer(DataConsumer) {} + + const IndexingOptions &getIndexOpts() const { return IndexOpts; } + IndexDataConsumer &getDataConsumer() { return DataConsumer; } + + void setASTContext(ASTContext &ctx) { Ctx = &ctx; } + + bool shouldSuppressRefs() const { + return false; + } + + bool shouldIndexFunctionLocalSymbols() const; + + bool shouldIndexImplicitTemplateInsts() const { + return false; + } + + static bool isFunctionLocalDecl(const Decl *D); + static bool isTemplateImplicitInstantiation(const Decl *D); + + bool handleDecl(const Decl *D, SymbolRoleSet Roles = SymbolRoleSet(), + ArrayRef<SymbolRelation> Relations = None); + + bool handleDecl(const Decl *D, SourceLocation Loc, + SymbolRoleSet Roles = SymbolRoleSet(), + ArrayRef<SymbolRelation> Relations = None, + const DeclContext *DC = nullptr); + + bool handleReference(const NamedDecl *D, SourceLocation Loc, + const NamedDecl *Parent, + const DeclContext *DC, + SymbolRoleSet Roles, + ArrayRef<SymbolRelation> Relations = None, + const Expr *RefE = nullptr, + const Decl *RefD = nullptr); + + bool importedModule(const ImportDecl *ImportD); + + bool indexDecl(const Decl *D); + + void indexTagDecl(const TagDecl *D); + + void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent, + const DeclContext *DC = nullptr, + bool isBase = false); + + void indexTypeLoc(TypeLoc TL, const NamedDecl *Parent, + const DeclContext *DC = nullptr, + bool isBase = false); + + void indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, + const NamedDecl *Parent, + const DeclContext *DC = nullptr); + + bool indexDeclContext(const DeclContext *DC); + + void indexBody(const Stmt *S, const NamedDecl *Parent, + const DeclContext *DC = nullptr); + + bool indexTopLevelDecl(const Decl *D); + bool indexDeclGroupRef(DeclGroupRef DG); + +private: + bool shouldIgnoreIfImplicit(const Decl *D); + + bool handleDeclOccurrence(const Decl *D, SourceLocation Loc, + bool IsRef, const Decl *Parent, + SymbolRoleSet Roles, + ArrayRef<SymbolRelation> Relations, + const Expr *RefE, + const Decl *RefD, + const DeclContext *ContainerDC); +}; + +} // end namespace index +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/lib/Index/SimpleFormatContext.h b/contrib/llvm/tools/clang/lib/Index/SimpleFormatContext.h new file mode 100644 index 000000000000..2c26e4d82e08 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/SimpleFormatContext.h @@ -0,0 +1,75 @@ +//===--- SimpleFormatContext.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file +/// +/// \brief Defines a utility class for use of clang-format in libclang +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_INDEX_SIMPLEFORMATCONTEXT_H +#define LLVM_CLANG_LIB_INDEX_SIMPLEFORMATCONTEXT_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { +namespace index { + +/// \brief A small class to be used by libclang clients to format +/// a declaration string in memory. This object is instantiated once +/// and used each time a formatting is needed. +class SimpleFormatContext { +public: + SimpleFormatContext(LangOptions Options) + : DiagOpts(new DiagnosticOptions()), + Diagnostics(new DiagnosticsEngine(new DiagnosticIDs, + DiagOpts.get())), + InMemoryFileSystem(new vfs::InMemoryFileSystem), + Files(FileSystemOptions(), InMemoryFileSystem), + Sources(*Diagnostics, Files), + Rewrite(Sources, Options) { + Diagnostics->setClient(new IgnoringDiagConsumer, true); + } + + FileID createInMemoryFile(StringRef Name, StringRef Content) { + InMemoryFileSystem->addFile(Name, 0, + llvm::MemoryBuffer::getMemBuffer(Content)); + const FileEntry *Entry = Files.getFile(Name); + assert(Entry != nullptr); + return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User); + } + + std::string getRewrittenText(FileID ID) { + std::string Result; + llvm::raw_string_ostream OS(Result); + Rewrite.getEditBuffer(ID).write(OS); + OS.flush(); + return Result; + } + + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; + IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics; + IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem; + FileManager Files; + SourceManager Sources; + Rewriter Rewrite; +}; + +} // end namespace index +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp b/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp new file mode 100644 index 000000000000..58f61c3c65b7 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/USRGeneration.cpp @@ -0,0 +1,931 @@ +//===- USRGeneration.cpp - Routines for USR generation --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/USRGeneration.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace clang::index; + +//===----------------------------------------------------------------------===// +// USR generation. +//===----------------------------------------------------------------------===// + +/// \returns true on error. +static bool printLoc(llvm::raw_ostream &OS, SourceLocation Loc, + const SourceManager &SM, bool IncludeOffset) { + if (Loc.isInvalid()) { + return true; + } + Loc = SM.getExpansionLoc(Loc); + const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(Loc); + const FileEntry *FE = SM.getFileEntryForID(Decomposed.first); + if (FE) { + OS << llvm::sys::path::filename(FE->getName()); + } else { + // This case really isn't interesting. + return true; + } + if (IncludeOffset) { + // Use the offest into the FileID to represent the location. Using + // a line/column can cause us to look back at the original source file, + // which is expensive. + OS << '@' << Decomposed.second; + } + return false; +} + +namespace { +class USRGenerator : public ConstDeclVisitor<USRGenerator> { + SmallVectorImpl<char> &Buf; + llvm::raw_svector_ostream Out; + bool IgnoreResults; + ASTContext *Context; + bool generatedLoc; + + llvm::DenseMap<const Type *, unsigned> TypeSubstitutions; + +public: + explicit USRGenerator(ASTContext *Ctx, SmallVectorImpl<char> &Buf) + : Buf(Buf), + Out(Buf), + IgnoreResults(false), + Context(Ctx), + generatedLoc(false) + { + // Add the USR space prefix. + Out << getUSRSpacePrefix(); + } + + bool ignoreResults() const { return IgnoreResults; } + + // Visitation methods from generating USRs from AST elements. + void VisitDeclContext(const DeclContext *D); + void VisitFieldDecl(const FieldDecl *D); + void VisitFunctionDecl(const FunctionDecl *D); + void VisitNamedDecl(const NamedDecl *D); + void VisitNamespaceDecl(const NamespaceDecl *D); + void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D); + void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D); + void VisitClassTemplateDecl(const ClassTemplateDecl *D); + void VisitObjCContainerDecl(const ObjCContainerDecl *CD); + void VisitObjCMethodDecl(const ObjCMethodDecl *MD); + void VisitObjCPropertyDecl(const ObjCPropertyDecl *D); + void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D); + void VisitTagDecl(const TagDecl *D); + void VisitTypedefDecl(const TypedefDecl *D); + void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D); + void VisitVarDecl(const VarDecl *D); + void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D); + void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D); + + void VisitLinkageSpecDecl(const LinkageSpecDecl *D) { + IgnoreResults = true; + } + + void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { + IgnoreResults = true; + } + + void VisitUsingDecl(const UsingDecl *D) { + IgnoreResults = true; + } + + void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { + IgnoreResults = true; + } + + void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) { + IgnoreResults = true; + } + + bool ShouldGenerateLocation(const NamedDecl *D); + + bool isLocal(const NamedDecl *D) { + return D->getParentFunctionOrMethod() != nullptr; + } + + /// Generate the string component containing the location of the + /// declaration. + bool GenLoc(const Decl *D, bool IncludeOffset); + + /// String generation methods used both by the visitation methods + /// and from other clients that want to directly generate USRs. These + /// methods do not construct complete USRs (which incorporate the parents + /// of an AST element), but only the fragments concerning the AST element + /// itself. + + /// Generate a USR for an Objective-C class. + void GenObjCClass(StringRef cls) { + generateUSRForObjCClass(cls, Out); + } + + /// Generate a USR for an Objective-C class category. + void GenObjCCategory(StringRef cls, StringRef cat) { + generateUSRForObjCCategory(cls, cat, Out); + } + + /// Generate a USR fragment for an Objective-C property. + void GenObjCProperty(StringRef prop, bool isClassProp) { + generateUSRForObjCProperty(prop, isClassProp, Out); + } + + /// Generate a USR for an Objective-C protocol. + void GenObjCProtocol(StringRef prot) { + generateUSRForObjCProtocol(prot, Out); + } + + void VisitType(QualType T); + void VisitTemplateParameterList(const TemplateParameterList *Params); + void VisitTemplateName(TemplateName Name); + void VisitTemplateArgument(const TemplateArgument &Arg); + + /// Emit a Decl's name using NamedDecl::printName() and return true if + /// the decl had no name. + bool EmitDeclName(const NamedDecl *D); +}; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Generating USRs from ASTS. +//===----------------------------------------------------------------------===// + +bool USRGenerator::EmitDeclName(const NamedDecl *D) { + const unsigned startSize = Buf.size(); + D->printName(Out); + const unsigned endSize = Buf.size(); + return startSize == endSize; +} + +bool USRGenerator::ShouldGenerateLocation(const NamedDecl *D) { + if (D->isExternallyVisible()) + return false; + if (D->getParentFunctionOrMethod()) + return true; + SourceLocation Loc = D->getLocation(); + if (Loc.isInvalid()) + return false; + const SourceManager &SM = Context->getSourceManager(); + return !SM.isInSystemHeader(Loc); +} + +void USRGenerator::VisitDeclContext(const DeclContext *DC) { + if (const NamedDecl *D = dyn_cast<NamedDecl>(DC)) + Visit(D); +} + +void USRGenerator::VisitFieldDecl(const FieldDecl *D) { + // The USR for an ivar declared in a class extension is based on the + // ObjCInterfaceDecl, not the ObjCCategoryDecl. + if (const ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D)) + Visit(ID); + else + VisitDeclContext(D->getDeclContext()); + Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@"); + if (EmitDeclName(D)) { + // Bit fields can be anonymous. + IgnoreResults = true; + return; + } +} + +void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) { + if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D))) + return; + + VisitDeclContext(D->getDeclContext()); + bool IsTemplate = false; + if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) { + IsTemplate = true; + Out << "@FT@"; + VisitTemplateParameterList(FunTmpl->getTemplateParameters()); + } else + Out << "@F@"; + + PrintingPolicy Policy(Context->getLangOpts()); + // Forward references can have different template argument names. Suppress the + // template argument names in constructors to make their USR more stable. + Policy.SuppressTemplateArgsInCXXConstructors = true; + D->getDeclName().print(Out, Policy); + + ASTContext &Ctx = *Context; + if ((!Ctx.getLangOpts().CPlusPlus || D->isExternC()) && + !D->hasAttr<OverloadableAttr>()) + return; + + if (const TemplateArgumentList * + SpecArgs = D->getTemplateSpecializationArgs()) { + Out << '<'; + for (unsigned I = 0, N = SpecArgs->size(); I != N; ++I) { + Out << '#'; + VisitTemplateArgument(SpecArgs->get(I)); + } + Out << '>'; + } + + // Mangle in type information for the arguments. + for (auto PD : D->parameters()) { + Out << '#'; + VisitType(PD->getType()); + } + if (D->isVariadic()) + Out << '.'; + if (IsTemplate) { + // Function templates can be overloaded by return type, for example: + // \code + // template <class T> typename T::A foo() {} + // template <class T> typename T::B foo() {} + // \endcode + Out << '#'; + VisitType(D->getReturnType()); + } + Out << '#'; + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { + if (MD->isStatic()) + Out << 'S'; + if (unsigned quals = MD->getTypeQualifiers()) + Out << (char)('0' + quals); + switch (MD->getRefQualifier()) { + case RQ_None: break; + case RQ_LValue: Out << '&'; break; + case RQ_RValue: Out << "&&"; break; + } + } +} + +void USRGenerator::VisitNamedDecl(const NamedDecl *D) { + VisitDeclContext(D->getDeclContext()); + Out << "@"; + + if (EmitDeclName(D)) { + // The string can be empty if the declaration has no name; e.g., it is + // the ParmDecl with no name for declaration of a function pointer type, + // e.g.: void (*f)(void *); + // In this case, don't generate a USR. + IgnoreResults = true; + } +} + +void USRGenerator::VisitVarDecl(const VarDecl *D) { + // VarDecls can be declared 'extern' within a function or method body, + // but their enclosing DeclContext is the function, not the TU. We need + // to check the storage class to correctly generate the USR. + if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D))) + return; + + VisitDeclContext(D->getDeclContext()); + + if (VarTemplateDecl *VarTmpl = D->getDescribedVarTemplate()) { + Out << "@VT"; + VisitTemplateParameterList(VarTmpl->getTemplateParameters()); + } else if (const VarTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<VarTemplatePartialSpecializationDecl>(D)) { + Out << "@VP"; + VisitTemplateParameterList(PartialSpec->getTemplateParameters()); + } + + // Variables always have simple names. + StringRef s = D->getName(); + + // The string can be empty if the declaration has no name; e.g., it is + // the ParmDecl with no name for declaration of a function pointer type, e.g.: + // void (*f)(void *); + // In this case, don't generate a USR. + if (s.empty()) + IgnoreResults = true; + else + Out << '@' << s; + + // For a template specialization, mangle the template arguments. + if (const VarTemplateSpecializationDecl *Spec + = dyn_cast<VarTemplateSpecializationDecl>(D)) { + const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs(); + Out << '>'; + for (unsigned I = 0, N = Args.size(); I != N; ++I) { + Out << '#'; + VisitTemplateArgument(Args.get(I)); + } + } +} + +void USRGenerator::VisitNonTypeTemplateParmDecl( + const NonTypeTemplateParmDecl *D) { + GenLoc(D, /*IncludeOffset=*/true); +} + +void USRGenerator::VisitTemplateTemplateParmDecl( + const TemplateTemplateParmDecl *D) { + GenLoc(D, /*IncludeOffset=*/true); +} + +void USRGenerator::VisitNamespaceDecl(const NamespaceDecl *D) { + if (D->isAnonymousNamespace()) { + Out << "@aN"; + return; + } + + VisitDeclContext(D->getDeclContext()); + if (!IgnoreResults) + Out << "@N@" << D->getName(); +} + +void USRGenerator::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { + VisitFunctionDecl(D->getTemplatedDecl()); +} + +void USRGenerator::VisitClassTemplateDecl(const ClassTemplateDecl *D) { + VisitTagDecl(D->getTemplatedDecl()); +} + +void USRGenerator::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) { + VisitDeclContext(D->getDeclContext()); + if (!IgnoreResults) + Out << "@NA@" << D->getName(); +} + +void USRGenerator::VisitObjCMethodDecl(const ObjCMethodDecl *D) { + const DeclContext *container = D->getDeclContext(); + if (const ObjCProtocolDecl *pd = dyn_cast<ObjCProtocolDecl>(container)) { + Visit(pd); + } + else { + // The USR for a method declared in a class extension or category is based on + // the ObjCInterfaceDecl, not the ObjCCategoryDecl. + const ObjCInterfaceDecl *ID = D->getClassInterface(); + if (!ID) { + IgnoreResults = true; + return; + } + Visit(ID); + } + // Ideally we would use 'GenObjCMethod', but this is such a hot path + // for Objective-C code that we don't want to use + // DeclarationName::getAsString(). + Out << (D->isInstanceMethod() ? "(im)" : "(cm)") + << DeclarationName(D->getSelector()); +} + +void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D) { + switch (D->getKind()) { + default: + llvm_unreachable("Invalid ObjC container."); + case Decl::ObjCInterface: + case Decl::ObjCImplementation: + GenObjCClass(D->getName()); + break; + case Decl::ObjCCategory: { + const ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D); + const ObjCInterfaceDecl *ID = CD->getClassInterface(); + if (!ID) { + // Handle invalid code where the @interface might not + // have been specified. + // FIXME: We should be able to generate this USR even if the + // @interface isn't available. + IgnoreResults = true; + return; + } + // Specially handle class extensions, which are anonymous categories. + // We want to mangle in the location to uniquely distinguish them. + if (CD->IsClassExtension()) { + Out << "objc(ext)" << ID->getName() << '@'; + GenLoc(CD, /*IncludeOffset=*/true); + } + else + GenObjCCategory(ID->getName(), CD->getName()); + + break; + } + case Decl::ObjCCategoryImpl: { + const ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D); + const ObjCInterfaceDecl *ID = CD->getClassInterface(); + if (!ID) { + // Handle invalid code where the @interface might not + // have been specified. + // FIXME: We should be able to generate this USR even if the + // @interface isn't available. + IgnoreResults = true; + return; + } + GenObjCCategory(ID->getName(), CD->getName()); + break; + } + case Decl::ObjCProtocol: + GenObjCProtocol(cast<ObjCProtocolDecl>(D)->getName()); + break; + } +} + +void USRGenerator::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { + // The USR for a property declared in a class extension or category is based + // on the ObjCInterfaceDecl, not the ObjCCategoryDecl. + if (const ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D)) + Visit(ID); + else + Visit(cast<Decl>(D->getDeclContext())); + GenObjCProperty(D->getName(), D->isClassProperty()); +} + +void USRGenerator::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { + if (ObjCPropertyDecl *PD = D->getPropertyDecl()) { + VisitObjCPropertyDecl(PD); + return; + } + + IgnoreResults = true; +} + +void USRGenerator::VisitTagDecl(const TagDecl *D) { + // Add the location of the tag decl to handle resolution across + // translation units. + if (!isa<EnumDecl>(D) && + ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D))) + return; + + D = D->getCanonicalDecl(); + VisitDeclContext(D->getDeclContext()); + + bool AlreadyStarted = false; + if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) { + if (ClassTemplateDecl *ClassTmpl = CXXRecord->getDescribedClassTemplate()) { + AlreadyStarted = true; + + switch (D->getTagKind()) { + case TTK_Interface: + case TTK_Class: + case TTK_Struct: Out << "@ST"; break; + case TTK_Union: Out << "@UT"; break; + case TTK_Enum: llvm_unreachable("enum template"); + } + VisitTemplateParameterList(ClassTmpl->getTemplateParameters()); + } else if (const ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) { + AlreadyStarted = true; + + switch (D->getTagKind()) { + case TTK_Interface: + case TTK_Class: + case TTK_Struct: Out << "@SP"; break; + case TTK_Union: Out << "@UP"; break; + case TTK_Enum: llvm_unreachable("enum partial specialization"); + } + VisitTemplateParameterList(PartialSpec->getTemplateParameters()); + } + } + + if (!AlreadyStarted) { + switch (D->getTagKind()) { + case TTK_Interface: + case TTK_Class: + case TTK_Struct: Out << "@S"; break; + case TTK_Union: Out << "@U"; break; + case TTK_Enum: Out << "@E"; break; + } + } + + Out << '@'; + assert(Buf.size() > 0); + const unsigned off = Buf.size() - 1; + + if (EmitDeclName(D)) { + if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl()) { + Buf[off] = 'A'; + Out << '@' << *TD; + } + else { + if (D->isEmbeddedInDeclarator() && !D->isFreeStanding()) { + printLoc(Out, D->getLocation(), Context->getSourceManager(), true); + } else { + Buf[off] = 'a'; + if (auto *ED = dyn_cast<EnumDecl>(D)) { + // Distinguish USRs of anonymous enums by using their first enumerator. + auto enum_range = ED->enumerators(); + if (enum_range.begin() != enum_range.end()) { + Out << '@' << **enum_range.begin(); + } + } + } + } + } + + // For a class template specialization, mangle the template arguments. + if (const ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs(); + Out << '>'; + for (unsigned I = 0, N = Args.size(); I != N; ++I) { + Out << '#'; + VisitTemplateArgument(Args.get(I)); + } + } +} + +void USRGenerator::VisitTypedefDecl(const TypedefDecl *D) { + if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D))) + return; + const DeclContext *DC = D->getDeclContext(); + if (const NamedDecl *DCN = dyn_cast<NamedDecl>(DC)) + Visit(DCN); + Out << "@T@"; + Out << D->getName(); +} + +void USRGenerator::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { + GenLoc(D, /*IncludeOffset=*/true); +} + +bool USRGenerator::GenLoc(const Decl *D, bool IncludeOffset) { + if (generatedLoc) + return IgnoreResults; + generatedLoc = true; + + // Guard against null declarations in invalid code. + if (!D) { + IgnoreResults = true; + return true; + } + + // Use the location of canonical decl. + D = D->getCanonicalDecl(); + + IgnoreResults = + IgnoreResults || printLoc(Out, D->getLocStart(), + Context->getSourceManager(), IncludeOffset); + + return IgnoreResults; +} + +void USRGenerator::VisitType(QualType T) { + // This method mangles in USR information for types. It can possibly + // just reuse the naming-mangling logic used by codegen, although the + // requirements for USRs might not be the same. + ASTContext &Ctx = *Context; + + do { + T = Ctx.getCanonicalType(T); + Qualifiers Q = T.getQualifiers(); + unsigned qVal = 0; + if (Q.hasConst()) + qVal |= 0x1; + if (Q.hasVolatile()) + qVal |= 0x2; + if (Q.hasRestrict()) + qVal |= 0x4; + if(qVal) + Out << ((char) ('0' + qVal)); + + // Mangle in ObjC GC qualifiers? + + if (const PackExpansionType *Expansion = T->getAs<PackExpansionType>()) { + Out << 'P'; + T = Expansion->getPattern(); + } + + if (const BuiltinType *BT = T->getAs<BuiltinType>()) { + unsigned char c = '\0'; + switch (BT->getKind()) { + case BuiltinType::Void: + c = 'v'; break; + case BuiltinType::Bool: + c = 'b'; break; + case BuiltinType::UChar: + c = 'c'; break; + case BuiltinType::Char16: + c = 'q'; break; + case BuiltinType::Char32: + c = 'w'; break; + case BuiltinType::UShort: + c = 's'; break; + case BuiltinType::UInt: + c = 'i'; break; + case BuiltinType::ULong: + c = 'l'; break; + case BuiltinType::ULongLong: + c = 'k'; break; + case BuiltinType::UInt128: + c = 'j'; break; + case BuiltinType::Char_U: + case BuiltinType::Char_S: + c = 'C'; break; + case BuiltinType::SChar: + c = 'r'; break; + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + c = 'W'; break; + case BuiltinType::Short: + c = 'S'; break; + case BuiltinType::Int: + c = 'I'; break; + case BuiltinType::Long: + c = 'L'; break; + case BuiltinType::LongLong: + c = 'K'; break; + case BuiltinType::Int128: + c = 'J'; break; + case BuiltinType::Half: + c = 'h'; break; + case BuiltinType::Float: + c = 'f'; break; + case BuiltinType::Double: + c = 'd'; break; + case BuiltinType::LongDouble: + c = 'D'; break; + case BuiltinType::Float128: + c = 'Q'; break; + case BuiltinType::NullPtr: + c = 'n'; break; +#define BUILTIN_TYPE(Id, SingletonId) +#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id: +#include "clang/AST/BuiltinTypes.def" + case BuiltinType::Dependent: +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + case BuiltinType::Id: +#include "clang/Basic/OpenCLImageTypes.def" + case BuiltinType::OCLEvent: + case BuiltinType::OCLClkEvent: + case BuiltinType::OCLQueue: + case BuiltinType::OCLNDRange: + case BuiltinType::OCLReserveID: + case BuiltinType::OCLSampler: + IgnoreResults = true; + return; + case BuiltinType::ObjCId: + c = 'o'; break; + case BuiltinType::ObjCClass: + c = 'O'; break; + case BuiltinType::ObjCSel: + c = 'e'; break; + } + Out << c; + return; + } + + // If we have already seen this (non-built-in) type, use a substitution + // encoding. + llvm::DenseMap<const Type *, unsigned>::iterator Substitution + = TypeSubstitutions.find(T.getTypePtr()); + if (Substitution != TypeSubstitutions.end()) { + Out << 'S' << Substitution->second << '_'; + return; + } else { + // Record this as a substitution. + unsigned Number = TypeSubstitutions.size(); + TypeSubstitutions[T.getTypePtr()] = Number; + } + + if (const PointerType *PT = T->getAs<PointerType>()) { + Out << '*'; + T = PT->getPointeeType(); + continue; + } + if (const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>()) { + Out << '*'; + T = OPT->getPointeeType(); + continue; + } + if (const RValueReferenceType *RT = T->getAs<RValueReferenceType>()) { + Out << "&&"; + T = RT->getPointeeType(); + continue; + } + if (const ReferenceType *RT = T->getAs<ReferenceType>()) { + Out << '&'; + T = RT->getPointeeType(); + continue; + } + if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) { + Out << 'F'; + VisitType(FT->getReturnType()); + for (const auto &I : FT->param_types()) + VisitType(I); + if (FT->isVariadic()) + Out << '.'; + return; + } + if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) { + Out << 'B'; + T = BT->getPointeeType(); + continue; + } + if (const ComplexType *CT = T->getAs<ComplexType>()) { + Out << '<'; + T = CT->getElementType(); + continue; + } + if (const TagType *TT = T->getAs<TagType>()) { + Out << '$'; + VisitTagDecl(TT->getDecl()); + return; + } + if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) { + Out << '$'; + VisitObjCInterfaceDecl(OIT->getDecl()); + return; + } + if (const ObjCObjectType *OIT = T->getAs<ObjCObjectType>()) { + Out << 'Q'; + VisitType(OIT->getBaseType()); + for (auto *Prot : OIT->getProtocols()) + VisitObjCProtocolDecl(Prot); + return; + } + if (const TemplateTypeParmType *TTP = T->getAs<TemplateTypeParmType>()) { + Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); + return; + } + if (const TemplateSpecializationType *Spec + = T->getAs<TemplateSpecializationType>()) { + Out << '>'; + VisitTemplateName(Spec->getTemplateName()); + Out << Spec->getNumArgs(); + for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) + VisitTemplateArgument(Spec->getArg(I)); + return; + } + if (const DependentNameType *DNT = T->getAs<DependentNameType>()) { + Out << '^'; + // FIXME: Encode the qualifier, don't just print it. + PrintingPolicy PO(Ctx.getLangOpts()); + PO.SuppressTagKeyword = true; + PO.SuppressUnwrittenScope = true; + PO.ConstantArraySizeAsWritten = false; + PO.AnonymousTagLocations = false; + DNT->getQualifier()->print(Out, PO); + Out << ':' << DNT->getIdentifier()->getName(); + return; + } + if (const InjectedClassNameType *InjT = T->getAs<InjectedClassNameType>()) { + T = InjT->getInjectedSpecializationType(); + continue; + } + + // Unhandled type. + Out << ' '; + break; + } while (true); +} + +void USRGenerator::VisitTemplateParameterList( + const TemplateParameterList *Params) { + if (!Params) + return; + Out << '>' << Params->size(); + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + Out << '#'; + if (isa<TemplateTypeParmDecl>(*P)) { + if (cast<TemplateTypeParmDecl>(*P)->isParameterPack()) + Out<< 'p'; + Out << 'T'; + continue; + } + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + if (NTTP->isParameterPack()) + Out << 'p'; + Out << 'N'; + VisitType(NTTP->getType()); + continue; + } + + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P); + if (TTP->isParameterPack()) + Out << 'p'; + Out << 't'; + VisitTemplateParameterList(TTP->getTemplateParameters()); + } +} + +void USRGenerator::VisitTemplateName(TemplateName Name) { + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(Template)) { + Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); + return; + } + + Visit(Template); + return; + } + + // FIXME: Visit dependent template names. +} + +void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + break; + + case TemplateArgument::Declaration: + Visit(Arg.getAsDecl()); + break; + + case TemplateArgument::NullPtr: + break; + + case TemplateArgument::TemplateExpansion: + Out << 'P'; // pack expansion of... + // Fall through + case TemplateArgument::Template: + VisitTemplateName(Arg.getAsTemplateOrTemplatePattern()); + break; + + case TemplateArgument::Expression: + // FIXME: Visit expressions. + break; + + case TemplateArgument::Pack: + Out << 'p' << Arg.pack_size(); + for (const auto &P : Arg.pack_elements()) + VisitTemplateArgument(P); + break; + + case TemplateArgument::Type: + VisitType(Arg.getAsType()); + break; + + case TemplateArgument::Integral: + Out << 'V'; + VisitType(Arg.getIntegralType()); + Out << Arg.getAsIntegral(); + break; + } +} + +//===----------------------------------------------------------------------===// +// USR generation functions. +//===----------------------------------------------------------------------===// + +void clang::index::generateUSRForObjCClass(StringRef Cls, raw_ostream &OS) { + OS << "objc(cs)" << Cls; +} + +void clang::index::generateUSRForObjCCategory(StringRef Cls, StringRef Cat, + raw_ostream &OS) { + OS << "objc(cy)" << Cls << '@' << Cat; +} + +void clang::index::generateUSRForObjCIvar(StringRef Ivar, raw_ostream &OS) { + OS << '@' << Ivar; +} + +void clang::index::generateUSRForObjCMethod(StringRef Sel, + bool IsInstanceMethod, + raw_ostream &OS) { + OS << (IsInstanceMethod ? "(im)" : "(cm)") << Sel; +} + +void clang::index::generateUSRForObjCProperty(StringRef Prop, bool isClassProp, + raw_ostream &OS) { + OS << (isClassProp ? "(cpy)" : "(py)") << Prop; +} + +void clang::index::generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS) { + OS << "objc(pl)" << Prot; +} + +bool clang::index::generateUSRForDecl(const Decl *D, + SmallVectorImpl<char> &Buf) { + if (!D) + return true; + // We don't ignore decls with invalid source locations. Implicit decls, like + // C++'s operator new function, can have invalid locations but it is fine to + // create USRs that can identify them. + + USRGenerator UG(&D->getASTContext(), Buf); + UG.Visit(D); + return UG.ignoreResults(); +} + +bool clang::index::generateUSRForMacro(const MacroDefinitionRecord *MD, + const SourceManager &SM, + SmallVectorImpl<char> &Buf) { + // Don't generate USRs for things with invalid locations. + if (!MD || MD->getLocation().isInvalid()) + return true; + + llvm::raw_svector_ostream Out(Buf); + + // Assume that system headers are sane. Don't put source location + // information into the USR if the macro comes from a system header. + SourceLocation Loc = MD->getLocation(); + bool ShouldGenerateLocation = !SM.isInSystemHeader(Loc); + + Out << getUSRSpacePrefix(); + if (ShouldGenerateLocation) + printLoc(Out, Loc, SM, /*IncludeOffset=*/true); + Out << "@macro@"; + Out << MD->getName()->getName(); + return false; +} |
